@@ -55,6 +55,10 @@ pub(crate) use resolver_config::ResolverConfig;
5555
5656pub ( crate ) const DEFAULT_PORT : u16 = 27017 ;
5757
58+ const TLS_INSECURE : & str = "tlsinsecure" ;
59+ const TLS_ALLOW_INVALID_CERTIFICATES : & str = "tlsallowinvalidcertificates" ;
60+ #[ cfg( feature = "openssl-tls" ) ]
61+ const TLS_ALLOW_INVALID_HOSTNAMES : & str = "tlsallowinvalidhostnames" ;
5862const URI_OPTIONS : & [ & str ] = & [
5963 "appname" ,
6064 "authmechanism" ,
@@ -82,8 +86,8 @@ const URI_OPTIONS: &[&str] = &[
8286 "sockettimeoutms" ,
8387 "tls" ,
8488 "ssl" ,
85- "tlsinsecure" ,
86- "tlsallowinvalidcertificates" ,
89+ TLS_INSECURE ,
90+ TLS_ALLOW_INVALID_CERTIFICATES ,
8791 "tlscafile" ,
8892 "tlscertificatekeyfile" ,
8993 "uuidRepresentation" ,
@@ -1646,7 +1650,9 @@ impl ConnectionString {
16461650 }
16471651
16481652 /// Relax TLS constraints as much as possible (e.g. allowing invalid certificates or hostname
1649- /// mismatches). Not supported by the Rust driver.
1653+ /// mismatches). This option can only be set in a URI. If it is set in a URI provided to
1654+ /// [`ConnectionString::parse`], [`TlsOptions::allow_invalid_certificates`] and
1655+ /// [`TlsOptions::allow_invalid_hostnames`] are set to its value.
16501656 pub fn tls_insecure ( & self ) -> Option < bool > {
16511657 self . tls_insecure
16521658 }
@@ -1661,42 +1667,47 @@ impl ConnectionString {
16611667 return Ok ( parts) ;
16621668 }
16631669
1664- let mut keys: Vec < & str > = Vec :: new ( ) ;
1670+ let mut keys = HashSet :: new ( ) ;
16651671
16661672 for option_pair in options. split ( '&' ) {
1667- let ( key, value) = match option_pair. find ( '=' ) {
1668- Some ( index ) => option_pair . split_at ( index ) ,
1673+ let ( key, value) = match option_pair. split_once ( '=' ) {
1674+ Some ( ( key , value ) ) => ( key . to_lowercase ( ) , value ) ,
16691675 None => {
1670- return Err ( ErrorKind :: InvalidArgument {
1671- message : format ! (
1672- "connection string options is not a `key=value` pair: {}" ,
1673- option_pair,
1674- ) ,
1675- }
1676- . into ( ) )
1676+ return Err ( Error :: invalid_argument ( format ! (
1677+ "connection string option is not a 'key=value' pair: {option_pair}"
1678+ ) ) )
16771679 }
16781680 } ;
16791681
1680- if key. to_lowercase ( ) != "readpreferencetags" && keys. contains ( & key) {
1681- return Err ( ErrorKind :: InvalidArgument {
1682- message : "repeated options are not allowed in the connection string"
1683- . to_string ( ) ,
1684- }
1685- . into ( ) ) ;
1686- } else {
1687- keys. push ( key) ;
1682+ if !keys. insert ( key. clone ( ) ) && key != "readpreferencetags" {
1683+ return Err ( Error :: invalid_argument (
1684+ "repeated options are not allowed in the connection string" ,
1685+ ) ) ;
16881686 }
16891687
1690- // Skip leading '=' in value.
16911688 self . parse_option_pair (
16921689 & mut parts,
1693- & key. to_lowercase ( ) ,
1694- percent_encoding:: percent_decode ( & value. as_bytes ( ) [ 1 .. ] )
1690+ & key,
1691+ percent_encoding:: percent_decode ( value. as_bytes ( ) )
16951692 . decode_utf8_lossy ( )
16961693 . as_ref ( ) ,
16971694 ) ?;
16981695 }
16991696
1697+ if keys. contains ( TLS_INSECURE ) {
1698+ #[ cfg( feature = "openssl-tls" ) ]
1699+ let disallowed = [ TLS_ALLOW_INVALID_CERTIFICATES , TLS_ALLOW_INVALID_HOSTNAMES ] ;
1700+ #[ cfg( not( feature = "openssl-tls" ) ) ]
1701+ let disallowed = [ TLS_ALLOW_INVALID_CERTIFICATES ] ;
1702+ for option in disallowed {
1703+ if keys. contains ( option) {
1704+ return Err ( Error :: invalid_argument ( format ! (
1705+ "cannot set both {TLS_INSECURE} and {option} in the connection string"
1706+ ) ) ) ;
1707+ }
1708+ }
1709+ }
1710+
17001711 if let Some ( tags) = parts. read_preference_tags . take ( ) {
17011712 self . read_preference = match self . read_preference . take ( ) {
17021713 Some ( read_pref) => Some ( read_pref. with_tags ( tags) ?) ,
@@ -2042,63 +2053,63 @@ impl ConnectionString {
20422053 k @ "tls" | k @ "ssl" => {
20432054 let tls = get_bool ! ( value, k) ;
20442055
2045- match ( self . tls . as_ref ( ) , tls) {
2046- ( Some ( Tls :: Disabled ) , true ) | ( Some ( Tls :: Enabled ( ..) ) , false ) => {
2047- return Err ( ErrorKind :: InvalidArgument {
2048- message : "All instances of `tls` and `ssl` must have the same
2049- value"
2050- . to_string ( ) ,
2056+ match self . tls {
2057+ Some ( Tls :: Enabled ( _) ) if !tls => {
2058+ return Err ( Error :: invalid_argument (
2059+ "cannot set {key}={tls} if other TLS options are set" ,
2060+ ) )
2061+ }
2062+ Some ( Tls :: Disabled ) if tls => {
2063+ return Err ( Error :: invalid_argument (
2064+ "cannot set {key}={tls} if TLS is disabled" ,
2065+ ) )
2066+ }
2067+ None => {
2068+ if tls {
2069+ self . tls = Some ( Tls :: Enabled ( Default :: default ( ) ) )
2070+ } else {
2071+ self . tls = Some ( Tls :: Disabled )
20512072 }
2052- . into ( ) ) ;
20532073 }
20542074 _ => { }
2055- } ;
2056-
2057- if self . tls . is_none ( ) {
2058- let tls = if tls {
2059- Tls :: Enabled ( Default :: default ( ) )
2060- } else {
2061- Tls :: Disabled
2062- } ;
2063-
2064- self . tls = Some ( tls) ;
20652075 }
20662076 }
2067- k @ "tlsinsecure" | k @ "tlsallowinvalidcertificates" => {
2068- let val = get_bool ! ( value, k) ;
2069-
2070- let allow_invalid_certificates = if k == "tlsinsecure" { !val } else { val } ;
2077+ TLS_INSECURE => {
2078+ let val = get_bool ! ( value, key) ;
2079+ self . tls_insecure = Some ( val) ;
20712080
2072- match self . tls {
2073- Some ( Tls :: Disabled ) => {
2074- return Err ( ErrorKind :: InvalidArgument {
2075- message : "'tlsInsecure' can't be set if tls=false" . into ( ) ,
2081+ match self
2082+ . tls
2083+ . get_or_insert_with ( || Tls :: Enabled ( Default :: default ( ) ) )
2084+ {
2085+ Tls :: Enabled ( ref mut options) => {
2086+ options. allow_invalid_certificates = Some ( val) ;
2087+ #[ cfg( feature = "openssl-tls" ) ]
2088+ {
2089+ options. allow_invalid_hostnames = Some ( val) ;
20762090 }
2077- . into ( ) )
20782091 }
2079- Some ( Tls :: Enabled ( ref options) )
2080- if options. allow_invalid_certificates . is_some ( )
2081- && options. allow_invalid_certificates
2082- != Some ( allow_invalid_certificates) =>
2083- {
2084- return Err ( ErrorKind :: InvalidArgument {
2085- message : "all instances of 'tlsInsecure' and \
2086- 'tlsAllowInvalidCertificates' must be consistent (e.g. \
2087- 'tlsInsecure' cannot be true when \
2088- 'tlsAllowInvalidCertificates' is false, or vice-versa)"
2089- . into ( ) ,
2090- }
2091- . into ( ) ) ;
2092+ Tls :: Disabled => {
2093+ return Err ( Error :: invalid_argument ( format ! (
2094+ "cannot set {key} when TLS is disabled"
2095+ ) ) ) ;
20922096 }
2093- Some ( Tls :: Enabled ( ref mut options) ) => {
2094- options. allow_invalid_certificates = Some ( allow_invalid_certificates) ;
2097+ }
2098+ }
2099+ TLS_ALLOW_INVALID_CERTIFICATES => {
2100+ let val = get_bool ! ( value, key) ;
2101+
2102+ match self
2103+ . tls
2104+ . get_or_insert_with ( || Tls :: Enabled ( Default :: default ( ) ) )
2105+ {
2106+ Tls :: Enabled ( ref mut options) => {
2107+ options. allow_invalid_certificates = Some ( val) ;
20952108 }
2096- None => {
2097- self . tls = Some ( Tls :: Enabled (
2098- TlsOptions :: builder ( )
2099- . allow_invalid_certificates ( allow_invalid_certificates)
2100- . build ( ) ,
2101- ) )
2109+ Tls :: Disabled => {
2110+ return Err ( Error :: invalid_argument ( format ! (
2111+ "cannot set {key} when TLS is disabled"
2112+ ) ) )
21022113 }
21032114 }
21042115 }
0 commit comments