@@ -29,6 +29,7 @@ use super::dns::{self, GaiResolver, Resolve, TokioThreadpoolGaiResolver};
2929pub struct HttpConnector < R = GaiResolver > {
3030 enforce_http : bool ,
3131 handle : Option < Handle > ,
32+ resolve_timeout : Option < Duration > ,
3233 connect_timeout : Option < Duration > ,
3334 happy_eyeballs_timeout : Option < Duration > ,
3435 keep_alive_timeout : Option < Duration > ,
@@ -121,6 +122,7 @@ impl<R> HttpConnector<R> {
121122 HttpConnector {
122123 enforce_http : true ,
123124 handle : None ,
125+ resolve_timeout : None ,
124126 connect_timeout : None ,
125127 happy_eyeballs_timeout : Some ( Duration :: from_millis ( 300 ) ) ,
126128 keep_alive_timeout : None ,
@@ -189,6 +191,17 @@ impl<R> HttpConnector<R> {
189191 self . local_address = addr;
190192 }
191193
194+ /// Set timeout for hostname resolution.
195+ ///
196+ /// If `None`, then no timeout is applied by the connector, making it
197+ /// subject to the timeout imposed by the operating system.
198+ ///
199+ /// Default is `None`.
200+ #[ inline]
201+ pub fn set_resolve_timeout ( & mut self , dur : Option < Duration > ) {
202+ self . resolve_timeout = dur;
203+ }
204+
192205 /// Set the connect timeout.
193206 ///
194207 /// If a domain resolves to multiple IP addresses, the timeout will be
@@ -272,6 +285,7 @@ where
272285 HttpConnecting {
273286 state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . local_address ) ,
274287 handle : self . handle . clone ( ) ,
288+ resolve_timeout : self . resolve_timeout ,
275289 connect_timeout : self . connect_timeout ,
276290 happy_eyeballs_timeout : self . happy_eyeballs_timeout ,
277291 keep_alive_timeout : self . keep_alive_timeout ,
@@ -299,6 +313,7 @@ fn invalid_url<R: Resolve>(err: InvalidUrl, handle: &Option<Handle>) -> HttpConn
299313 keep_alive_timeout : None ,
300314 nodelay : false ,
301315 port : 0 ,
316+ resolve_timeout : None ,
302317 connect_timeout : None ,
303318 happy_eyeballs_timeout : None ,
304319 reuse_address : false ,
@@ -334,6 +349,7 @@ impl StdError for InvalidUrl {
334349pub struct HttpConnecting < R : Resolve = GaiResolver > {
335350 state : State < R > ,
336351 handle : Option < Handle > ,
352+ resolve_timeout : Option < Duration > ,
337353 connect_timeout : Option < Duration > ,
338354 happy_eyeballs_timeout : Option < Duration > ,
339355 keep_alive_timeout : Option < Duration > ,
@@ -346,11 +362,16 @@ pub struct HttpConnecting<R: Resolve = GaiResolver> {
346362
347363enum State < R : Resolve > {
348364 Lazy ( R , String , Option < IpAddr > ) ,
349- Resolving ( R :: Future , Option < IpAddr > ) ,
365+ Resolving ( ResolvingFuture < R > , Option < IpAddr > ) ,
350366 Connecting ( ConnectingTcp ) ,
351367 Error ( Option < io:: Error > ) ,
352368}
353369
370+ enum ResolvingFuture < R : Resolve > {
371+ Timed ( Timeout < R :: Future > ) ,
372+ Untimed ( R :: Future ) ,
373+ }
374+
354375impl < R : Resolve > Future for HttpConnecting < R > {
355376 type Item = ( TcpStream , Connected ) ;
356377 type Error = io:: Error ;
@@ -367,11 +388,27 @@ impl<R: Resolve> Future for HttpConnecting<R> {
367388 local_addr, addrs, self . connect_timeout , self . happy_eyeballs_timeout , self . reuse_address ) ) ;
368389 } else {
369390 let name = dns:: Name :: new ( mem:: replace ( host, String :: new ( ) ) ) ;
370- state = State :: Resolving ( resolver. resolve ( name) , local_addr) ;
391+ let future = resolver. resolve ( name) ;
392+ state = if let Some ( timeout) = self . resolve_timeout {
393+ State :: Resolving ( ResolvingFuture :: Timed ( Timeout :: new ( future, timeout) ) , local_addr)
394+ } else {
395+ State :: Resolving ( ResolvingFuture :: Untimed ( future) , local_addr)
396+ }
371397 }
372398 } ,
373- State :: Resolving ( ref mut future, local_addr) => {
374- match future. poll ( ) ? {
399+ State :: Resolving ( ref mut rfuture, local_addr) => {
400+ let res: Async < R :: Addrs > = match rfuture {
401+ ResolvingFuture :: Timed ( future) => match future. poll ( ) {
402+ Ok ( res) => res,
403+ Err ( err) => if err. is_inner ( ) {
404+ return Err ( err. into_inner ( ) . unwrap ( ) )
405+ } else {
406+ return Err ( io:: Error :: new ( io:: ErrorKind :: TimedOut , err. description ( ) ) )
407+ } ,
408+ } ,
409+ ResolvingFuture :: Untimed ( future) => future. poll ( ) ?,
410+ } ;
411+ match res {
375412 Async :: NotReady => return Ok ( Async :: NotReady ) ,
376413 Async :: Ready ( addrs) => {
377414 let port = self . port ;
0 commit comments