@@ -55,6 +55,10 @@ pub(crate) use resolver_config::ResolverConfig;
55
55
56
56
pub ( crate ) const DEFAULT_PORT : u16 = 27017 ;
57
57
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" ;
58
62
const URI_OPTIONS : & [ & str ] = & [
59
63
"appname" ,
60
64
"authmechanism" ,
@@ -82,8 +86,8 @@ const URI_OPTIONS: &[&str] = &[
82
86
"sockettimeoutms" ,
83
87
"tls" ,
84
88
"ssl" ,
85
- "tlsinsecure" ,
86
- "tlsallowinvalidcertificates" ,
89
+ TLS_INSECURE ,
90
+ TLS_ALLOW_INVALID_CERTIFICATES ,
87
91
"tlscafile" ,
88
92
"tlscertificatekeyfile" ,
89
93
"uuidRepresentation" ,
@@ -1646,7 +1650,9 @@ impl ConnectionString {
1646
1650
}
1647
1651
1648
1652
/// 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.
1650
1656
pub fn tls_insecure ( & self ) -> Option < bool > {
1651
1657
self . tls_insecure
1652
1658
}
@@ -1661,42 +1667,47 @@ impl ConnectionString {
1661
1667
return Ok ( parts) ;
1662
1668
}
1663
1669
1664
- let mut keys: Vec < & str > = Vec :: new ( ) ;
1670
+ let mut keys = HashSet :: new ( ) ;
1665
1671
1666
1672
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 ) ,
1669
1675
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
+ ) ) )
1677
1679
}
1678
1680
} ;
1679
1681
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
+ ) ) ;
1688
1686
}
1689
1687
1690
- // Skip leading '=' in value.
1691
1688
self . parse_option_pair (
1692
1689
& 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 ( ) )
1695
1692
. decode_utf8_lossy ( )
1696
1693
. as_ref ( ) ,
1697
1694
) ?;
1698
1695
}
1699
1696
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
+
1700
1711
if let Some ( tags) = parts. read_preference_tags . take ( ) {
1701
1712
self . read_preference = match self . read_preference . take ( ) {
1702
1713
Some ( read_pref) => Some ( read_pref. with_tags ( tags) ?) ,
@@ -2042,63 +2053,63 @@ impl ConnectionString {
2042
2053
k @ "tls" | k @ "ssl" => {
2043
2054
let tls = get_bool ! ( value, k) ;
2044
2055
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 )
2051
2072
}
2052
- . into ( ) ) ;
2053
2073
}
2054
2074
_ => { }
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) ;
2065
2075
}
2066
2076
}
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) ;
2071
2080
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) ;
2076
2090
}
2077
- . into ( ) )
2078
2091
}
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
+ ) ) ) ;
2092
2096
}
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) ;
2095
2108
}
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
+ ) ) )
2102
2113
}
2103
2114
}
2104
2115
}
0 commit comments