diff --git a/Cargo.lock b/Cargo.lock index 7c46383d4a..1a96602229 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,41 @@ dependencies = [ "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cookie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crypt32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "curl" version = "0.3.0" @@ -171,6 +206,39 @@ dependencies = [ "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hpack" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.0" @@ -213,11 +281,21 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.11" @@ -241,6 +319,11 @@ dependencies = [ "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "markdown" version = "0.1.2" @@ -263,6 +346,14 @@ dependencies = [ "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz-sys" version = "0.1.7" @@ -272,6 +363,25 @@ dependencies = [ "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "native-tls" +version = "0.1.0" +source = "git+https://github.com/sfackler/rust-native-tls.git#fac4b0379153b782928df33aa4fe2f4173c2c125" +dependencies = [ + "openssl 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.0.2 (git+https://github.com/sfackler/schannel-rs?branch=rewrite)", + "security-framework 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ole32-sys" version = "0.2.0" @@ -281,6 +391,19 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "openssl" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys-extras 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "openssl-sys" version = "0.7.11" @@ -293,6 +416,24 @@ dependencies = [ "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "openssl-sys-extras" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-verify" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "openssl 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pipeline" version = "0.5.0" @@ -341,6 +482,14 @@ name = "rustc-serialize" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustup-dist" version = "0.1.12" @@ -392,9 +541,12 @@ dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.1.12", + "hyper 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.0 (git+https://github.com/sfackler/rust-native-tls.git)", "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -407,11 +559,57 @@ dependencies = [ "winreg 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schannel" +version = "0.0.2" +source = "git+https://github.com/sfackler/schannel-rs?branch=rewrite#fa053fe4deb459fed77ddaa1289927c4dc32ad88" +dependencies = [ + "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "secur32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "sha2" version = "0.1.2" @@ -429,6 +627,15 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "solicit" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.4.1" @@ -495,6 +702,24 @@ dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "traitobject" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-bidi" version = "0.2.3" @@ -559,10 +784,16 @@ dependencies = [ "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi" +version = "0.2.7" +source = "git+https://github.com/sfackler/winapi-rs#e8473a5ec1ae02302fa2a749eeda9c3d3aa066ed" + [[package]] name = "winapi" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +replace = "winapi 0.2.7 (git+https://github.com/sfackler/winapi-rs)" [[package]] name = "winapi-build" diff --git a/Cargo.toml b/Cargo.toml index 3fffd31b96..6a55664824 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,6 @@ test = false # no unit tests name = "rustup-init" path = "src/rustup-cli/main.rs" test = false # no unit tests + +[replace] +"winapi:0.2.7" = { git = "https://github.com/sfackler/winapi-rs" } diff --git a/src/rustup-dist/Cargo.toml b/src/rustup-dist/Cargo.toml index 34b6c889ab..bac309240f 100644 --- a/src/rustup-dist/Cargo.toml +++ b/src/rustup-dist/Cargo.toml @@ -39,3 +39,6 @@ libc = "0.2.0" [lib] name = "rustup_dist" + +[replace] +"winapi:0.2.7" = { git = "https://github.com/sfackler/winapi-rs" } diff --git a/src/rustup-mock/Cargo.toml b/src/rustup-mock/Cargo.toml index 128a54886a..42eccc5399 100644 --- a/src/rustup-mock/Cargo.toml +++ b/src/rustup-mock/Cargo.toml @@ -25,3 +25,6 @@ sha2 = "0.1.2" [target."cfg(windows)".dependencies] winapi = "0.2.4" winreg = "0.3.2" + +[replace] +"winapi:0.2.7" = { git = "https://github.com/sfackler/winapi-rs" } diff --git a/src/rustup-utils/Cargo.toml b/src/rustup-utils/Cargo.toml index 28a4574d35..50d2ce14e7 100644 --- a/src/rustup-utils/Cargo.toml +++ b/src/rustup-utils/Cargo.toml @@ -21,6 +21,14 @@ sha2 = "0.1.2" curl = "0.3" url = "1.1" toml = "0.1.27" +native-tls = { git = "https://github.com/sfackler/rust-native-tls.git" } + +[target.'cfg(not(any(target_os = "windows", target_os = "macos")))'.dependencies] +openssl-sys = "0.7.11" + +[dependencies.hyper] +version = "0.9.8" +default-features = false [target."cfg(windows)".dependencies] winapi = "0.2.4" @@ -30,3 +38,6 @@ ole32-sys = "0.2.0" kernel32-sys = "0.2.1" advapi32-sys = "0.2.0" userenv-sys = "0.2.0" + +[replace] +"winapi:0.2.7" = { git = "https://github.com/sfackler/winapi-rs" } diff --git a/src/rustup-utils/src/lib.rs b/src/rustup-utils/src/lib.rs index 07f74373c3..e8655ad7d7 100644 --- a/src/rustup-utils/src/lib.rs +++ b/src/rustup-utils/src/lib.rs @@ -9,6 +9,10 @@ extern crate rustc_serialize; extern crate sha2; extern crate url; extern crate toml; +extern crate hyper; +extern crate native_tls; +#[cfg(not(any(target_os = "windows", target_os = "macos")))] +extern crate openssl_sys; #[cfg(windows)] extern crate winapi; diff --git a/src/rustup-utils/src/raw.rs b/src/rustup-utils/src/raw.rs index 20cbe474ab..63446243e8 100644 --- a/src/rustup-utils/src/raw.rs +++ b/src/rustup-utils/src/raw.rs @@ -155,6 +155,265 @@ pub fn tee_file(path: &Path, mut w: &mut W) -> io::Result<()> { } } +mod hyper { + use hyper; + use notifications::Notification; + use sha2::{Digest, Sha256}; + use std::fs; + use std::io; + use std::path::Path; + use std::time::Duration; + use url::Url; + use errors::*; + + fn proxy_from_env(url: &Url) -> Option<(String, u16)> { + use std::env::var_os; + + let mut maybe_https_proxy = var_os("https_proxy").map(|ref v| v.to_str().unwrap_or("").to_string()); + if maybe_https_proxy.is_none() { + maybe_https_proxy = var_os("HTTPS_PROXY").map(|ref v| v.to_str().unwrap_or("").to_string()); + } + let maybe_http_proxy = var_os("http_proxy").map(|ref v| v.to_str().unwrap_or("").to_string()); + let mut maybe_all_proxy = var_os("all_proxy").map(|ref v| v.to_str().unwrap_or("").to_string()); + if maybe_all_proxy.is_none() { + maybe_all_proxy = var_os("ALL_PROXY").map(|ref v| v.to_str().unwrap_or("").to_string()); + } + if let Some(url_value) = match url.scheme() { + "https" => maybe_https_proxy.or(maybe_http_proxy.or(maybe_all_proxy)), + "http" => maybe_http_proxy.or(maybe_all_proxy), + _ => maybe_all_proxy, + } { + if let Ok(proxy_url) = Url::parse(&url_value) { + if let Some(host) = proxy_url.host_str() { + let port = proxy_url.port().unwrap_or(8080); + return Some((host.to_string(), port)); + } + } + } + None + } + + pub fn download_file(url: &Url, + path: &Path, + mut hasher: Option<&mut Sha256>, + notify_handler: &Fn(Notification)) + -> Result<()> { + + // Short-circuit hyper for the "file:" URL scheme + if try!(download_from_file_url(url, path, &mut hasher)) { + return Ok(()); + } + + use hyper::client::{Client, ProxyConfig}; + use hyper::error::Result as HyperResult; + use hyper::header::ContentLength; + use hyper::net::{SslClient, NetworkStream, HttpsConnector}; + use native_tls; + use std::io::Result as IoResult; + use std::io::{Read, Write}; + use std::net::{SocketAddr, Shutdown}; + use std::sync::{Arc, Mutex}; + + // The Hyper HTTP client + let client; + + let maybe_proxy = proxy_from_env(url); + if url.scheme() == "https" { + + // All the following is adapter code to use native_tls with hyper. + + struct NativeSslClient; + + impl SslClient for NativeSslClient { + type Stream = NativeSslStream; + + fn wrap_client(&self, stream: T, host: &str) -> HyperResult { + use native_tls::ClientBuilder as TlsClientBuilder; + use hyper::error::Error as HyperError; + + let mut ssl_builder = try!(TlsClientBuilder::new() + .map_err(|e| HyperError::Ssl(Box::new(e)))); + let ssl_stream = try!(ssl_builder.handshake(host, stream) + .map_err(|e| HyperError::Ssl(Box::new(e)))); + + Ok(NativeSslStream(Arc::new(Mutex::new(ssl_stream)))) + } + } + + #[derive(Clone)] + struct NativeSslStream(Arc>>); + + #[derive(Debug)] + struct NativeSslPoisonError; + + impl ::std::error::Error for NativeSslPoisonError { + fn description(&self) -> &str { "mutex poisoned during TLS operation" } + } + + impl ::std::fmt::Display for NativeSslPoisonError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { + f.write_str(::std::error::Error::description(self)) + } + } + + impl NetworkStream for NativeSslStream + where T: NetworkStream + { + fn peer_addr(&mut self) -> IoResult { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|mut t| t.get_mut().peer_addr()) + } + fn set_read_timeout(&self, dur: Option) -> IoResult<()> { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|t| t.get_ref().set_read_timeout(dur)) + } + fn set_write_timeout(&self, dur: Option) -> IoResult<()> { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|t| t.get_ref().set_write_timeout(dur)) + } + fn close(&mut self, how: Shutdown) -> IoResult<()> { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|mut t| t.get_mut().close(how)) + } + } + + impl Read for NativeSslStream + where T: Read + Write + { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|mut t| t.read(buf)) + } + } + + impl Write for NativeSslStream + where T: Read + Write + { + fn write(&mut self, buf: &[u8]) -> IoResult { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|mut t| t.write(buf)) + } + fn flush(&mut self) -> IoResult<()> { + self.0.lock() + .map_err(|_| io::Error::new(io::ErrorKind::Other, NativeSslPoisonError)) + .and_then(|mut t| t.flush()) + } + } + + maybe_init_certs(); + + if maybe_proxy.is_none() { + // Connect with hyper + native_tls + client = Client::with_connector(HttpsConnector::new(NativeSslClient)); + } else { + let proxy_host_port = maybe_proxy.unwrap(); + client = Client::with_proxy_config(ProxyConfig(proxy_host_port.0, proxy_host_port.1, NativeSslClient)); + } + } else if url.scheme() == "http" { + if maybe_proxy.is_none() { + client = Client::new(); + } else { + let proxy_host_port = maybe_proxy.unwrap(); + client = Client::with_http_proxy(proxy_host_port.0, proxy_host_port.1); + } + } else { + return Err(format!("unsupported URL scheme: '{}'", url.scheme()).into()); + } + + let mut res = try!(client.get(url.clone()).send() + .chain_err(|| "failed to make network request")); + if res.status != hyper::Ok { + return Err(ErrorKind::HttpStatus(res.status.to_u16() as u32).into()); + } + + let buffer_size = 0x10000; + let mut buffer = vec![0u8; buffer_size]; + + let mut file = try!(fs::File::create(path).chain_err( + || "error creating file for download")); + + if let Some(len) = res.headers.get::().cloned() { + notify_handler(Notification::DownloadContentLengthReceived(len.0)); + } + + loop { + let bytes_read = try!(io::Read::read(&mut res, &mut buffer) + .chain_err(|| "error reading from socket")); + + if bytes_read != 0 { + if let Some(ref mut h) = hasher { + h.input(&buffer[0..bytes_read]); + } + try!(io::Write::write_all(&mut file, &mut buffer[0..bytes_read]) + .chain_err(|| "unable to write download to disk")); + notify_handler(Notification::DownloadDataReceived(bytes_read)); + } else { + try!(file.sync_data().chain_err(|| "unable to sync download to disk")); + notify_handler(Notification::DownloadFinished); + return Ok(()); + } + } + } + + // Tell our statically-linked OpenSSL where to find root certs + // cc https://github.com/alexcrichton/git2-rs/blob/master/libgit2-sys/lib.rs#L1267 + #[cfg(not(any(target_os = "windows", target_os = "macos")))] + fn maybe_init_certs() { + use std::sync::{Once, ONCE_INIT}; + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + ::openssl_sys::probe::init_ssl_cert_env_vars(); + }); + } + + #[cfg(any(target_os = "windows", target_os = "macos"))] + fn maybe_init_certs() { } + + fn download_from_file_url(url: &Url, + path: &Path, + hasher: &mut Option<&mut Sha256>) + -> Result { + use super::is_file; + + // The file scheme is mostly for use by tests to mock the dist server + if url.scheme() == "file" { + let src = try!(url.to_file_path() + .map_err(|_| Error::from(format!("bogus file url: '{}'", url)))); + if !is_file(&src) { + // Because some of multirust's logic depends on checking + // the error when a downloaded file doesn't exist, make + // the file case return the same error value as the + // network case. + return Err(ErrorKind::HttpStatus(hyper::status::StatusCode::NotFound.to_u16() as u32).into()); + } + try!(fs::copy(&src, path).chain_err(|| "failure copying file")); + + if let Some(ref mut h) = *hasher { + let ref mut f = try!(fs::File::open(path) + .chain_err(|| "unable to open downloaded file")); + + let ref mut buffer = vec![0u8; 0x10000]; + loop { + let bytes_read = try!(io::Read::read(f, buffer) + .chain_err(|| "unable to read downloaded file")); + if bytes_read == 0 { break } + h.input(&buffer[0..bytes_read]); + } + } + + Ok(true) + } else { + Ok(false) + } + } +} + pub fn download_file(url: &Url, path: &Path, mut hasher: Option<&mut Sha256>, @@ -163,6 +422,10 @@ pub fn download_file(url: &Url, use notifications::Notification; use std::io::Write; + if ::std::env::var_os("RUSTUP_USE_HYPER").is_some() { + return self::hyper::download_file(url, path, hasher, notify_handler); + } + let mut file = try!(fs::File::create(&path).chain_err( || "error creating file for download"));