Skip to content

Commit

Permalink
Re-add rustls support and enable it by default
Browse files Browse the repository at this point in the history
rustls is seen as mature enough for curl to depend on it optionally,
and it recently has had an audit.

This commit adds back rustls support removed by 86bb185
and enables it by default.

You can opt out of rustls use by setting the RUSTUP_AVOID_RUSTLS env
variable.
  • Loading branch information
est31 committed Oct 10, 2020
1 parent 243b453 commit a3b4b9e
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 21 deletions.
95 changes: 95 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ version = "1.22.1"

[features]
curl-backend = ["download/curl-backend"]
default = ["curl-backend", "reqwest-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"]
reqwest-rustls-tls = ["download/reqwest-rustls-tls"]

# Include in the default set to disable self-update and uninstall.
no-self-update = []

Expand All @@ -25,7 +30,7 @@ anyhow = "1.0.31"
cfg-if = "0.1"
chrono = "0.4"
clap = "2"
download = {path = "download"}
download = { path = "download", default-features = false }
error-chain = "0.12"
flate2 = "1"
git-testament = "0.1.4"
Expand Down
6 changes: 4 additions & 2 deletions download/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ license = "MIT/Apache-2.0"

[features]

default = ["reqwest-backend"]
default = ["reqwest-backend", "reqwest-rustls-tls", "reqwest-default-tls"]

curl-backend = ["curl"]
reqwest-backend = ["reqwest", "env_proxy", "lazy_static"]
reqwest-default-tls = ["reqwest/default-tls"]
reqwest-rustls-tls = ["reqwest/rustls-tls"]

[dependencies]
error-chain = "0.12"
url = "2.1"
curl = { version = "0.4.11", optional = true }
env_proxy = { version = "0.4.1", optional = true }
lazy_static = { version = "1.0", optional = true }
reqwest = { version = "0.10", features = ["blocking", "gzip", "socks"], optional = true }
reqwest = { version = "0.10", default-features = false, features = ["blocking", "gzip", "socks"], optional = true }

[dev-dependencies]
hyper = { version = "0.13", default-features = false, features = ["tcp"] }
Expand Down
66 changes: 55 additions & 11 deletions download/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ pub use crate::errors::*;
#[derive(Debug, Copy, Clone)]
pub enum Backend {
Curl,
Reqwest,
Reqwest(TlsBackend),
}

#[derive(Debug, Copy, Clone)]
pub enum TlsBackend {
Rustls,
Default,
}

#[derive(Debug, Copy, Clone)]
Expand All @@ -30,7 +36,7 @@ fn download_with_backend(
) -> Result<()> {
match backend {
Backend::Curl => curl::download(url, resume_from, callback),
Backend::Reqwest => reqwest_be::download(url, resume_from, callback),
Backend::Reqwest(tls) => reqwest_be::download(url, resume_from, callback, tls),
}
}

