11use std:: fmt;
22use std:: io;
3- use std:: sync:: Arc ;
43
5- use futures:: { Future , future, Poll } ;
4+ use futures:: { Async , Future , future, Poll } ;
65use hyper:: client:: connect:: { Connect , Connected , Destination , HttpConnector } ;
76pub use native_tls:: Error ;
8- use native_tls:: TlsConnector ;
9- use tokio_tls:: TlsConnectorExt ;
7+ use native_tls:: { self , HandshakeError , TlsConnector } ;
108
11- use stream:: MaybeHttpsStream ;
9+ use stream:: { MaybeHttpsStream , TlsStream } ;
1210
1311/// A Connector for the `https` scheme.
1412#[ derive( Clone ) ]
1513pub struct HttpsConnector < T > {
16- hostname_verification : bool ,
1714 force_https : bool ,
1815 http : T ,
19- tls : Arc < TlsConnector > ,
16+ tls : TlsConnector ,
2017}
2118
2219impl HttpsConnector < HttpConnector > {
23-
2420 /// Construct a new HttpsConnector.
2521 ///
2622 /// Takes number of DNS worker threads.
@@ -29,35 +25,35 @@ impl HttpsConnector<HttpConnector> {
2925 /// If you wish to use something besides the defaults, use `From::from`.
3026 ///
3127 /// # Note
32- /// By default this connector will use plain HTTP if the URL provded
33- /// uses the HTTP scheme (eg: http://example.com/).
34- /// If you would like to force the use of HTTPS
35- /// then call force_https(true) on the returned connector.
28+ ///
29+ /// By default this connector will use plain HTTP if the URL provded uses
30+ /// the HTTP scheme (eg: http://example.com/).
31+ ///
32+ /// If you would like to force the use of HTTPS then call force_https(true)
33+ /// on the returned connector.
3634 pub fn new ( threads : usize ) -> Result < Self , Error > {
35+ TlsConnector :: builder ( )
36+ . build ( )
37+ . map ( |tls| HttpsConnector :: new_ ( threads, tls) )
38+ }
39+
40+ fn new_ ( threads : usize , tls : TlsConnector ) -> Self {
3741 let mut http = HttpConnector :: new ( threads) ;
3842 http. enforce_http ( false ) ;
39- let tls = TlsConnector :: builder ( ) ?. build ( ) ?;
40- Ok ( HttpsConnector :: from ( ( http, tls) ) )
43+ HttpsConnector :: from ( ( http, tls) )
4144 }
4245}
4346
4447impl < T > HttpsConnector < T > {
45- /// Disable hostname verification when connecting.
46- ///
47- /// # Warning
48+ /// Force the use of HTTPS when connecting.
4849 ///
49- /// You should think very carefully before you use this method. If hostname
50- /// verification is not used, any valid certificate for any site will be
51- /// trusted for use from any other. This introduces a significant
52- /// vulnerability to man-in-the-middle attacks.
53- pub fn danger_disable_hostname_verification ( & mut self , disable : bool ) {
54- self . hostname_verification = !disable;
50+ /// If a URL is not `https` when connecting, an error is returned.
51+ pub fn https_only ( & mut self , enable : bool ) {
52+ self . force_https = enable;
5553 }
56- }
5754
58- impl < T > HttpsConnector < T > {
59- /// Force the use of HTTPS when connecting.
60- /// If HTTPS cannot be used the connection will be aborted.
55+ #[ doc( hidden) ]
56+ #[ deprecated( since = "0.3" , note = "use `https_only` method instead" ) ]
6157 pub fn force_https ( & mut self , enable : bool ) {
6258 self . force_https = enable;
6359 }
@@ -66,18 +62,16 @@ impl<T> HttpsConnector<T> {
6662impl < T > From < ( T , TlsConnector ) > for HttpsConnector < T > {
6763 fn from ( args : ( T , TlsConnector ) ) -> HttpsConnector < T > {
6864 HttpsConnector {
69- hostname_verification : true ,
7065 force_https : false ,
7166 http : args. 0 ,
72- tls : Arc :: new ( args. 1 ) ,
67+ tls : args. 1 ,
7368 }
7469 }
7570}
7671
7772impl < T : fmt:: Debug > fmt:: Debug for HttpsConnector < T > {
7873 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
7974 f. debug_struct ( "HttpsConnector" )
80- . field ( "hostname_verification" , & self . hostname_verification )
8175 . field ( "force_https" , & self . force_https )
8276 . field ( "http" , & self . http )
8377 . finish ( )
@@ -101,20 +95,17 @@ where
10195 let err = io:: Error :: new ( io:: ErrorKind :: Other , "HTTPS scheme forced but can't be used" ) ;
10296 return HttpsConnecting ( Box :: new ( future:: err ( err) ) ) ;
10397 }
104-
98+
10599 let host = dst. host ( ) . to_owned ( ) ;
106100 let connecting = self . http . connect ( dst) ;
107101 let tls = self . tls . clone ( ) ;
108- let verification = self . hostname_verification ;
109102 let fut: BoxedFut < T :: Transport > = if is_https {
110103 let fut = connecting. and_then ( move |( tcp, connected) | {
111- let handshake = if verification {
112- tls. connect_async ( & host, tcp)
113- } else {
114- tls. danger_connect_async_without_providing_domain_for_certificate_verification_and_server_name_indication ( tcp)
104+ let handshake = Handshaking {
105+ inner : Some ( tls. connect ( & host, tcp) ) ,
115106 } ;
116107 handshake
117- . map ( |conn| ( MaybeHttpsStream :: Https ( conn) , connected) )
108+ . map ( |conn| ( MaybeHttpsStream :: Https ( TlsStream :: new ( conn) ) , connected) )
118109 . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) )
119110 } ) ;
120111 Box :: new ( fut)
@@ -149,3 +140,28 @@ impl<T> fmt::Debug for HttpsConnecting<T> {
149140 }
150141}
151142
143+ struct Handshaking < T > {
144+ inner : Option < Result < native_tls:: TlsStream < T > , HandshakeError < T > > > ,
145+ }
146+
147+ impl < T : io:: Read + io:: Write > Future for Handshaking < T > {
148+ type Item = native_tls:: TlsStream < T > ;
149+ type Error = native_tls:: Error ;
150+
151+ fn poll ( & mut self ) -> Poll < Self :: Item , Self :: Error > {
152+ match self . inner . take ( ) . expect ( "polled after ready" ) {
153+ Ok ( stream) => Ok ( stream. into ( ) ) ,
154+ Err ( HandshakeError :: WouldBlock ( mid) ) => {
155+ match mid. handshake ( ) {
156+ Ok ( stream) => Ok ( stream. into ( ) ) ,
157+ Err ( HandshakeError :: Failure ( err) ) => Err ( err) ,
158+ Err ( HandshakeError :: WouldBlock ( mid) ) => {
159+ self . inner = Some ( Err ( HandshakeError :: WouldBlock ( mid) ) ) ;
160+ Ok ( Async :: NotReady )
161+ }
162+ }
163+ } ,
164+ Err ( HandshakeError :: Failure ( err) ) => Err ( err) ,
165+ }
166+ }
167+ }
0 commit comments