summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Myers <ncm@cantrip.org>2017-07-07 01:06:40 -0400
committerNathan Myers <ncm@cantrip.org>2017-07-07 01:06:40 -0400
commitf2b3f835300b7bfff370ad92b61f08bf285f79b1 (patch)
tree63bc418a23b150aac1ed71e635821d81241cb38f /src
parente09a21c0d849878792e647d2326d6fde865ac458 (diff)
downloadmongo-f2b3f835300b7bfff370ad92b61f08bf285f79b1.tar.gz
Revert "SERVER-15194 Refactor base64::decode Implementation"
This reverts commit 4b222edf455a34667cfaf7b67e7f8dfdca42bd9c.
Diffstat (limited to 'src')
-rw-r--r--src/mongo/bson/json.cpp8
-rw-r--r--src/mongo/util/SConscript10
-rw-r--r--src/mongo/util/base64.cpp105
-rw-r--r--src/mongo/util/base64.h48
-rw-r--r--src/mongo/util/base64_test.cpp93
5 files changed, 81 insertions, 183 deletions
diff --git a/src/mongo/bson/json.cpp b/src/mongo/bson/json.cpp
index 647accf31ba..d6a94ea08eb 100644
--- a/src/mongo/bson/json.cpp
+++ b/src/mongo/bson/json.cpp
@@ -1280,7 +1280,13 @@ bool JParse::isHexString(StringData str) const {
bool JParse::isBase64String(StringData str) const {
MONGO_JSON_DEBUG("str: " << str);
- return base64::validate(str);
+ std::size_t i;
+ for (i = 0; i < str.size(); i++) {
+ if (!match(str[i], base64::chars)) {
+ return false;
+ }
+ }
+ return true;
}
bool JParse::isArray() {
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript
index 856d15ae6e1..e348375d4a7 100644
--- a/src/mongo/util/SConscript
+++ b/src/mongo/util/SConscript
@@ -610,16 +610,6 @@ env.CppUnitTest(
]
)
-env.CppUnitTest(
- target='base64_test',
- source=[
- 'base64_test.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- ],
-)
-
if env.TargetOSIs('linux'):
env.Library(
target='procparser',
diff --git a/src/mongo/util/base64.cpp b/src/mongo/util/base64.cpp
index 2f1f28bfda2..59fdfb63872 100644
--- a/src/mongo/util/base64.cpp
+++ b/src/mongo/util/base64.cpp
@@ -32,53 +32,18 @@
#include "mongo/util/base64.h"
-#include "mongo/util/assert_util.h"
-
-#include <array>
+#include <sstream>
namespace mongo {
-using std::begin;
-using std::end;
using std::string;
using std::stringstream;
-namespace {
-constexpr unsigned char kInvalid = -1;
-
-const class Alphabet {
-public:
- Alphabet() {
- decode.fill(kInvalid);
- for (size_t i = 0; i < encode.size(); ++i) {
- decode[encode[i]] = i;
- }
- }
-
- unsigned char e(std::uint8_t x) const {
- return encode[x & 0x3f];
- }
-
- std::uint8_t d(unsigned char x) const {
- auto const c = decode[x];
- uassert(40533, "Invalid base64 character", c != kInvalid);
- return c;
- }
-
- bool valid(unsigned char x) const {
- return decode[x] != kInvalid;
- }
+namespace base64 {
-private:
- StringData encode{
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/"};
- std::array<unsigned char, 256> decode;
-} alphabet;
-} // namespace
+Alphabet alphabet;
-void base64::encode(stringstream& ss, const char* data, int size) {
+void encode(stringstream& ss, const char* data, int size) {
for (int i = 0; i < size; i += 3) {
int left = size - i;
const unsigned char* start = (const unsigned char*)data + i;
@@ -117,59 +82,51 @@ void base64::encode(stringstream& ss, const char* data, int size) {
}
-string base64::encode(const char* data, int size) {
+string encode(const char* data, int size) {
stringstream ss;
encode(ss, data, size);
return ss.str();
}
-string base64::encode(const string& s) {
+string encode(const string& s) {
return encode(s.c_str(), s.size());
}
-void base64::decode(stringstream& ss, const string& s) {
+void decode(stringstream& ss, const string& s) {
uassert(10270, "invalid base64", s.size() % 4 == 0);
- auto const data = reinterpret_cast<const unsigned char*>(s.c_str());
- auto const size = s.size();
- bool done = false;
-
- for (size_t i = 0; i < size; i += 4) {
- uassert(
- 40534, "Invalid Base64 stream. Additional data following terminating sequence.", !done);
- auto const start = data + i;
- done = (start[2] == '=') || (start[3] == '=');
-
- ss << (char)(((alphabet.d(start[0]) << 2) & 0xFC) | ((alphabet.d(start[1]) >> 4) & 0x3));
- if (start[2] != '=') {
- ss << (char)(((alphabet.d(start[1]) << 4) & 0xF0) |
- ((alphabet.d(start[2]) >> 2) & 0xF));
- if (!done) {
- ss << (char)(((alphabet.d(start[2]) << 6) & 0xC0) |
- ((alphabet.d(start[3]) & 0x3F)));
+ const unsigned char* data = (const unsigned char*)s.c_str();
+ int size = s.size();
+
+ unsigned char buf[3];
+ for (int i = 0; i < size; i += 4) {
+ const unsigned char* start = data + i;
+ buf[0] =
+ ((alphabet.decode[start[0]] << 2) & 0xFC) | ((alphabet.decode[start[1]] >> 4) & 0x3);
+ buf[1] =
+ ((alphabet.decode[start[1]] << 4) & 0xF0) | ((alphabet.decode[start[2]] >> 2) & 0xF);
+ buf[2] = ((alphabet.decode[start[2]] << 6) & 0xC0) | ((alphabet.decode[start[3]] & 0x3F));
+
+ int len = 3;
+ if (start[3] == '=') {
+ len = 2;
+ if (start[2] == '=') {
+ len = 1;
}
}
+ ss.write((const char*)buf, len);
}
}
-string base64::decode(const string& s) {
+string decode(const string& s) {
stringstream ss;
decode(ss, s);
return ss.str();
}
-bool base64::validate(const StringData s) {
- if (s.size() % 4) {
- return false;
- }
- if (s.empty()) {
- return true;
- }
-
- auto const unwindTerminator = [](auto it) { return (*(it - 1) == '=') ? (it - 1) : it; };
- auto const e = unwindTerminator(unwindTerminator(end(s)));
-
- return e == std::find_if(begin(s), e, [](const char ch) { return !alphabet.valid(ch); });
+const char* chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/=";
+}
}
-
-} // namespace mongo
diff --git a/src/mongo/util/base64.h b/src/mongo/util/base64.h
index a9f3ea93b57..740811936ff 100644
--- a/src/mongo/util/base64.h
+++ b/src/mongo/util/base64.h
@@ -29,14 +29,51 @@
#pragma once
-#include <sstream>
+#include <iosfwd>
+#include <memory>
#include <string>
-#include "mongo/base/string_data.h"
+#include "mongo/util/assert_util.h"
namespace mongo {
namespace base64 {
+class Alphabet {
+public:
+ Alphabet()
+ : encode((unsigned char*)
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "+/")
+ , decode(new unsigned char[257]) {
+ memset(decode.get(), 0, 256);
+ for (int i = 0; i < 64; i++) {
+ decode[encode[i]] = i;
+ }
+
+ test();
+ }
+ void test() {
+ verify(strlen((char*)encode) == 64);
+ for (int i = 0; i < 26; i++)
+ verify(encode[i] == toupper(encode[i + 26]));
+ }
+
+ char e(int x) {
+ return encode[x & 0x3f];
+ }
+
+private:
+ const unsigned char* encode;
+
+public:
+ std::unique_ptr<unsigned char[]> decode;
+};
+
+extern Alphabet alphabet;
+
+
void encode(std::stringstream& ss, const char* data, int size);
std::string encode(const char* data, int size);
std::string encode(const std::string& s);
@@ -44,7 +81,8 @@ std::string encode(const std::string& s);
void decode(std::stringstream& ss, const std::string& s);
std::string decode(const std::string& s);
-bool validate(StringData);
+extern const char* chars;
-} // namespace base64
-} // namespace mongo
+void testAlphabet();
+}
+}
diff --git a/src/mongo/util/base64_test.cpp b/src/mongo/util/base64_test.cpp
deleted file mode 100644
index ab347da87cc..00000000000
--- a/src/mongo/util/base64_test.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Copyright (C) 2017 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/unittest/unittest.h"
-#include "mongo/util/base64.h"
-
-namespace mongo {
-namespace {
-
-TEST(Base64Test, transcode) {
- const struct {
- std::string plain;
- std::string encoded;
- } tests[] = {
- {"", ""},
- {"a", "YQ=="},
- {"aa", "YWE="},
- {"aaa", "YWFh"},
- {"aaaa", "YWFhYQ=="},
-
- {"A", "QQ=="},
- {"AA", "QUE="},
- {"AAA", "QUFB"},
- {"AAAA", "QUFBQQ=="},
-
- {"The quick brown fox jumped over the lazy dog.",
- "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"},
- {std::string("\0\1\2\3\4\5\6\7", 8), "AAECAwQFBgc="},
- {std::string("\0\277\1\276\2\275", 6), "AL8BvgK9"},
- };
-
- for (auto const& t : tests) {
- ASSERT_TRUE(base64::validate(t.encoded));
-
- ASSERT_EQUALS(base64::encode(t.plain), t.encoded);
- ASSERT_EQUALS(base64::decode(t.encoded), t.plain);
- }
-}
-
-TEST(Base64Test, parseFail) {
- const struct {
- std::string encoded;
- int code;
- } tests[] = {
- {"BadLength", 10270},
- {"Has Whitespace==", 40533},
- {"Hasbadchar$=", 40533},
- {"Hasbadchar\xFF=", 40533},
- {"Hasbadcahr\t=", 40533},
- {"too=soon", 40534},
- };
-
- for (auto const& t : tests) {
- ASSERT_FALSE(base64::validate(t.encoded));
-
- try {
- base64::decode(t.encoded);
- ASSERT_TRUE(false);
- } catch (const UserException& e) {
- ASSERT_EQ(e.getCode(), t.code);
- }
- }
-}
-
-} // namespace
-} // namespace mongo