diff options
author | Amirsaman Memaripour <amirsaman.memaripour@10gen.com> | 2020-02-03 23:15:40 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2020-02-03 23:15:40 +0000 |
commit | 6527449a3c0d0acba0ace9c421fd0580b4afbffa (patch) | |
tree | 47fda59e385b1e7430b94f52a44dc8f31b6422c3 | |
parent | 860b5fdf681581e211d3be50bfc67007c81530a9 (diff) | |
download | mongo-6527449a3c0d0acba0ace9c421fd0580b4afbffa.tar.gz |
SERVER-45920 Validate writeConcern.w
-rw-r--r-- | jstests/replsets/drop_db.js | 4 | ||||
-rw-r--r-- | jstests/replsets/server_status_metrics.js | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_config.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_config.h | 6 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/write_concern_options_test.cpp | 9 |
6 files changed, 27 insertions, 6 deletions
diff --git a/jstests/replsets/drop_db.js b/jstests/replsets/drop_db.js index 49ee3e04406..bebc101a7f9 100644 --- a/jstests/replsets/drop_db.js +++ b/jstests/replsets/drop_db.js @@ -49,10 +49,10 @@ checkWriteConcern(() => assert.commandWorked(primaryDB.dropDatabase({w: 1})), (c }); primaryDB.createCollection(collName); -checkWriteConcern(() => assert.commandFailedWithCode(primaryDB.dropDatabase({w: 100000}), +checkWriteConcern(() => assert.commandFailedWithCode(primaryDB.dropDatabase({w: 45}), ErrorCodes.UnsatisfiableWriteConcern), (cmdObj) => { - assert.eq(cmdObj.writeConcern, {w: 100000}); + assert.eq(cmdObj.writeConcern, {w: 45}); }); rst.stopSet(); diff --git a/jstests/replsets/server_status_metrics.js b/jstests/replsets/server_status_metrics.js index f3579a44a2d..28178a4711e 100644 --- a/jstests/replsets/server_status_metrics.js +++ b/jstests/replsets/server_status_metrics.js @@ -175,7 +175,8 @@ assert.commandWorked(testDB.a.insert({x: 1}, {writeConcern: {w: 1, wtimeout: 500 assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis); assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum); -assert.commandWorked(testDB.a.insert({x: 1}, {writeConcern: {w: -11, wtimeout: 5000}})); +assert.commandFailedWithCode(testDB.a.insert({x: 1}, {writeConcern: {w: -11, wtimeout: 5000}}), + ErrorCodes.FailedToParse); assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis); assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum); diff --git a/src/mongo/db/repl/repl_set_config.cpp b/src/mongo/db/repl/repl_set_config.cpp index c19addc5cda..375e2a73d61 100644 --- a/src/mongo/db/repl/repl_set_config.cpp +++ b/src/mongo/db/repl/repl_set_config.cpp @@ -47,7 +47,6 @@ namespace repl { // Allow the heartbeat interval to be forcibly overridden on this node. MONGO_FAIL_POINT_DEFINE(forceHeartbeatIntervalMS); -const size_t ReplSetConfig::kMaxMembers; const size_t ReplSetConfig::kMaxVotingMembers; const Milliseconds ReplSetConfig::kInfiniteCatchUpTimeout(-1); const Milliseconds ReplSetConfig::kCatchUpDisabled(0); diff --git a/src/mongo/db/repl/repl_set_config.h b/src/mongo/db/repl/repl_set_config.h index 66075c5c105..d5f065d5f7b 100644 --- a/src/mongo/db/repl/repl_set_config.h +++ b/src/mongo/db/repl/repl_set_config.h @@ -63,7 +63,11 @@ public: // should never be included in a valid configuration document. static const std::string kRepairedFieldName; - static const size_t kMaxMembers = 50; + /** + * Inline `kMaxMembers` to allow others (e.g, `WriteConcernOptions`) use + * the constant without linking to `repl_set_config.cpp`. + */ + inline static const size_t kMaxMembers = 50; static const size_t kMaxVotingMembers = 7; static const Milliseconds kInfiniteCatchUpTimeout; static const Milliseconds kCatchUpDisabled; diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index 80e1c8bd0e4..f24ec703469 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -35,6 +35,7 @@ #include "mongo/base/string_data.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/field_parser.h" +#include "mongo/db/repl/repl_set_config.h" #include "mongo/util/str.h" namespace mongo { @@ -151,7 +152,14 @@ StatusWith<WriteConcernOptions> WriteConcernOptions::parse(const BSONObj& obj) { } if (wEl.isNumber()) { - writeConcern.wNumNodes = wEl.numberInt(); + auto wNumNodes = wEl.safeNumberLong(); + if (wNumNodes < 0 || + wNumNodes > static_cast<decltype(wNumNodes)>(repl::ReplSetConfig::kMaxMembers)) { + return Status(ErrorCodes::FailedToParse, + str::stream() << "w has to be a non-negative number and not greater than " + << repl::ReplSetConfig::kMaxMembers); + } + writeConcern.wNumNodes = static_cast<decltype(writeConcern.wNumNodes)>(wNumNodes); writeConcern.usedDefaultW = false; } else if (wEl.type() == String) { writeConcern.wNumNodes = 0; diff --git a/src/mongo/db/write_concern_options_test.cpp b/src/mongo/db/write_concern_options_test.cpp index d99eaab2204..70df61cb16a 100644 --- a/src/mongo/db/write_concern_options_test.cpp +++ b/src/mongo/db/write_concern_options_test.cpp @@ -110,6 +110,15 @@ TEST(WriteConcernOptionsTest, ParseReturnsFailedToParseIfWIsNotNumberOrString) { ASSERT_EQUALS("w has to be a number or a string", status.reason()); } +TEST(WriteConcernOptionsTest, ParseReturnsFailedToParseIfWIsNegativeOrExceedsMaxMembers) { + auto st1 = WriteConcernOptions::parse(BSON("w" << 123)).getStatus(); + ASSERT_EQUALS(ErrorCodes::FailedToParse, st1); + + auto st2 = WriteConcernOptions::parse(BSON("w" << -1)).getStatus(); + ASSERT_EQUALS(ErrorCodes::FailedToParse, st2); + ASSERT_EQUALS(st1.reason(), st2.reason()); +} + TEST(WriteConcernOptionsTest, ParseSetsWNumNodesIfWIsANumber) { auto sw = WriteConcernOptions::parse(BSON("w" << 3)); ASSERT_OK(sw.getStatus()); |