11use std:: fmt;
2- use std:: sync:: Arc ;
2+ use std:: { sync:: Arc , time :: Duration } ;
33
44use hyper_util:: rt:: TokioIo ;
55use tokio:: io:: { AsyncRead , AsyncWrite } ;
6+ use tokio:: time;
67use tokio_rustls:: {
78 rustls:: {
89 crypto,
@@ -23,6 +24,7 @@ pub(crate) struct TlsConnector {
2324 config : Arc < ClientConfig > ,
2425 domain : Arc < ServerName < ' static > > ,
2526 assume_http2 : bool ,
27+ timeout : Option < Duration > ,
2628}
2729
2830impl TlsConnector {
@@ -34,6 +36,7 @@ impl TlsConnector {
3436 assume_http2 : bool ,
3537 #[ cfg( feature = "tls-native-roots" ) ] with_native_roots : bool ,
3638 #[ cfg( feature = "tls-webpki-roots" ) ] with_webpki_roots : bool ,
39+ timeout : Option < Duration > ,
3740 ) -> Result < Self , crate :: BoxError > {
3841 fn with_provider (
3942 provider : Arc < crypto:: CryptoProvider > ,
@@ -92,16 +95,22 @@ impl TlsConnector {
9295 config : Arc :: new ( config) ,
9396 domain : Arc :: new ( ServerName :: try_from ( domain) ?. to_owned ( ) ) ,
9497 assume_http2,
98+ timeout,
9599 } )
96100 }
97101
98102 pub ( crate ) async fn connect < I > ( & self , io : I ) -> Result < BoxedIo , crate :: BoxError >
99103 where
100104 I : AsyncRead + AsyncWrite + Send + Unpin + ' static ,
101105 {
102- let io = RustlsConnector :: from ( self . config . clone ( ) )
103- . connect ( self . domain . as_ref ( ) . to_owned ( ) , io)
104- . await ?;
106+ let conn_fut =
107+ RustlsConnector :: from ( self . config . clone ( ) ) . connect ( self . domain . as_ref ( ) . to_owned ( ) , io) ;
108+ let io = match self . timeout {
109+ Some ( timeout) => time:: timeout ( timeout, conn_fut)
110+ . await
111+ . map_err ( |_| TlsError :: HandshakeTimeout ) ?,
112+ None => conn_fut. await ,
113+ } ?;
105114
106115 // Generally we require ALPN to be negotiated, but if the user has
107116 // explicitly set `assume_http2` to true, we'll allow it to be missing.
0 commit comments