Skip to content

Commit 39102e1

Browse files
committed
NODE-931 Validates all the options for MongoClient.connect and fixes missing connection settings
1 parent 38c037c commit 39102e1

File tree

6 files changed

+171
-14
lines changed

6 files changed

+171
-14
lines changed

docs/reference/content/reference/connecting/connection-settings.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,17 @@ The table below shows all settings and what topology they affect.
6363
| **ignoreUndefined** | Server, ReplicaSet, Mongos | boolean | false | Specify if the BSON serializer should ignore undefined fields. |
6464
| **raw** | Server, ReplicaSet, Mongos | boolean | false | Return document results as raw BSON buffers. |
6565
| **promoteLongs** | Server, ReplicaSet, Mongos | boolean | true | Promotes Long values to number if they fit inside the 53 bits resolution. |
66+
| **promoteBuffers** | Server, ReplicaSet, Mongos | boolean | false | Promotes Binary BSON values to native Node Buffers. |
67+
| **promoteValues** | Server, ReplicaSet, Mongos | boolean | true | Promotes BSON values to native types where possible, set to false to only receive wrapper types. |
68+
| **domainsEnabled** | Server, ReplicaSet, Mongos | boolean | false | Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit. |
6669
| **bufferMaxEntries** | Server, ReplicaSet, Mongos | integer | -1 | Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited. |
6770
| **readPreference** | Server, ReplicaSet, Mongos | object | null | The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). |
6871
| **pkFactory** | Server, ReplicaSet, Mongos | object | null | A primary key factory object for generation of custom _id keys. |
6972
| **promiseLibrary** | Server, ReplicaSet, Mongos | object | null | A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible. |
7073
| **readConcern** | Server, ReplicaSet, Mongos | object | null | Specify a read concern for the collection. (only MongoDB 3.2 or higher supported). |
7174
| **maxStalenessSeconds** | Replicaset | number | null | Specify a maxStalenessSeconds value for secondary reads, minimum is 90 seconds |
75+
| **loggerLevel** | Server, Replicaset, Mongos | string | null | Specify the log level used by the driver logger (error/warn/info/debug) |
76+
| **logger** | Server, Replicaset, Mongos | object | null | Specify a customer logger mechanism, can be used to log using your app level logger |
7277
# Ensure you connection string is valid for Replica Sets
7378

7479
The connection string passed to the driver must use the fully qualified host names for the servers as set in the replicaset config. Given the following configuration settings for your replicaset.

lib/mongo_client.js

Lines changed: 120 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,36 @@ var parse = require('./url_parser')
2626
* db.close();
2727
* });
2828
*/
29+
var validOptionNames = ['poolSize', 'ssl', 'sslValidate', 'sslCA', 'sslCert',
30+
'sslKey', 'sslPass', 'autoReconnect', 'noDelay', 'keepAlive', 'connectTimeoutMS',
31+
'socketTimeoutMS', 'reconnectTries', 'reconnectInterval', 'ha', 'haInterval',
32+
'replicaSet', 'secondaryAcceptableLatencyMS', 'acceptableLatencyMS',
33+
'connectWithNoPrimary', 'authSource', 'w', 'wtimeout', 'j', 'forceServerObjectId',
34+
'serializeFunctions', 'ignoreUndefined', 'raw', 'promoteLongs', 'bufferMaxEntries',
35+
'readPreference', 'pkFactory', 'promiseLibrary', 'readConcern', 'maxStalenessSeconds',
36+
'loggerLevel', 'logger', 'promoteValues', 'promoteBuffers', 'promoteLongs',
37+
'domainsEnabled', 'keepAliveInitialDelay', 'checkServerIdentity'];
38+
var ignoreOptionNames = ['native_parser'];
39+
var legacyOptionNames = ['server', 'replset', 'mongos', 'db'];
40+
41+
function validOptions(options) {
42+
var _validOptions = validOptionNames.concat(legacyOptionNames);
43+
44+
for(var name in options) {
45+
if(ignoreOptionNames.indexOf(name) != -1) {
46+
continue;
47+
}
48+
49+
if(_validOptions.indexOf(name) == -1) {
50+
return new MongoError(f('option %s is not supported', name));
51+
}
52+
53+
if(legacyOptionNames.indexOf(name) == -1) {
54+
console.warn(f('the server/replset/mongos options are deprecated, '
55+
+ 'all their options are supported at the top level of the options object [%s]', validOptionNames));
56+
}
57+
}
58+
}
2959

