1
+ use std:: convert:: TryFrom ;
1
2
use std:: future:: Future ;
2
3
use std:: pin:: Pin ;
3
4
use std:: sync:: Arc ;
4
5
use std:: task:: { Context , Poll } ;
5
6
use std:: { fmt, io} ;
6
- use std:: convert:: TryFrom ;
7
7
8
- #[ cfg( feature = "tokio-runtime" ) ]
9
- use hyper:: client:: connect:: HttpConnector ;
10
8
use hyper:: { client:: connect:: Connection , service:: Service , Uri } ;
11
- use rustls:: { ClientConfig , RootCertStore } ;
12
9
use tokio:: io:: { AsyncRead , AsyncWrite } ;
13
10
use tokio_rustls:: TlsConnector ;
14
11
15
12
use crate :: stream:: MaybeHttpsStream ;
16
13
14
+ pub mod builder;
15
+
17
16
type BoxError = Box < dyn std:: error:: Error + Send + Sync > ;
18
17
19
18
/// A Connector for the `https` scheme.
20
19
#[ derive( Clone ) ]
21
20
pub struct HttpsConnector < T > {
22
21
force_https : bool ,
23
22
http : T ,
24
- tls_config : Arc < ClientConfig > ,
25
- }
26
-
27
- #[ cfg( all(
28
- any( feature = "rustls-native-certs" , feature = "webpki-roots" ) ,
29
- feature = "tokio-runtime"
30
- ) ) ]
31
- impl HttpsConnector < HttpConnector > {
32
- /// Construct a new `HttpsConnector` using the OS root store
33
- #[ cfg( feature = "rustls-native-certs" ) ]
34
- #[ cfg_attr( docsrs, doc( cfg( feature = "rustls-native-certs" ) ) ) ]
35
- pub fn with_native_roots ( ) -> Self {
36
- let certs = match rustls_native_certs:: load_native_certs ( ) {
37
- Ok ( certs) => certs,
38
- Err ( err) => Err ( err) . expect ( "cannot access native cert store" ) ,
39
- } ;
40
-
41
- if certs. is_empty ( ) {
42
- panic ! ( "no CA certificates found" ) ;
43
- }
44
-
45
- let mut roots = RootCertStore :: empty ( ) ;
46
- for cert in certs {
47
- roots. add_parsable_certificates ( & [ cert. 0 ] ) ;
48
- }
49
-
50
- Self :: build ( roots)
51
- }
52
-
53
- /// Construct a new `HttpsConnector` using the `webpki_roots`
54
- #[ cfg( feature = "webpki-roots" ) ]
55
- #[ cfg_attr( docsrs, doc( cfg( feature = "webpki-roots" ) ) ) ]
56
- pub fn with_webpki_roots ( ) -> Self {
57
- let mut roots = rustls:: RootCertStore :: empty ( ) ;
58
- roots. add_server_trust_anchors ( webpki_roots:: TLS_SERVER_ROOTS . 0 ) ;
59
- Self :: build ( roots)
60
- }
61
-
62
- /// Force the use of HTTPS when connecting.
63
- ///
64
- /// If a URL is not `https` when connecting, an error is returned. Disabled by default.
65
- pub fn https_only ( & mut self , enable : bool ) {
66
- self . force_https = enable;
67
- }
68
-
69
- fn build ( mut config : ClientConfig ) -> Self {
70
- let mut http = HttpConnector :: new ( ) ;
71
- http. enforce_http ( false ) ;
72
-
73
- config. alpn_protocols . clear ( ) ;
74
- #[ cfg( feature = "http2" ) ]
75
- {
76
- config. alpn_protocols . push ( b"h2" . to_vec ( ) ) ;
77
- }
78
-
79
- #[ cfg( feature = "http1" ) ]
80
- {
81
- config. alpn_protocols . push ( b"http/1.1" . to_vec ( ) ) ;
82
- }
83
-
84
- //let mut config = ClientConfig::builder()
85
- // .with_safe_defaults()
86
- // .with_root_certificates(roots)
87
- // //.with_certificate_transparency_logs(ct_logs::LOGS, XXX)
88
- // .with_no_client_auth();
89
-
90
- ( http, config) . into ( )
91
- }
23
+ tls_config : Arc < rustls:: ClientConfig > ,
92
24
}
93
25
94
26
impl < T > fmt:: Debug for HttpsConnector < T > {
@@ -101,7 +33,7 @@ impl<T> fmt::Debug for HttpsConnector<T> {
101
33
102
34
impl < H , C > From < ( H , C ) > for HttpsConnector < H >
103
35
where
104
- C : Into < Arc < ClientConfig > > ,
36
+ C : Into < Arc < rustls :: ClientConfig > > ,
105
37
{
106
38
fn from ( ( http, cfg) : ( H , C ) ) -> Self {
107
39
HttpsConnector {
@@ -135,38 +67,43 @@ where
135
67
}
136
68
137
69
fn call ( & mut self , dst : Uri ) -> Self :: Future {
138
- let is_https = dst. scheme_str ( ) == Some ( "https" ) ;
139
-
140
- if !is_https && self . force_https {
141
- // Early abort if HTTPS is forced but can't be used
142
- let err = io:: Error :: new ( io:: ErrorKind :: Other , "https required but URI was not https" ) ;
143
- Box :: pin ( async move { Err ( err. into ( ) ) } )
144
- } else if !is_https {
145
- let connecting_future = self . http . call ( dst) ;
146
-
147
- let f = async move {
148
- let tcp = connecting_future. await . map_err ( Into :: into) ?;
149
-
150
- Ok ( MaybeHttpsStream :: Http ( tcp) )
151
- } ;
152
- Box :: pin ( f)
70
+ // dst.scheme() would need to derive Eq to be matchable;
71
+ // use an if cascade instead
72
+ if let Some ( sch) = dst. scheme ( ) {
73
+ if sch == & http:: uri:: Scheme :: HTTP && !self . force_https {
74
+ let connecting_future = self . http . call ( dst) ;
75
+
76
+ let f = async move {
77
+ let tcp = connecting_future. await . map_err ( Into :: into) ?;
78
+
79
+ Ok ( MaybeHttpsStream :: Http ( tcp) )
80
+ } ;
81
+ Box :: pin ( f)
82
+ } else if sch == & http:: uri:: Scheme :: HTTPS {
83
+ let cfg = self . tls_config . clone ( ) ;
84
+ let hostname = dst. host ( ) . unwrap_or_default ( ) . to_string ( ) ;
85
+ let connecting_future = self . http . call ( dst) ;
86
+
87
+ let f = async move {
88
+ let tcp = connecting_future. await . map_err ( Into :: into) ?;
89
+ let connector = TlsConnector :: from ( cfg) ;
90
+ let dnsname = rustls:: ServerName :: try_from ( hostname. as_str ( ) )
91
+ . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: Other , "invalid dnsname" ) ) ?;
92
+ let tls = connector
93
+ . connect ( dnsname, tcp)
94
+ . await
95
+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
96
+ Ok ( MaybeHttpsStream :: Https ( tls) )
97
+ } ;
98
+ Box :: pin ( f)
99
+ } else {
100
+ let err =
101
+ io:: Error :: new ( io:: ErrorKind :: Other , format ! ( "Unsupported scheme {}" , sch) ) ;
102
+ Box :: pin ( async move { Err ( err. into ( ) ) } )
103
+ }
153
104
} else {
154
- let cfg = self . tls_config . clone ( ) ;
155
- let hostname = dst. host ( ) . unwrap_or_default ( ) . to_string ( ) ;
156
- let connecting_future = self . http . call ( dst) ;
157
-
158
- let f = async move {
159
- let tcp = connecting_future. await . map_err ( Into :: into) ?;
160
- let connector = TlsConnector :: from ( cfg) ;
161
- let dnsname = rustls:: ServerName :: try_from ( hostname. as_str ( ) )
162
- . map_err ( |_| io:: Error :: new ( io:: ErrorKind :: Other , "invalid dnsname" ) ) ?;
163
- let tls = connector
164
- . connect ( dnsname, tcp)
165
- . await
166
- . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
167
- Ok ( MaybeHttpsStream :: Https ( tls) )
168
- } ;
169
- Box :: pin ( f)
105
+ let err = io:: Error :: new ( io:: ErrorKind :: Other , "Missing scheme" ) ;
106
+ Box :: pin ( async move { Err ( err. into ( ) ) } )
170
107
}
171
108
}
172
109
}
0 commit comments