diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs index b9ddbae63..aa6fe7ef9 100644 --- a/src/async_impl/request.rs +++ b/src/async_impl/request.rs @@ -112,7 +112,19 @@ impl Request { impl RequestBuilder { pub(super) fn new(client: Client, request: crate::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 + } } /// Add a `Header` to this Request. @@ -430,6 +442,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; @@ -588,6 +631,21 @@ mod tests { assert!(clone.is_none()); } + #[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=="); +>>>>>>> 6334345... support url with authority (#735) + } + /* use {body, Method}; use super::Client; diff --git a/src/blocking/request.rs b/src/blocking/request.rs index d7442a46a..76e08dab8 100644 --- a/src/blocking/request.rs +++ b/src/blocking/request.rs @@ -122,7 +122,19 @@ impl Request { impl RequestBuilder { pub(crate) fn new(client: Client, request: crate::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 + } } /// Add a `Header` to this Request. @@ -872,4 +884,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=="); + } }