3060
/**
3161
* Creates a new MongoClient instance
@@ -49,13 +79,48 @@ function MongoClient() {
4979
*
5080
* @method
5181
* @param {string} url The connection URI string
52-
* @param {object} [options=null] Optional settings.
53-
* @param {boolean} [options.uri_decode_auth=false] Uri decode the user name and password for authentication
54-
* @param {object} [options.db=null] A hash of options to set on the db object, see **Db constructor**
55-
* @param {object} [options.server=null] A hash of options to set on the server objects, see **Server** constructor**
56-
* @param {object} [options.replSet=null] A hash of options to set on the replSet object, see **ReplSet** constructor**
57-
* @param {object} [options.mongos=null] A hash of options to set on the mongos object, see **Mongos** constructor**
82+
* @param {object} [options] Optional settings.
83+
* @param {number} [options.poolSize=5] poolSize The maximum size of the individual server pool.
84+
* @param {boolean} [options.ssl=false] Enable SSL connection.
85+
* @param {Buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
86+
* @param {Buffer} [options.sslCert=undefined] SSL Certificate binary buffer
87+
* @param {Buffer} [options.sslKey=undefined] SSL Key file binary buffer
88+
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
89+
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
90+
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
91+
* @param {boolean} [options.noDelay=true] TCP Connection no delay
92+
* @param {boolean} [options.keepAlive=0] The number of milliseconds to wait before initiating keepAlive on the TCP socket.
93+
* @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
94+
* @param {number} [options.socketTimeoutMS=30000] TCP Socket timeout setting
95+
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
96+
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
97+
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies.
98+
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
99+
* @param {string} [options.replicaSet=undefined] The Replicaset set name
100+
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
101+
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection.
102+
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
103+
* @param {string} [options.authSource=undefined] Define the database to authenticate against
104+
* @param {(number|string)} [options.w=null] The write concern.
105+
* @param {number} [options.wtimeout=null] The write concern timeout.
106+
* @param {boolean} [options.j=false] Specify a journal write concern.
107+
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
108+
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
109+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
110+
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
111+
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
112+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
113+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
114+
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
115+
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
116+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
117+
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
58118
* @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
119+
* @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
120+
* @param {object} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
121+
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
122+
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
123+
* @param {object} [options.logger=undefined] Custom logger object
59124
* @param {MongoClient~connectCallback} [callback] The command result callback
60125
* @return {Promise} returns Promise if no callback passed
61126
*/
@@ -74,13 +139,48 @@ var define = MongoClient.define = new Define('MongoClient', MongoClient, false);
74139
* @method
75140
* @static
76141
* @param {string} url The connection URI string
77-
* @param {object} [options=null] Optional settings.
78-
* @param {boolean} [options.uri_decode_auth=false] Uri decode the user name and password for authentication
79-
* @param {object} [options.db=null] A hash of options to set on the db object, see **Db constructor**
80-
* @param {object} [options.server=null] A hash of options to set on the server objects, see **Server** constructor**
81-
* @param {object} [options.replSet=null] A hash of options to set on the replSet object, see **ReplSet** constructor**
82-
* @param {object} [options.mongos=null] A hash of options to set on the mongos object, see **Mongos** constructor**
142+
* @param {object} [options] Optional settings.
143+
* @param {number} [options.poolSize=5] poolSize The maximum size of the individual server pool.
144+
* @param {boolean} [options.ssl=false] Enable SSL connection.
145+
* @param {Buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
146+
* @param {Buffer} [options.sslCert=undefined] SSL Certificate binary buffer
147+
* @param {Buffer} [options.sslKey=undefined] SSL Key file binary buffer
148+
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
149+
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
150+
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
151+
* @param {boolean} [options.noDelay=true] TCP Connection no delay
152+
* @param {boolean} [options.keepAlive=0] The number of milliseconds to wait before initiating keepAlive on the TCP socket.
153+
* @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
154+
* @param {number} [options.socketTimeoutMS=30000] TCP Socket timeout setting
155+
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
156+
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
157+
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies.
158+
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
159+
* @param {string} [options.replicaSet=undefined] The Replicaset set name
160+
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
161+
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection.
162+
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
163+
* @param {string} [options.authSource=undefined] Define the database to authenticate against
164+
* @param {(number|string)} [options.w=null] The write concern.
165+
* @param {number} [options.wtimeout=null] The write concern timeout.
166+
* @param {boolean} [options.j=false] Specify a journal write concern.
167+
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
168+
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
169+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
170+
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
171+
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
172+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
173+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
174+
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
175+
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
176+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
177+
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
83178
* @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
179+
* @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
180+
* @param {object} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
181+
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
182+
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
183+
* @param {object} [options.logger=undefined] Custom logger object
84184
* @param {MongoClient~connectCallback} [callback] The command result callback
85185
* @return {Promise} returns Promise if no callback passed
86186
*/
@@ -90,6 +190,9 @@ MongoClient.connect = function(url, options, callback) {
90190
options = args.length ? args.shift() : null;
91191
options = options || {};
92192

193+
// Validate options object
194+
var err = validOptions(options);
195+
93196
// Get the promiseLibrary
94197
var promiseLibrary = options.promiseLibrary;
95198

@@ -102,13 +205,18 @@ MongoClient.connect = function(url, options, callback) {
102205
// Return a promise
103206
if(typeof callback != 'function') {
104207
return new promiseLibrary(function(resolve, reject) {
208+
// Did we have a validation error
209+
if(err) return reject(err);
210+
// Attempt to connect
105211
connect(url, options, function(err, db) {
106212
if(err) return reject(err);
107213
resolve(db);
108214
});
109215
});
110216
}
111217

218+
// Did we have a validation error
219+
if(err) return callback(err);
112220
// Fallback to callback based connect
113221
connect(url, options, callback);
114222
}

lib/replset.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ var legalOptionNames = ['ha', 'haInterval', 'replicaSet', 'rs_name', 'secondaryA
4545
, 'store', 'auto_reconnect', 'autoReconnect', 'emitError'
4646
, 'keepAlive', 'noDelay', 'connectTimeoutMS', 'socketTimeoutMS', 'strategy', 'debug'
4747
, 'loggerLevel', 'logger', 'reconnectTries', 'appname', 'domainsEnabled'
48-
, 'servername', 'promoteLongs', 'promoteValues', 'promoteBuffers'];
48+
, 'servername', 'promoteLongs', 'promoteValues', 'promoteBuffers', 'maxStalenessSeconds'];
4949

5050
// Get package.json variable
5151
var driverVersion = require(__dirname + '/../package.json').version;
@@ -81,6 +81,7 @@ var release = os.release();
8181
* @param {number} [options.socketOptions.connectTimeoutMS=10000] TCP Connection timeout setting
8282
* @param {number} [options.socketOptions.socketTimeoutMS=0] TCP Socket timeout setting
8383
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
84+
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
8485
* @fires ReplSet#connect
8586
* @fires ReplSet#ha
8687
* @fires ReplSet#joined

test/functional/authentication_tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ var setUp = function(configuration, options, callback) {
658658
dbpath: f('%s/../db/31001', __dirname),
659659
}
660660
}, {
661+
// arbiter: true,
661662
options: {
662663
bind_ip: 'localhost', port: 31002,
663664
dbpath: f('%s/../db/31002', __dirname),
@@ -718,6 +719,7 @@ exports['Should correctly handle replicaset master stepdown and stepup without l
718719
// Add a user
719720
db.admin().addUser("root", "root", {w:3, wtimeout: 25000}, function(err, result) {
720721
test.equal(null, err);
722+
// process.exit(0)
721723

722724
db.admin().authenticate("root", "root", function(err, result) {
723725
test.equal(null, err);

test/functional/mongo_client_options_tests.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,47 @@ exports['pass in server and db top level options'] = {
2020
}
2121
}
2222

23+
/**
24+
* @ignore
25+
*/
26+
exports['pass in server and db top level options'] = {
27+
metadata: { requires: { topology: 'single' } },
28+
29+
// The actual test we wish to run
30+
test: function(configuration, test) {
31+
var connect = configuration.require;
32+
33+
connect(configuration.url(),
34+
{ autoReconnect: true, poolSize: 4 },
35+
connectionTester(test, 'testConnectServerOptions', function(db) {
36+
test.equal(1, db.serverConfig.poolSize);
37+
test.equal(4, db.serverConfig.s.server.s.pool.size);
38+
test.equal(true, db.serverConfig.autoReconnect);
39+
db.close();
40+
test.done();
41+
}));
42+
}
43+
}
44+
45+
/**
46+
* @ignore
47+
*/
48+
exports['should error on unexpected options'] = {
49+
metadata: { requires: { topology: 'single' } },
50+
51+
// The actual test we wish to run
52+
test: function(configuration, test) {
53+
var connect = configuration.require;
54+
55+
connect(configuration.url(), {
56+
autoReconnect: true, poolSize: 4, notlegal: {}
57+
}, function(err, db) {
58+
test.ok(err.message.indexOf('option notlegal is not supported') != -1);
59+
test.done();
60+
});
61+
}
62+
}
63+
2364
/**
2465
* @ignore
2566
*/

test/functional/uri_tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ exports['Should correctly connect using uri encoded username and password'] = {
187187
db.addUser(user, pass, function(err) {
188188
test.equal(null, err);
189189
var uri = "mongodb://" + encodeURIComponent(user) + ":" + encodeURIComponent(pass) + "@localhost:27017/integration_tests";
190-
MongoClient.connect(uri, {uri_decode_auth: true, native_parser:true}, function(err, authenticatedDb) {
190+
MongoClient.connect(uri, {native_parser:true}, function(err, authenticatedDb) {
191191
test.equal(null, err);
192192

193193
db.close();

0 commit comments

Comments
 (0)