blob: 5619e05cb1c096895a9b40c3a43262b8863f1b24 [file] [log] [blame]
henrike@webrtc.orgf7795df2014-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
39int InternalUrlDecode(const char *source, char *dest,
40 bool encode_space_as_plus) {
41 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
77int UrlDecode(const char *source, char *dest) {
78 return InternalUrlDecode(source, dest, true);
79}
80
81int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest) {
82 return InternalUrlDecode(source, dest, false);
83}
84
85bool IsValidUrlChar(char ch, bool unsafe_only) {
86 if (unsafe_only) {
87 return !(ch <= ' ' || strchr("\\\"^&`<>[]{}", ch));
88 } else {
89 return isalnum(ch) || strchr("-_.!~*'()", ch);
90 }
91}
92
93int 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
123int UrlEncode(const char *source, char *dest, unsigned max) {
124 return InternalUrlEncode(source, dest, max, true, false);
125}
126
127int UrlEncodeWithoutEncodingSpaceAsPlus(const char *source, char *dest,
128 unsigned max) {
129 return InternalUrlEncode(source, dest, max, false, false);
130}
131
132int UrlEncodeOnlyUnsafeChars(const char *source, char *dest, unsigned max) {
133 return InternalUrlEncode(source, dest, max, false, true);
134}
135
136std::string
137InternalUrlDecodeString(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
145std::string
146UrlDecodeString(const std::string & encoded) {
147 return InternalUrlDecodeString(encoded, true);
148}
149
150std::string
151UrlDecodeStringWithoutEncodingSpaceAsPlus(const std::string & encoded) {
152 return InternalUrlDecodeString(encoded, false);
153}
154
155std::string
156InternalUrlEncodeString(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
166std::string
167UrlEncodeString(const std::string & decoded) {
168 return InternalUrlEncodeString(decoded, true, false);
169}
170
171std::string
172UrlEncodeStringWithoutEncodingSpaceAsPlus(const std::string & decoded) {
173 return InternalUrlEncodeString(decoded, false, false);
174}
175
176std::string
177UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded) {
178 return InternalUrlEncodeString(decoded, false, true);
179}