]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Fix Headers.update to correctly handle repeated headers (#2038)
authorAdrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>
Fri, 21 Jan 2022 16:35:10 +0000 (08:35 -0800)
committerGitHub <noreply@github.com>
Fri, 21 Jan 2022 16:35:10 +0000 (08:35 -0800)
httpx/_models.py
tests/client/test_headers.py

index f6cd6db93953292c8bc2302f4eec021fbac685e5..3755c2548c633dc4441b71a55abedc5afb6c84fc 100644 (file)
@@ -964,8 +964,10 @@ class Headers(typing.MutableMapping[str, str]):
 
     def update(self, headers: HeaderTypes = None) -> None:  # type: ignore
         headers = Headers(headers)
-        for key, value in headers.raw:
-            self[key.decode(headers.encoding)] = value.decode(headers.encoding)
+        for key in headers.keys():
+            if key in self:
+                self.pop(key)
+        self._list.extend(headers._list)
 
     def copy(self) -> "Headers":
         return Headers(self, encoding=self.encoding)
index ba862fd52109849c0fdcc119bcfb9e5f37bb9579..264ca0bd67004541b85545d9aac19c0895a4f332 100755 (executable)
@@ -10,6 +10,16 @@ def echo_headers(request: httpx.Request) -> httpx.Response:
     return httpx.Response(200, json=data)
 
 
+def echo_repeated_headers_multi_items(request: httpx.Request) -> httpx.Response:
+    data = {"headers": list(request.headers.multi_items())}
+    return httpx.Response(200, json=data)
+
+
+def echo_repeated_headers_items(request: httpx.Request) -> httpx.Response:
+    data = {"headers": list(request.headers.items())}
+    return httpx.Response(200, json=data)
+
+
 def test_client_header():
     """
     Set a header in the Client.
@@ -110,6 +120,35 @@ def test_header_update():
     }
 
 
+def test_header_repeated_items():
+    url = "http://example.org/echo_headers"
+    client = httpx.Client(transport=httpx.MockTransport(echo_repeated_headers_items))
+    response = client.get(url, headers=[("x-header", "1"), ("x-header", "2,3")])
+
+    assert response.status_code == 200
+
+    echoed_headers = response.json()["headers"]
+    # as per RFC 7230, the whitespace after a comma is insignificant
+    # so we split and strip here so that we can do a safe comparison
+    assert ["x-header", ["1", "2", "3"]] in [
+        [k, [subv.lstrip() for subv in v.split(",")]] for k, v in echoed_headers
+    ]
+
+
+def test_header_repeated_multi_items():
+    url = "http://example.org/echo_headers"
+    client = httpx.Client(
+        transport=httpx.MockTransport(echo_repeated_headers_multi_items)
+    )
+    response = client.get(url, headers=[("x-header", "1"), ("x-header", "2,3")])
+
+    assert response.status_code == 200
+
+    echoed_headers = response.json()["headers"]
+    assert ["x-header", "1"] in echoed_headers
+    assert ["x-header", "2,3"] in echoed_headers
+
+
 def test_remove_default_header():
     """
     Remove a default header from the Client.