nghtpx: Add BlockAllocator version of base64
This commit is contained in:
parent
e1a865c406
commit
5aec60fbeb
54
src/base64.h
54
src/base64.h
|
@ -29,6 +29,9 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#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 <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[] = {
|
||||
-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};
|
||||
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<size_t>(*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 <typename InputIt> std::string decode(InputIt first, InputIt last) {
|
|||
*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;
|
||||
}
|
||||
|
||||
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 nghttp2
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<const uint8_t *>(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)) {
|
||||
|
|
40
src/util.cc
40
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 {
|
||||
|
|
|
@ -426,7 +426,8 @@ template <typename T> 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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue