1 /*
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
HexPairValue(const char * code)16 static int HexPairValue(const char * code) {
17 int value = 0;
18 for (const char * pch = code; pch < code + 2; ++pch) {
19 value <<= 4;
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 }
34 return value;
35 }
36
InternalUrlDecode(const char * source,char * dest,bool encode_space_as_plus)37 static int InternalUrlDecode(const char *source, char *dest,
38 bool encode_space_as_plus) {
39 char * start = dest;
40
41 while (*source) {
42 switch (*source) {
43 case '+':
44 if (encode_space_as_plus) {
45 *(dest++) = ' ';
46 } else {
47 *dest++ = *source;
48 }
49 break;
50 case '%':
51 if (source[1] && source[2]) {
52 int value = HexPairValue(source + 1);
53 if (value >= 0) {
54 *(dest++) = static_cast<char>(value);
55 source += 2;
56 }
57 else {
58 *dest++ = '?';
59 }
60 }
61 else {
62 *dest++ = '?';
63 }
64 break;
65 default:
66 *dest++ = *source;
67 }
68 source++;
69 }
70
71 *dest = 0;
72 return static_cast<int>(dest - start);
73 }
74
IsValidUrlChar(char ch,bool unsafe_only)75 static bool IsValidUrlChar(char ch, bool unsafe_only) {
76 if (unsafe_only) {
77 return !(ch <= ' ' || strchr("\\\"^&`<>[]{}", ch));
78 } else {
79 return isalnum(ch) || strchr("-_.!~*'()", ch);
80 }
81 }
82
83 namespace rtc {
84
UrlDecode(const char * source,char * dest)85 int UrlDecode(const char *source, char *dest) {
86 return InternalUrlDecode(source, dest, true);
87 }
88
UrlDecodeWithoutEncodingSpaceAsPlus(const char * source,char * dest)89 int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest) {
90 return InternalUrlDecode(source, dest, false);
91 }
92
InternalUrlEncode(const char * source,char * dest,unsigned int max,bool encode_space_as_plus,bool unsafe_only)93 int InternalUrlEncode(const char *source, char *dest, unsigned int max,
94 bool encode_space_as_plus, bool unsafe_only) {
95 static const char *digits = "0123456789ABCDEF";
96 if (max == 0) {
97 return 0;
98 }
99
100 char *start = dest;
101 while (static_cast<unsigned>(dest - start) < max && *source) {
102 unsigned char ch = static_cast<unsigned char>(*source);
103 if (*source == ' ' && encode_space_as_plus && !unsafe_only) {
104 *dest++ = '+';
105 } else if (IsValidUrlChar(ch, unsafe_only)) {
106 *dest++ = *source;
107 } else {
108 if (static_cast<unsigned>(dest - start) + 4 > max) {
109 break;
110 }
111 *dest++ = '%';
112 *dest++ = digits[(ch >> 4) & 0x0F];
113 *dest++ = digits[ ch & 0x0F];
114 }
115 source++;
116 }
117 ASSERT(static_cast<unsigned int>(dest - start) < max);
118 *dest = 0;
119
120 return static_cast<int>(dest - start);
121 }
122
UrlEncode(const char * source,char * dest,unsigned max)123 int UrlEncode(const char *source, char *dest, unsigned max) {
124 return InternalUrlEncode(source, dest, max, true, false);
125 }
126
UrlEncodeWithoutEncodingSpaceAsPlus(const char * source,char * dest,unsigned max)127 int UrlEncodeWithoutEncodingSpaceAsPlus(const char *source, char *dest,
128 unsigned max) {
129 return InternalUrlEncode(source, dest, max, false, false);
130 }
131
UrlEncodeOnlyUnsafeChars(const char * source,char * dest,unsigned max)132 int UrlEncodeOnlyUnsafeChars(const char *source, char *dest, unsigned max) {
133 return InternalUrlEncode(source, dest, max, false, true);
134 }
135
136 std::string
InternalUrlDecodeString(const std::string & encoded,bool encode_space_as_plus)137 InternalUrlDecodeString(const std::string & encoded,
138 bool encode_space_as_plus) {
139 size_t needed_length = encoded.length() + 1;
140 char* buf = STACK_ARRAY(char, needed_length);
141 InternalUrlDecode(encoded.c_str(), buf, encode_space_as_plus);
142 return buf;
143 }
144
145 std::string
UrlDecodeString(const std::string & encoded)146 UrlDecodeString(const std::string & encoded) {
147 return InternalUrlDecodeString(encoded, true);
148 }
149
150 std::string
UrlDecodeStringWithoutEncodingSpaceAsPlus(const std::string & encoded)151 UrlDecodeStringWithoutEncodingSpaceAsPlus(const std::string & encoded) {
152 return InternalUrlDecodeString(encoded, false);
153 }
154
155 std::string
InternalUrlEncodeString(const std::string & decoded,bool encode_space_as_plus,bool unsafe_only)156 InternalUrlEncodeString(const std::string & decoded,
157 bool encode_space_as_plus,
158 bool unsafe_only) {
159 int needed_length = static_cast<int>(decoded.length()) * 3 + 1;
160 char* buf = STACK_ARRAY(char, needed_length);
161 InternalUrlEncode(decoded.c_str(), buf, needed_length,
162 encode_space_as_plus, unsafe_only);
163 return buf;
164 }
165
166 std::string
UrlEncodeString(const std::string & decoded)167 UrlEncodeString(const std::string & decoded) {
168 return InternalUrlEncodeString(decoded, true, false);
169 }
170
171 std::string
UrlEncodeStringWithoutEncodingSpaceAsPlus(const std::string & decoded)172 UrlEncodeStringWithoutEncodingSpaceAsPlus(const std::string & decoded) {
173 return InternalUrlEncodeString(decoded, false, false);
174 }
175
176 std::string
UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded)177 UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded) {
178 return InternalUrlEncodeString(decoded, false, true);
179 }
180
181 } // namespace rtc
182