Repository: sagebind/isahc (Rust)

Issue:
Custom User-Agent can NOT be set
In `isahc = "0.9.2"`, I can not set a custom user-agent to `isahc::HttpClient`. It let every request to always have the default user-agent.

I use `nc -l 8888` to catch the network package of a request which is sent to localhost and then find the issue. The problem is caused by setting default user-agent to `http::Request` before inserting these headers of `HttpClient` to the `http::Request`.

As following code:

1. Setting default user-agent if `request` has not user-agent.
https://github.com/sagebind/isahc/blob/b517b90aad1a3124868c9764d725eaac6110588e/src/client.rs#L791-L794

2. Because above code, `parts.headers` had have the default user-agent !!!.
  So, the costom user-agent in `self.default_headers` can NOT be set to `parts.headers`.
https://github.com/sagebind/isahc/blob/b517b90aad1a3124868c9764d725eaac6110588e/src/client.rs#L984-L990

-------

Following code is my test code.
```rust
use isahc::HttpClient;

let c = HttpClient::builder()
    .default_headers(&[
        ("user-agent", "abc/0.1"),
        ("AAA", "BBB"),
        ("Accept-Encoding", "*/*"),
    ])
    .build()
    .unwrap();

c.get("http://localhost:8888").unwrap();
```

Network package
```
$ nc -l 8888
GET / HTTP/1.1
Host: localhost:8888
Accept: */*
user-agent: curl/7.70.0-DEV isahc/0.9.2
aaa: BBB
accept-encoding: */*
```


Discussion:
Oops, sorry about that! That's no good. Thanks for opening a detailed report, I will look into this as soon as I can.
This is now fixed in 0.9.3!



Patch:
diff --git a/src/client.rs b/src/client.rs
index 42f87546..a0f2199b 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -801,6 +801,17 @@ impl HttpClient {
         );
 
         async move {
+            // We are checking here if header already contains the key, simply ignore it.
+            // In case the key wasn't present in parts.headers ensure that
+            // we have all the headers from default headers.
+            for name in self.default_headers.keys() {
+                if !request.headers().contains_key(name) {
+                    for v in self.default_headers.get_all(name).iter() {
+                        request.headers_mut().append(name, v.clone());
+                    }
+                }
+            }
+
             // Set default user agent if not specified.
             request
                 .headers_mut()
@@ -994,17 +1005,6 @@ impl HttpClient {
             }
         }
 
-        // We are checking here if header already contains the key, simply ignore it.
-        // In case the key wasn't present in parts.headers ensure that
-        // we have all the headers from default headers.
-        for name in self.default_headers.keys() {
-            if !parts.headers.contains_key(name) {
-                for v in self.default_headers.get_all(name).iter() {
-                    parts.headers.append(name, v.clone());
-                }
-            }
-        }
-
         parts.headers.set_opt(&mut easy)?;
 
         Ok((easy, future))


Test patch:
diff --git a/tests/headers.rs b/tests/headers.rs
index bea0251e..dab2a072 100644
--- a/tests/headers.rs
+++ b/tests/headers.rs
@@ -27,6 +27,22 @@ speculate::speculate! {
         m.assert();
     }
 
+    // Issue [#190](https://github.com/sagebind/isahc/issues/190)
+    test "override client default user agent" {
+        let client = HttpClient::builder()
+           .default_header("user-agent", "foo")
+           .build()
+           .unwrap();
+
+        let m = mock("GET", "/")
+            .match_header("user-agent", "foo")
+            .create();
+
+        client.get(server_url()).unwrap();
+
+        m.assert();
+    }
+
     test "header can be inserted in HttpClient::builder" {
 
         let host_header = server_url().replace("http://", "");