Skip to content

Commit

Permalink
Fix Headers.update to correctly handle repeated headers (#2038)
Browse files Browse the repository at this point in the history
  • Loading branch information
adriangb committed Jan 21, 2022
1 parent 8dc9b6b commit 321d4aa
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
6 changes: 4 additions & 2 deletions httpx/_models.py
Expand Up @@ -964,8 +964,10 @@ def get_list(self, key: str, split_commas: bool = False) -> typing.List[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)
Expand Down
39 changes: 39 additions & 0 deletions tests/client/test_headers.py
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 321d4aa

Please sign in to comment.