diff --git a/CHANGES/7651.bugfix b/CHANGES/7651.bugfix new file mode 100644 index 00000000000..bc013ecf5fa --- /dev/null +++ b/CHANGES/7651.bugfix @@ -0,0 +1 @@ +Fixed display of ``BadStatusLine`` messages from ``llhttp`` -- by :user:`Dreamsorcerer` diff --git a/aiohttp/_http_parser.pyx b/aiohttp/_http_parser.pyx index 2b4b844d05e..3f28fbdab43 100644 --- a/aiohttp/_http_parser.pyx +++ b/aiohttp/_http_parser.pyx @@ -2,7 +2,6 @@ # # Based on https://github.com/MagicStack/httptools # -from __future__ import absolute_import, print_function from cpython cimport ( Py_buffer, @@ -813,7 +812,9 @@ cdef parser_error_from_errno(cparser.llhttp_t* parser, data, pointer): cdef cparser.llhttp_errno_t errno = cparser.llhttp_get_errno(parser) cdef bytes desc = cparser.llhttp_get_error_reason(parser) - if errno in (cparser.HPE_CB_MESSAGE_BEGIN, + err_msg = "{}:\n\n {!r}\n {}".format(desc.decode("latin-1"), data, pointer) + + if errno in {cparser.HPE_CB_MESSAGE_BEGIN, cparser.HPE_CB_HEADERS_COMPLETE, cparser.HPE_CB_MESSAGE_COMPLETE, cparser.HPE_CB_CHUNK_HEADER, @@ -823,22 +824,13 @@ cdef parser_error_from_errno(cparser.llhttp_t* parser, data, pointer): cparser.HPE_INVALID_CONTENT_LENGTH, cparser.HPE_INVALID_CHUNK_SIZE, cparser.HPE_INVALID_EOF_STATE, - cparser.HPE_INVALID_TRANSFER_ENCODING): - cls = BadHttpMessage - - elif errno == cparser.HPE_INVALID_STATUS: - cls = BadStatusLine - - elif errno == cparser.HPE_INVALID_METHOD: - cls = BadStatusLine - - elif errno == cparser.HPE_INVALID_VERSION: - cls = BadStatusLine - + cparser.HPE_INVALID_TRANSFER_ENCODING}: + return BadHttpMessage(err_msg) + elif errno in {cparser.HPE_INVALID_STATUS, + cparser.HPE_INVALID_METHOD, + cparser.HPE_INVALID_VERSION}: + return BadStatusLine(error=err_msg) elif errno == cparser.HPE_INVALID_URL: - cls = InvalidURLError - - else: - cls = BadHttpMessage + return InvalidURLError(err_msg) - return cls("{}:\n\n {!r}\n {}".format(desc.decode("latin-1"), data, pointer)) + return BadHttpMessage(err_msg) diff --git a/aiohttp/http_exceptions.py b/aiohttp/http_exceptions.py index 728824f856f..f1711321f78 100644 --- a/aiohttp/http_exceptions.py +++ b/aiohttp/http_exceptions.py @@ -93,10 +93,10 @@ def __init__(self, hdr: Union[bytes, str]) -> None: class BadStatusLine(BadHttpMessage): - def __init__(self, line: str = "") -> None: + def __init__(self, line: str = "", error: Optional[str] = None) -> None: if not isinstance(line, str): line = repr(line) - super().__init__(f"Bad status line {line!r}") + super().__init__(error or f"Bad status line {line!r}") self.args = (line,) self.line = line diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index 5a39823cbd4..6c43438cd94 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -578,8 +578,10 @@ def test_http_request_parser(parser: Any) -> None: def test_http_request_bad_status_line(parser: Any) -> None: text = b"getpath \r\n\r\n" - with pytest.raises(http_exceptions.BadStatusLine): + with pytest.raises(http_exceptions.BadStatusLine) as exc_info: parser.feed_data(text) + # Check for accidentally escaped message. + assert r"\n" not in exc_info.value.message def test_http_request_upgrade(parser: Any) -> None: