summaryrefslogtreecommitdiff
path: root/src/mongo/rpc/metadata/client_metadata.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/rpc/metadata/client_metadata.h')
-rw-r--r--src/mongo/rpc/metadata/client_metadata.h143
1 files changed, 114 insertions, 29 deletions
diff --git a/src/mongo/rpc/metadata/client_metadata.h b/src/mongo/rpc/metadata/client_metadata.h
index eb467caab6a..294a88815ec 100644
--- a/src/mongo/rpc/metadata/client_metadata.h
+++ b/src/mongo/rpc/metadata/client_metadata.h
@@ -46,38 +46,35 @@ constexpr auto kMetadataDocumentName = "client"_sd;
/**
* The ClientMetadata class is responsible for parsing the client metadata document that is received
- * in isMaster from clients. This class also provides static methods for client libraries to create
- * a valid client metadata document.
+ * in the "client" field of the first hello from clients. The client metadata document can also be
+ * parsed from the "$client" field of any operation. This class also provides static methods for
+ * client libraries to write a valid client metadata document.
*
- * Example document of isMaster request with client metadata document:
+ * Example client metadata document:
* {
- * "isMaster" : 1,
- * "client" : {
- * "application" : { // Optional
- * "name" : "string" // Optional with caveats
- * },
- * "driver" : { // Required, Informational Only
- * "name" : "string", // Required, Informational Only
- * "version" : "string" // Required, Informational Only
- * },
- * "os" : { // Required, Informational Only
- * "type" : "string", // Required, Informational Only, See note
- * "name" : "string", // Optional, Informational Only
- * "architecture" : "string", // Optional, Informational Only
- * "version" : "string" // Optional, Informational Only
- * }
- * "mongos" : { // Optional, Informational Only
- * "host" : "string", // Optional, Informational Only
- * "client" : "string", // Optional, Informational Only
- * "version" : "string" // Optional, Informational Only
- * }
- * }
+ * "application" : { // Optional
+ * "name" : "string" // Optional with caveats
+ * },
+ * "driver" : { // Required, Informational Only
+ * "name" : "string", // Required, Informational Only
+ * "version" : "string" // Required, Informational Only
+ * },
+ * "os" : { // Required, Informational Only
+ * "type" : "string", // Required, Informational Only, See note
+ * "name" : "string", // Optional, Informational Only
+ * "architecture" : "string", // Optional, Informational Only
+ * "version" : "string" // Optional, Informational Only
+ * }
+ * "mongos" : { // Optional, Informational Only
+ * "host" : "string", // Optional, Informational Only
+ * "client" : "string", // Optional, Informational Only
+ * "version" : "string" // Optional, Informational Only
+ * }
* }
*
- * For this classes' purposes, the client metadata document is the sub-document in "client". It is
- * allowed to contain additional fields that are not listed in the example above. These additional
- * fields are ignore by this class. The "os" document "type" field is required (defaults to
- * "unknown" in Mongo Drivers). The "driver", and "os" documents while required, are for
+ * It is allowed to contain additional fields that are not listed in the example above. These
+ * additional fields are ignore by this class. The "os" document "type" field is required (defaults
+ * to "unknown" in Mongo Drivers). The "driver", and "os" documents while required, are for
* informational purposes only. The content is logged to disk but otherwise ignored.
*
* See Driver Specification: "MongoDB Handshake" for more information.
@@ -91,7 +88,54 @@ public:
ClientMetadata& operator=(ClientMetadata&&) = default;
/**
- * Parse and validate a client metadata document contained in an isMaster request.
+ * Get the ClientMetadata for the Client.
+ *
+ * This function may return nullptr if there was no ClientMetadata provided for the
+ * Client.
+ *
+ * The pointer to ClientMetadata is valid to use if:
+ * - You hold the Client lock.
+ * - You are on the Client's thread.
+ */
+ static const ClientMetadata* getForClient(Client* client) noexcept;
+
+ /**
+ * Get the ClientMetadata for the OperationContext.
+ *
+ * This function may return nullptr if there was no ClientMetadata provided for the
+ * OperationContext.
+ *
+ * The pointer to ClientMetadata is valid to use if:
+ * - You hold the Client lock.
+ * - You are on the Client's thread.
+ */
+ static const ClientMetadata* getForOperation(OperationContext* opCtx) noexcept;
+
+ /**
+ * Get the prioritized ClientMetadata for the Client.
+ *
+ * This function returns getForOperation() if it returns a valid pointer, otherwise it returns
+ * getForClient().
+ *
+ * The pointer to ClientMetadata is valid to use if:
+ * - You hold the Client lock.
+ * - You are on the Client's thread.
+ */
+ static const ClientMetadata* get(Client* client) noexcept;
+
+ /**
+ * Set the ClientMetadata for the Client directly.
+ *
+ * This should only be used in testing. It sets the ClientMetadata as finalized but does not
+ * check if it was previously finalized. It allows the user to replace the ClientMetadata for
+ * a Client, which is disallowed if done via setFromMetadata().
+ *
+ * This function takes the Client lock.
+ */
+ static void setAndFinalize(Client* client, boost::optional<ClientMetadata> meta);
+
+ /**
+ * Parse and validate a client metadata document contained in a hello request.
*
* Empty or non-existent sub-documents are permitted. Non-empty documents are required to have
* the fields driver.name, driver.version, and os.type which must be strings.
@@ -155,6 +199,47 @@ public:
BSONObjBuilder* builder);
/**
+ * Mark the ClientMetadata as finalized.
+ *
+ * Once this function is called, no future hello can mutate the ClientMetadata.
+ *
+ * This function takes the Client lock.
+ */
+ static bool tryFinalize(Client* client);
+
+ /**
+ * Set the ClientMetadata for the Client by reading it from the given BSONElement.
+ *
+ * This function throws if the ClientMetadata has already been finalized but the BSONElement is
+ * an object. ClientMetadata is allowed to be set via the first hello only.
+ *
+ * This function takes the Client lock.
+ */
+ static void setFromMetadata(Client* client, BSONElement& elem);
+
+ /**
+ * Set the ClientMetadata for the OperationContext by reading it from the given BSONElement.
+ *
+ * This function throws if called more than once for the same OperationContext.
+ *
+ * This function takes the Client lock.
+ */
+ static void setFromMetadataForOperation(OperationContext* opCtx, BSONElement& elem);
+
+ /**
+ * Read from the $client field in requests.
+ *
+ * Throws an error if the $client section is not valid. It is valid for it to not exist though.
+ */
+ static boost::optional<ClientMetadata> readFromMetadata(BSONElement& elem);
+
+ /**
+ * Write the $client section to request bodies if there is a non-empty client metadata
+ * connection with the current client.
+ */
+ void writeToMetadata(BSONObjBuilder* builder) const noexcept;
+
+ /**
* Modify the existing client metadata document to include a mongos section.
*
* hostAndPort is "host:port" of the running MongoS.