Expand Down Expand Up @@ -249,9 +255,10 @@ pub mod curl {
#[cfg(feature = "reqwest-backend")]
pub mod reqwest_be {
use super::Event;
use super::TlsBackend;
use crate::errors::*;
use lazy_static::lazy_static;
use reqwest::blocking::{Client, Response};
use reqwest::blocking::{Client, ClientBuilder, Response};
use reqwest::{header, Proxy};
use std::io;
use std::time::Duration;
Expand All @@ -261,13 +268,15 @@ pub mod reqwest_be {
url: &Url,
resume_from: u64,
callback: &dyn Fn(Event<'_>) -> Result<()>,
tls: TlsBackend,
) -> Result<()> {
// Short-circuit reqwest for the "file:" URL scheme
if download_from_file_url(url, resume_from, callback)? {
return Ok(());
}

let mut res = request(url, resume_from).chain_err(|| "failed to make network request")?;
let mut res =
request(url, resume_from, tls).chain_err(|| "failed to make network request")?;

if !res.status().is_success() {
let code: u16 = res.status().into();
Expand Down Expand Up @@ -295,13 +304,34 @@ pub mod reqwest_be {
}
}

fn client_generic() -> ClientBuilder {
Client::builder()
.gzip(false)
.proxy(Proxy::custom(env_proxy))
.timeout(Duration::from_secs(30))
}
#[cfg(feature = "reqwest-rustls-tls")]
lazy_static! {
static ref CLIENT: Client = {
static ref CLIENT_RUSTLS_TLS: Client = {
let catcher = || {
Client::builder()
.gzip(false)
.proxy(Proxy::custom(env_proxy))
.timeout(Duration::from_secs(30))
client_generic().use_rustls_tls()
.build()
};

// woah, an unwrap?!
// It's OK. This is the same as what is happening in curl.
//
// 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.
catcher().unwrap()
};
}
#[cfg(feature = "reqwest-default-tls")]
lazy_static! {
static ref CLIENT_DEFAULT_TLS: Client = {
let catcher = || {
client_generic()
.build()
};

Expand All @@ -319,8 +349,22 @@ pub mod reqwest_be {
env_proxy::for_url(url).to_url()
}

fn request(url: &Url, resume_from: u64) -> reqwest::Result<Response> {
let mut req = CLIENT.get(url.as_str());
fn request(url: &Url, resume_from: u64, backend: TlsBackend) -> reqwest::Result<Response> {
let client: &Client = match backend {
#[cfg(feature = "reqwest-rustls-tls")]
TlsBackend::Rustls => &CLIENT_RUSTLS_TLS,
#[cfg(not(feature = "reqwest-rustls-tls"))]
TlsBackend::Default => {
panic!("Instructed to use rustls TLS, but not enabled at build time")
}
#[cfg(feature = "reqwest-default-tls")]
TlsBackend::Default => &CLIENT_DEFAULT_TLS,
#[cfg(not(feature = "reqwest-default-tls"))]
TlsBackend::Default => {
panic!("Instructed to use default TLS, but not enabled at build time")
}
};
let mut req = client.get(url.as_str());

if resume_from != 0 {
req = req.header(header::RANGE, format!("bytes={}-", resume_from));
Expand Down
12 changes: 9 additions & 3 deletions download/tests/download-reqwest-resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ fn resume_partial_from_file_url() {
write_file(&target_path, "123");

let from_url = Url::from_file_path(&from_path).unwrap();
download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, true, None)
.expect("Test download failed");
download_to_path_with_backend(
Backend::Reqwest(TlsBackend::Default),
&from_url,
&target_path,
true,
None,
)
.expect("Test download failed");

assert_eq!(std::fs::read_to_string(&target_path).unwrap(), "12345");
}
Expand All @@ -41,7 +47,7 @@ fn callback_gets_all_data_as_if_the_download_happened_all_at_once() {
let received_in_callback = Mutex::new(Vec::new());

download_to_path_with_backend(
Backend::Reqwest,
Backend::Reqwest(TlsBackend::Default),
&from_url,
&target_path,
true,
Expand Down
19 changes: 16 additions & 3 deletions src/utils/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ fn download_file_(
notify_handler: &dyn Fn(Notification<'_>),
) -> Result<()> {
use download::download_to_path_with_backend;
use download::{Backend, Event};
use download::{Backend, Event, TlsBackend};
use sha2::Digest;
use std::cell::RefCell;

Expand Down Expand Up @@ -241,12 +241,25 @@ fn download_file_(

// Download the file

// Keep the hyper env var around for a bit
// Keep the curl env var around for a bit
let use_curl_backend = process().var_os("RUSTUP_USE_CURL").is_some();
let avoid_rustls = process().var_os("RUSTUP_AVOID_RUSTLS").is_some();
let (backend, notification) = if use_curl_backend {
(Backend::Curl, Notification::UsingCurl)
} else {
(Backend::Reqwest, Notification::UsingReqwest)
let tls_backend = if avoid_rustls {
TlsBackend::Default
} else {
#[cfg(feature = "reqwest-rustls-tls")]
{
TlsBackend::Rustls
}
#[cfg(not(feature = "reqwest-rustls-tls"))]
{
TlsBackend::Default
}
};
(Backend::Reqwest(tls_backend), Notification::UsingReqwest)
};
notify_handler(notification);
let res =
Expand Down

0 comments on commit a3b4b9e

Please sign in to comment.