From 5aec60fbebfd1f31df774d33b5d80aed9412d3aa Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 2 Oct 2016 10:22:33 +0900 Subject: [PATCH] nghtpx: Add BlockAllocator version of base64 --- src/base64.h | 54 ++++++++++++++++++++++++++----------- src/base64_test.cc | 12 +++++++++ src/shrpx_http2_upstream.cc | 13 ++++----- src/util.cc | 40 ++++++++++++++++----------- src/util.h | 3 ++- src/util_test.cc | 11 ++++---- 6 files changed, 90 insertions(+), 43 deletions(-) diff --git a/src/base64.h b/src/base64.h index de45c5d3..c173a5a5 100644 --- a/src/base64.h +++ b/src/base64.h @@ -29,6 +29,9 @@ #include +#include "template.h" +#include "allocator.h" + namespace nghttp2 { namespace base64 { @@ -87,7 +90,8 @@ InputIt next_decode_input(InputIt first, InputIt last, const int *tbl) { return first; } -template std::string decode(InputIt first, InputIt last) { +template +OutputIt decode(InputIt first, InputIt last, OutputIt d_first) { 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, @@ -104,37 +108,29 @@ template 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}; - 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;) { uint32_t n = 0; for (int i = 1; i <= 4; ++i, ++first) { auto idx = INDEX_TABLE[static_cast(*first)]; if (idx == -1) { if (i <= 2) { - return ""; + return d_first; } if (i == 3) { if (*first == '=' && *(first + 1) == '=' && first + 2 == last) { *p++ = n >> 16; - res.resize(p - std::begin(res)); - return res; + return p; } - return ""; + return d_first; } if (*first == '=' && first + 1 == last) { *p++ = n >> 16; *p++ = n >> 8 & 0xffu; - res.resize(p - std::begin(res)); - return res; + return p; } - return ""; + return d_first; } n += idx << (24 - i * 6); @@ -145,9 +141,37 @@ template std::string decode(InputIt first, InputIt last) { *p++ = n & 0xffu; } + return p; +} + +template 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; } +template +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 nghttp2 diff --git a/src/base64_test.cc b/src/base64_test.cc index 1fa79915..4324bd74 100644 --- a/src/base64_test.cc +++ b/src/base64_test.cc @@ -59,31 +59,40 @@ void test_base64_encode(void) { } void test_base64_decode(void) { + BlockAllocator balloc(4096, 4096); { std::string in = "/w=="; auto out = base64::decode(std::begin(in), std::end(in)); CU_ASSERT("\xff" == out); + CU_ASSERT("\xff" == base64::decode(balloc, std::begin(in), std::end(in))); } { std::string in = "//4="; auto out = base64::decode(std::begin(in), std::end(in)); CU_ASSERT("\xff\xfe" == out); + CU_ASSERT("\xff\xfe" == + base64::decode(balloc, std::begin(in), std::end(in))); } { std::string in = "//79"; auto out = base64::decode(std::begin(in), std::end(in)); 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=="; auto out = base64::decode(std::begin(in), std::end(in)); 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 std::string in = "//79="; auto out = base64::decode(std::begin(in), std::end(in)); 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 @@ -91,18 +100,21 @@ void test_base64_decode(void) { std::string in = "bmdodHRw\n"; auto out = base64::decode(std::begin(in), std::end(in)); CU_ASSERT("" == out); + CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); } { // after seeing '=', subsequent input must be also '='. std::string in = "//79/A=A"; auto out = base64::decode(std::begin(in), std::end(in)); CU_ASSERT("" == out); + CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); } { // additional '=' at the end is bad std::string in = "//79/A======"; auto out = base64::decode(std::begin(in), std::end(in)); CU_ASSERT("" == out); + CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); } } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 50e5a81e..9d1104b1 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -108,15 +108,16 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, int Http2Upstream::upgrade_upstream(HttpsUpstream *http) { int rv; - auto http2_settings = http->get_downstream()->get_http2_settings().str(); - util::to_base64(http2_settings); + auto &balloc = http->get_downstream()->get_block_allocator(); - auto settings_payload = - base64::decode(std::begin(http2_settings), std::end(http2_settings)); + auto http2_settings = http->get_downstream()->get_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( - session_, reinterpret_cast(settings_payload.c_str()), - settings_payload.size(), + session_, settings_payload.byte(), settings_payload.size(), http->get_downstream()->request().method == HTTP_HEAD, nullptr); if (rv != 0) { if (LOG_ENABLED(INFO)) { diff --git a/src/util.cc b/src/util.cc index 056c7cd9..91f469c2 100644 --- a/src/util.cc +++ b/src/util.cc @@ -410,22 +410,32 @@ void to_token68(std::string &base64str) { std::end(base64str)); } -void to_base64(std::string &token68str) { - std::transform(std::begin(token68str), std::end(token68str), - std::begin(token68str), [](char c) { - switch (c) { - case '-': - return '+'; - case '_': - return '/'; - default: - return c; - } - }); - if (token68str.size() & 0x3) { - token68str.append(4 - (token68str.size() & 0x3), '='); +StringRef to_base64(BlockAllocator &balloc, const StringRef &token68str) { + // At most 3 padding '=' + auto len = token68str.size() + 3; + auto iov = make_byte_ref(balloc, len + 1); + auto p = iov.base; + + p = std::transform(std::begin(token68str), std::end(token68str), p, + [](char c) { + switch (c) { + case '-': + return '+'; + case '_': + return '/'; + 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 { diff --git a/src/util.h b/src/util.h index e192864d..28172c7c 100644 --- a/src/util.h +++ b/src/util.h @@ -426,7 +426,8 @@ template std::string utox(T n) { } 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); diff --git a/src/util_test.cc b/src/util_test.cc index e8e24fcf..d9bce306 100644 --- a/src/util_test.cc +++ b/src/util_test.cc @@ -114,13 +114,12 @@ void test_util_inp_strlower(void) { } void test_util_to_base64(void) { - std::string x = "AAA--B_"; - util::to_base64(x); - CU_ASSERT("AAA++B/=" == x); + BlockAllocator balloc(4096, 4096); - x = "AAA--B_B"; - util::to_base64(x); - CU_ASSERT("AAA++B/B" == x); + CU_ASSERT("AAA++B/=" == + util::to_base64(balloc, StringRef::from_lit("AAA--B_"))); + CU_ASSERT("AAA++B/B" == + util::to_base64(balloc, StringRef::from_lit("AAA--B_B"))); } void test_util_to_token68(void) {