diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-08-02 16:46:16 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-08-05 11:05:32 -0400 |
commit | 18808cd923789a34abd7f13d62e7a73fafd5ce5f (patch) | |
tree | 81b58c1f98a005cfbdd0f9ac1128fdefcebb71b4 /src | |
parent | 197ea2a625dc04d95a7ad4933283b5f02ca2ad9e (diff) | |
download | mongo-18808cd923789a34abd7f13d62e7a73fafd5ce5f.tar.gz |
SERVER-19711 detect invalid wrapped queries in ServerSelectionMetadata upconversion
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/rpc/metadata/server_selection_metadata.cpp | 30 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/server_selection_metadata_test.cpp | 10 |
2 files changed, 32 insertions, 8 deletions
diff --git a/src/mongo/rpc/metadata/server_selection_metadata.cpp b/src/mongo/rpc/metadata/server_selection_metadata.cpp index 1441243a4e7..a4fbbde3fca 100644 --- a/src/mongo/rpc/metadata/server_selection_metadata.cpp +++ b/src/mongo/rpc/metadata/server_selection_metadata.cpp @@ -55,17 +55,26 @@ const char kQueryWrapper[] = "query"; /** * Utility to unwrap a '$query' or 'query' wrapped command object. The first element of the - * return value indicates whether the command was unwrapped, and the second element is either + * returned tuple indicates whether the command was unwrapped, and the second element is either * the unwrapped command (if it was wrapped), or the original command if it was not. */ -std::tuple<bool, BSONObj> unwrapCommand(const BSONObj& maybeWrapped) { +StatusWith<std::tuple<bool, BSONObj>> unwrapCommand(const BSONObj& maybeWrapped) { const auto firstElFieldName = maybeWrapped.firstElementFieldName(); - if ((firstElFieldName == StringData(kDollarQueryWrapper)) || - (firstElFieldName == StringData(kQueryWrapper))) { - // TODO: do we need getOwned here? - return std::make_tuple(true, maybeWrapped.firstElement().embeddedObject()); + + if ((firstElFieldName != StringData(kDollarQueryWrapper)) && + (firstElFieldName != StringData(kQueryWrapper))) { + return std::make_tuple(false, maybeWrapped); + } + + BSONElement inner; + auto extractStatus = + bsonExtractTypedField(maybeWrapped, firstElFieldName, mongo::Object, &inner); + + if (!extractStatus.isOK()) { + return extractStatus; } - return std::make_tuple(false, maybeWrapped); + + return std::make_tuple(true, inner.Obj()); } /** @@ -215,9 +224,14 @@ Status ServerSelectionMetadata::upconvert(const BSONObj& legacyCommand, // First we need to check if we have a wrapped command. That is, a command of the form // {'$query': { 'commandName': 1, ...}, '$someOption': 5, ....}. Curiously, the field name // of the wrapped query can be either '$query', or 'query'. + auto swUnwrapped = unwrapCommand(legacyCommand); + if (!swUnwrapped.isOK()) { + return swUnwrapped.getStatus(); + } + BSONObj maybeUnwrapped; bool wasWrapped; - std::tie(wasWrapped, maybeUnwrapped) = unwrapCommand(legacyCommand); + std::tie(wasWrapped, maybeUnwrapped) = swUnwrapped.getValue(); if (wasWrapped) { // Check if legacyCommand has an invalid $maxTimeMS option. diff --git a/src/mongo/rpc/metadata/server_selection_metadata_test.cpp b/src/mongo/rpc/metadata/server_selection_metadata_test.cpp index ae8d4057b45..40e7aebae58 100644 --- a/src/mongo/rpc/metadata/server_selection_metadata_test.cpp +++ b/src/mongo/rpc/metadata/server_selection_metadata_test.cpp @@ -177,6 +177,16 @@ TEST(ServerSelectionMetadata, UpconvertInvalidMetadata) { << "pong" << "$queryOptions" << BSONObj()), ErrorCodes::NoSuchKey); + + // invalid wrapped query + checkUpconvertFails(BSON("$query" << 1), ErrorCodes::TypeMismatch); + checkUpconvertFails(BSON("$query" + << ""), + ErrorCodes::TypeMismatch); + checkUpconvertFails(BSON("query" << 1), ErrorCodes::TypeMismatch); + checkUpconvertFails(BSON("query" + << ""), + ErrorCodes::TypeMismatch); } } // namespace |