diff options
author | Varun Ravichandran <varun.ravichandran@mongodb.com> | 2022-08-23 15:43:11 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-23 23:45:45 +0000 |
commit | b97bcd00e8b8b4ebf3988feb6eea288b705bf00c (patch) | |
tree | 468249083fbeec68321fac3acb173e21250ef05f /src/mongo/util | |
parent | ec2724c6a4cb6582d710f450714398c8bd6a70fb (diff) | |
download | mongo-b97bcd00e8b8b4ebf3988feb6eea288b705bf00c.tar.gz |
Revert "SERVER-67464 Add base64url encode/decode"
This reverts commit ef8c3a1546b72894360dab8e3121434ba306c884.
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/base64.cpp | 163 | ||||
-rw-r--r-- | src/mongo/util/base64.h | 31 | ||||
-rw-r--r-- | src/mongo/util/base64_test.cpp | 100 |
3 files changed, 65 insertions, 229 deletions
diff --git a/src/mongo/util/base64.cpp b/src/mongo/util/base64.cpp index 048864dbbdc..fefe3160bde 100644 --- a/src/mongo/util/base64.cpp +++ b/src/mongo/util/base64.cpp @@ -37,7 +37,7 @@ #include <cstdint> #include <iostream> -namespace mongo { +namespace mongo::base64 { namespace { constexpr unsigned char kInvalid = ~0; @@ -55,33 +55,21 @@ constexpr auto invertTable(StringData table, std::index_sequence<Cs...>) { {static_cast<unsigned char>(search(table, Cs))...}}; } -struct Base64 { - static constexpr auto kEncodeTable = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"_sd; - static constexpr auto kDecodeTable = invertTable(kEncodeTable, std::make_index_sequence<256>{}); - static constexpr bool kTerminatorRequired = true; -}; - -struct Base64URL { - static constexpr auto kEncodeTable = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"_sd; - static constexpr auto kDecodeTable = invertTable(kEncodeTable, std::make_index_sequence<256>{}); - static constexpr bool kTerminatorRequired = false; -}; - -template <typename Mode> +constexpr StringData kEncodeTable = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"_sd; + +constexpr auto kDecodeTable = invertTable(kEncodeTable, std::make_index_sequence<256>{}); + bool valid(unsigned char x) { - static_assert(Mode::kDecodeTable.size() == 256, "Invalid decode table"); - return Mode::kDecodeTable[x] != kInvalid; + return kDecodeTable[x] != kInvalid; } -template <typename Mode, typename Writer> +template <typename Writer> void encodeImpl(Writer&& write, StringData in) { - static_assert(Mode::kEncodeTable.size() == 64, "Invalid encoding table"); const char* data = in.rawData(); std::size_t size = in.size(); auto readOctet = [&data] { return static_cast<std::uint8_t>(*data++); }; - auto encodeSextet = [](unsigned x) { return Mode::kEncodeTable[x & 0b11'1111]; }; + auto encodeSextet = [](unsigned x) { return kEncodeTable[x & 0b11'1111]; }; std::array<char, 512> buf; std::array<char, 512>::iterator p; @@ -114,9 +102,7 @@ void encodeImpl(Writer&& write, StringData in) { *p++ = encodeSextet(accum >> (6 * (3 - 0))); *p++ = encodeSextet(accum >> (6 * (3 - 1))); *p++ = encodeSextet(accum >> (6 * (3 - 2))); - if (Mode::kTerminatorRequired) { - *p++ = '='; - } + *p++ = '='; write(buf.data(), p - buf.begin()); break; case 1: @@ -125,10 +111,8 @@ void encodeImpl(Writer&& write, StringData in) { accum |= readOctet() << (8 * (2 - 0)); *p++ = encodeSextet(accum >> (6 * (3 - 0))); *p++ = encodeSextet(accum >> (6 * (3 - 1))); - if (Mode::kTerminatorRequired) { - *p++ = '='; - *p++ = '='; - } + *p++ = '='; + *p++ = '='; write(buf.data(), p - buf.begin()); break; case 0: @@ -136,25 +120,16 @@ void encodeImpl(Writer&& write, StringData in) { } } -template <typename Mode, typename Writer> +template <typename Writer> void decodeImpl(const Writer& write, StringData in) { - static_assert(Mode::kDecodeTable.size() == 256, "Invalid decode table"); const char* data = in.rawData(); std::size_t size = in.size(); - if (size == 0) { + if (size == 0) return; - } - - const std::size_t lastBlockSize = (size % 4) ? (size % 4) : 4; - constexpr std::size_t kMinLastBlockSize = Mode::kTerminatorRequired ? 4 : 2; - uassert(10270, "invalid base64", lastBlockSize >= kMinLastBlockSize); + uassert(10270, "invalid base64", size % 4 == 0); auto decodeSextet = [](char x) { - static_assert(std::numeric_limits<unsigned char>::min() == 0, - "Unexpected range for unsigned char"); - static_assert(std::numeric_limits<unsigned char>::max() == 255, - "Unexpected range for unsigned char"); - auto c = Mode::kDecodeTable[static_cast<unsigned char>(x)]; + auto c = kDecodeTable[static_cast<unsigned char>(x)]; uassert(40537, "Invalid base64 character", c != kInvalid); return c; }; @@ -164,7 +139,7 @@ void decodeImpl(const Writer& write, StringData in) { std::uint32_t accum; // All but the final group to avoid '='-related conditionals in the bulk path. - for (std::size_t groups = (size - lastBlockSize) / 4; groups;) { + for (std::size_t groups = size / 4 - 1; groups;) { std::size_t chunkGroups = std::min(groups, buf.size() / 3); groups -= chunkGroups; p = buf.begin(); @@ -184,11 +159,10 @@ void decodeImpl(const Writer& write, StringData in) { { // Final group might have some equal signs std::size_t nbits = 24; - if ((lastBlockSize < 4) || (data[3] == '=')) { + if (data[3] == '=') { nbits -= 8; - if ((lastBlockSize < 3) || (data[2] == '=')) { + if (data[2] == '=') nbits -= 8; - } } accum = 0; accum |= decodeSextet(*data++) << (6 * (3 - 0)); @@ -211,42 +185,40 @@ void decodeImpl(const Writer& write, StringData in) { } // namespace -// Base64 - -std::string base64::encode(StringData in) { +std::string encode(StringData in) { std::string r; r.reserve(encodedLength(in.size())); - encodeImpl<Base64>([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); + encodeImpl([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); return r; } -std::string base64::decode(StringData in) { +std::string decode(StringData in) { std::string r; r.reserve(in.size() / 4 * 3); - decodeImpl<Base64>([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); + decodeImpl([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); return r; } -void base64::encode(std::stringstream& ss, StringData in) { - encodeImpl<Base64>([&](const char* s, std::size_t n) { ss.write(s, n); }, in); +void encode(std::stringstream& ss, StringData in) { + encodeImpl([&](const char* s, std::size_t n) { ss.write(s, n); }, in); } -void base64::decode(std::stringstream& ss, StringData in) { - decodeImpl<Base64>([&](const char* s, std::size_t n) { ss.write(s, n); }, in); +void decode(std::stringstream& ss, StringData in) { + decodeImpl([&](const char* s, std::size_t n) { ss.write(s, n); }, in); } -void base64::encode(fmt::memory_buffer& buffer, StringData in) { +void encode(fmt::memory_buffer& buffer, StringData in) { buffer.reserve(buffer.size() + encodedLength(in.size())); - encodeImpl<Base64>([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); + encodeImpl([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); } -void base64::decode(fmt::memory_buffer& buffer, StringData in) { +void decode(fmt::memory_buffer& buffer, StringData in) { buffer.reserve(buffer.size() + in.size() / 4 * 3); - decodeImpl<Base64>([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); + decodeImpl([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); } -bool base64::validate(StringData s) { +bool validate(StringData s) { if (s.size() % 4) { return false; } @@ -254,74 +226,13 @@ bool base64::validate(StringData s) { return true; } - auto const unwindTerminator = [](auto it) { return (*(it - 1) == '=') ? (it - 1) : it; }; - auto const e = unwindTerminator(unwindTerminator(std::end(s))); - - return e == std::find_if(std::begin(s), e, [](const char ch) { return !valid<Base64>(ch); }); -} - -// Base64URL - -std::string base64url::encode(StringData in) { - std::string r; - r.reserve(encodedLength(in.size())); - encodeImpl<Base64URL>([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); - return r; -} - -std::string base64url::decode(StringData in) { - std::string r; - // effectively ceil(in.size() / 4) * 3 - r.reserve(((in.size() + 3) / 4) * 3); - decodeImpl<Base64URL>([&](const char* s, std::size_t n) { r.append(s, s + n); }, in); - return r; -} - -void base64url::encode(std::stringstream& ss, StringData in) { - encodeImpl<Base64URL>([&](const char* s, std::size_t n) { ss.write(s, n); }, in); -} - -void base64url::decode(std::stringstream& ss, StringData in) { - decodeImpl<Base64URL>([&](const char* s, std::size_t n) { ss.write(s, n); }, in); -} - -void base64url::encode(fmt::memory_buffer& buffer, StringData in) { - buffer.reserve(buffer.size() + encodedLength(in.size())); - encodeImpl<Base64URL>([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); -} - -void base64url::decode(fmt::memory_buffer& buffer, StringData in) { - buffer.reserve(buffer.size() + in.size() / 4 * 3); - decodeImpl<Base64URL>([&](const char* s, std::size_t n) { buffer.append(s, s + n); }, in); -} - - -bool base64url::validate(StringData s) { - if (s.empty()) { - return true; - } + using std::begin; + using std::end; auto const unwindTerminator = [](auto it) { return (*(it - 1) == '=') ? (it - 1) : it; }; - auto e = std::end(s); - - switch (s.size() % 4) { - case 1: - // Invalid length for a Base64URL block. - return false; - case 2: - // Valid length when no terminators present. - break; - case 3: - // Valid with one optional terminator. - e = unwindTerminator(e); - break; - case 0: - // Valid with up to two optional terminators. - e = unwindTerminator(unwindTerminator(e)); - break; - } + auto const e = unwindTerminator(unwindTerminator(end(s))); - return e == std::find_if(std::begin(s), e, [](const char ch) { return !valid<Base64URL>(ch); }); + return e == std::find_if(begin(s), e, [](const char ch) { return !valid(ch); }); } -} // namespace mongo +} // namespace mongo::base64 diff --git a/src/mongo/util/base64.h b/src/mongo/util/base64.h index 28ef7a553f7..7a2627338d2 100644 --- a/src/mongo/util/base64.h +++ b/src/mongo/util/base64.h @@ -35,8 +35,7 @@ #include "mongo/base/string_data.h" -namespace mongo { -namespace base64 { +namespace mongo::base64 { std::string encode(StringData in); std::string decode(StringData in); @@ -60,31 +59,5 @@ bool validate(StringData s); constexpr std::size_t encodedLength(std::size_t inLen) { return (inLen + 2) / 3 * 4; } -} // namespace base64 -// base64url encoding is a "url safe" variant of base64. -// '+' is replaced with '-' -// '/' is replaced with '_' -// '=' at the end of the string are optional -namespace base64url { - -std::string encode(StringData in); -std::string decode(StringData out); - -void encode(std::stringstream& ss, StringData in); -void decode(std::stringstream& ss, StringData in); - -void encode(fmt::memory_buffer& buffer, StringData in); -void decode(fmt::memory_buffer& buffer, StringData in); - -inline std::string encode(const void* data, std::size_t len) { - return encode(StringData(reinterpret_cast<const char*>(data), len)); -} - -bool validate(StringData s); - -constexpr std::size_t encodedLength(std::size_t inLen) { - return base64::encodedLength(inLen); -} -} // namespace base64url -} // namespace mongo +} // namespace mongo::base64 diff --git a/src/mongo/util/base64_test.cpp b/src/mongo/util/base64_test.cpp index 296f831bdab..a4a3575c185 100644 --- a/src/mongo/util/base64_test.cpp +++ b/src/mongo/util/base64_test.cpp @@ -48,40 +48,30 @@ TEST(Base64Test, transcode) { int line; StringData plain; StringData encoded; - StringData encodedUrl; } const tests[] = { - {__LINE__, ""_sd, ""_sd}, - {__LINE__, "a"_sd, "YQ=="_sd, "YQ"_sd}, - {__LINE__, "aa"_sd, "YWE="_sd, "YWE"_sd}, - {__LINE__, "aaa"_sd, "YWFh"_sd, "YWFh"_sd}, - {__LINE__, "aaaa"_sd, "YWFhYQ=="_sd, "YWFhYQ"_sd}, + {__LINE__, "", ""}, + {__LINE__, "a", "YQ=="}, + {__LINE__, "aa", "YWE="}, + {__LINE__, "aaa", "YWFh"}, + {__LINE__, "aaaa", "YWFhYQ=="}, - {__LINE__, "A"_sd, "QQ=="_sd, "QQ"_sd}, - {__LINE__, "AA"_sd, "QUE="_sd, "QUE"_sd}, - {__LINE__, "AAA"_sd, "QUFB"_sd, "QUFB"_sd}, - {__LINE__, "AAAA"_sd, "QUFBQQ=="_sd, "QUFBQQ"_sd}, + {__LINE__, "A", "QQ=="}, + {__LINE__, "AA", "QUE="}, + {__LINE__, "AAA", "QUFB"}, + {__LINE__, "AAAA", "QUFBQQ=="}, {__LINE__, - "The quick brown fox jumped over the lazy dog."_sd, - "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"_sd, - "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"_sd}, - {__LINE__, "\0\1\2\3\4\5\6\7"_sd, "AAECAwQFBgc="_sd, "AAECAwQFBgc"_sd}, - {__LINE__, "\0\277\1\276\2\275"_sd, "AL8BvgK9"_sd, "AL8BvgK9"_sd}, - - {__LINE__, "\x7E\x8A\x3E\xFD\xB6\xAB"_sd, "foo+/bar"_sd, "foo-_bar"_sd}, + "The quick brown fox jumped over the lazy dog.", + "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"}, + {__LINE__, "\0\1\2\3\4\5\6\7"_sd, "AAECAwQFBgc="}, + {__LINE__, "\0\277\1\276\2\275"_sd, "AL8BvgK9"}, }; for (const auto& t : tests) { - ASSERT_TRUE(base64::validate(t.encoded)) << t.line; - ASSERT_EQUALS(base64::encode(t.plain), t.encoded) - << "line: " << t.line << ", plain: '" << t.plain << "'"; - ASSERT_EQUALS(base64::decode(t.encoded), t.plain) - << "line: " << t.line << ", encoded: '" << t.encoded << "'"; - - ASSERT_TRUE(base64url::validate(t.encodedUrl)) << t.line; - ASSERT_EQUALS(base64url::encode(t.plain), t.encodedUrl) + ASSERT_TRUE(base64::validate(std::string{t.encoded})) << t.line; + ASSERT_EQUALS(base64::encode(std::string{t.plain}), t.encoded) << "line: " << t.line << ", plain: '" << t.plain << "'"; - ASSERT_EQUALS(base64url::decode(t.encodedUrl), t.plain) + ASSERT_EQUALS(base64::decode(std::string{t.encoded}), t.plain) << "line: " << t.line << ", encoded: '" << t.encoded << "'"; } } @@ -99,19 +89,13 @@ TEST(Base64Test, encodeAllPossibleGroups) { std::string s = base64::encode(buf); ASSERT_EQ(s.size(), 4); if (kSuperVerbose) { - LOGV2(23509, "buffer", "buf"_attr = mongo::hexblob::encode(buf), "s"_attr = s); + LOGV2(23509, + "buf=[{buf}] s=`{s}`", + "buf"_attr = mongo::hexblob::encode(buf), + "s"_attr = s); } std::string recovered = base64::decode(s); ASSERT_EQ(buf, recovered); - - s = base64url::encode(buf); - ASSERT_GTE(s.size(), 2); - ASSERT_LTE(s.size(), 4); - if (kSuperVerbose) { - LOGV2(6746400, "buffer", "buf"_attr = mongo::hexblob::encode(buf), "s"_attr = s); - } - recovered = base64url::decode(s); - ASSERT_EQ(buf, recovered); } } } @@ -122,14 +106,12 @@ TEST(Base64Test, parseFail) { StringData encoded; boost::optional<int> code; } const tests[] = { - {__LINE__, "BadLength"_sd, 10270}, - {__LINE__, "Has Whitespace=="_sd, 40537}, - {__LINE__, "Hasbadchar$="_sd, 40537}, - {__LINE__, "Hasbadchar\xFF="_sd, 40537}, - {__LINE__, "Hasbadchar\t="_sd, 40537}, - {__LINE__, "Has-dash"_sd, 40537}, - {__LINE__, "Has_Underscore=="_sd, 40537}, - {__LINE__, "too=soon"_sd, {}}, // fail, don't care how + {__LINE__, "BadLength", 10270}, + {__LINE__, "Has Whitespace==", 40537}, + {__LINE__, "Hasbadchar$=", 40537}, + {__LINE__, "Hasbadchar\xFF=", 40537}, + {__LINE__, "Hasbadcahr\t=", 40537}, + {__LINE__, "too=soon", {}}, // fail, don't care how }; for (const auto& t : tests) { @@ -146,35 +128,5 @@ TEST(Base64Test, parseFail) { } } -TEST(Base64UrlTest, parseFail) { - struct { - int line; - StringData encoded; - boost::optional<int> code; - } const tests[] = { - {__LINE__, "BadLength"_sd, 10270}, - {__LINE__, "Has Whitespace=="_sd, 40537}, - {__LINE__, "Hasbadchar$="_sd, 40537}, - {__LINE__, "Hasbadchar\xFF="_sd, 40537}, - {__LINE__, "Hasbadchar\t="_sd, 40537}, - {__LINE__, "Has+plus"_sd, 40537}, - {__LINE__, "Has/Solidus="_sd, 40537}, - {__LINE__, "too=soon"_sd, {}}, // fail, don't care how - }; - - for (const auto& t : tests) { - ASSERT_FALSE(base64url::validate(t.encoded)) << t.line; - - try { - base64url::decode(t.encoded); - ASSERT_TRUE(false) << t.line; - } catch (const AssertionException& e) { - if (t.code) { - ASSERT_EQ(e.code(), *t.code) << t.line << " e: " << e.toString(); - } - } - } -} - } // namespace } // namespace mongo |