diff --git a/CHANGES/9018.bugfix.rst b/CHANGES/9018.bugfix.rst new file mode 100644 index 00000000000..2de6d142900 --- /dev/null +++ b/CHANGES/9018.bugfix.rst @@ -0,0 +1 @@ +Updated Python parser to reject messages after a close message, matching C parser behaviour -- by :user:`Dreamsorcerer`. diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py index a79710414af..024e53f4d40 100644 --- a/aiohttp/http_parser.py +++ b/aiohttp/http_parser.py @@ -306,6 +306,7 @@ def feed_data( start_pos = 0 loop = self.loop + should_close = False while start_pos < data_len: # read HTTP message (request/response line + headers), \r\n\r\n # and split by lines @@ -317,6 +318,9 @@ def feed_data( continue if pos >= start_pos: + if should_close: + raise BadHttpMessage("Data after `Connection: close`") + # line found line = data[start_pos:pos] if SEP == b"\n": # For lax response parsing @@ -426,6 +430,7 @@ def get_content_length() -> Optional[int]: payload = EMPTY_PAYLOAD messages.append((msg, payload)) + should_close = msg.should_close else: self._tail = data[start_pos:] data = EMPTY diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index 23ad9bf7758..96a3f11d1cf 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -851,6 +851,14 @@ def test_http_request_bad_status_line_whitespace(parser: HttpRequestParser) -> N parser.feed_data(text) +def test_http_request_message_after_close(parser: HttpRequestParser) -> None: + text = b"GET / HTTP/1.1\r\nConnection: close\r\n\r\nInvalid\r\n\r\n" + with pytest.raises( + http_exceptions.BadHttpMessage, match="Data after `Connection: close`" + ): + parser.feed_data(text) + + def test_http_request_upgrade(parser: HttpRequestParser) -> None: text = ( b"GET /test HTTP/1.1\r\n"