diff options
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r-- | src/mongo/rpc/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/client_metadata.cpp | 109 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/client_metadata.h | 20 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/client_metadata.idl | 44 |
4 files changed, 79 insertions, 95 deletions
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript index 257e556da03..957647e5721 100644 --- a/src/mongo/rpc/SConscript +++ b/src/mongo/rpc/SConscript @@ -135,7 +135,6 @@ env.Library( target='client_metadata', source=[ 'metadata/client_metadata.cpp', - 'metadata/client_metadata.idl', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', diff --git a/src/mongo/rpc/metadata/client_metadata.cpp b/src/mongo/rpc/metadata/client_metadata.cpp index 6ea09b44b02..a4a8767aadc 100644 --- a/src/mongo/rpc/metadata/client_metadata.cpp +++ b/src/mongo/rpc/metadata/client_metadata.cpp @@ -84,7 +84,7 @@ const auto getOperationState = OperationContext::declareDecoration<ClientMetadat } // namespace -StatusWith<boost::optional<ClientMetadata>> ClientMetadata::parse(const BSONElement& element) try { +StatusWith<boost::optional<ClientMetadata>> ClientMetadata::parse(const BSONElement& element) { if (element.eoo()) { return {boost::none}; } @@ -93,50 +93,84 @@ StatusWith<boost::optional<ClientMetadata>> ClientMetadata::parse(const BSONElem return Status(ErrorCodes::TypeMismatch, "The client metadata document must be a document"); } - return boost::make_optional(parseFromBSON(element.Obj())); -} catch (const DBException& ex) { - return ex.toStatus(); + ClientMetadata clientMetadata; + Status s = clientMetadata.parseClientMetadataDocument(element.Obj()); + if (!s.isOK()) { + return s; + } + + return {std::move(clientMetadata)}; } -ClientMetadata::ClientMetadata(BSONObj doc) { +Status ClientMetadata::parseClientMetadataDocument(const BSONObj& doc) { uint32_t maxLength = kMaxMongoDMetadataDocumentByteLength; if (isMongos()) { maxLength = kMaxMongoSMetadataDocumentByteLength; } - uassert(ErrorCodes::ClientMetadataDocumentTooLarge, - str::stream() << "The client metadata document must be less then or equal to " - << maxLength << "bytes", - static_cast<uint32_t>(doc.objsize()) <= maxLength); - - const auto isobj = [](StringData name, const BSONElement& e) { - uassert(ErrorCodes::TypeMismatch, - str::stream() - << "The '" << name - << "' field is required to be a BSON document in the client metadata document", - e.isABSONObj()); - }; + if (static_cast<uint32_t>(doc.objsize()) > maxLength) { + return Status(ErrorCodes::ClientMetadataDocumentTooLarge, + str::stream() << "The client metadata document must be less then or equal to " + << maxLength << "bytes"); + } // Get a copy so that we can take a stable reference to the app name inside - _document = doc.getOwned(); + BSONObj docOwned = doc.getOwned(); + StringData appName; bool foundDriver = false; bool foundOperatingSystem = false; - for (const auto& e : _document) { - auto name = e.fieldNameStringData(); + + BSONObjIterator i(docOwned); + while (i.more()) { + BSONElement e = i.next(); + StringData name = e.fieldNameStringData(); if (name == kApplication) { // Application is an optional sub-document, but we require it to be a document if // specified. - isobj(kApplication, e); - _appName = uassertStatusOK(parseApplicationDocument(e.Obj())); + if (!e.isABSONObj()) { + return Status(ErrorCodes::TypeMismatch, + str::stream() << "The '" << kApplication + << "' field is required to be a BSON document in the " + "client metadata document"); + } + + auto swAppName = parseApplicationDocument(e.Obj()); + if (!swAppName.getStatus().isOK()) { + return swAppName.getStatus(); + } + + appName = swAppName.getValue(); + } else if (name == kDriver) { - isobj(kDriver, e); - uassertStatusOK(validateDriverDocument(e.Obj())); + if (!e.isABSONObj()) { + return Status(ErrorCodes::TypeMismatch, + str::stream() << "The '" << kDriver + << "' field is required to be a " + "BSON document in the client " + "metadata document"); + } + + Status s = validateDriverDocument(e.Obj()); + if (!s.isOK()) { + return s; + } + foundDriver = true; } else if (name == kOperatingSystem) { - isobj(kOperatingSystem, e); - uassertStatusOK(validateOperatingSystemDocument(e.Obj())); + if (!e.isABSONObj()) { + return Status(ErrorCodes::TypeMismatch, + str::stream() << "The '" << kOperatingSystem + << "' field is required to be a BSON document in the " + "client metadata document"); + } + + Status s = validateOperatingSystemDocument(e.Obj()); + if (!s.isOK()) { + return s; + } + foundOperatingSystem = true; } @@ -144,16 +178,23 @@ ClientMetadata::ClientMetadata(BSONObj doc) { } // Driver is a required sub document. - uassert(ErrorCodes::ClientMetadataMissingField, - str::stream() << "Missing required sub-document '" << kDriver - << "' in the client metadata document", - foundDriver); + if (!foundDriver) { + return Status(ErrorCodes::ClientMetadataMissingField, + str::stream() << "Missing required sub-document '" << kDriver + << "' in the client metadata document"); + } // OS is a required sub document. - uassert(ErrorCodes::ClientMetadataMissingField, - str::stream() << "Missing required sub-document '" << kOperatingSystem - << "' in the client metadata document", - foundOperatingSystem); + if (!foundOperatingSystem) { + return Status(ErrorCodes::ClientMetadataMissingField, + str::stream() << "Missing required sub-document '" << kOperatingSystem + << "' in the client metadata document"); + } + + _document = std::move(docOwned); + _appName = std::move(appName); + + return Status::OK(); } StatusWith<StringData> ClientMetadata::parseApplicationDocument(const BSONObj& doc) { diff --git a/src/mongo/rpc/metadata/client_metadata.h b/src/mongo/rpc/metadata/client_metadata.h index 309eb5668e0..cc3d870a4f0 100644 --- a/src/mongo/rpc/metadata/client_metadata.h +++ b/src/mongo/rpc/metadata/client_metadata.h @@ -80,16 +80,10 @@ constexpr auto kMetadataDocumentName = "client"_sd; * See Driver Specification: "MongoDB Handshake" for more information. */ class ClientMetadata { -public: - explicit ClientMetadata(BSONObj obj); - - ClientMetadata(const ClientMetadata& src) : ClientMetadata(src._document) {} - ClientMetadata& operator=(const ClientMetadata& src) { - ClientMetadata copy(src._document); - *this = std::move(copy); - return *this; - } + ClientMetadata(const ClientMetadata&) = delete; + ClientMetadata& operator=(const ClientMetadata&) = delete; +public: ClientMetadata(ClientMetadata&&) = default; ClientMetadata& operator=(ClientMetadata&&) = default; @@ -151,13 +145,6 @@ public: static StatusWith<boost::optional<ClientMetadata>> parse(const BSONElement& element); /** - * Wrapper for BSONObj constructor used by IDL parsers. - */ - static ClientMetadata parseFromBSON(BSONObj obj) { - return ClientMetadata(obj); - } - - /** * Create a new client metadata document with os information from the ProcessInfo class. * * This method outputs the "client" field, and client metadata sub-document in the @@ -324,6 +311,7 @@ public: private: ClientMetadata() = default; + Status parseClientMetadataDocument(const BSONObj& doc); static Status validateDriverDocument(const BSONObj& doc); static Status validateOperatingSystemDocument(const BSONObj& doc); static StatusWith<StringData> parseApplicationDocument(const BSONObj& doc); diff --git a/src/mongo/rpc/metadata/client_metadata.idl b/src/mongo/rpc/metadata/client_metadata.idl deleted file mode 100644 index d1726153d98..00000000000 --- a/src/mongo/rpc/metadata/client_metadata.idl +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2021-present MongoDB, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the Server Side Public License, version 1, -# as published by MongoDB, Inc. -# -# 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 -# Server Side Public License for more details. -# -# You should have received a copy of the Server Side Public License -# along with this program. If not, see -# <http://www.mongodb.com/licensing/server-side-public-license>. -# -# 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 Server Side 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. -# - -global: - cpp_namespace: "mongo" - cpp_includes: - - "mongo/rpc/metadata/client_metadata.h" - -imports: - - "mongo/idl/basic_types.idl" - -types: - ClientMetadata: - description: "Client metadata document" - bson_serialization_type: object - cpp_type: ClientMetadata - serializer: "mongo::ClientMetadata::getDocument" - deserializer: "mongo::ClientMetadata::parseFromBSON" - |