@@ -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" ,
@@ -1647,7 +1651,9 @@ impl ConnectionString {
1647
1651
}
1648
1652
1649
1653
/// Relax TLS constraints as much as possible (e.g. allowing invalid certificates or hostname
1650
- /// mismatches). Not supported by the Rust driver.
1654
+ /// mismatches). This option can only be set in a URI. If it is set in a URI provided to
1655
+ /// [`ConnectionString::parse`], [`TlsOptions::allow_invalid_certificates`] and
1656
+ /// [`TlsOptions::allow_invalid_hostnames`] are set to its value.
1651
1657
pub fn tls_insecure ( & self ) -> Option < bool > {
1652
1658
self . tls_insecure
1653
1659
}
@@ -1662,41 +1668,47 @@ impl ConnectionString {
1662
1668
return Ok ( parts) ;
1663
1669
}
1664
1670
1665
- let mut keys: Vec < & str > = Vec :: new ( ) ;
1671
+ let mut keys = HashSet :: new ( ) ;
1666
1672
1667
1673
for option_pair in options. split ( '&' ) {
1668
- let ( key, value) = match option_pair. find ( '=' ) {
1669
- Some ( index ) => option_pair . split_at ( index ) ,
1674
+ let ( key, value) = match option_pair. split_once ( '=' ) {
1675
+ Some ( ( key , value ) ) => ( key . to_lowercase ( ) , value ) ,
1670
1676
None => {
1671
- return Err ( ErrorKind :: InvalidArgument {
1672
- message : format ! (
1673
- "connection string options is not a `key=value` pair: {option_pair}" ,
1674
- ) ,
1675
- }
1676
- . into ( ) )
1677
+ return Err ( Error :: invalid_argument ( format ! (
1678
+ "connection string option is not a 'key=value' pair: {option_pair}"
1679
+ ) ) )
1677
1680
}
1678
1681
} ;
1679
1682
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) ;
1683
+ if !keys. insert ( key. clone ( ) ) && key != "readpreferencetags" {
1684
+ return Err ( Error :: invalid_argument (
1685
+ "repeated options are not allowed in the connection string" ,
1686
+ ) ) ;
1688
1687
}
1689
1688
1690
- // Skip leading '=' in value.
1691
1689
self . parse_option_pair (
1692
1690
& mut parts,
1693
- & key. to_lowercase ( ) ,
1694
- percent_encoding:: percent_decode ( & value. as_bytes ( ) [ 1 .. ] )
1691
+ & key,
1692
+ percent_encoding:: percent_decode ( value. as_bytes ( ) )
1695
1693
. decode_utf8_lossy ( )
1696
1694
. as_ref ( ) ,
1697
1695
) ?;
1698
1696
}
1699
1697
1698
+ if keys. contains ( TLS_INSECURE ) {
1699
+ #[ cfg( feature = "openssl-tls" ) ]
1700
+ let disallowed = [ TLS_ALLOW_INVALID_CERTIFICATES , TLS_ALLOW_INVALID_HOSTNAMES ] ;
1701
+ #[ cfg( not( feature = "openssl-tls" ) ) ]
1702
+ let disallowed = [ TLS_ALLOW_INVALID_CERTIFICATES ] ;
1703
+ for option in disallowed {
1704
+ if keys. contains ( option) {
1705
+ return Err ( Error :: invalid_argument ( format ! (
1706
+ "cannot set both {TLS_INSECURE} and {option} in the connection string"
1707
+ ) ) ) ;
1708
+ }
1709
+ }
1710
+ }
1711
+
1700
1712
if let Some ( tags) = parts. read_preference_tags . take ( ) {
1701
1713
self . read_preference = match self . read_preference . take ( ) {
1702
1714
Some ( read_pref) => Some ( read_pref. with_tags ( tags) ?) ,
@@ -2017,63 +2029,63 @@ impl ConnectionString {
2017
2029
k @ "tls" | k @ "ssl" => {
2018
2030
let tls = get_bool ! ( value, k) ;
2019
2031
2020
- match ( self . tls . as_ref ( ) , tls) {
2021
- ( Some ( Tls :: Disabled ) , true ) | ( Some ( Tls :: Enabled ( ..) ) , false ) => {
2022
- return Err ( ErrorKind :: InvalidArgument {
2023
- message : "All instances of `tls` and `ssl` must have the same
2024
- value"
2025
- . to_string ( ) ,
2032
+ match self . tls {
2033
+ Some ( Tls :: Enabled ( _) ) if !tls => {
2034
+ return Err ( Error :: invalid_argument (
2035
+ "cannot set {key}={tls} if other TLS options are set" ,
2036
+ ) )
2037
+ }
2038
+ Some ( Tls :: Disabled ) if tls => {
2039
+ return Err ( Error :: invalid_argument (
2040
+ "cannot set {key}={tls} if TLS is disabled" ,
2041
+ ) )
2042
+ }
2043
+ None => {
2044
+ if tls {
2045
+ self . tls = Some ( Tls :: Enabled ( Default :: default ( ) ) )
2046
+ } else {
2047
+ self . tls = Some ( Tls :: Disabled )
2026
2048
}
2027
- . into ( ) ) ;
2028
2049
}
2029
2050
_ => { }
2030
- } ;
2031
-
2032
- if self . tls . is_none ( ) {
2033
- let tls = if tls {
2034
- Tls :: Enabled ( Default :: default ( ) )
2035
- } else {
2036
- Tls :: Disabled
2037
- } ;
2038
-
2039
- self . tls = Some ( tls) ;
2040
2051
}
2041
2052
}
2042
- k @ "tlsinsecure" | k @ "tlsallowinvalidcertificates" => {
2043
- let val = get_bool ! ( value, k) ;
2044
-
2045
- let allow_invalid_certificates = if k == "tlsinsecure" { !val } else { val } ;
2046
-
2047
- match self . tls {
2048
- Some ( Tls :: Disabled ) => {
2049
- return Err ( ErrorKind :: InvalidArgument {
2050
- message : "'tlsInsecure' can't be set if tls=false" . into ( ) ,
2053
+ TLS_INSECURE => {
2054
+ let val = get_bool ! ( value, key) ;
2055
+ self . tls_insecure = Some ( val) ;
2056
+
2057
+ match self
2058
+ . tls
2059
+ . get_or_insert_with ( || Tls :: Enabled ( Default :: default ( ) ) )
2060
+ {
2061
+ Tls :: Enabled ( ref mut options) => {
2062
+ options. allow_invalid_certificates = Some ( val) ;
2063
+ #[ cfg( feature = "openssl-tls" ) ]
2064
+ {
2065
+ options. allow_invalid_hostnames = Some ( val) ;
2051
2066
}
2052
- . into ( ) )
2053
2067
}
2054
- Some ( Tls :: Enabled ( ref options) )
2055
- if options. allow_invalid_certificates . is_some ( )
2056
- && options. allow_invalid_certificates
2057
- != Some ( allow_invalid_certificates) =>
2058
- {
2059
- return Err ( ErrorKind :: InvalidArgument {
2060
- message : "all instances of 'tlsInsecure' and \
2061
- 'tlsAllowInvalidCertificates' must be consistent (e.g. \
2062
- 'tlsInsecure' cannot be true when \
2063
- 'tlsAllowInvalidCertificates' is false, or vice-versa)"
2064
- . into ( ) ,
2065
- }
2066
- . into ( ) ) ;
2068
+ Tls :: Disabled => {
2069
+ return Err ( Error :: invalid_argument ( format ! (
2070
+ "cannot set {key} when TLS is disabled"
2071
+ ) ) ) ;
2067
2072
}
2068
- Some ( Tls :: Enabled ( ref mut options) ) => {
2069
- options. allow_invalid_certificates = Some ( allow_invalid_certificates) ;
2073
+ }
2074
+ }
2075
+ TLS_ALLOW_INVALID_CERTIFICATES => {
2076
+ let val = get_bool ! ( value, key) ;
2077
+
2078
+ match self
2079
+ . tls
2080
+ . get_or_insert_with ( || Tls :: Enabled ( Default :: default ( ) ) )
2081
+ {
2082
+ Tls :: Enabled ( ref mut options) => {
2083
+ options. allow_invalid_certificates = Some ( val) ;
2070
2084
}
2071
- None => {
2072
- self . tls = Some ( Tls :: Enabled (
2073
- TlsOptions :: builder ( )
2074
- . allow_invalid_certificates ( allow_invalid_certificates)
2075
- . build ( ) ,
2076
- ) )
2085
+ Tls :: Disabled => {
2086
+ return Err ( Error :: invalid_argument ( format ! (
2087
+ "cannot set {key} when TLS is disabled"
2088
+ ) ) )
2077
2089
}
2078
2090
}
2079
2091
}
0 commit comments