diff --git a/Cargo.lock b/Cargo.lock index b636412375..56f2ebc954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -443,36 +443,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "curl" -version = "0.4.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "curl-sys" -version = "0.4.72+curl-8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.52.0", -] - [[package]] name = "cvt" version = "0.1.2" @@ -517,7 +487,6 @@ name = "download" version = "1.27.1" dependencies = [ "anyhow", - "curl", "env_proxy", "http-body-util", "hyper 1.3.1", @@ -1149,18 +1118,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "libz-sys" -version = "1.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.4.13" diff --git a/Cargo.toml b/Cargo.toml index 5807cc17a8..2cd86aa831 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,11 @@ repository = "https://github.com/rust-lang/rustup" build = "build.rs" [features] -curl-backend = ["download/curl-backend"] default = [ - "curl-backend", - "reqwest-backend", "reqwest-default-tls", "reqwest-rustls-tls", ] -reqwest-backend = ["download/reqwest-backend"] vendored-openssl = ['openssl/vendored'] reqwest-default-tls = ["download/reqwest-default-tls"] @@ -61,7 +57,7 @@ itertools = "0.12" libc = "0.2" once_cell.workspace = true opener = "0.7.0" -# `openssl` is used by `curl` or `reqwest` backend although it isn't imported by rustup: this +# `openssl` is used by or `reqwest` backend although it isn't imported by rustup: this # allows controlling the vendoring status without exposing the presence of the download crate. # HACK: We temporarily pin the OpenSSL version due to build issues encountered in # https://github.com/rust-lang/rustup/pull/3668. @@ -192,4 +188,4 @@ opt-level = 0 [package.metadata.cargo-all-features] # Building with no web backend will error. -always_include_features = ["reqwest-backend", "reqwest-rustls-tls"] +always_include_features = ["reqwest-rustls-tls"] diff --git a/ci/run.bash b/ci/run.bash index 4e4dd0cef3..530d7c13fc 100644 --- a/ci/run.bash +++ b/ci/run.bash @@ -8,7 +8,7 @@ rustc -vV cargo -vV -FEATURES=('--no-default-features' '--features' 'curl-backend,reqwest-backend,reqwest-default-tls') +FEATURES=('--no-default-features' '--features' 'reqwest-default-tls') case "$(uname -s)" in *NT* ) ;; # Windows NT * ) FEATURES+=('--features' 'vendored-openssl') ;; @@ -39,7 +39,7 @@ target_cargo() { target_cargo build download_pkg_test() { - features=('--no-default-features' '--features' 'curl-backend,reqwest-backend,reqwest-default-tls') + features=('--no-default-features' '--features' 'reqwest-default-tls') case "$TARGET" in # these platforms aren't supported by ring: powerpc* ) ;; diff --git a/download/Cargo.toml b/download/Cargo.toml index 3f3fb2455d..3f02c65df3 100644 --- a/download/Cargo.toml +++ b/download/Cargo.toml @@ -6,17 +6,14 @@ license = "MIT OR Apache-2.0" [features] -default = ["reqwest-backend", "reqwest-rustls-tls", "reqwest-default-tls"] +default = ["reqwest-rustls-tls", "reqwest-default-tls"] -curl-backend = ["curl"] -reqwest-backend = ["reqwest", "env_proxy"] reqwest-default-tls = ["reqwest/default-tls", "dep:once_cell"] reqwest-rustls-tls = ["reqwest/rustls-tls-native-roots", "dep:once_cell"] [dependencies] anyhow.workspace = true -curl = { version = "0.4.44", optional = true } -env_proxy = { version = "0.4.1", optional = true } +env_proxy = "0.4.1" once_cell = { workspace = true, optional = true } reqwest = { version = "0.12", default-features = false, features = ["blocking", "gzip", "socks"], optional = true } thiserror.workspace = true diff --git a/download/src/errors.rs b/download/src/errors.rs index 37d50a1bf3..f43e9787b2 100644 --- a/download/src/errors.rs +++ b/download/src/errors.rs @@ -12,10 +12,6 @@ pub enum DownloadError { Message(String), #[error(transparent)] IoError(#[from] std::io::Error), - #[cfg(feature = "reqwest-backend")] #[error(transparent)] Reqwest(#[from] ::reqwest::Error), - #[cfg(feature = "curl-backend")] - #[error(transparent)] - CurlError(#[from] curl::Error), } diff --git a/download/src/lib.rs b/download/src/lib.rs index 8176197fe3..854700bd66 100644 --- a/download/src/lib.rs +++ b/download/src/lib.rs @@ -16,7 +16,6 @@ const USER_AGENT: &str = concat!("rustup/", env!("CARGO_PKG_VERSION")); #[derive(Debug, Copy, Clone)] pub enum Backend { - Curl, Reqwest(TlsBackend), } @@ -35,20 +34,19 @@ pub enum Event<'a> { DownloadDataReceived(&'a [u8]), } +type DownloadCallback<'a> = &'a dyn Fn(Event<'_>) -> Result<()>; + fn download_with_backend( backend: Backend, url: &Url, resume_from: u64, - callback: &dyn Fn(Event<'_>) -> Result<()>, + callback: DownloadCallback<'_>, ) -> Result<()> { match backend { - Backend::Curl => curl::download(url, resume_from, callback), Backend::Reqwest(tls) => reqwest_be::download(url, resume_from, callback, tls), } } -type DownloadCallback<'a> = &'a dyn Fn(Event<'_>) -> Result<()>; - pub fn download_to_path_with_backend( backend: Backend, url: &Url, @@ -141,125 +139,6 @@ pub fn download_to_path_with_backend( }) } -#[cfg(all(not(feature = "reqwest-backend"), not(feature = "curl-backend")))] -compile_error!("Must enable at least one backend"); - -/// Download via libcurl; encrypt with the native (or OpenSSl) TLS -/// stack via libcurl -#[cfg(feature = "curl-backend")] -pub mod curl { - use std::cell::RefCell; - use std::str; - use std::time::Duration; - - use anyhow::{Context, Result}; - use curl::easy::Easy; - use url::Url; - - use super::Event; - use crate::errors::*; - - pub fn download( - url: &Url, - resume_from: u64, - callback: &dyn Fn(Event<'_>) -> Result<()>, - ) -> Result<()> { - // Fetch either a cached libcurl handle (which will preserve open - // connections) or create a new one if it isn't listed. - // - // Once we've acquired it, reset the lifetime from 'static to our local - // scope. - thread_local!(static EASY: RefCell = RefCell::new(Easy::new())); - EASY.with(|handle| { - let mut handle = handle.borrow_mut(); - - handle.url(url.as_ref())?; - handle.follow_location(true)?; - handle.useragent(super::USER_AGENT)?; - - if resume_from > 0 { - handle.resume_from(resume_from)?; - } else { - // an error here indicates that the range header isn't supported by underlying curl, - // so there's nothing to "clear" - safe to ignore this error. - let _ = handle.resume_from(0); - } - - // Take at most 30s to connect - handle.connect_timeout(Duration::new(30, 0))?; - - { - let cberr = RefCell::new(None); - let mut transfer = handle.transfer(); - - // Data callback for libcurl which is called with data that's - // downloaded. We just feed it into our hasher and also write it out - // to disk. - transfer.write_function(|data| { - match callback(Event::DownloadDataReceived(data)) { - Ok(()) => Ok(data.len()), - Err(e) => { - *cberr.borrow_mut() = Some(e); - Ok(0) - } - } - })?; - - // Listen for headers and parse out a `Content-Length` (case-insensitive) if it - // comes so we know how much we're downloading. - transfer.header_function(|header| { - if let Ok(data) = str::from_utf8(header) { - let prefix = "content-length: "; - if data.to_ascii_lowercase().starts_with(prefix) { - if let Ok(s) = data[prefix.len()..].trim().parse::() { - let msg = Event::DownloadContentLengthReceived(s + resume_from); - match callback(msg) { - Ok(()) => (), - Err(e) => { - *cberr.borrow_mut() = Some(e); - return false; - } - } - } - } - } - true - })?; - - // If an error happens check to see if we had a filesystem error up - // in `cberr`, but we always want to punt it up. - transfer.perform().or_else(|e| { - // If the original error was generated by one of our - // callbacks, return it. - match cberr.borrow_mut().take() { - Some(cberr) => Err(cberr), - None => { - // Otherwise, return the error from curl - if e.is_file_couldnt_read_file() { - Err(e).context(DownloadError::FileNotFound) - } else { - Err(e).context("error during download")? - } - } - } - })?; - } - - // If we didn't get a 20x or 0 ("OK" for files) then return an error - let code = handle.response_code()?; - match code { - 0 | 200..=299 => {} - _ => { - return Err(DownloadError::HttpStatus(code).into()); - } - }; - - Ok(()) - }) - } -} - -#[cfg(feature = "reqwest-backend")] pub mod reqwest_be { #[cfg(all( not(feature = "reqwest-rustls-tls"), @@ -332,11 +211,10 @@ pub mod reqwest_be { let catcher = || client_generic().use_rustls_tls().build(); // woah, an unwrap?! - // It's OK. This is the same as what is happening in curl. + // It's OK. // - // The curl::Easy::new() internally assert!s that the initialized - // Easy is not null. Inside reqwest, the errors here would be from - // the TLS library returning a null pointer as well. + // Inside reqwest, the errors here would be from the TLS library + // returning a null pointer. catcher().unwrap() }); @@ -345,11 +223,10 @@ pub mod reqwest_be { let catcher = || client_generic().build(); // woah, an unwrap?! - // It's OK. This is the same as what is happening in curl. + // It's OK. // - // The curl::Easy::new() internally assert!s that the initialized - // Easy is not null. Inside reqwest, the errors here would be from - // the TLS library returning a null pointer as well. + // Inside reqwest, the errors here would be from the TLS library + // returning a null pointer. catcher().unwrap() }); @@ -423,41 +300,3 @@ pub mod reqwest_be { } } } - -#[cfg(not(feature = "curl-backend"))] -pub mod curl { - - use anyhow::{anyhow, Result}; - - use super::Event; - use crate::errors::*; - use url::Url; - - pub fn download( - _url: &Url, - _resume_from: u64, - _callback: &dyn Fn(Event<'_>) -> Result<()>, - ) -> Result<()> { - Err(anyhow!(DownloadError::BackendUnavailable("curl"))) - } -} - -#[cfg(not(feature = "reqwest-backend"))] -pub mod reqwest_be { - - use anyhow::{anyhow, Result}; - - use super::Event; - use super::TlsBackend; - use crate::errors::*; - use url::Url; - - pub fn download( - _url: &Url, - _resume_from: u64, - _callback: &dyn Fn(Event<'_>) -> Result<()>, - _tls: TlsBackend, - ) -> Result<()> { - Err(anyhow!(DownloadError::BackendUnavailable("reqwest"))) - } -} diff --git a/download/tests/download-curl-resume.rs b/download/tests/download-curl-resume.rs deleted file mode 100644 index 3ac0e78871..0000000000 --- a/download/tests/download-curl-resume.rs +++ /dev/null @@ -1,76 +0,0 @@ -#![cfg(feature = "curl-backend")] - -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Mutex; - -use url::Url; - -use download::*; - -mod support; -use crate::support::{serve_file, tmp_dir, write_file}; - -#[test] -fn partially_downloaded_file_gets_resumed_from_byte_offset() { - let tmpdir = tmp_dir(); - let from_path = tmpdir.path().join("download-source"); - write_file(&from_path, "xxx45"); - - let target_path = tmpdir.path().join("downloaded"); - write_file(&target_path, "123"); - - let from_url = Url::from_file_path(&from_path).unwrap(); - download_to_path_with_backend(Backend::Curl, &from_url, &target_path, true, None) - .expect("Test download failed"); - - assert_eq!(std::fs::read_to_string(&target_path).unwrap(), "12345"); -} - -#[test] -fn callback_gets_all_data_as_if_the_download_happened_all_at_once() { - let tmpdir = tmp_dir(); - let target_path = tmpdir.path().join("downloaded"); - write_file(&target_path, "123"); - - let addr = serve_file(b"xxx45".to_vec()); - - let from_url = format!("http://{addr}").parse().unwrap(); - - let callback_partial = AtomicBool::new(false); - let callback_len = Mutex::new(None); - let received_in_callback = Mutex::new(Vec::new()); - - download_to_path_with_backend( - Backend::Curl, - &from_url, - &target_path, - true, - Some(&|msg| { - match msg { - Event::ResumingPartialDownload => { - assert!(!callback_partial.load(Ordering::SeqCst)); - callback_partial.store(true, Ordering::SeqCst); - } - Event::DownloadContentLengthReceived(len) => { - let mut flag = callback_len.lock().unwrap(); - assert!(flag.is_none()); - *flag = Some(len); - } - Event::DownloadDataReceived(data) => { - for b in data.iter() { - received_in_callback.lock().unwrap().push(*b); - } - } - } - - Ok(()) - }), - ) - .expect("Test download failed"); - - assert!(callback_partial.into_inner()); - assert_eq!(*callback_len.lock().unwrap(), Some(5)); - let observed_bytes = received_in_callback.into_inner().unwrap(); - assert_eq!(observed_bytes, vec![b'1', b'2', b'3', b'4', b'5']); - assert_eq!(std::fs::read_to_string(&target_path).unwrap(), "12345"); -} diff --git a/download/tests/download-reqwest-resume.rs b/download/tests/download-resume.rs similarity index 98% rename from download/tests/download-reqwest-resume.rs rename to download/tests/download-resume.rs index d326da6dc3..3a02bd28fd 100644 --- a/download/tests/download-reqwest-resume.rs +++ b/download/tests/download-resume.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "reqwest-backend")] - use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Mutex; diff --git a/download/tests/read-proxy-env.rs b/download/tests/read-proxy-env.rs index b55bd326f5..6162d87e15 100644 --- a/download/tests/read-proxy-env.rs +++ b/download/tests/read-proxy-env.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "reqwest-backend")] - use std::env::{remove_var, set_var}; use std::error::Error; use std::net::TcpListener; diff --git a/src/utils/notifications.rs b/src/utils/notifications.rs index 67f1785a8c..ef0f022239 100644 --- a/src/utils/notifications.rs +++ b/src/utils/notifications.rs @@ -32,8 +32,6 @@ pub enum Notification<'a> { /// utils::notifications by the time tar unpacking is called. SetDefaultBufferSize(usize), Error(String), - UsingCurl, - UsingReqwest, /// Renaming encountered a file in use error and is retrying. /// The InUse aspect is a heuristic - the OS specifies /// Permission denied, but as we work in users home dirs and @@ -57,9 +55,7 @@ impl<'a> Notification<'a> { | DownloadPushUnit(_) | DownloadPopUnit | DownloadFinished - | ResumingPartialDownload - | UsingCurl - | UsingReqwest => NotificationLevel::Verbose, + | ResumingPartialDownload => NotificationLevel::Verbose, RenameInUse(_, _) => NotificationLevel::Info, NoCanonicalPath(_) => NotificationLevel::Warn, Error(_) => NotificationLevel::Error, @@ -99,8 +95,6 @@ impl<'a> Display for Notification<'a> { DownloadFinished => write!(f, "download finished"), NoCanonicalPath(path) => write!(f, "could not canonicalize path: '{}'", path.display()), ResumingPartialDownload => write!(f, "resuming partial download"), - UsingCurl => write!(f, "downloading with curl"), - UsingReqwest => write!(f, "downloading with reqwest"), } } } diff --git a/src/utils/utils.rs b/src/utils/utils.rs index e2ad7c0ba8..cf49938412 100644 --- a/src/utils/utils.rs +++ b/src/utils/utils.rs @@ -221,11 +221,8 @@ fn download_file_( // Download the file // Keep the curl env var around for a bit - let use_curl_backend = process().var_os("RUSTUP_USE_CURL").is_some(); let use_rustls = process().var_os("RUSTUP_USE_RUSTLS").is_some(); - let (backend, notification) = if use_curl_backend { - (Backend::Curl, Notification::UsingCurl) - } else { + let backend = { let tls_backend = if use_rustls { TlsBackend::Rustls } else { @@ -238,9 +235,8 @@ fn download_file_( TlsBackend::Rustls } }; - (Backend::Reqwest(tls_backend), Notification::UsingReqwest) + Backend::Reqwest(tls_backend) }; - notify_handler(notification); let res = download_to_path_with_backend(backend, url, path, resume_from_partial, Some(callback));