From f016f0680e4ace6742b03a70cb0382ce86abe371 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 31 Oct 2021 19:03:06 +0200 Subject: [PATCH] Raise '400: Content-Length can't be present with Transfer-Encoding' if both Content-Length and Transfer-Encoding are sent by peer (#6182) --- CHANGES/6182.bugfix | 1 + aiohttp/http_parser.py | 12 ++++++++++-- tests/test_http_parser.py | 15 ++++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 CHANGES/6182.bugfix diff --git a/CHANGES/6182.bugfix b/CHANGES/6182.bugfix new file mode 100644 index 0000000000..28daaa328a --- /dev/null +++ b/CHANGES/6182.bugfix @@ -0,0 +1 @@ +Raise ``400: Content-Length can't be present with Transfer-Encoding`` if both ``Content-Length`` and ``Transfer-Encoding`` are sent by peer by both C and Python implementations diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py index 4a4ae31ae6..e1b86e8e4f 100644 --- a/aiohttp/http_parser.py +++ b/aiohttp/http_parser.py @@ -28,6 +28,7 @@ from .base_protocol import BaseProtocol from .helpers import NO_EXTENSIONS, BaseTimerContext from .http_exceptions import ( + BadHttpMessage, BadStatusLine, ContentEncodingError, ContentLengthError, @@ -489,8 +490,15 @@ def parse_headers( # chunking te = headers.get(hdrs.TRANSFER_ENCODING) - if te and "chunked" in te.lower(): - chunked = True + if te is not None: + te_lower = te.lower() + if "chunked" in te_lower: + chunked = True + + if hdrs.CONTENT_LENGTH in headers: + raise BadHttpMessage( + "Content-Length can't be present with Transfer-Encoding", + ) return (headers, raw_headers, close_conn, encoding, upgrade, chunked) diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index 78e9ea6401..d86d238f58 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -291,7 +291,20 @@ def test_request_chunked(parser) -> None: assert isinstance(payload, streams.StreamReader) -def test_conn_upgrade(parser) -> None: +def test_request_te_chunked_with_content_length(parser: Any) -> None: + text = ( + b"GET /test HTTP/1.1\r\n" + b"content-length: 1234\r\n" + b"transfer-encoding: chunked\r\n\r\n" + ) + with pytest.raises( + http_exceptions.BadHttpMessage, + match="Content-Length can't be present with Transfer-Encoding", + ): + parser.feed_data(text) + + +def test_conn_upgrade(parser: Any) -> None: text = ( b"GET /test HTTP/1.1\r\n" b"connection: upgrade\r\n"