blob: b3468b9e3fadda8326e2abff96a496c4ba9bab90 [file] [log] [blame]
Alex Vakulenkoad93c042014-08-20 15:47:36 -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 <chromeos/data_encoding.h>
6
7#include <base/strings/stringprintf.h>
Alex Vakulenko15104662014-08-27 11:00:57 -07008#include <chromeos/strings/string_utils.h>
Alex Vakulenkoad93c042014-08-20 15:47:36 -07009#include <cstring>
10
11namespace {
12
13inline int HexToDec(int hex) {
14 int dec = -1;
15 if (hex >= '0' && hex <= '9') {
16 dec = hex - '0';
17 } else if (hex >= 'A' && hex <= 'F') {
18 dec = hex - 'A' + 10;
19 } else if (hex >= 'a' && hex <= 'f') {
20 dec = hex - 'a' + 10;
21 }
22 return dec;
23}
24
25} // namespace
26
27/////////////////////////////////////////////////////////////////////////
28namespace chromeos {
29namespace data_encoding {
30
31std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) {
32 std::string result;
33
34 while (*data) {
35 char c = *data++;
36 // According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html),
37 // section 2.3. - Unreserved Characters
Alex Vakulenko05d29042015-01-13 09:39:25 -080038 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
39 (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' ||
40 c == '~') {
Alex Vakulenkoad93c042014-08-20 15:47:36 -070041 result += c;
42 } else if (c == ' ' && encodeSpaceAsPlus) {
43 // For historical reasons, some URLs have spaces encoded as '+',
44 // this also applies to form data encoded as
45 // 'application/x-www-form-urlencoded'
46 result += '+';
47 } else {
Alex Vakulenko05d29042015-01-13 09:39:25 -080048 base::StringAppendF(&result,
49 "%%%02X",
Alex Vakulenkoad93c042014-08-20 15:47:36 -070050 static_cast<unsigned char>(c)); // Encode as %NN
51 }
52 }
53 return result;
54}
55
56std::string UrlDecode(const char* data) {
57 std::string result;
58 while (*data) {
59 char c = *data++;
60 int part1 = 0, part2 = 0;
61 // HexToDec would return -1 even for character 0 (end of string),
62 // so it is safe to access data[0] and data[1] without overrunning the buf.
Alex Vakulenko05d29042015-01-13 09:39:25 -080063 if (c == '%' && (part1 = HexToDec(data[0])) >= 0 &&
64 (part2 = HexToDec(data[1])) >= 0) {
Alex Vakulenkoad93c042014-08-20 15:47:36 -070065 c = static_cast<char>((part1 << 4) | part2);
66 data += 2;
67 } else if (c == '+') {
68 c = ' ';
69 }
70 result += c;
71 }
72 return result;
73}
74
75std::string WebParamsEncode(const WebParamList& params,
76 bool encodeSpaceAsPlus) {
77 std::vector<std::string> pairs;
78 pairs.reserve(params.size());
79 for (const auto& p : params) {
80 std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus);
81 std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus);
82 pairs.push_back(chromeos::string_utils::Join('=', key, value));
83 }
84
85 return chromeos::string_utils::Join('&', pairs);
86}
87
88WebParamList WebParamsDecode(const std::string& data) {
89 WebParamList result;
90 std::vector<std::string> params = chromeos::string_utils::Split(data, '&');
91 for (const auto& p : params) {
92 auto pair = chromeos::string_utils::SplitAtFirst(p, '=');
93 result.emplace_back(UrlDecode(pair.first.c_str()),
94 UrlDecode(pair.second.c_str()));
95 }
96 return result;
97}
98
99} // namespace data_encoding
100} // namespace chromeos