nghtpx: Add BlockAllocator version of base64

This commit is contained in:
Tatsuhiro Tsujikawa 2016-10-02 10:22:33 +09:00
parent e1a865c406
commit 5aec60fbeb
6 changed files with 90 additions and 43 deletions

View File

@ -29,6 +29,9 @@
#include <string> #include <string>
#include "template.h"
#include "allocator.h"
namespace nghttp2 { namespace nghttp2 {
namespace base64 { namespace base64 {
@ -87,7 +90,8 @@ InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) {
return first; return first;
} }
template <typename InputIt> std::string decode(InputIt first, InputIt last) { template <typename InputIt, typename OutputIt>
OutputIt decode(InputIt first, InputIt last, OutputIt d_first) {
static constexpr int INDEX_TABLE[] = { static constexpr int INDEX_TABLE[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@ -104,37 +108,29 @@ template <typename InputIt> std::string decode(InputIt first, InputIt last) {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1}; -1, -1, -1, -1};
auto len = last - first;
if (len % 4 != 0) {
return "";
}
std::string res;
res.resize(len / 4 * 3);
auto p = std::begin(res); auto p = d_first;
for (; first != last;) { for (; first != last;) {
uint32_t n = 0; uint32_t n = 0;
for (int i = 1; i <= 4; ++i, ++first) { for (int i = 1; i <= 4; ++i, ++first) {
auto idx = INDEX_TABLE[static_cast<size_t>(*first)]; auto idx = INDEX_TABLE[static_cast<size_t>(*first)];
if (idx == -1) { if (idx == -1) {
if (i <= 2) { if (i <= 2) {
return ""; return d_first;
} }
if (i == 3) { if (i == 3) {
if (*first == '=' && *(first + 1) == '=' && first + 2 == last) { if (*first == '=' && *(first + 1) == '=' && first + 2 == last) {
*p++ = n >> 16; *p++ = n >> 16;
res.resize(p - std::begin(res)); return p;
return res;
} }
return ""; return d_first;
} }
if (*first == '=' && first + 1 == last) { if (*first == '=' && first + 1 == last) {
*p++ = n >> 16; *p++ = n >> 16;
*p++ = n >> 8 & 0xffu; *p++ = n >> 8 & 0xffu;
res.resize(p - std::begin(res)); return p;
return res;
} }
return ""; return d_first;
} }
n += idx << (24 - i * 6); n += idx << (24 - i * 6);
@ -145,9 +141,37 @@ template <typename InputIt> std::string decode(InputIt first, InputIt last) {
*p++ = n & 0xffu; *p++ = n & 0xffu;
} }
return p;
}
template <typename InputIt> std::string decode(InputIt first, InputIt last) {
auto len = std::distance(first, last);
if (len % 4 != 0) {
return "";
}
std::string res;
res.resize(len / 4 * 3);
res.erase(decode(first, last, std::begin(res)), std::end(res));
return res; return res;
} }
template <typename InputIt>
StringRef decode(BlockAllocator &balloc, InputIt first, InputIt last) {
auto len = std::distance(first, last);
if (len % 4 != 0) {
return StringRef::from_lit("");
}
auto iov = make_byte_ref(balloc, len / 4 * 3 + 1);
auto p = iov.base;
p = decode(first, last, p);
*p = '\0';
return StringRef{iov.base, p};
}
} // namespace base64 } // namespace base64
} // namespace nghttp2 } // namespace nghttp2

View File

@ -59,31 +59,40 @@ void test_base64_encode(void) {
} }
void test_base64_decode(void) { void test_base64_decode(void) {
BlockAllocator balloc(4096, 4096);
{ {
std::string in = "/w=="; std::string in = "/w==";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff" == out); CU_ASSERT("\xff" == out);
CU_ASSERT("\xff" == base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
std::string in = "//4="; std::string in = "//4=";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe" == out); CU_ASSERT("\xff\xfe" == out);
CU_ASSERT("\xff\xfe" ==
base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
std::string in = "//79"; std::string in = "//79";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd" == out); CU_ASSERT("\xff\xfe\xfd" == out);
CU_ASSERT("\xff\xfe\xfd" ==
base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
std::string in = "//79/A=="; std::string in = "//79/A==";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("\xff\xfe\xfd\xfc" == out); CU_ASSERT("\xff\xfe\xfd\xfc" == out);
CU_ASSERT("\xff\xfe\xfd\xfc" ==
base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
// we check the number of valid input must be multiples of 4 // we check the number of valid input must be multiples of 4
std::string in = "//79="; std::string in = "//79=";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
// ending invalid character at the boundary of multiples of 4 is // ending invalid character at the boundary of multiples of 4 is
@ -91,18 +100,21 @@ void test_base64_decode(void) {
std::string in = "bmdodHRw\n"; std::string in = "bmdodHRw\n";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
// after seeing '=', subsequent input must be also '='. // after seeing '=', subsequent input must be also '='.
std::string in = "//79/A=A"; std::string in = "//79/A=A";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
} }
{ {
// additional '=' at the end is bad // additional '=' at the end is bad
std::string in = "//79/A======"; std::string in = "//79/A======";
auto out = base64::decode(std::begin(in), std::end(in)); auto out = base64::decode(std::begin(in), std::end(in));
CU_ASSERT("" == out); CU_ASSERT("" == out);
CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in)));
} }
} }

View File

@ -108,15 +108,16 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
int Http2Upstream::upgrade_upstream(HttpsUpstream *http) { int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
int rv; int rv;
auto http2_settings = http->get_downstream()->get_http2_settings().str(); auto &balloc = http->get_downstream()->get_block_allocator();
util::to_base64(http2_settings);
auto settings_payload = auto http2_settings = http->get_downstream()->get_http2_settings();
base64::decode(std::begin(http2_settings), std::end(http2_settings)); http2_settings = util::to_base64(balloc, http2_settings);
auto settings_payload = base64::decode(balloc, std::begin(http2_settings),
std::end(http2_settings));
rv = nghttp2_session_upgrade2( rv = nghttp2_session_upgrade2(
session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()), session_, settings_payload.byte(), settings_payload.size(),
settings_payload.size(),
http->get_downstream()->request().method == HTTP_HEAD, nullptr); http->get_downstream()->request().method == HTTP_HEAD, nullptr);
if (rv != 0) { if (rv != 0) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {

View File

@ -410,22 +410,32 @@ void to_token68(std::string &base64str) {
std::end(base64str)); std::end(base64str));
} }
void to_base64(std::string &token68str) { StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str) {
std::transform(std::begin(token68str), std::end(token68str), // At most 3 padding '='
std::begin(token68str), [](char c) { auto len = token68str.size() + 3;
switch (c) { auto iov = make_byte_ref(balloc, len + 1);
case '-': auto p = iov.base;
return '+';
case '_': p = std::transform(std::begin(token68str), std::end(token68str), p,
return '/'; [](char c) {
default: switch (c) {
return c; case '-':
} return '+';
}); case '_':
if (token68str.size() & 0x3) { return '/';
token68str.append(4 - (token68str.size() & 0x3), '='); default:
return c;
}
});
auto rem = token68str.size() & 0x3;
if (rem) {
p = std::fill_n(p, 4 - rem, '=');
} }
return;
*p = '\0';
return StringRef{iov.base, p};
} }
namespace { namespace {

View File

@ -426,7 +426,8 @@ template <typename T> std::string utox(T n) {
} }
void to_token68(std::string &base64str); void to_token68(std::string &base64str);
void to_base64(std::string &token68str);
StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str);
void show_candidates(const char *unkopt, option *options); void show_candidates(const char *unkopt, option *options);

View File

@ -114,13 +114,12 @@ void test_util_inp_strlower(void) {
} }
void test_util_to_base64(void) { void test_util_to_base64(void) {
std::string x = "AAA--B_"; BlockAllocator balloc(4096, 4096);
util::to_base64(x);
CU_ASSERT("AAA++B/=" == x);
x = "AAA--B_B"; CU_ASSERT("AAA++B/=" ==
util::to_base64(x); util::to_base64(balloc, StringRef::from_lit("AAA--B_")));
CU_ASSERT("AAA++B/B" == x); CU_ASSERT("AAA++B/B" ==
util::to_base64(balloc, StringRef::from_lit("AAA--B_B")));
} }
void test_util_to_token68(void) { void test_util_to_token68(void) {