Skip to content

Commit bf699dd

Browse files
fix(download_timeout): introduce RUSTUP_DOWNLOAD_TIMEOUT for overriding download timeout
As some (corporate) firewalls take too much time to verify the downloads, the timeout is reached and the user cannot complete its installation. Besides changing the timeout from 30 secs to 3 mins, a new environment variable is introduced to allow users to override the timeout value to their taste.
1 parent 7a9e227 commit bf699dd

File tree

2 files changed

+26
-10
lines changed

2 files changed

+26
-10
lines changed

doc/user-guide/src/environment-variables.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@
6666

6767
- `RUSTUP_TERM_WIDTH` (default: none). Allows to override the terminal width for progress bars.
6868

69+
- `RUSTUP_DOWNLOAD_TIMEOUT` (default: 180). Allows to override the default
70+
timeout for downloading components.
71+
6972
[directive syntax]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
7073
[dc]: https://docs.docker.com/storage/storagedriver/overlayfs-driver/#modifying-files-or-directories
7174
[override]: overrides.md

src/download/mod.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Easy file downloading
22
33
use std::fs::remove_file;
4+
use std::num::NonZeroU64;
45
use std::path::Path;
6+
use std::time::Duration;
57

68
use anyhow::Context;
79
#[cfg(any(
@@ -202,7 +204,7 @@ async fn download_file_(
202204
});
203205

204206
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)
206208
.await;
207209

208210
notify_handler(Notification::DownloadFinished);
@@ -241,9 +243,10 @@ impl Backend {
241243
path: &Path,
242244
resume_from_partial: bool,
243245
callback: Option<DownloadCallback<'_>>,
246+
process: &Process,
244247
) -> anyhow::Result<()> {
245248
let Err(err) = self
246-
.download_impl(url, path, resume_from_partial, callback)
249+
.download_impl(url, path, resume_from_partial, callback, process)
247250
.await
248251
else {
249252
return Ok(());
@@ -265,6 +268,7 @@ impl Backend {
265268
path: &Path,
266269
resume_from_partial: bool,
267270
callback: Option<DownloadCallback<'_>>,
271+
process: &Process,
268272
) -> anyhow::Result<()> {
269273
use std::cell::RefCell;
270274
use std::fs::OpenOptions;
@@ -322,9 +326,15 @@ impl Backend {
322326
};
323327

324328
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+
});
325335

326336
// 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| {
328338
if let Event::DownloadDataReceived(data) = event {
329339
file.borrow_mut()
330340
.write_all(data)
@@ -356,13 +366,14 @@ impl Backend {
356366
self,
357367
url: &Url,
358368
resume_from: u64,
369+
timeout: &Duration,
359370
callback: DownloadCallback<'_>,
360371
) -> anyhow::Result<()> {
361372
match self {
362373
#[cfg(feature = "curl-backend")]
363-
Self::Curl => curl::download(url, resume_from, callback),
374+
Self::Curl => curl::download(url, resume_from, callback, timeout),
364375
#[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,
366377
}
367378
}
368379
}
@@ -383,10 +394,11 @@ impl TlsBackend {
383394
url: &Url,
384395
resume_from: u64,
385396
callback: DownloadCallback<'_>,
397+
timeout: &Duration,
386398
) -> anyhow::Result<()> {
387399
let client = match self {
388400
#[cfg(feature = "reqwest-rustls-tls")]
389-
Self::Rustls => reqwest_be::rustls_client()?,
401+
Self::Rustls => reqwest_be::rustls_client(timeout)?,
390402
#[cfg(feature = "reqwest-native-tls")]
391403
Self::NativeTls => &reqwest_be::CLIENT_NATIVE_TLS,
392404
};
@@ -424,6 +436,7 @@ mod curl {
424436
url: &Url,
425437
resume_from: u64,
426438
callback: &dyn Fn(Event<'_>) -> Result<()>,
439+
timeout: &Duration,
427440
) -> Result<()> {
428441
// Fetch either a cached libcurl handle (which will preserve open
429442
// connections) or create a new one if it isn't listed.
@@ -446,8 +459,8 @@ mod curl {
446459
let _ = handle.resume_from(0);
447460
}
448461

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)?;
451464

452465
{
453466
let cberr = RefCell::new(None);
@@ -586,11 +599,10 @@ mod reqwest_be {
586599
.pool_max_idle_per_host(0)
587600
.gzip(false)
588601
.proxy(Proxy::custom(env_proxy))
589-
.read_timeout(Duration::from_secs(30))
590602
}
591603

592604
#[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> {
594606
if let Some(client) = CLIENT_RUSTLS_TLS.get() {
595607
return Ok(client);
596608
}
@@ -607,6 +619,7 @@ mod reqwest_be {
607619
tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
608620

609621
let client = client_generic()
622+
.read_timeout(*timeout)
610623
.use_preconfigured_tls(tls_config)
611624
.user_agent(super::REQWEST_RUSTLS_TLS_USER_AGENT)
612625
.build()

0 commit comments

Comments
 (0)