@@ -31,6 +31,12 @@ import { Logger, LoggerLevelId } from './logger';
3131import { PromiseProvider } from './promise_provider' ;
3232import { Encrypter } from './encrypter' ;
3333
34+ const VALID_TXT_RECORDS = [ 'authSource' , 'replicaSet' , 'loadBalanced' ] ;
35+
36+ const LB_SINGLE_HOST = 'loadBalanced option only supported with a single host in the URI' ;
37+ const LB_REPLICA_SET = 'loadBalanced option not supported with a replicaSet option' ;
38+ const LB_DIRECT_CONNECTION = 'loadBalanced option not supported when directConnection is provided' ;
39+
3440/**
3541 * Determines whether a provided address matches the provided parent domain in order
3642 * to avoid certain attack vectors.
@@ -83,6 +89,11 @@ export function resolveSRVRecord(options: MongoOptions, callback: Callback<HostA
8389 HostAddress . fromString ( `${ r . name } :${ r . port ?? 27017 } ` )
8490 ) ;
8591
92+ const lbError = checkLoadBalancerOptions ( options , hostAddresses ) ;
93+ if ( lbError ) {
94+ return callback ( lbError ) ;
95+ }
96+
8697 // Resolve TXT record and add options from there if they exist.
8798 dns . resolveTxt ( lookupAddress , ( err , record ) => {
8899 if ( err ) {
@@ -96,14 +107,15 @@ export function resolveSRVRecord(options: MongoOptions, callback: Callback<HostA
96107
97108 const txtRecordOptions = new URLSearchParams ( record [ 0 ] . join ( '' ) ) ;
98109 const txtRecordOptionKeys = [ ...txtRecordOptions . keys ( ) ] ;
99- if ( txtRecordOptionKeys . some ( key => key !== 'authSource' && key !== 'replicaSet' ) ) {
110+ if ( txtRecordOptionKeys . some ( key => ! VALID_TXT_RECORDS . includes ( key ) ) ) {
100111 return callback (
101- new MongoParseError ( ' Text record must only set `authSource` or `replicaSet`' )
112+ new MongoParseError ( ` Text record must only set one of: ${ VALID_TXT_RECORDS . join ( ', ' ) } ` )
102113 ) ;
103114 }
104115
105116 const source = txtRecordOptions . get ( 'authSource' ) ?? undefined ;
106117 const replicaSet = txtRecordOptions . get ( 'replicaSet' ) ?? undefined ;
118+ const loadBalanced = txtRecordOptions . get ( 'loadBalanced' ) ?? undefined ;
107119
108120 if ( source === '' || replicaSet === '' ) {
109121 return callback ( new MongoParseError ( 'Cannot have empty URI params in DNS TXT Record' ) ) ;
@@ -116,13 +128,49 @@ export function resolveSRVRecord(options: MongoOptions, callback: Callback<HostA
116128 if ( ! options . userSpecifiedReplicaSet && replicaSet ) {
117129 options . replicaSet = replicaSet ;
118130 }
131+
132+ if ( loadBalanced === 'true' ) {
133+ options . loadBalanced = true ;
134+ }
135+
136+ const lbError = checkLoadBalancerOptions ( options , hostAddresses ) ;
137+ if ( lbError ) {
138+ return callback ( lbError ) ;
139+ }
140+
141+ if ( options . loadBalanced ) {
142+ if ( options . replicaSet ) {
143+ return callback ( new MongoParseError ( LB_REPLICA_SET ) ) ;
144+ }
145+
146+ if ( hostAddresses . length > 1 ) {
147+ return callback ( new MongoParseError ( LB_SINGLE_HOST ) ) ;
148+ }
149+ }
119150 }
120151
121152 callback ( undefined , hostAddresses ) ;
122153 } ) ;
123154 } ) ;
124155}
125156
157+ function checkLoadBalancerOptions (
158+ options : MongoOptions ,
159+ addresses : HostAddress [ ]
160+ ) : MongoParseError | null {
161+ if ( options . loadBalanced ) {
162+ if ( options . replicaSet ) {
163+ return new MongoParseError ( LB_REPLICA_SET ) ;
164+ }
165+
166+ if ( addresses . length > 1 ) {
167+ return new MongoParseError ( LB_SINGLE_HOST ) ;
168+ }
169+ return null ;
170+ }
171+ return null ;
172+ }
173+
126174/**
127175 * Checks if TLS options are valid
128176 *
@@ -431,6 +479,8 @@ export function parseOptions(
431479 throw new MongoParseError ( 'directConnection not supported with SRV URI' ) ;
432480 }
433481
482+ validateLoadBalancedOptions ( hosts , mongoOptions ) ;
483+
434484 // Potential SRV Overrides
435485 mongoOptions . userSpecifiedAuthSource =
436486 objectOptions . has ( 'authSource' ) || urlOptions . has ( 'authSource' ) ;
@@ -446,6 +496,20 @@ export function parseOptions(
446496 return mongoOptions ;
447497}
448498
499+ function validateLoadBalancedOptions ( hosts : HostAddress [ ] | string [ ] , mongoOptions : MongoOptions ) {
500+ if ( mongoOptions . loadBalanced ) {
501+ if ( hosts . length > 1 ) {
502+ throw new MongoParseError ( LB_SINGLE_HOST ) ;
503+ }
504+ if ( mongoOptions . replicaSet ) {
505+ throw new MongoParseError ( LB_REPLICA_SET ) ;
506+ }
507+ if ( mongoOptions . directConnection ) {
508+ throw new MongoParseError ( LB_DIRECT_CONNECTION ) ;
509+ }
510+ }
511+ }
512+
449513function setOption (
450514 mongoOptions : any ,
451515 key : string ,
@@ -706,6 +770,10 @@ export const OPTIONS = {
706770 default : 120000 ,
707771 type : 'uint'
708772 } ,
773+ loadBalanced : {
774+ default : false ,
775+ type : 'boolean'
776+ } ,
709777 localThresholdMS : {
710778 default : 15 ,
711779 type : 'uint'
0 commit comments