diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2017-06-07 13:56:30 +0300 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2017-07-06 18:05:57 -0400 |
commit | e09a21c0d849878792e647d2326d6fde865ac458 (patch) | |
tree | b3cd6c002db115e73fa8151609467a4ec7ce3d0d /src/mongo/db/commands/write_commands | |
parent | 1447d3db59804752e6c2882a6a8a4a14d7ae71ad (diff) | |
download | mongo-e09a21c0d849878792e647d2326d6fde865ac458.tar.gz |
SERVER-28752 Use IDL for write commands parsing
Diffstat (limited to 'src/mongo/db/commands/write_commands')
3 files changed, 105 insertions, 52 deletions
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index b9e92e13947..dcab92230d2 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -41,8 +41,8 @@ #include "mongo/db/ops/parsed_delete.h" #include "mongo/db/ops/parsed_update.h" #include "mongo/db/ops/update_lifecycle_impl.h" +#include "mongo/db/ops/write_ops.h" #include "mongo/db/ops/write_ops_exec.h" -#include "mongo/db/ops/write_ops_parsers.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/repl/repl_client_info.h" @@ -53,10 +53,6 @@ #include "mongo/s/stale_exception.h" namespace mongo { - -using std::string; -using std::stringstream; - namespace { void redactTooLongLog(mutablebson::Document* cmdObj, StringData fieldName) { @@ -225,8 +221,6 @@ public: BSONObjBuilder& result) = 0; }; -} // namespace - class CmdInsert final : public WriteCommand { public: CmdInsert() : WriteCommand("insert") {} @@ -235,7 +229,7 @@ public: redactTooLongLog(cmdObj, "documents"); } - void help(stringstream& help) const final { + void help(std::stringstream& help) const final { help << "insert documents"; } @@ -251,12 +245,12 @@ public: void runImpl(OperationContext* opCtx, const OpMsgRequest& request, BSONObjBuilder& result) final { - const auto batch = parseInsertCommand(request); + const auto batch = InsertOp::parse(request); const auto reply = performInserts(opCtx, batch); serializeReply(opCtx, ReplyStyle::kNotUpdate, - batch.continueOnError, - batch.documents.size(), + !batch.getWriteCommandBase().getOrdered(), + batch.getDocuments().size(), reply, &result); } @@ -270,7 +264,7 @@ public: redactTooLongLog(cmdObj, "updates"); } - void help(stringstream& help) const final { + void help(std::stringstream& help) const final { help << "update documents"; } @@ -286,12 +280,12 @@ public: void runImpl(OperationContext* opCtx, const OpMsgRequest& request, BSONObjBuilder& result) final { - const auto batch = parseUpdateCommand(request); + const auto batch = UpdateOp::parse(request); const auto reply = performUpdates(opCtx, batch); serializeReply(opCtx, ReplyStyle::kUpdate, - batch.continueOnError, - batch.updates.size(), + !batch.getWriteCommandBase().getOrdered(), + batch.getUpdates().size(), reply, &result); } @@ -301,21 +295,21 @@ public: const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, BSONObjBuilder* out) const final { - auto request = OpMsgRequest::fromDBAndBody(dbname, cmdObj); - const auto batch = parseUpdateCommand(request); + const auto opMsgRequest(OpMsgRequest::fromDBAndBody(dbname, cmdObj)); + const auto batch = UpdateOp::parse(opMsgRequest); uassert(ErrorCodes::InvalidLength, "explained write batches must be of size 1", - batch.updates.size() == 1); + batch.getUpdates().size() == 1); - UpdateLifecycleImpl updateLifecycle(batch.ns); - UpdateRequest updateRequest(batch.ns); + UpdateLifecycleImpl updateLifecycle(batch.getNamespace()); + UpdateRequest updateRequest(batch.getNamespace()); updateRequest.setLifecycle(&updateLifecycle); - updateRequest.setQuery(batch.updates[0].query); - updateRequest.setCollation(batch.updates[0].collation); - updateRequest.setUpdates(batch.updates[0].update); - updateRequest.setArrayFilters(batch.updates[0].arrayFilters); - updateRequest.setMulti(batch.updates[0].multi); - updateRequest.setUpsert(batch.updates[0].upsert); + updateRequest.setQuery(batch.getUpdates()[0].getQ()); + updateRequest.setUpdates(batch.getUpdates()[0].getU()); + updateRequest.setCollation(write_ops::collationOf(batch.getUpdates()[0])); + updateRequest.setArrayFilters(write_ops::arrayFiltersOf(batch.getUpdates()[0])); + updateRequest.setMulti(batch.getUpdates()[0].getMulti()); + updateRequest.setUpsert(batch.getUpdates()[0].getUpsert()); updateRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO); updateRequest.setExplain(); @@ -324,7 +318,7 @@ public: // Explains of write commands are read-only, but we take write locks so that timing // info is more accurate. - AutoGetCollection collection(opCtx, batch.ns, MODE_IX); + AutoGetCollection collection(opCtx, batch.getNamespace(), MODE_IX); auto exec = uassertStatusOK(getExecutorUpdate( opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedUpdate)); @@ -341,7 +335,7 @@ public: redactTooLongLog(cmdObj, "deletes"); } - void help(stringstream& help) const final { + void help(std::stringstream& help) const final { help << "delete documents"; } @@ -357,12 +351,12 @@ public: void runImpl(OperationContext* opCtx, const OpMsgRequest& request, BSONObjBuilder& result) final { - const auto batch = parseDeleteCommand(request); + const auto batch = DeleteOp::parse(request); const auto reply = performDeletes(opCtx, batch); serializeReply(opCtx, ReplyStyle::kNotUpdate, - batch.continueOnError, - batch.deletes.size(), + !batch.getWriteCommandBase().getOrdered(), + batch.getDeletes().size(), reply, &result); } @@ -372,16 +366,16 @@ public: const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, BSONObjBuilder* out) const final { - auto request = OpMsgRequest::fromDBAndBody(dbname, cmdObj); - const auto batch = parseDeleteCommand(request); + const auto opMsgRequest(OpMsgRequest::fromDBAndBody(dbname, cmdObj)); + const auto batch = DeleteOp::parse(opMsgRequest); uassert(ErrorCodes::InvalidLength, "explained write batches must be of size 1", - batch.deletes.size() == 1); + batch.getDeletes().size() == 1); - DeleteRequest deleteRequest(batch.ns); - deleteRequest.setQuery(batch.deletes[0].query); - deleteRequest.setCollation(batch.deletes[0].collation); - deleteRequest.setMulti(batch.deletes[0].multi); + DeleteRequest deleteRequest(batch.getNamespace()); + deleteRequest.setQuery(batch.getDeletes()[0].getQ()); + deleteRequest.setCollation(write_ops::collationOf(batch.getDeletes()[0])); + deleteRequest.setMulti(batch.getDeletes()[0].getMulti()); deleteRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO); deleteRequest.setExplain(); @@ -390,7 +384,7 @@ public: // Explains of write commands are read-only, but we take write locks so that timing // info is more accurate. - AutoGetCollection collection(opCtx, batch.ns, MODE_IX); + AutoGetCollection collection(opCtx, batch.getNamespace(), MODE_IX); // Explain the plan tree. auto exec = uassertStatusOK(getExecutorDelete( @@ -400,4 +394,5 @@ public: } } cmdDelete; +} // namespace } // namespace mongo diff --git a/src/mongo/db/commands/write_commands/write_commands_common.cpp b/src/mongo/db/commands/write_commands/write_commands_common.cpp index aa208a1d3c7..9a5eb5d6cd8 100644 --- a/src/mongo/db/commands/write_commands/write_commands_common.cpp +++ b/src/mongo/db/commands/write_commands/write_commands_common.cpp @@ -37,19 +37,76 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/catalog/document_validation.h" +#include "mongo/db/ops/write_ops.h" #include "mongo/util/assert_util.h" namespace mongo { namespace auth { +namespace { -using std::string; -using std::vector; +using write_ops::Insert; +using write_ops::Update; +using write_ops::UpdateOpEntry; + +/** + * Helper to determine whether or not there are any upserts in the batch + */ +bool containsUpserts(const BSONObj& writeCmdObj) { + BSONElement updatesEl = writeCmdObj[Update::kUpdatesFieldName]; + if (updatesEl.type() != Array) { + return false; + } + + for (const auto& updateEl : updatesEl.Array()) { + if (!updateEl.isABSONObj()) + continue; + + if (updateEl.Obj()[UpdateOpEntry::kUpsertFieldName].trueValue()) + return true; + } + + return false; +} + +/** + * Helper to extract the namespace being indexed from a raw BSON write command. + * + * TODO: Remove when we have parsing hooked before authorization. + */ +StatusWith<NamespaceString> getIndexedNss(const BSONObj& writeCmdObj) { + BSONElement documentsEl = writeCmdObj[Insert::kDocumentsFieldName]; + if (documentsEl.type() != Array) { + return {ErrorCodes::FailedToParse, "index write batch is invalid"}; + } + + BSONObjIterator it(documentsEl.Obj()); + if (!it.more()) { + return {ErrorCodes::FailedToParse, "index write batch is empty"}; + } + + BSONElement indexDescEl = it.next(); + + const std::string nsToIndex = indexDescEl["ns"].str(); + if (nsToIndex.empty()) { + return {ErrorCodes::FailedToParse, + "index write batch contains an invalid index descriptor"}; + } + + if (it.more()) { + return {ErrorCodes::FailedToParse, + "index write batches may only contain a single index descriptor"}; + } + + return {NamespaceString(std::move(nsToIndex))}; +} + +} // namespace Status checkAuthForWriteCommand(AuthorizationSession* authzSession, BatchedCommandRequest::BatchType cmdType, const NamespaceString& cmdNSS, const BSONObj& cmdObj) { - vector<Privilege> privileges; + std::vector<Privilege> privileges; ActionSet actionsOnCommandNSS; if (shouldBypassDocumentValidationForCommand(cmdObj)) { @@ -61,12 +118,12 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession, actionsOnCommandNSS.addAction(ActionType::insert); } else { // Special-case indexes until we have a command - string nsToIndex, errMsg; - if (!BatchedCommandRequest::getIndexedNS(cmdObj, &nsToIndex, &errMsg)) { - return Status(ErrorCodes::FailedToParse, errMsg); + const auto swNssToIndex = getIndexedNss(cmdObj); + if (!swNssToIndex.isOK()) { + return swNssToIndex.getStatus(); } - NamespaceString nssToIndex(nsToIndex); + const auto& nssToIndex = swNssToIndex.getValue(); privileges.push_back( Privilege(ResourcePattern::forExactNamespace(nssToIndex), ActionType::createIndex)); } @@ -74,7 +131,7 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession, actionsOnCommandNSS.addAction(ActionType::update); // Upsert also requires insert privs - if (BatchedCommandRequest::containsUpserts(cmdObj)) { + if (containsUpserts(cmdObj)) { actionsOnCommandNSS.addAction(ActionType::insert); } } else { @@ -82,7 +139,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession, actionsOnCommandNSS.addAction(ActionType::remove); } - if (!actionsOnCommandNSS.empty()) { privileges.emplace_back(ResourcePattern::forExactNamespace(cmdNSS), actionsOnCommandNSS); } @@ -92,5 +148,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession, return Status(ErrorCodes::Unauthorized, "unauthorized"); } -} -} + +} // namespace auth +} // namespace mongo diff --git a/src/mongo/db/commands/write_commands/write_commands_common.h b/src/mongo/db/commands/write_commands/write_commands_common.h index 53ba02aad05..8f8206d3c70 100644 --- a/src/mongo/db/commands/write_commands/write_commands_common.h +++ b/src/mongo/db/commands/write_commands/write_commands_common.h @@ -44,5 +44,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession, BatchedCommandRequest::BatchType cmdType, const NamespaceString& cmdNSS, const BSONObj& cmdObj); -} -} + +} // namespace auth +} // namespace mongo |