diff options
-rw-r--r-- | jstests/core/constructors.js | 9 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/bindata.cpp | 52 | ||||
-rw-r--r-- | src/mongo/shell/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/util/uuid.cpp | 2 | ||||
-rw-r--r-- | src/mongo/util/uuid.h | 7 | ||||
-rw-r--r-- | src/mongo/util/uuid_test.cpp | 11 |
6 files changed, 66 insertions, 18 deletions
diff --git a/jstests/core/constructors.js b/jstests/core/constructors.js index 9e2cd26bbe8..b1a6b144896 100644 --- a/jstests/core/constructors.js +++ b/jstests/core/constructors.js @@ -196,11 +196,16 @@ var bindataConstructors = { var uuidConstructors = { "valid": [ - 'UUID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")', + 'UUID("0123456789abcdef0123456789ABCDEF")', + 'UUID("0a1A2b3B-4c5C-6d7D-8e9E-AfBFC0D1E3F4")', + 'UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")', + 'UUID()', + UUID().toString(), ], "invalid": [ 'UUID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0)', - 'UUID()', + 'UUID("aaaaaaaa-aaaa-aaaa-aaaaaaaa-aaaaaaaa")', + 'UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaa-aaaaaaa")', 'UUID("aa")', 'UUID("invalidhex")', 'UUID("invalidhexbutstilltherequiredlen")', diff --git a/src/mongo/scripting/mozjs/bindata.cpp b/src/mongo/scripting/mozjs/bindata.cpp index d528f6b1651..6d91dea8008 100644 --- a/src/mongo/scripting/mozjs/bindata.cpp +++ b/src/mongo/scripting/mozjs/bindata.cpp @@ -33,6 +33,7 @@ #include <cctype> #include <iomanip> +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/scripting/mozjs/implscope.h" #include "mongo/scripting/mozjs/internedstring.h" #include "mongo/scripting/mozjs/objectwrapper.h" @@ -42,6 +43,7 @@ #include "mongo/util/base64.h" #include "mongo/util/hex.h" #include "mongo/util/mongoutils/str.h" +#include "mongo/util/uuid.h" namespace mongo { namespace mozjs { @@ -114,16 +116,30 @@ void BinDataInfo::finalize(JSFreeOp* fop, JSObject* obj) { } void BinDataInfo::Functions::UUID::call(JSContext* cx, JS::CallArgs args) { - if (args.length() != 1) - uasserted(ErrorCodes::BadValue, "UUID needs 1 argument"); - - auto arg = args.get(0); - auto str = ValueWriter(cx, arg).toString(); - - if (str.length() != 32) - uasserted(ErrorCodes::BadValue, "UUID string must have 32 characters"); - - hexToBinData(cx, bdtUUID, arg, args.rval()); + boost::optional<mongo::UUID> uuid; + + if (args.length() == 0) { + uuid = mongo::UUID::gen(); + } else { + uassert(ErrorCodes::BadValue, "UUID needs 0 or 1 arguments", args.length() == 1); + auto arg = args.get(0); + std::string str = ValueWriter(cx, arg).toString(); + + // For backward compatibility quietly accept and convert 32-character hex strings to + // BinData(3, ...) as used for the deprecated UUID v3 BSON type. + if (str.length() == 32) { + hexToBinData(cx, bdtUUID, arg, args.rval()); + return; + } + uuid = uassertStatusOK(mongo::UUID::parse(str)); + }; + ConstDataRange cdr = uuid->toCDR(); + std::string encoded = mongo::base64::encode(cdr.data(), cdr.length()); + + JS::AutoValueArray<2> newArgs(cx); + newArgs[0].setInt32(newUUID); + ValueReader(cx, newArgs[1]).fromStringData(encoded); + getScope(cx)->getProto<BinDataInfo>().newInstance(newArgs, args.rval()); } void BinDataInfo::Functions::MD5::call(JSContext* cx, JS::CallArgs args) { @@ -158,9 +174,21 @@ void BinDataInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) { auto str = getEncoded(args.thisv()); str::stream ss; + auto binType = o.getNumber(InternedString::type); + + if (binType == newUUID) { + auto decoded = mongo::base64::decode(*str); + + // If this is in fact a UUID, use a more friendly string representation. + if (decoded.length() == mongo::UUID::kNumBytes) { + mongo::UUID uuid = mongo::UUID::fromCDR({decoded.data(), decoded.length()}); + ss << "UUID(\"" << uuid.toString() << "\")"; + ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); + return; + } + } - ss << "BinData(" << o.getNumber(InternedString::type) << ",\"" << *str << "\")"; - + ss << "BinData(" << binType << ",\"" << *str << "\")"; ValueReader(cx, args.rval()).fromStringData(ss.operator std::string()); } diff --git a/src/mongo/shell/SConscript b/src/mongo/shell/SConscript index c4f33385344..3e66a33cf4e 100644 --- a/src/mongo/shell/SConscript +++ b/src/mongo/shell/SConscript @@ -55,6 +55,7 @@ env.Library( 'mongo.cpp', ], LIBDEPS=[ - "$BUILD_DIR/mongo/base" + "$BUILD_DIR/mongo/base", + "$BUILD_DIR/mongo/util/uuid" ], ) diff --git a/src/mongo/util/uuid.cpp b/src/mongo/util/uuid.cpp index ca84906eab2..e3326b718bf 100644 --- a/src/mongo/util/uuid.cpp +++ b/src/mongo/util/uuid.cpp @@ -60,7 +60,7 @@ StatusWith<UUID> UUID::parse(BSONElement from) { StatusWith<UUID> UUID::parse(const std::string& s) { if (!isUUIDString(s)) { - return {ErrorCodes::InvalidUUID, "Invalid uuid string"}; + return {ErrorCodes::InvalidUUID, "Invalid UUID string: " + s}; } UUIDStorage uuid; diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h index 4f86e26aa7c..9e1caa88b6c 100644 --- a/src/mongo/util/uuid.h +++ b/src/mongo/util/uuid.h @@ -87,6 +87,13 @@ public: */ static UUID parse(const BSONObj& obj); + static UUID fromCDR(ConstDataRange cdr) { + UUID uuid; + invariant(cdr.length() == uuid._uuid.size()); + memcpy(uuid._uuid.data(), cdr.data(), uuid._uuid.size()); + return uuid; + } + /** * Returns whether this string represents a valid UUID. */ diff --git a/src/mongo/util/uuid_test.cpp b/src/mongo/util/uuid_test.cpp index b0a5d12dada..c6b0388ef06 100644 --- a/src/mongo/util/uuid_test.cpp +++ b/src/mongo/util/uuid_test.cpp @@ -141,7 +141,14 @@ TEST(UUIDTest, toAndFromString) { ASSERT_EQUALS(ErrorCodes::InvalidUUID, UUID::parse("samsamsa-sams-4sam-8sam-samsamsamsam")); } -TEST(UUIDTest, toAndFromBSONTest) { +TEST(UUIDTest, toAndFromCDR) { + UUID uuid = UUID::gen(); + ConstDataRange cdr = uuid.toCDR(); + UUID roundtripped = UUID::fromCDR(cdr); + ASSERT_EQUALS(roundtripped, uuid); +} + +TEST(UUIDTest, toAndFromBSON) { // UUID -> BSON -> UUID UUID uuid = UUID::gen(); auto uuidBSON = uuid.toBSON(); @@ -170,7 +177,7 @@ TEST(UUIDTest, toAndFromBSONTest) { ASSERT_EQUALS(ErrorCodes::InvalidUUID, UUID::parse(bson4.getField("uuid"))); } -TEST(UUIDTest, toBSONUsingBSONMacroTest) { +TEST(UUIDTest, toBSONUsingBSONMacro) { auto uuid = UUID::gen(); auto bson = BSON("myuuid" << uuid); |