@@ -29,6 +29,7 @@ use super::dns::{self, GaiResolver, Resolve, TokioThreadpoolGaiResolver};
29
29
pub struct HttpConnector < R = GaiResolver > {
30
30
enforce_http : bool ,
31
31
handle : Option < Handle > ,
32
+ resolve_timeout : Option < Duration > ,
32
33
connect_timeout : Option < Duration > ,
33
34
happy_eyeballs_timeout : Option < Duration > ,
34
35
keep_alive_timeout : Option < Duration > ,
@@ -121,6 +122,7 @@ impl<R> HttpConnector<R> {
121
122
HttpConnector {
122
123
enforce_http : true ,
123
124
handle : None ,
125
+ resolve_timeout : None ,
124
126
connect_timeout : None ,
125
127
happy_eyeballs_timeout : Some ( Duration :: from_millis ( 300 ) ) ,
126
128
keep_alive_timeout : None ,
@@ -189,6 +191,17 @@ impl<R> HttpConnector<R> {
189
191
self . local_address = addr;
190
192
}
191
193
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
+
192
205
/// Set the connect timeout.
193
206
///
194
207
/// If a domain resolves to multiple IP addresses, the timeout will be
@@ -272,6 +285,7 @@ where
272
285
HttpConnecting {
273
286
state : State :: Lazy ( self . resolver . clone ( ) , host. into ( ) , self . local_address ) ,
274
287
handle : self . handle . clone ( ) ,
288
+ resolve_timeout : self . resolve_timeout ,
275
289
connect_timeout : self . connect_timeout ,
276
290
happy_eyeballs_timeout : self . happy_eyeballs_timeout ,
277
291
keep_alive_timeout : self . keep_alive_timeout ,
@@ -299,6 +313,7 @@ fn invalid_url<R: Resolve>(err: InvalidUrl, handle: &Option<Handle>) -> HttpConn
299
313
keep_alive_timeout : None ,
300
314
nodelay : false ,
301
315
port : 0 ,
316
+ resolve_timeout : None ,
302
317
connect_timeout : None ,
303
318
happy_eyeballs_timeout : None ,
304
319
reuse_address : false ,
@@ -334,6 +349,7 @@ impl StdError for InvalidUrl {
334
349
pub struct HttpConnecting < R : Resolve = GaiResolver > {
335
350
state : State < R > ,
336
351
handle : Option < Handle > ,
352
+ resolve_timeout : Option < Duration > ,
337
353
connect_timeout : Option < Duration > ,
338
354
happy_eyeballs_timeout : Option < Duration > ,
339
355
keep_alive_timeout : Option < Duration > ,
@@ -346,11 +362,16 @@ pub struct HttpConnecting<R: Resolve = GaiResolver> {
346
362
347
363
enum State < R : Resolve > {
348
364
Lazy ( R , String , Option < IpAddr > ) ,
349
- Resolving ( R :: Future , Option < IpAddr > ) ,
365
+ Resolving ( ResolvingFuture < R > , Option < IpAddr > ) ,
350
366
Connecting ( ConnectingTcp ) ,
351
367
Error ( Option < io:: Error > ) ,
352
368
}
353
369
370
+ enum ResolvingFuture < R : Resolve > {
371
+ Timed ( Timeout < R :: Future > ) ,
372
+ Untimed ( R :: Future ) ,
373
+ }
374
+
354
375
impl < R : Resolve > Future for HttpConnecting < R > {
355
376
type Item = ( TcpStream , Connected ) ;
356
377
type Error = io:: Error ;
@@ -367,11 +388,27 @@ impl<R: Resolve> Future for HttpConnecting<R> {
367
388
local_addr, addrs, self . connect_timeout , self . happy_eyeballs_timeout , self . reuse_address ) ) ;
368
389
} else {
369
390
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
+ }
371
397
}
372
398
} ,
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 {
375
412
Async :: NotReady => return Ok ( Async :: NotReady ) ,
376
413
Async :: Ready ( addrs) => {
377
414
let port = self . port ;
0 commit comments