Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable] warn about TLS for github specifically #5086

Merged
merged 1 commit into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ pub fn fetch(repo: &mut git2::Repository,
opts.remote_callbacks(cb)
.download_tags(git2::AutotagOption::All);

network::with_retry(config, || {
network::with_retry(config, url, || {
debug!("initiating fetch of {} from {}", refspec, url);
remote.fetch(&[refspec], Some(&mut opts), None)
.map_err(CargoError::from)
Expand Down
11 changes: 6 additions & 5 deletions src/cargo/sources/registry/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,13 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
// TODO: don't download into memory, but ensure that if we ctrl-c a
// download we should resume either from the start or the middle
// on the next time
let url = url.to_string();
let mut handle = self.config.http()?.borrow_mut();
handle.get(true)?;
handle.url(&url)?;
handle.url(&url.to_string())?;
handle.follow_location(true)?;
let mut state = Sha256::new();
let mut body = Vec::new();
network::with_retry(self.config, || {
network::with_retry(self.config, &url, || {
state = Sha256::new();
body = Vec::new();
let mut pb = Progress::new("Fetch", self.config);
Expand All @@ -242,8 +241,10 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
}
let code = handle.response_code()?;
if code != 200 && code != 0 {
let url = handle.effective_url()?.unwrap_or(&url);
Err(HttpNot200 { code, url: url.to_string() }.into())
let url = handle.effective_url()?
.map(|url| url.to_string())
.unwrap_or_else(|| url.to_string());
Err(HttpNot200 { code, url }.into())
} else {
Ok(())
}
Expand Down
51 changes: 44 additions & 7 deletions src/cargo/util/network.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use curl;
use git2;
use url::Url;

use failure::Error;

Expand Down Expand Up @@ -33,6 +34,35 @@ fn maybe_spurious(err: &Error) -> bool {
false
}


/// Suggest the user to update their windows 7 to support modern TLS versions.
/// See https://github.com/rust-lang/cargo/issues/5066 for details.
#[cfg(windows)]
fn should_warn_about_old_tls_for_win7(url: &Url, err: &Error) -> bool {
let is_github = url.host_str() == Some("github.com");
let is_cert_error = err.causes()
.filter_map(|e| e.downcast_ref::<git2::Error>())
.find(|e| e.class() == git2::ErrorClass::Net && e.code() == git2::ErrorCode::Certificate)
.is_some();
is_github && is_cert_error
}

#[cfg(not(windows))]
fn should_warn_about_old_tls_for_win7(_url: &Url, _err: &Error) -> bool {
false
}

const WIN7_TLS_WARNING: &str = "\
Certificate check failure might be caused by outdated TLS on older versions of Windows.
If you are using Windows 7, Windows Server 2008 R2 or Windows Server 2012,
please follow these instructions to enable more secure TLS:

https://support.microsoft.com/en-us/help/3140245/

See https://github.com/rust-lang/cargo/issues/5066 for details.
";


/// Wrapper method for network call retry logic.
///
/// Retry counts provided by Config object `net.retry`. Config shell outputs
Expand All @@ -44,19 +74,24 @@ fn maybe_spurious(err: &Error) -> bool {
///
/// ```ignore
/// use util::network;
/// cargo_result = network.with_retry(&config, || something.download());
/// cargo_result = network::with_retry(&config, || something.download());
/// ```
pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
pub fn with_retry<T, F>(config: &Config, url: &Url, mut callback: F) -> CargoResult<T>
where F: FnMut() -> CargoResult<T>
{
let mut remaining = config.net_retry()?;
loop {
match callback() {
Ok(ret) => return Ok(ret),
Err(ref e) if maybe_spurious(e) && remaining > 0 => {
let msg = format!("spurious network error ({} tries \
remaining): {}", remaining, e);
config.shell().warn(msg)?;
config.shell().warn(
format!("spurious network error ({} tries remaining): {}", remaining, e)
)?;

if should_warn_about_old_tls_for_win7(url, e) {
config.shell().warn(WIN7_TLS_WARNING)?;
}

remaining -= 1;
}
//todo impl from
Expand All @@ -71,7 +106,8 @@ fn with_retry_repeats_the_call_then_works() {
let error2 = HttpNot200 { code: 502, url: "Uri".to_string() }.into();
let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
let config = Config::default().unwrap();
let result = with_retry(&config, || results.pop().unwrap());
let url = "http://example.com".parse().unwrap();
let result = with_retry(&config, &url, || results.pop().unwrap());
assert_eq!(result.unwrap(), ())
}

Expand All @@ -87,6 +123,7 @@ fn with_retry_finds_nested_spurious_errors() {
let error2 = CargoError::from(error2.context("A second chained error"));
let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
let config = Config::default().unwrap();
let result = with_retry(&config, || results.pop().unwrap());
let url = "http://example.com".parse().unwrap();
let result = with_retry(&config, &url, || results.pop().unwrap());
assert_eq!(result.unwrap(), ())
}