diff --git a/Cargo.lock b/Cargo.lock index 24f2dd548b6..e54186ca897 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,11 +84,6 @@ name = "bitflags" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.0" @@ -108,38 +103,24 @@ dependencies = [ ] [[package]] -name = "cookie" -version = "0.2.4" -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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "curl" +version = "0.2.18" +source = "git+https://github.com/alexcrichton/curl-rust?branch=rewrite#241b0a408686b48850a9d91dab9c8f924db8877a" dependencies = [ - "core-foundation-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.1.34 (git+https://github.com/alexcrichton/curl-rust?branch=rewrite)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "core-foundation-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "curl-sys" +version = "0.1.34" +source = "git+https://github.com/alexcrichton/curl-rust?branch=rewrite#241b0a408686b48850a9d91dab9c8f924db8877a" 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)", -] - -[[package]] -name = "crypt32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -188,39 +169,6 @@ dependencies = [ "winapi 0.2.6 (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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cookie 0.2.4 (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.11 (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" @@ -263,21 +211,11 @@ 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" @@ -292,9 +230,14 @@ dependencies = [ ] [[package]] -name = "log" -version = "0.3.6" +name = "libz-sys" +version = "1.0.3" 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)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "markdown" @@ -318,14 +261,6 @@ 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" @@ -335,25 +270,6 @@ 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#a3d03b6ab5cee02313ff79a9e96a10b0c9b9e28a" -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)", - "security-framework 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "0.2.11" -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" @@ -363,19 +279,6 @@ 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.6.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" @@ -388,24 +291,6 @@ 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" @@ -454,14 +339,6 @@ 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.10" @@ -505,11 +382,10 @@ name = "rustup-utils" version = "0.1.10" dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.2.18 (git+https://github.com/alexcrichton/curl-rust?branch=rewrite)", "error-chain 0.1.10", - "hyper 0.9.4 (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)", @@ -517,62 +393,17 @@ dependencies = [ "scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "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#d16f7949939777375bae9716f098145b151c28e5" -dependencies = [ - "crypt32-sys 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)", - "rustc-serialize 0.3.19 (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.6 (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.6 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 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)", - "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.1 (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" @@ -590,15 +421,6 @@ 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" @@ -665,24 +487,6 @@ 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" diff --git a/src/rustup-cli/common.rs b/src/rustup-cli/common.rs index 9bd92fbc1e3..8c0428b8bca 100644 --- a/src/rustup-cli/common.rs +++ b/src/rustup-cli/common.rs @@ -6,7 +6,7 @@ use errors::*; use rustup_utils::utils; use rustup_utils::notify::NotificationLevel; use self_update; -use std::io::{Write, Read, BufRead}; +use std::io::{Write, BufRead}; use std::process::Command; use std::{cmp, iter}; use std::str::FromStr; diff --git a/src/rustup-cli/self_update.rs b/src/rustup-cli/self_update.rs index f071bc295ae..fd40cc649ec 100644 --- a/src/rustup-cli/self_update.rs +++ b/src/rustup-cli/self_update.rs @@ -31,7 +31,6 @@ //! and racy on Windows. use common::{self, Confirm}; -use itertools::Itertools; use rustup::{NotifyHandler}; use errors::*; use rustup_dist::dist; @@ -1069,7 +1068,7 @@ pub fn prepare_update() -> Result> { info!("checking for self-updates"); let hash_url = try!(utils::parse_url(&(url.clone() + ".sha256"))); let hash_file = tempdir.path().join("hash"); - try!(utils::download_file(hash_url, &hash_file, None, ntfy!(&NotifyHandler::none()))); + try!(utils::download_file(&hash_url, &hash_file, None, ntfy!(&NotifyHandler::none()))); let mut latest_hash = try!(utils::read_file("hash", &hash_file)); latest_hash.truncate(64); @@ -1085,7 +1084,7 @@ pub fn prepare_update() -> Result> { // Download new version info!("downloading self-update"); let mut hasher = Sha256::new(); - try!(utils::download_file(download_url, + try!(utils::download_file(&download_url, &setup_path, Some(&mut hasher), ntfy!(&NotifyHandler::none()))); diff --git a/src/rustup-dist/src/dist.rs b/src/rustup-dist/src/dist.rs index a1d3ca351b5..f5279bd1513 100644 --- a/src/rustup-dist/src/dist.rs +++ b/src/rustup-dist/src/dist.rs @@ -13,7 +13,6 @@ use std::fmt; use regex::Regex; use sha2::{Sha256, Digest}; -use itertools::Itertools; pub const DEFAULT_DIST_ROOT: &'static str = "https://static.rust-lang.org/dist"; pub const UPDATE_HASH_LEN: usize = 20; @@ -76,7 +75,7 @@ impl TargetTriple { if let Some(triple) = option_env!("RUSTUP_OVERRIDE_HOST_TRIPLE") { TargetTriple::from_str(triple) } else { - TargetTriple::from_str(include_str!(concat!(env!("OUT_DIR"), "/target.txt"))) + TargetTriple::from_str(include_str!(concat!(env!("OUT_DIR"), "/target.txt"))) } } } @@ -342,7 +341,7 @@ pub fn download_and_check<'a>(url_str: &str, let file = try!(cfg.temp_cfg.new_file_with_ext("", ext)); let mut hasher = Sha256::new(); - try!(utils::download_file(url, &file, Some(&mut hasher), ntfy!(&cfg.notify_handler))); + try!(utils::download_file(&url, &file, Some(&mut hasher), ntfy!(&cfg.notify_handler))); let actual_hash = hasher.result_str(); if hash != actual_hash { @@ -372,7 +371,7 @@ pub fn download_hash(url: &str, cfg: DownloadCfg) -> Result { let hash_url = try!(utils::parse_url(&(url.to_owned() + ".sha256"))); let hash_file = try!(cfg.temp_cfg.new_file()); - try!(utils::download_file(hash_url, &hash_file, None, ntfy!(&cfg.notify_handler))); + try!(utils::download_file(&hash_url, &hash_file, None, ntfy!(&cfg.notify_handler))); Ok(try!(utils::read_file("hash", &hash_file).map(|s| s[0..64].to_owned()))) } diff --git a/src/rustup-dist/src/download.rs b/src/rustup-dist/src/download.rs index eadeceb2fd2..09b9ea907e6 100644 --- a/src/rustup-dist/src/download.rs +++ b/src/rustup-dist/src/download.rs @@ -22,14 +22,14 @@ impl<'a> DownloadCfg<'a> { let sig_url = try!(utils::parse_url(&format!("{}.asc", url))); let sig_file = try!(self.temp_cfg.new_file()); - try!(utils::download_file(sig_url, &sig_file, None, ntfy!(&self.notify_handler))); + try!(utils::download_file(&sig_url, &sig_file, None, ntfy!(&self.notify_handler))); let target_url = try!(utils::parse_url(url)); let target_file = try!(self.temp_cfg.new_file()); { let target_filename: &Path = &target_file; - try!(utils::download_file(target_url, + try!(utils::download_file(&target_url, &target_file, None, ntfy!(&self.notify_handler))); @@ -62,14 +62,14 @@ impl<'a> DownloadCfg<'a> { let hash_url = try!(utils::parse_url(&format!("{}.sha256", url))); let hash_file = try!(self.temp_cfg.new_file()); - try!(utils::download_file(hash_url, &hash_file, None, ntfy!(&self.notify_handler))); + try!(utils::download_file(&hash_url, &hash_file, None, ntfy!(&self.notify_handler))); let hash = try!(utils::read_file("hash", &hash_file).map(|s| s[0..64].to_owned())); let mut hasher = Sha256::new(); let target_url = try!(utils::parse_url(url)); let target_file = try!(self.temp_cfg.new_file()); - try!(utils::download_file(target_url, + try!(utils::download_file(&target_url, &target_file, Some(&mut hasher), ntfy!(&self.notify_handler))); diff --git a/src/rustup-dist/src/manifestation.rs b/src/rustup-dist/src/manifestation.rs index 976c5ebfaf3..ee82fcfdab8 100644 --- a/src/rustup-dist/src/manifestation.rs +++ b/src/rustup-dist/src/manifestation.rs @@ -11,7 +11,6 @@ use notifications::*; use rustup_utils::utils; use prefix::InstallPrefix; use sha2::{Sha256, Digest}; -use itertools::Itertools; use std::path::Path; pub const DIST_MANIFEST: &'static str = "multirust-channel-manifest.toml"; @@ -136,7 +135,7 @@ impl Manifestation { let url_url = try!(utils::parse_url(&url)); let mut hasher = Sha256::new(); - try!(utils::download_file(url_url, &temp_file, Some(&mut hasher), ntfy!(¬ify_handler)) + try!(utils::download_file(&url_url, &temp_file, Some(&mut hasher), ntfy!(¬ify_handler)) .chain_err(|| ErrorKind::ComponentDownloadFailed(component.clone()))); let actual_hash = hasher.result_str(); diff --git a/src/rustup-mock/src/dist.rs b/src/rustup-mock/src/dist.rs index acd56041978..a8d142b0a0d 100644 --- a/src/rustup-mock/src/dist.rs +++ b/src/rustup-mock/src/dist.rs @@ -9,7 +9,6 @@ use std::collections::HashMap; use std::io::{Read, Write}; use tempdir::TempDir; use sha2::{Sha256, Digest}; -use itertools::Itertools; use toml; use flate2; use tar; diff --git a/src/rustup-utils/Cargo.toml b/src/rustup-utils/Cargo.toml index 13d672c54a9..215eb46da34 100644 --- a/src/rustup-utils/Cargo.toml +++ b/src/rustup-utils/Cargo.toml @@ -16,9 +16,10 @@ rand = "0.3.11" scopeguard = "0.1.2" error-chain = { path = "../error-chain", version = "0.1.10" } libc = "0.2.0" -native-tls = { git = "https://github.com/sfackler/rust-native-tls.git" } rustc-serialize = "0.3.19" sha2 = "0.1.2" +curl = { git = "https://github.com/alexcrichton/curl-rust", branch = "rewrite" } +url = "1.1" [target.'cfg(not(any(target_os = "windows", target_os = "macos")))'.dependencies] openssl-sys = "0.7.11" @@ -31,7 +32,3 @@ ole32-sys = "0.2.0" kernel32-sys = "0.2.1" advapi32-sys = "0.2.0" userenv-sys = "0.2.0" - -[dependencies.hyper] -version = "0.9.2" -default-features = false diff --git a/src/rustup-utils/src/errors.rs b/src/rustup-utils/src/errors.rs index 1c54032e638..4088c3bd4cd 100644 --- a/src/rustup-utils/src/errors.rs +++ b/src/rustup-utils/src/errors.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use std::ffi::OsString; -use hyper; +use curl; +use url::Url; error_chain! { types { @@ -67,19 +68,23 @@ error_chain! { description("could not rename directory") display("could not rename {} directory from '{}' to '{}'", name, src.display(), dest.display()) } - HttpStatus(e: hyper::status::StatusCode) { + HttpError(e: curl::Error) { + description("http request did not succeed") + display("http request returned failure: {}", e) + } + HttpStatus(e: u32) { description("http request returned an unsuccessful status code") display("http request returned an unsuccessful status code: {}", e) } DownloadingFile { - url: hyper::Url, + url: Url, path: PathBuf, } { description("could not download file") display("could not download file from '{}' to '{}", url, path.display()) } Download404 { - url: hyper::Url, + url: Url, path: PathBuf, } { description("could not download file") diff --git a/src/rustup-utils/src/lib.rs b/src/rustup-utils/src/lib.rs index b1e3a2b8076..3e9f0886442 100644 --- a/src/rustup-utils/src/lib.rs +++ b/src/rustup-utils/src/lib.rs @@ -2,16 +2,16 @@ #![feature(fundamental)] #![recursion_limit = "1024"] // for error_chain! -extern crate hyper; +extern crate curl; extern crate rand; extern crate scopeguard; #[macro_use] extern crate error_chain; -extern crate native_tls; extern crate rustc_serialize; extern crate sha2; #[cfg(not(any(target_os = "windows", target_os = "macos")))] extern crate openssl_sys; +extern crate url; #[cfg(windows)] extern crate winapi; diff --git a/src/rustup-utils/src/notifications.rs b/src/rustup-utils/src/notifications.rs index 47671b9cb63..8dcc880e925 100644 --- a/src/rustup-utils/src/notifications.rs +++ b/src/rustup-utils/src/notifications.rs @@ -1,6 +1,7 @@ use std::path::Path; use std::fmt::{self, Display}; -use hyper; + +use url::Url; use notify::{self, NotificationLevel, Notifyable}; @@ -10,7 +11,7 @@ pub enum Notification<'a> { LinkingDirectory(&'a Path, &'a Path), CopyingDirectory(&'a Path, &'a Path), RemovingDirectory(&'a str, &'a Path), - DownloadingFile(&'a hyper::Url, &'a Path), + DownloadingFile(&'a Url, &'a Path), /// Received the Content-Length of the to-be downloaded data. DownloadContentLengthReceived(u64), /// Received some data. diff --git a/src/rustup-utils/src/raw.rs b/src/rustup-utils/src/raw.rs index 5ce2e1f4c59..943eedcfba2 100644 --- a/src/rustup-utils/src/raw.rs +++ b/src/rustup-utils/src/raw.rs @@ -1,19 +1,22 @@ use notifications::NotifyHandler; +use std::cell::RefCell; +use std::char::from_u32; use std::error; +use std::ffi::{OsStr, OsString}; +use std::fmt; use std::fs; -use std::path::Path; -use std::io; -use std::char::from_u32; use std::io::Write; +use std::io; +use std::path::Path; use std::process::{Command, Stdio, ExitStatus}; -use std::ffi::{OsStr, OsString}; -use std::fmt; +use std::str; use std::thread; use std::time::Duration; -use hyper::{self, Client}; +use curl::easy::Easy; use sha2::{Sha256, Digest}; use errors::*; +use url::Url; use rand::random; @@ -152,161 +155,93 @@ pub fn tee_file(path: &Path, mut w: &mut W) -> io::Result<()> { } } -pub fn download_file>(url: hyper::Url, - path: P, - mut hasher: Option<&mut Sha256>, - notify_handler: NotifyHandler) - -> Result<()> { - - // Short-circuit hyper for the "file:" URL scheme - if try!(download_from_file_url(&url, &path, &mut hasher)) { - return Ok(()); - } - - use hyper::error::Result as HyperResult; - use hyper::header::ContentLength; - use hyper::net::{SslClient, NetworkStream, HttpsConnector}; - use native_tls; +pub fn download_file(url: &Url, + path: &Path, + mut hasher: Option<&mut Sha256>, + notify_handler: NotifyHandler) + -> Result<()> { use notifications::Notification; - 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; - - 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; + use std::io::Write; - fn wrap_client(&self, stream: T, host: &str) -> HyperResult { - use native_tls::ClientBuilder as TlsClientBuilder; - use hyper::error::Error as HyperError; + maybe_init_certs(); - 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; + let mut file = try!(fs::File::create(&path).chain_err( + || "error creating file for download")); + let fserr = RefCell::new(None); - impl ::std::error::Error for NativeSslPoisonError { - fn description(&self) -> &str { "mutex poisoned during TLS operation" } + // 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. + let mut ondata = |data: &[u8]| { + if let Some(ref mut h) = hasher { + h.input(data); } - - 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)) + notify_handler.call(Notification::DownloadDataReceived(data.len())); + match file.write_all(data) { + Ok(()) => data.len(), + Err(e) => { + *fserr.borrow_mut() = Some(e); + 0 } } + }; - 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)) + // Listen for headers and parse out a `Content-Length` if it comes so we + // know how much we're downloading. + let mut onheader = |data: &[u8]| { + if let Ok(data) = str::from_utf8(data) { + let prefix = "Content-Length: "; + if data.starts_with(prefix) { + if let Ok(s) = data[prefix.len()..].trim().parse() { + notify_handler.call(Notification::DownloadContentLengthReceived(s)); + } } } + true + }; - 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()) - } + // 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(None)); + let handle = EASY.with(|e| e.borrow_mut().take()).unwrap_or(Easy::new()); + let mut handle = handle.reset_lifetime(); + + try!(handle.url(&url.to_string()).chain_err(|| "failed to set url")); + try!(handle.follow_location(true).chain_err(|| "failed to set follow redirects")); + try!(handle.write_function(&mut ondata).chain_err(|| "failed to set write")); + try!(handle.header_function(&mut onheader).chain_err(|| "failed to set header")); + + // Take at most 30s to connect + try!(handle.connect_timeout(Duration::new(30, 0)).chain_err(|| "failed to set connect timeout")); + + // Fail if less than 10 bytes are transferred every 30 seconds + try!(handle.low_speed_limit(10).chain_err(|| "failed to set low speed limit")); + try!(handle.low_speed_time(Duration::new(30, 0)).chain_err(|| "failed to set low speed time")); + + // If an error happens check to see if we had a filesystem error up in + // `fserr`, but we always want to punt it up. + try!(handle.perform().or_else(|e| { + match fserr.borrow_mut().take() { + Some(fs) => Err(fs).chain_err(|| ErrorKind::HttpError(e)), + None => Err(ErrorKind::HttpError(e).into()) } + })); - maybe_init_certs(); - - // Connect with hyper + native_tls - client = Client::with_connector(HttpsConnector::new(NativeSslClient)); - } else if url.scheme() == "http" { - client = Client::new(); - } else { - return Err(format!("unsupported URL scheme: '{}'", url.scheme()).into()); - } - - let mut res = try!(client.get(url).send() - .chain_err(|| "failed to make network request")); - if res.status != hyper::Ok { - return Err(ErrorKind::HttpStatus(res.status).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.call(Notification::DownloadContentLengthReceived(len.0)); + // If we didn't get a 200 then return an error + let code = try!(handle.response_code().chain_err(|| "failed to get response code")); + if code != 200 { + return Err(ErrorKind::HttpStatus(code).into()); } - 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.call(Notification::DownloadDataReceived(bytes_read)); - } else { - try!(file.sync_data().chain_err(|| "unable to sync download to disk")); - notify_handler.call(Notification::DownloadFinished); - return Ok(()); - } - } + // If everything worked out, put our handle back (with a reset to 'static) + // and then send off a notification for the completed download. + EASY.with(|e| { + *e.borrow_mut() = Some(handle.reset_lifetime()); + }); + notify_handler.call(Notification::DownloadFinished); + Ok(()) } // Tell our statically-linked OpenSSL where to find root certs @@ -323,42 +258,6 @@ fn maybe_init_certs() { #[cfg(any(target_os = "windows", target_os = "macos"))] fn maybe_init_certs() { } -fn download_from_file_url>(url: &hyper::Url, - path: P, - hasher: &mut Option<&mut Sha256>) - -> Result { - // 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).into()); - } - try!(fs::copy(&src, path.as_ref()).chain_err(|| "failure copying file")); - - if let Some(ref mut h) = *hasher { - let ref mut f = try!(fs::File::open(path.as_ref()) - .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 symlink_dir(src: &Path, dest: &Path) -> io::Result<()> { #[cfg(windows)] fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> { @@ -429,7 +328,7 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, ptr::null_mut()); - + let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; let mut db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; @@ -458,7 +357,7 @@ fn symlink_junction_inner(target: &Path, junction: &Path) -> io::Result<()> { ptr::null_mut(), 0, &mut ret, ptr::null_mut()); - + if res == 0 { Err(io::Error::last_os_error()) } else { diff --git a/src/rustup-utils/src/utils.rs b/src/rustup-utils/src/utils.rs index bb32a4a23f1..5ca392211b2 100644 --- a/src/rustup-utils/src/utils.rs +++ b/src/rustup-utils/src/utils.rs @@ -5,9 +5,7 @@ use std::io::{self, Write}; use std::process::Command; use std::ffi::OsString; use std::env; -use hyper; use sha2::Sha256; -use notify::Notifyable; use notifications::{Notification, NotifyHandler}; use raw; #[cfg(windows)] @@ -15,6 +13,7 @@ use winapi::DWORD; #[cfg(windows)] use winreg; use std::cmp::Ord; +use url::Url; pub use raw::{is_directory, is_file, path_exists, if_not_empty, random_string, prefix_arg, has_cmd, find_cmd}; @@ -140,34 +139,41 @@ pub fn tee_file(name: &'static str, path: &Path, w: &mut W) -> Res }) } -pub fn download_file(url: hyper::Url, +pub fn download_file(url: &Url, path: &Path, hasher: Option<&mut Sha256>, notify_handler: NotifyHandler) -> Result<()> { - use hyper::status::StatusCode::NotFound; - - notify_handler.call(Notification::DownloadingFile(&url, path)); - match raw::download_file(url.clone(), path, hasher, notify_handler) { + notify_handler.call(Notification::DownloadingFile(url, path)); + match raw::download_file(url, path, hasher, notify_handler) { Ok(_) => Ok(()), - Err(e @ Error(ErrorKind::HttpStatus(NotFound), _)) => { - Err(e).chain_err(|| ErrorKind::Download404 { - url: url, - path: path.to_path_buf(), + Err(Error(ErrorKind::HttpError(e), d)) => { + if e.is_file_couldnt_read_file() { + return Err(Error(ErrorKind::HttpError(e), d)).chain_err(|| { + ErrorKind::Download404 { + url: url.clone(), + path: path.to_path_buf(), + } + }) + } + Err(Error(ErrorKind::HttpError(e), d)).chain_err(|| { + ErrorKind::DownloadingFile { + url: url.clone(), + path: path.to_path_buf(), + } }) } Err(e) => { Err(e).chain_err(|| ErrorKind::DownloadingFile { - url: url, + url: url.clone(), path: path.to_path_buf(), }) } } } -pub fn parse_url(url: &str) -> Result { - hyper::Url::parse(url) - .chain_err(|| ErrorKind::InvalidUrl { url: url.to_owned() }) +pub fn parse_url(url: &str) -> Result { + Url::parse(url).chain_err(|| format!("failed to parse url: {}", url)) } pub fn cmd_status(name: &'static str, cmd: &mut Command) -> Result<()> { @@ -448,7 +454,7 @@ pub fn multirust_home() -> Result { pub fn format_path_for_display(path: &str) -> String { let unc_present = path.find(r"\\?\"); - + match unc_present { None => path.to_owned(), Some(_) => path[4..].to_owned(), diff --git a/src/rustup/config.rs b/src/rustup/config.rs index 916eb19b3e5..bd8e062b673 100644 --- a/src/rustup/config.rs +++ b/src/rustup/config.rs @@ -4,9 +4,6 @@ use std::env; use std::io; use std::process::Command; use std::fmt::{self, Display}; -use std::str::FromStr; - -use itertools::Itertools; use errors::*; use notifications::*; @@ -406,7 +403,7 @@ impl Cfg { fn enable_telemetry(&self) -> Result<()> { let work_file = try!(self.temp_cfg.new_file()); - + let _ = utils::ensure_dir_exists("telemetry", &self.multirust_dir.join("telemetry"), ntfy!(&NotifyHandler::none())); try!(utils::write_file("temp", &work_file, "")); diff --git a/src/rustup/toolchain.rs b/src/rustup/toolchain.rs index 113f33cc78d..fe83df6db6f 100644 --- a/src/rustup/toolchain.rs +++ b/src/rustup/toolchain.rs @@ -158,7 +158,7 @@ impl<'a> Toolchain<'a> { self.install(InstallMethod::Dist(&try!(self.desc()), update_hash.as_ref().map(|p| &**p), self.download_cfg())) - } + } pub fn install_from_dist_with_telemetry(&self) -> Result { let result = self.install_from_dist_inner(); @@ -169,12 +169,12 @@ impl<'a> Toolchain<'a> { success: true }; match self.telemetry.log_telemetry(te) { Ok(_) => Ok(us), - Err(e) => { + Err(e) => { self.cfg.notify_handler.call(Notification::TelemetryCleanupError(&e)); Ok(us) } } - } + } Err(e) => { let te = TelemetryEvent::ToolchainUpdate { toolchain: self.name().to_string() , success: true }; @@ -236,7 +236,7 @@ impl<'a> Toolchain<'a> { // Download to a local file let local_installer = try!(self.cfg.temp_cfg.new_file_with_ext("", ".tar.gz")); - try!(utils::download_file(url, + try!(utils::download_file(&url, &local_installer, None, ntfy!(&self.cfg.notify_handler))); @@ -404,19 +404,19 @@ impl<'a> Toolchain<'a> { match output { Ok(_) => { - let te = TelemetryEvent::ToolchainUpdate { toolchain: self.name.to_owned(), + let te = TelemetryEvent::ToolchainUpdate { toolchain: self.name.to_owned(), success: true }; match self.telemetry.log_telemetry(te) { Ok(_) => Ok(()), - Err(e) => { + Err(e) => { self.cfg.notify_handler.call(Notification::TelemetryCleanupError(&e)); Ok(()) } } }, Err(e) => { - let te = TelemetryEvent::ToolchainUpdate { toolchain: self.name.to_owned(), + let te = TelemetryEvent::ToolchainUpdate { toolchain: self.name.to_owned(), success: false }; let _ = self.telemetry.log_telemetry(te).map_err(|xe| {