You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.7 KiB
154 lines
4.7 KiB
// Copyright 2014 The Chromium OS Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style license that can be |
|
// found in the LICENSE file. |
|
|
|
#include <brillo/data_encoding.h> |
|
#include <modp_b64/modp_b64.h> |
|
|
|
#include <memory> |
|
|
|
#include <base/logging.h> |
|
#include <base/strings/string_util.h> |
|
#include <base/strings/stringprintf.h> |
|
#include <brillo/strings/string_utils.h> |
|
|
|
namespace { |
|
|
|
inline int HexToDec(int hex) { |
|
int dec = -1; |
|
if (hex >= '0' && hex <= '9') { |
|
dec = hex - '0'; |
|
} else if (hex >= 'A' && hex <= 'F') { |
|
dec = hex - 'A' + 10; |
|
} else if (hex >= 'a' && hex <= 'f') { |
|
dec = hex - 'a' + 10; |
|
} |
|
return dec; |
|
} |
|
|
|
// Helper for Base64Encode() and Base64EncodeWrapLines(). |
|
std::string Base64EncodeHelper(const void* data, size_t size) { |
|
std::vector<char> buffer; |
|
buffer.resize(modp_b64_encode_len(size)); |
|
size_t out_size = modp_b64_encode(buffer.data(), |
|
static_cast<const char*>(data), |
|
size); |
|
return std::string{buffer.begin(), buffer.begin() + out_size}; |
|
} |
|
|
|
} // namespace |
|
|
|
///////////////////////////////////////////////////////////////////////// |
|
namespace brillo { |
|
namespace data_encoding { |
|
|
|
std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) { |
|
std::string result; |
|
|
|
while (*data) { |
|
char c = *data++; |
|
// According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html), |
|
// section 2.3. - Unreserved Characters |
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || |
|
(c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || |
|
c == '~') { |
|
result += c; |
|
} else if (c == ' ' && encodeSpaceAsPlus) { |
|
// For historical reasons, some URLs have spaces encoded as '+', |
|
// this also applies to form data encoded as |
|
// 'application/x-www-form-urlencoded' |
|
result += '+'; |
|
} else { |
|
base::StringAppendF(&result, |
|
"%%%02X", |
|
static_cast<unsigned char>(c)); // Encode as %NN |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
std::string UrlDecode(const char* data) { |
|
std::string result; |
|
while (*data) { |
|
char c = *data++; |
|
int part1 = 0, part2 = 0; |
|
// HexToDec would return -1 even for character 0 (end of string), |
|
// so it is safe to access data[0] and data[1] without overrunning the buf. |
|
if (c == '%' && (part1 = HexToDec(data[0])) >= 0 && |
|
(part2 = HexToDec(data[1])) >= 0) { |
|
c = static_cast<char>((part1 << 4) | part2); |
|
data += 2; |
|
} else if (c == '+') { |
|
c = ' '; |
|
} |
|
result += c; |
|
} |
|
return result; |
|
} |
|
|
|
std::string WebParamsEncode(const WebParamList& params, |
|
bool encodeSpaceAsPlus) { |
|
std::vector<std::string> pairs; |
|
pairs.reserve(params.size()); |
|
for (const auto& p : params) { |
|
std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus); |
|
std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus); |
|
pairs.push_back(brillo::string_utils::Join("=", key, value)); |
|
} |
|
|
|
return brillo::string_utils::Join("&", pairs); |
|
} |
|
|
|
WebParamList WebParamsDecode(const std::string& data) { |
|
WebParamList result; |
|
std::vector<std::string> params = brillo::string_utils::Split(data, "&"); |
|
for (const auto& p : params) { |
|
auto pair = brillo::string_utils::SplitAtFirst(p, "="); |
|
result.emplace_back(UrlDecode(pair.first.c_str()), |
|
UrlDecode(pair.second.c_str())); |
|
} |
|
return result; |
|
} |
|
|
|
std::string Base64Encode(const void* data, size_t size) { |
|
return Base64EncodeHelper(data, size); |
|
} |
|
|
|
std::string Base64EncodeWrapLines(const void* data, size_t size) { |
|
std::string unwrapped = Base64EncodeHelper(data, size); |
|
std::string wrapped; |
|
|
|
for (size_t i = 0; i < unwrapped.size(); i += 64) { |
|
wrapped.append(unwrapped, i, 64); |
|
wrapped.append("\n"); |
|
} |
|
return wrapped; |
|
} |
|
|
|
bool Base64Decode(const std::string& input, brillo::Blob* output) { |
|
std::string temp_buffer; |
|
const std::string* data = &input; |
|
if (input.find_first_of("\r\n") != std::string::npos) { |
|
base::ReplaceChars(input, "\n", "", &temp_buffer); |
|
base::ReplaceChars(temp_buffer, "\r", "", &temp_buffer); |
|
data = &temp_buffer; |
|
} |
|
// base64 decoded data has 25% fewer bytes than the original (since every |
|
// 3 source octets are encoded as 4 characters in base64). |
|
// modp_b64_decode_len provides an upper estimate of the size of the output |
|
// data. |
|
output->resize(modp_b64_decode_len(data->size())); |
|
|
|
size_t size_read = modp_b64_decode(reinterpret_cast<char*>(output->data()), |
|
data->data(), data->size()); |
|
if (size_read == MODP_B64_ERROR) { |
|
output->resize(0); |
|
return false; |
|
} |
|
output->resize(size_read); |
|
|
|
return true; |
|
} |
|
|
|
} // namespace data_encoding |
|
} // namespace brillo
|
|
|