Skip to content

Commit

Permalink
Fix Python parser when chunk separators align (#8720) (#8722)
Browse files Browse the repository at this point in the history
(cherry picked from commit 6d3d1fc)
  • Loading branch information
Dreamsorcerer authored Aug 16, 2024
1 parent 5ef8cba commit 78d45e7
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES/8720.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed an edge case in the Python parser when chunk separators happen to align with network chunks -- by :user:`Dreamsorcerer`.
4 changes: 2 additions & 2 deletions aiohttp/http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,13 +870,13 @@ def feed_data(
self._chunk_size = 0
self.payload.feed_data(chunk[:required], required)
chunk = chunk[required:]
if self._lax and chunk.startswith(b"\r"):
chunk = chunk[1:]
self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF
self.payload.end_http_chunk_receiving()

# toss the CRLF at the end of the chunk
if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF:
if self._lax and chunk.startswith(b"\r"):
chunk = chunk[1:]
if chunk[: len(SEP)] == SEP:
chunk = chunk[len(SEP) :]
self._chunk = ChunkState.PARSE_CHUNKED_SIZE
Expand Down
23 changes: 23 additions & 0 deletions tests/test_http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,29 @@ def test_parse_chunked_payload_empty_body_than_another_chunked(
assert b"second" == b"".join(d for d in payload._buffer)


async def test_parse_chunked_payload_split_chunks(response: Any) -> None:
network_chunks = (
b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n",
b"5\r\nfi",
b"rst",
# This simulates a bug in lax mode caused when the \r\n separator, before the
# next HTTP chunk, appears at the start of the next network chunk.
b"\r\n",
b"6",
b"\r",
b"\n",
b"second\r",
b"\n0\r\n\r\n",
)
reader = response.feed_data(network_chunks[0])[0][0][1]
for c in network_chunks[1:]:
response.feed_data(c)

assert response.feed_eof() is None
assert reader.is_eof()
assert await reader.read() == b"firstsecond"


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

0 comments on commit 78d45e7

Please sign in to comment.