Skip to content

Commit 35c979b

Browse files
authored
Fix headers being mutated if passed to web.Response as a CIMultiDict (#10672)
## What do these changes do? If `CIMultiDict` is passed in we need to make a copy to avoid mutating it. In some cases we used to copy these twice which was fixed in #10045 but for this case that was the only copy being made and the source of this regression. fixes #10670
1 parent 3d11b55 commit 35c979b

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

CHANGES/10672.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed :class:`multidict.CIMultiDict` being mutated when passed to :class:`aiohttp.web.Response` -- by :user:`bdraco`.

aiohttp/web_response.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,8 @@ def __init__(
532532

533533
if headers is None:
534534
real_headers: CIMultiDict[str] = CIMultiDict()
535-
elif not isinstance(headers, CIMultiDict):
536-
real_headers = CIMultiDict(headers)
537535
else:
538-
real_headers = headers # = cast('CIMultiDict[str]', headers)
536+
real_headers = CIMultiDict(headers)
539537

540538
if content_type is not None and "charset" in content_type:
541539
raise ValueError("charset must not be in content_type argument")

tests/test_web_response.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import aiosignal
1414
import pytest
15-
from multidict import CIMultiDict, CIMultiDictProxy
15+
from multidict import CIMultiDict, CIMultiDictProxy, MultiDict
1616

1717
from aiohttp import HttpVersion, HttpVersion10, HttpVersion11, hdrs, web
1818
from aiohttp.abc import AbstractStreamWriter
@@ -1384,3 +1384,15 @@ async def test_warn_large_cookie(buf: bytearray, writer: AbstractStreamWriter) -
13841384
assert match is not None
13851385
cookie = match.group(1)
13861386
assert len(cookie) == 4097
1387+
1388+
1389+
@pytest.mark.parametrize("loose_header_type", (MultiDict, CIMultiDict, dict))
1390+
async def test_passing_cimultidict_to_web_response_not_mutated(
1391+
loose_header_type: type,
1392+
) -> None:
1393+
req = make_request("GET", "/")
1394+
headers = loose_header_type({})
1395+
resp = web.Response(body=b"answer", headers=headers)
1396+
await resp.prepare(req)
1397+
assert resp.content_length == 6
1398+
assert not headers

0 commit comments

Comments
 (0)