Skip to content

Commit

Permalink
Fix incorrect parsing of chunk extensions with the pure Python parser
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco committed Nov 13, 2024
1 parent a9a0d84 commit 1cd18c3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES/9851.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed incorrect parsing of chunk extensions with the pure Python parser -- by :user:`bdraco`.
7 changes: 7 additions & 0 deletions aiohttp/http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,13 @@ def feed_data(
i = chunk.find(CHUNK_EXT, 0, pos)
if i >= 0:
size_b = chunk[:i] # strip chunk-extensions
# Verify no LF in the chunk-extension
if b"\n" in (ext := chunk[i:pos]):
exc = BadHttpMessage(
f"Unexpected LF in chunk-extension: {ext!r}"
)
set_exception(self.payload, exc)
raise exc
else:
size_b = chunk[:pos]

Expand Down
48 changes: 48 additions & 0 deletions tests/test_http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,54 @@ async def test_parse_chunked_payload_split_chunks(response: HttpResponseParser)
assert await reader.read() == b"firstsecond"


@pytest.mark.skipif(NO_EXTENSIONS, reason="Only tests C parser.")
async def test_parse_chunked_payload_with_lf_in_extensions_c_parser(
loop: asyncio.AbstractEventLoop, protocol: BaseProtocol
) -> None:
"""Test the C-parser with a chunked payload that has a LF in the chunk extensions."""
# The C parser will raise a BadHttpMessage from feed_data
parser = HttpRequestParserC(
protocol,
loop,
2**16,
max_line_size=8190,
max_field_size=8190,
)
payload = (
b"GET / HTTP/1.1\r\nHost: localhost:5001\r\n"
b"Transfer-Encoding: chunked\r\n\r\n2;\nxx\r\n4c\r\n0\r\n\r\n"
b"GET /admin HTTP/1.1\r\nHost: localhost:5001\r\n"
b"Transfer-Encoding: chunked\r\n\r\n0\r\n\r\n"
)
with pytest.raises(http_exceptions.BadHttpMessage, match="\\\\nxx"):
parser.feed_data(payload)


async def test_parse_chunked_payload_with_lf_in_extensions_py_parser(
loop: asyncio.AbstractEventLoop, protocol: BaseProtocol
) -> None:
"""Test the py-parser with a chunked payload that has a LF in the chunk extensions."""
# The py parser will not raise the BadHttpMessage directly, but instead
# it will set the exception on the StreamReader.
parser = HttpRequestParserPy(
protocol,
loop,
2**16,
max_line_size=8190,
max_field_size=8190,
)
payload = (
b"GET / HTTP/1.1\r\nHost: localhost:5001\r\n"
b"Transfer-Encoding: chunked\r\n\r\n2;\nxx\r\n4c\r\n0\r\n\r\n"
b"GET /admin HTTP/1.1\r\nHost: localhost:5001\r\n"
b"Transfer-Encoding: chunked\r\n\r\n0\r\n\r\n"
)
messages, _, _ = parser.feed_data(payload)
reader = messages[0][1]
assert isinstance(reader.exception(), http_exceptions.BadHttpMessage)
assert "\\nxx" in str(reader.exception())


def test_partial_url(parser: HttpRequestParser) -> None:
messages, upgrade, tail = parser.feed_data(b"GET /te")
assert len(messages) == 0
Expand Down

0 comments on commit 1cd18c3

Please sign in to comment.