diff --git a/.travis.yml b/.travis.yml index c2a80c8e1..eac9a5982 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ matrix: script: cargo build --target "$TARGET" --no-default-features # minimum version - - rust: 1.34.0 + - rust: 1.36.0 script: cargo build sudo: false diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs index d88becda4..4355ff31c 100644 --- a/src/async_impl/request.rs +++ b/src/async_impl/request.rs @@ -95,9 +95,18 @@ impl Request { impl RequestBuilder { pub(super) fn new(client: Client, request: ::Result) -> RequestBuilder { - RequestBuilder { - client, - request, + let mut builder = RequestBuilder { client, request }; + + let auth = builder + .request + .as_mut() + .ok() + .and_then(|req| extract_authority(&mut req.url)); + + if let Some((username, password)) = auth { + builder.basic_auth(username, password) + } else { + builder } } @@ -170,7 +179,7 @@ impl RequestBuilder { Some(password) => format!("{}:{}", username, password), None => format!("{}:", username) }; - let header_value = format!("Basic {}", encode(&auth)); + let header_value = format!("Basic {}", encode(&dbg!(auth))); self.header(::header::AUTHORIZATION, &*header_value) } @@ -424,6 +433,37 @@ pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) { } } + +/// Check the request URL for a "username:password" type authority, and if +/// found, remove it from the URL and return it. +pub(crate) fn extract_authority(url: &mut Url) -> Option<(String, Option)> { + use url::percent_encoding::percent_decode; + + if url.has_authority() { + let username: String = percent_decode(url.username().as_bytes()) + .decode_utf8() + .ok()? + .into(); + let password = url.password().and_then(|pass| { + percent_decode(pass.as_bytes()) + .decode_utf8() + .ok() + .map(String::from) + }); + if !username.is_empty() || password.is_some() { + url + .set_username("") + .expect("has_authority means set_username shouldn't fail"); + url + .set_password(None) + .expect("has_authority means set_password shouldn't fail"); + return Some((username, password)) + } + } + + None +} + #[cfg(test)] mod tests { use super::Client; @@ -536,6 +576,20 @@ mod tests { assert_eq!(req.url().as_str(), "https://google.com/"); } + #[test] + fn convert_url_authority_into_basic_auth() { + let client = Client::new(); + let some_url = "https://Aladdin:open sesame@localhost/"; + + let req = client + .get(some_url) + .build() + .expect("request build"); + + assert_eq!(req.url().as_str(), "https://localhost/"); + assert_eq!(req.headers()["authorization"], "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="); + } + /* use {body, Method}; use super::Client; diff --git a/src/request.rs b/src/request.rs index 9bc5f1c1a..ee1eb6ef6 100644 --- a/src/request.rs +++ b/src/request.rs @@ -119,9 +119,18 @@ impl Request { impl RequestBuilder { pub(crate) fn new(client: Client, request: ::Result) -> RequestBuilder { - RequestBuilder { - client, - request, + let mut builder = RequestBuilder { client, request }; + + let auth = builder + .request + .as_mut() + .ok() + .and_then(|req| async_impl::request::extract_authority(req.url_mut())); + + if let Some((username, password)) = auth { + builder.basic_auth(username, password) + } else { + builder } } @@ -883,4 +892,18 @@ mod tests { assert_eq!(req.url().query(), None); assert_eq!(req.url().as_str(), "https://google.com/"); } + + #[test] + fn convert_url_authority_into_basic_auth() { + let client = Client::new(); + let some_url = "https://Aladdin:open sesame@localhost/"; + + let req = client + .get(some_url) + .build() + .expect("request build"); + + assert_eq!(req.url().as_str(), "https://localhost/"); + assert_eq!(req.headers()["authorization"], "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="); + } }