1
1
//! Easy file downloading
2
2
3
3
use std:: fs:: remove_file;
4
+ use std:: num:: NonZeroU64 ;
4
5
use std:: path:: Path ;
6
+ use std:: time:: Duration ;
5
7
6
8
use anyhow:: Context ;
7
9
#[ cfg( any(
@@ -202,7 +204,7 @@ async fn download_file_(
202
204
} ) ;
203
205
204
206
let res = backend
205
- . download_to_path ( url, path, resume_from_partial, Some ( callback) )
207
+ . download_to_path ( url, path, resume_from_partial, Some ( callback) , process )
206
208
. await ;
207
209
208
210
notify_handler ( Notification :: DownloadFinished ) ;
@@ -241,9 +243,10 @@ impl Backend {
241
243
path : & Path ,
242
244
resume_from_partial : bool ,
243
245
callback : Option < DownloadCallback < ' _ > > ,
246
+ process : & Process ,
244
247
) -> anyhow:: Result < ( ) > {
245
248
let Err ( err) = self
246
- . download_impl ( url, path, resume_from_partial, callback)
249
+ . download_impl ( url, path, resume_from_partial, callback, process )
247
250
. await
248
251
else {
249
252
return Ok ( ( ) ) ;
@@ -265,6 +268,7 @@ impl Backend {
265
268
path : & Path ,
266
269
resume_from_partial : bool ,
267
270
callback : Option < DownloadCallback < ' _ > > ,
271
+ process : & Process ,
268
272
) -> anyhow:: Result < ( ) > {
269
273
use std:: cell:: RefCell ;
270
274
use std:: fs:: OpenOptions ;
@@ -322,9 +326,15 @@ impl Backend {
322
326
} ;
323
327
324
328
let file = RefCell :: new ( file) ;
329
+ let timeout = Duration :: from_secs ( match process. var ( "RUSTUP_DOWNLOAD_TIMEOUT" ) {
330
+ Ok ( s) => s. parse :: < NonZeroU64 > ( ) . context (
331
+ "invalid value in RUSTUP_DOWNLOAD_TIMEOUT -- must be a natural number greater than zero" ,
332
+ ) . unwrap ( ) . get ( ) ,
333
+ Err ( _) => 180 ,
334
+ } ) ;
325
335
326
336
// TODO: the sync callback will stall the async runtime if IO calls block, which is OS dependent. Rearrange.
327
- self . download ( url, resume_from, & |event| {
337
+ self . download ( url, resume_from, & timeout , & |event| {
328
338
if let Event :: DownloadDataReceived ( data) = event {
329
339
file. borrow_mut ( )
330
340
. write_all ( data)
@@ -356,13 +366,14 @@ impl Backend {
356
366
self ,
357
367
url : & Url ,
358
368
resume_from : u64 ,
369
+ timeout : & Duration ,
359
370
callback : DownloadCallback < ' _ > ,
360
371
) -> anyhow:: Result < ( ) > {
361
372
match self {
362
373
#[ cfg( feature = "curl-backend" ) ]
363
- Self :: Curl => curl:: download ( url, resume_from, callback) ,
374
+ Self :: Curl => curl:: download ( url, resume_from, callback, timeout ) ,
364
375
#[ cfg( any( feature = "reqwest-rustls-tls" , feature = "reqwest-native-tls" ) ) ]
365
- Self :: Reqwest ( tls) => tls. download ( url, resume_from, callback) . await ,
376
+ Self :: Reqwest ( tls) => tls. download ( url, resume_from, callback, timeout ) . await ,
366
377
}
367
378
}
368
379
}
@@ -383,10 +394,11 @@ impl TlsBackend {
383
394
url : & Url ,
384
395
resume_from : u64 ,
385
396
callback : DownloadCallback < ' _ > ,
397
+ timeout : & Duration ,
386
398
) -> anyhow:: Result < ( ) > {
387
399
let client = match self {
388
400
#[ cfg( feature = "reqwest-rustls-tls" ) ]
389
- Self :: Rustls => reqwest_be:: rustls_client ( ) ?,
401
+ Self :: Rustls => reqwest_be:: rustls_client ( timeout ) ?,
390
402
#[ cfg( feature = "reqwest-native-tls" ) ]
391
403
Self :: NativeTls => & reqwest_be:: CLIENT_NATIVE_TLS ,
392
404
} ;
@@ -424,6 +436,7 @@ mod curl {
424
436
url : & Url ,
425
437
resume_from : u64 ,
426
438
callback : & dyn Fn ( Event < ' _ > ) -> Result < ( ) > ,
439
+ timeout : & Duration ,
427
440
) -> Result < ( ) > {
428
441
// Fetch either a cached libcurl handle (which will preserve open
429
442
// connections) or create a new one if it isn't listed.
@@ -446,8 +459,8 @@ mod curl {
446
459
let _ = handle. resume_from ( 0 ) ;
447
460
}
448
461
449
- // Take at most 30s to connect
450
- handle. connect_timeout ( Duration :: new ( 30 , 0 ) ) ?;
462
+ // Take at most 3m to connect if the `RUSTUP_DOWNLOAD_TIMEOUT` env var is not set.`
463
+ handle. connect_timeout ( * timeout ) ?;
451
464
452
465
{
453
466
let cberr = RefCell :: new ( None ) ;
@@ -586,11 +599,10 @@ mod reqwest_be {
586
599
. pool_max_idle_per_host ( 0 )
587
600
. gzip ( false )
588
601
. proxy ( Proxy :: custom ( env_proxy) )
589
- . read_timeout ( Duration :: from_secs ( 30 ) )
590
602
}
591
603
592
604
#[ cfg( feature = "reqwest-rustls-tls" ) ]
593
- pub ( super ) fn rustls_client ( ) -> Result < & ' static Client , DownloadError > {
605
+ pub ( super ) fn rustls_client ( timeout : & Duration ) -> Result < & ' static Client , DownloadError > {
594
606
if let Some ( client) = CLIENT_RUSTLS_TLS . get ( ) {
595
607
return Ok ( client) ;
596
608
}
@@ -607,6 +619,7 @@ mod reqwest_be {
607
619
tls_config. alpn_protocols = vec ! [ b"h2" . to_vec( ) , b"http/1.1" . to_vec( ) ] ;
608
620
609
621
let client = client_generic ( )
622
+ . read_timeout ( * timeout)
610
623
. use_preconfigured_tls ( tls_config)
611
624
. user_agent ( super :: REQWEST_RUSTLS_TLS_USER_AGENT )
612
625
. build ( )
0 commit comments