Home | History | Annotate | Download | only in base
      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 
     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 
     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 
     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 
     85 int UrlDecode(const char *source, char *dest) {
     86   return InternalUrlDecode(source, dest, true);
     87 }
     88 
     89 int UrlDecodeWithoutEncodingSpaceAsPlus(const char *source, char *dest) {
     90   return InternalUrlDecode(source, dest, false);
     91 }
     92 
     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 
    123 int UrlEncode(const char *source, char *dest, unsigned max) {
    124   return InternalUrlEncode(source, dest, max, true, false);
    125 }
    126 
    127 int UrlEncodeWithoutEncodingSpaceAsPlus(const char *source, char *dest,
    128                                         unsigned max) {
    129   return InternalUrlEncode(source, dest, max, false, false);
    130 }
    131 
    132 int UrlEncodeOnlyUnsafeChars(const char *source, char *dest, unsigned max) {
    133   return InternalUrlEncode(source, dest, max, false, true);
    134 }
    135 
    136 std::string
    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
    146 UrlDecodeString(const std::string & encoded) {
    147   return InternalUrlDecodeString(encoded, true);
    148 }
    149 
    150 std::string
    151 UrlDecodeStringWithoutEncodingSpaceAsPlus(const std::string & encoded) {
    152   return InternalUrlDecodeString(encoded, false);
    153 }
    154 
    155 std::string
    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
    167 UrlEncodeString(const std::string & decoded) {
    168   return InternalUrlEncodeString(decoded, true, false);
    169 }
    170 
    171 std::string
    172 UrlEncodeStringWithoutEncodingSpaceAsPlus(const std::string & decoded) {
    173   return InternalUrlEncodeString(decoded, false, false);
    174 }
    175 
    176 std::string
    177 UrlEncodeStringForOnlyUnsafeChars(const std::string & decoded) {
    178   return InternalUrlEncodeString(decoded, false, true);
    179 }
    180 
    181 }  // namespace rtc
    182