blob: f2de9375f5be125081dae0b1563c22bb70cd7519 [file] [log] [blame]
Chris Sosa45d9f102014-03-24 11:18:54 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "buffet/data_encoding.h"
6
7#include <base/strings/stringprintf.h>
8#include <string.h>
9
10#include "buffet/string_utils.h"
11
12namespace {
13
14inline int HexToDec(int hex) {
15 int dec = -1;
16 if (hex >= '0' && hex <= '9') {
17 dec = hex - '0';
18 } else if (hex >= 'A' && hex <= 'F') {
19 dec = hex - 'A' + 10;
20 } else if (hex >= 'a' && hex <= 'f') {
21 dec = hex - 'a' + 10;
22 }
23 return dec;
24}
25
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070026} // namespace
Chris Sosa45d9f102014-03-24 11:18:54 -070027
28/////////////////////////////////////////////////////////////////////////
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070029namespace buffet {
Chris Sosa45d9f102014-03-24 11:18:54 -070030namespace data_encoding {
31
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070032std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) {
Chris Sosa45d9f102014-03-24 11:18:54 -070033 std::string result;
34
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070035 while (*data) {
Chris Sosa45d9f102014-03-24 11:18:54 -070036 char c = *data++;
37 // According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html),
38 // section 2.3. - Unreserved Characters
39 if ((c >= '0' && c <= '9') ||
40 (c >= 'A' && c <= 'Z') ||
41 (c >= 'a' && c <= 'z') ||
42 c == '-' || c == '.' || c == '_' || c == '~') {
43 result += c;
44 } else if (c == ' ' && encodeSpaceAsPlus) {
45 // For historical reasons, some URLs have spaces encoded as '+',
46 // this also applies to form data encoded as
47 // 'application/x-www-form-urlencoded'
48 result += '+';
49 } else {
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070050 base::StringAppendF(&result, "%%%02X",
51 static_cast<unsigned char>(c)); // Encode as %NN
Chris Sosa45d9f102014-03-24 11:18:54 -070052 }
53 }
54 return result;
55}
56
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070057std::string UrlDecode(const char* data) {
Chris Sosa45d9f102014-03-24 11:18:54 -070058 std::string result;
59 while (*data) {
60 char c = *data++;
61 int part1 = 0, part2 = 0;
62 // HexToDec would return -1 even for character 0 (end of string),
63 // so it is safe to access data[0] and data[1] without overrunning the buf.
64 if (c == '%' &&
65 (part1 = HexToDec(data[0])) >= 0 && (part2 = HexToDec(data[1])) >= 0) {
Alex Vakulenkoaf23b322014-05-08 16:25:45 -070066 c = static_cast<char>((part1 << 4) | part2);
Chris Sosa45d9f102014-03-24 11:18:54 -070067 data += 2;
68 } else if (c == '+') {
69 c = ' ';
70 }
71 result += c;
72 }
73 return result;
74}
75
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070076std::string WebParamsEncode(const WebParamList& params,
Alex Vakulenkob645cc92014-04-15 11:34:35 -070077 bool encodeSpaceAsPlus) {
Chris Sosa45d9f102014-03-24 11:18:54 -070078 std::vector<std::string> pairs;
79 pairs.reserve(params.size());
Alex Vakulenkoa0424dd2014-06-13 16:10:17 -070080 for (const auto& p : params) {
Chris Sosa45d9f102014-03-24 11:18:54 -070081 std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus);
82 std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus);
83 pairs.push_back(string_utils::Join('=', key, value));
84 }
85
86 return string_utils::Join('&', pairs);
87}
88
Alex Vakulenkob8ba5952014-04-17 11:35:56 -070089WebParamList WebParamsDecode(const std::string& data) {
Alex Vakulenkob645cc92014-04-15 11:34:35 -070090 WebParamList result;
Chris Sosa45d9f102014-03-24 11:18:54 -070091 std::vector<std::string> params = string_utils::Split(data, '&');
Alex Vakulenkoa0424dd2014-06-13 16:10:17 -070092 for (const auto& p : params) {
Chris Sosa45d9f102014-03-24 11:18:54 -070093 auto pair = string_utils::SplitAtFirst(p, '=');
94 result.emplace_back(UrlDecode(pair.first.c_str()),
95 UrlDecode(pair.second.c_str()));
96 }
97 return result;
98}
99
Alex Vakulenkoaf23b322014-05-08 16:25:45 -0700100} // namespace data_encoding
101} // namespace buffet