From 6639f7df32bea3ee6952299173bdf90c95f9ee5f Mon Sep 17 00:00:00 2001 From: Anton Kasyanov Date: Tue, 3 Oct 2023 15:57:13 +0300 Subject: [PATCH] Fixed 7616: EmptyStreamReader.iter_chunks() never ends (#7644) ## What do these changes do? Fixes an issue reported in [7616](https://github.com/aio-libs/aiohttp/issues/7616) - An iteration of the chunks of an EmptyStreamReader with iter_chunks() never ends. ## Are there changes in behavior for the user? - `EmptyStreamReader` `iter_chunks()` does not get stuck - First call of `EmptyStreamReader` `readchunk()` now returns `(b"", False)`. All the subsequent calls return `(b"", True)`. Before this PR it was always `(b"", True)`. ## Related issue number [7616](https://github.com/aio-libs/aiohttp/issues/7616) --- CHANGES/7616.bugfix | 1 + aiohttp/streams.py | 6 +++++- tests/test_streams.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 CHANGES/7616.bugfix diff --git a/CHANGES/7616.bugfix b/CHANGES/7616.bugfix new file mode 100644 index 00000000000..3e6a06c8c44 --- /dev/null +++ b/CHANGES/7616.bugfix @@ -0,0 +1 @@ +Fixed ``EmptyStreamReader.iter_chunks()`` never ending -- by :user:`mind1m` diff --git a/aiohttp/streams.py b/aiohttp/streams.py index c287d856260..8ee088d3b5c 100644 --- a/aiohttp/streams.py +++ b/aiohttp/streams.py @@ -491,7 +491,7 @@ def _read_nowait(self, n: int) -> bytes: class EmptyStreamReader(StreamReader): # lgtm [py/missing-call-to-init] def __init__(self) -> None: - pass + self._read_eof_chunk = False def __repr__(self) -> str: return "<%s>" % self.__class__.__name__ @@ -535,6 +535,10 @@ async def readany(self) -> bytes: return b"" async def readchunk(self) -> Tuple[bytes, bool]: + if not self._read_eof_chunk: + self._read_eof_chunk = True + return (b"", False) + return (b"", True) async def readexactly(self, n: int) -> bytes: diff --git a/tests/test_streams.py b/tests/test_streams.py index 3d2c65f827f..6b32151e8a9 100644 --- a/tests/test_streams.py +++ b/tests/test_streams.py @@ -1109,12 +1109,22 @@ async def test_empty_stream_reader() -> None: assert await s.read() == b"" assert await s.readline() == b"" assert await s.readany() == b"" + assert await s.readchunk() == (b"", False) assert await s.readchunk() == (b"", True) with pytest.raises(asyncio.IncompleteReadError): await s.readexactly(10) assert s.read_nowait() == b"" +async def test_empty_stream_reader_iter_chunks() -> None: + s = streams.EmptyStreamReader() + + # check that iter_chunks() does not cause infinite loop + iter_chunks = s.iter_chunks() + with pytest.raises(StopAsyncIteration): + await iter_chunks.__anext__() + + @pytest.fixture async def buffer(loop: Any): return streams.DataQueue(loop)