blob: b152829ae833ebaec8e1d745cf4312c3f5c41b97 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2008 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/urlencode.h"
12
13#include "webrtc/base/common.h"
14#include "webrtc/base/stringutils.h"
15
16static int HexPairValue(const char * code) {
17 int value = 0;
18 const char * pch = code;
19 for (;;) {
20 int digit = *pch++;
21 if (digit >= '0' && digit <= '9') {
22 value += digit - '0';
23 }
24 else if (digit >= 'A' && digit <= 'F') {
25 value += digit - 'A' + 10;
26 }
27 else if (digit >= 'a' && digit <= 'f') {
28 value += digit - 'a' + 10;
29 }
30 else {
31 return -1;
32 }
33 if (pch == code + 2)
34 return value;
35 value <<= 4;
36 }
37}
38
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +000039static int InternalUrlDecode(const char *source, char *dest,
40 bool encode_space_as_plus) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041 char * start = dest;
42
43 while (*source) {
44 switch (*source) {
45 case '+':
46 if (encode_space_as_plus) {
47 *(dest++) = ' ';
48 } else {
49 *dest++ = *source;
50 }
51 break;
52 case '%':
53 if (source[1] && source[2]) {
54 int value = HexPairValue(source + 1);
55 if (value >= 0) {
56 *(dest++) = value;
57 source += 2;
58 }
59 else {
60 *dest++ = '?';
61 }
62 }
63 else {
64 *dest++ = '?';
65 }
66 break;
67 default:
68 *dest++ = *source;
69 }
70 source++;
71 }
72
73 *dest = 0;
74 return static_cast<int>(dest - start);
75}
76
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +000077static bool IsValidUrlChar(char ch, bool unsafe_only) {
78 if (unsafe_only) {
79 return !(ch <= ' ' || strchr("\\\"^&`<>[]{}", ch));
80 } else {
81 return isalnum(ch) || strchr("-_.!~*'()", ch);
82 }
83}
84
85namespace rtc {
86
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087int UrlDecode(const char *source, char *dest) {
88 return InternalUrlDecode(source, dest, true);
89}
90
91int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest) {
92 return InternalUrlDecode(source, dest, false);
93}
94
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095int InternalUrlEncode(const char *source, char *dest, unsigned int max,
96 bool encode_space_as_plus, bool unsafe_only) {
97 static const char *digits = "0123456789ABCDEF";
98 if (max == 0) {
99 return 0;
100 }
101
102 char *start = dest;
103 while (static_cast<unsigned>(dest - start) < max && *source) {
104 unsigned char ch = static_cast<unsigned char>(*source);
105 if (*source == ' ' && encode_space_as_plus && !unsafe_only) {
106 *dest++ = '+';
107 } else if (IsValidUrlChar(ch, unsafe_only)) {
108 *dest++ = *source;
109 } else {
110 if (static_cast<unsigned>(dest - start) + 4 > max) {
111 break;
112 }
113 *dest++ = '%';
114 *dest++ = digits[(ch >> 4) & 0x0F];
115 *dest++ = digits[ ch & 0x0F];
116 }
117 source++;
118 }
119 ASSERT(static_cast<unsigned int>(dest - start) < max);
120 *dest = 0;
121
122 return static_cast<int>(dest - start);
123}
124
125int UrlEncode(const char *source, char *dest, unsigned max) {
126 return InternalUrlEncode(source, dest, max, true, false);
127}
128
129int UrlEncodeWithoutEncodingSpaceAsPlus(const char *source, char *dest,
130 unsigned max) {
131 return InternalUrlEncode(source, dest, max, false, false);
132}
133
134int UrlEncodeOnlyUnsafeChars(const char *source, char *dest, unsigned max) {
135 return InternalUrlEncode(source, dest, max, false, true);
136}
137
138std::string
139InternalUrlDecodeString(const std::string & encoded,
140 bool encode_space_as_plus) {
141 size_t needed_length = encoded.length() + 1;
142 char* buf = STACK_ARRAY(char, needed_length);
143 InternalUrlDecode(encoded.c_str(), buf, encode_space_as_plus);
144 return buf;
145}
146
147std::string
148UrlDecodeString(const std::string & encoded) {
149 return InternalUrlDecodeString(encoded, true);
150}
151
152std::string
153UrlDecodeStringWithoutEncodingSpaceAsPlus(const std::string & encoded) {
154 return InternalUrlDecodeString(encoded, false);
155}
156
157std::string
158InternalUrlEncodeString(const std::string & decoded,
159 bool encode_space_as_plus,
160 bool unsafe_only) {
161 int needed_length = static_cast<int>(decoded.length()) * 3 + 1;
162 char* buf = STACK_ARRAY(char, needed_length);
163 InternalUrlEncode(decoded.c_str(), buf, needed_length,
164 encode_space_as_plus, unsafe_only);
165 return buf;
166}
167
168std::string
169UrlEncodeString(const std::string & decoded) {
170 return InternalUrlEncodeString(decoded, true, false);
171}
172
173std::string
174UrlEncodeStringWithoutEncodingSpaceAsPlus(const std::string & decoded) {
175 return InternalUrlEncodeString(decoded, false, false);
176}
177
178std::string
179UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded) {
180 return InternalUrlEncodeString(decoded, false, true);
181}
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +0000182
183} // namespace rtc