@@ -132,27 +132,28 @@ function parseSrvConnectionString(uri, options, callback) {
132
132
/**
133
133
* Parses a query string item according to the connection string spec
134
134
*
135
+ * @param {string } key The key for the parsed value
135
136
* @param {Array|String } value The value to parse
136
137
* @return {Array|Object|String } The parsed value
137
138
*/
138
- function parseQueryStringItemValue ( value ) {
139
+ function parseQueryStringItemValue ( key , value ) {
139
140
if ( Array . isArray ( value ) ) {
140
141
// deduplicate and simplify arrays
141
142
value = value . filter ( ( v , idx ) => value . indexOf ( v ) === idx ) ;
142
143
if ( value . length === 1 ) value = value [ 0 ] ;
143
144
} else if ( value . indexOf ( ':' ) > 0 ) {
144
145
value = value . split ( ',' ) . reduce ( ( result , pair ) => {
145
146
const parts = pair . split ( ':' ) ;
146
- result [ parts [ 0 ] ] = parseQueryStringItemValue ( parts [ 1 ] ) ;
147
+ result [ parts [ 0 ] ] = parseQueryStringItemValue ( key , parts [ 1 ] ) ;
147
148
return result ;
148
149
} , { } ) ;
149
150
} else if ( value . indexOf ( ',' ) > 0 ) {
150
151
value = value . split ( ',' ) . map ( v => {
151
- return parseQueryStringItemValue ( v ) ;
152
+ return parseQueryStringItemValue ( key , v ) ;
152
153
} ) ;
153
154
} else if ( value . toLowerCase ( ) === 'true' || value . toLowerCase ( ) === 'false' ) {
154
155
value = value . toLowerCase ( ) === 'true' ;
155
- } else if ( ! Number . isNaN ( value ) ) {
156
+ } else if ( ! Number . isNaN ( value ) && ! STRING_OPTIONS . has ( key ) ) {
156
157
const numericValue = parseFloat ( value ) ;
157
158
if ( ! Number . isNaN ( numericValue ) ) {
158
159
value = parseFloat ( value ) ;
@@ -173,6 +174,9 @@ const BOOLEAN_OPTIONS = new Set([
173
174
'j'
174
175
] ) ;
175
176
177
+ // Known string options, only used to bypass Number coercion in `parseQueryStringItemValue`
178
+ const STRING_OPTIONS = new Set ( [ 'authsource' ] ) ;
179
+
176
180
// Supported text representations of auth mechanisms
177
181
// NOTE: this list exists in native already, if it is merged here we should deduplicate
178
182
const AUTH_MECHANISMS = new Set ( [
@@ -225,27 +229,25 @@ const CASE_TRANSLATION = {
225
229
* @param {object } options The options used for option parsing
226
230
*/
227
231
function applyConnectionStringOption ( obj , key , value , options ) {
228
- let normalizedKey = key . toLowerCase ( ) ;
229
-
230
232
// simple key translation
231
- if ( normalizedKey === 'journal' ) {
232
- normalizedKey = 'j' ;
233
- } else if ( normalizedKey === 'wtimeoutms' ) {
234
- normalizedKey = 'wtimeout' ;
233
+ if ( key === 'journal' ) {
234
+ key = 'j' ;
235
+ } else if ( key === 'wtimeoutms' ) {
236
+ key = 'wtimeout' ;
235
237
}
236
238
237
239
// more complicated translation
238
- if ( BOOLEAN_OPTIONS . has ( normalizedKey ) ) {
240
+ if ( BOOLEAN_OPTIONS . has ( key ) ) {
239
241
value = value === 'true' || value === true ;
240
- } else if ( normalizedKey === 'appname' ) {
242
+ } else if ( key === 'appname' ) {
241
243
value = decodeURIComponent ( value ) ;
242
- } else if ( normalizedKey === 'readconcernlevel' ) {
243
- normalizedKey = 'readconcern' ;
244
+ } else if ( key === 'readconcernlevel' ) {
245
+ key = 'readconcern' ;
244
246
value = { level : value } ;
245
247
}
246
248
247
249
// simple validation
248
- if ( normalizedKey === 'compressors' ) {
250
+ if ( key === 'compressors' ) {
249
251
value = Array . isArray ( value ) ? value : [ value ] ;
250
252
251
253
if ( ! value . every ( c => c === 'snappy' || c === 'zlib' ) ) {
@@ -255,29 +257,29 @@ function applyConnectionStringOption(obj, key, value, options) {
255
257
}
256
258
}
257
259
258
- if ( normalizedKey === 'authmechanism' && ! AUTH_MECHANISMS . has ( value ) ) {
260
+ if ( key === 'authmechanism' && ! AUTH_MECHANISMS . has ( value ) ) {
259
261
return new MongoParseError (
260
262
'Value for `authMechanism` must be one of: `DEFAULT`, `GSSAPI`, `PLAIN`, `MONGODB-X509`, `SCRAM-SHA-1`, `SCRAM-SHA-256`'
261
263
) ;
262
264
}
263
265
264
- if ( normalizedKey === 'readpreference' && ! ReadPreference . isValid ( value ) ) {
266
+ if ( key === 'readpreference' && ! ReadPreference . isValid ( value ) ) {
265
267
return new MongoParseError (
266
268
'Value for `readPreference` must be one of: `primary`, `primaryPreferred`, `secondary`, `secondaryPreferred`, `nearest`'
267
269
) ;
268
270
}
269
271
270
- if ( normalizedKey === 'zlibcompressionlevel' && ( value < - 1 || value > 9 ) ) {
272
+ if ( key === 'zlibcompressionlevel' && ( value < - 1 || value > 9 ) ) {
271
273
return new MongoParseError ( 'zlibCompressionLevel must be an integer between -1 and 9' ) ;
272
274
}
273
275
274
276
// special cases
275
- if ( normalizedKey === 'compressors' || normalizedKey === 'zlibcompressionlevel' ) {
277
+ if ( key === 'compressors' || key === 'zlibcompressionlevel' ) {
276
278
obj . compression = obj . compression || { } ;
277
279
obj = obj . compression ;
278
280
}
279
281
280
- if ( normalizedKey === 'authmechanismproperties' ) {
282
+ if ( key === 'authmechanismproperties' ) {
281
283
if ( typeof value . SERVICE_NAME === 'string' ) obj . gssapiServiceName = value . SERVICE_NAME ;
282
284
if ( typeof value . SERVICE_REALM === 'string' ) obj . gssapiServiceRealm = value . SERVICE_REALM ;
283
285
if ( typeof value . CANONICALIZE_HOST_NAME !== 'undefined' ) {
@@ -286,12 +288,12 @@ function applyConnectionStringOption(obj, key, value, options) {
286
288
}
287
289
288
290
// set the actual value
289
- if ( options . caseTranslate && CASE_TRANSLATION [ normalizedKey ] ) {
290
- obj [ CASE_TRANSLATION [ normalizedKey ] ] = value ;
291
+ if ( options . caseTranslate && CASE_TRANSLATION [ key ] ) {
292
+ obj [ CASE_TRANSLATION [ key ] ] = value ;
291
293
return ;
292
294
}
293
295
294
- obj [ normalizedKey ] = value ;
296
+ obj [ key ] = value ;
295
297
}
296
298
297
299
/**
@@ -311,8 +313,9 @@ function parseQueryString(query, options) {
311
313
return new MongoParseError ( 'Incomplete key value pair for option' ) ;
312
314
}
313
315
314
- const parsedValue = parseQueryStringItemValue ( value ) ;
315
- const applyResult = applyConnectionStringOption ( result , key , parsedValue , options ) ;
316
+ const normalizedKey = key . toLowerCase ( ) ;
317
+ const parsedValue = parseQueryStringItemValue ( normalizedKey , value ) ;
318
+ const applyResult = applyConnectionStringOption ( result , normalizedKey , parsedValue , options ) ;
316
319
if ( applyResult instanceof MongoParseError ) {
317
320
return applyResult ;
318
321
}
0 commit comments