diff --git a/CHANGES/7835.bugfix b/CHANGES/7835.bugfix new file mode 100644 index 00000000000..4ce3af4f6f6 --- /dev/null +++ b/CHANGES/7835.bugfix @@ -0,0 +1 @@ +Fixed arbitrary sequence types being allowed to inject headers via version parameter -- by :user:`Dreamsorcerer` diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 851ab220b8a..4cea7466d8d 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -706,8 +706,8 @@ async def send(self, conn: "Connection") -> "ClientResponse": self.headers[hdrs.CONNECTION] = connection # status + headers - status_line = "{0} {1} HTTP/{2[0]}.{2[1]}".format( - self.method, path, self.version + status_line = "{0} {1} HTTP/{v.major}.{v.minor}".format( + self.method, path, v=self.version ) await writer.write_headers(status_line, self.headers) diff --git a/tests/test_client_request.py b/tests/test_client_request.py index 0f58d752de2..c8ce98d4034 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -21,6 +21,7 @@ _gen_default_accept_encoding, _merge_ssl_params, ) +from aiohttp.http import HttpVersion from aiohttp.test_utils import make_mocked_coro @@ -623,18 +624,18 @@ async def test_connection_header(loop, conn) -> None: req.headers.clear() req.keep_alive.return_value = True - req.version = (1, 1) + req.version = HttpVersion(1, 1) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") is None - req.version = (1, 0) + req.version = HttpVersion(1, 0) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") == "keep-alive" req.keep_alive.return_value = False - req.version = (1, 1) + req.version = HttpVersion(1, 1) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") == "close" @@ -1161,6 +1162,19 @@ async def gen(): resp.close() +async def test_bad_version(loop, conn) -> None: + req = ClientRequest( + "GET", + URL("http://python.org"), + loop=loop, + headers={"Connection": "Close"}, + version=("1", "1\r\nInjected-Header: not allowed"), + ) + + with pytest.raises(AttributeError): + await req.send(conn) + + async def test_custom_response_class(loop, conn) -> None: class CustomResponse(ClientResponse): def read(self, decode=False):