Repository: seanmonstar/reqwest (language: rust)

Issue:
support url with authority
For #715.

With this PR, the output of the example in #715 will be:
```
RequestBuilder {
    client: Client,
    request: Ok(
        Request {
            method: POST,
            url: "http://localhost:12345/",
            headers: {
                "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
                "content-type": "application/json",
            },
        },
    ),
}
```

I checked the logs of nginx, this request was same as the request which sent by `curl/7.65.0` with same url and same content.

- If the modification in this PR was acceptable, I can pull another PR to the master branch.


Discussion / hints:

Fix patch:
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<Request>) -> 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<String>)> {
+    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<Request>) -> 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==");
+    }
 }


Test patch: