@@ -27,11 +27,23 @@ use http_body_util::BodyExt;
2727
2828use std:: collections:: HashMap ;
2929use std:: sync:: Arc ;
30+ use std:: sync:: OnceLock ;
3031use std:: thread:: ThreadId ;
3132use std:: time:: Duration ;
3233use std:: time:: SystemTime ;
3334use thiserror:: Error ;
3435
36+ static FETCH_TIMEOUT : OnceLock < Option < Duration > > = OnceLock :: new ( ) ;
37+
38+ fn fetch_timeout ( ) -> Option < Duration > {
39+ * FETCH_TIMEOUT . get_or_init ( || {
40+ std:: env:: var ( "DENO_FETCH_TIMEOUT_SECS" )
41+ . ok ( )
42+ . and_then ( |v| v. parse :: < u64 > ( ) . ok ( ) )
43+ . map ( Duration :: from_secs)
44+ } )
45+ }
46+
3547// TODO(ry) HTTP headers are not unique key, value pairs. There may be more than
3648// one header line with the same key. This should be changed to something like
3749// Vec<(String, String)>
@@ -391,13 +403,27 @@ impl HttpClient {
391403 let accepts_val = HeaderValue :: from_str ( & accept) ?;
392404 request. headers_mut ( ) . insert ( ACCEPT , accepts_val) ;
393405 }
394- let response = match self . client . clone ( ) . send ( request) . await {
395- Ok ( resp) => resp,
396- Err ( err) => {
397- if err. is_connect_error ( ) {
398- return Ok ( FetchOnceResult :: RequestError ( err. to_string ( ) ) ) ;
406+ let response = {
407+ let send_fut = self . client . clone ( ) . send ( request) ;
408+ let resp = if let Some ( dur) = fetch_timeout ( ) {
409+ tokio:: time:: timeout ( dur, send_fut) . await . map_err ( |_| {
410+ anyhow:: anyhow!(
411+ "Fetch '{}' timed out after {}s" ,
412+ args. url,
413+ dur. as_secs( )
414+ )
415+ } ) ?
416+ } else {
417+ send_fut. await
418+ } ;
419+ match resp {
420+ Ok ( r) => r,
421+ Err ( err) => {
422+ if err. is_connect_error ( ) {
423+ return Ok ( FetchOnceResult :: RequestError ( err. to_string ( ) ) ) ;
424+ }
425+ return Err ( err. into ( ) ) ;
399426 }
400- return Err ( err. into ( ) ) ;
401427 }
402428 } ;
403429
@@ -450,7 +476,19 @@ impl HttpClient {
450476 return Err ( err) ;
451477 }
452478
453- let body = get_response_body_with_progress ( response) . await ?;
479+ let body = if let Some ( dur) = fetch_timeout ( ) {
480+ tokio:: time:: timeout ( dur, get_response_body_with_progress ( response) )
481+ . await
482+ . map_err ( |_| {
483+ anyhow:: anyhow!(
484+ "Fetch '{}' body timed out after {}s" ,
485+ args. url,
486+ dur. as_secs( )
487+ )
488+ } ) ??
489+ } else {
490+ get_response_body_with_progress ( response) . await ?
491+ } ;
454492
455493 Ok ( FetchOnceResult :: Code ( body, result_headers) )
456494 }
0 commit comments