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