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 16static 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 37static 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 75static 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 83namespace rtc { 84 85int UrlDecode(const char *source, char *dest) { 86 return InternalUrlDecode(source, dest, true); 87} 88 89int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest) { 90 return InternalUrlDecode(source, dest, false); 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} 180 181} // namespace rtc 182