From 420911bc693ec3a7f2fbd81c18cffb8fdb12e4c8 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 7 Feb 2022 09:19:26 +0000 Subject: [PATCH] Ensure that iter_bytes does not ever yield any zero-length chunks (#2068) --- httpx/_decoders.py | 2 +- httpx/_models.py | 4 ++-- tests/models/test_responses.py | 26 ++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/httpx/_decoders.py b/httpx/_decoders.py index 5081c86f9a..2d638b7d99 100644 --- a/httpx/_decoders.py +++ b/httpx/_decoders.py @@ -172,7 +172,7 @@ def __init__(self, chunk_size: int = None) -> None: def decode(self, content: bytes) -> typing.List[bytes]: if self._chunk_size is None: - return [content] + return [content] if content else [] self._buffer.write(content) if self._buffer.tell() >= self._chunk_size: diff --git a/httpx/_models.py b/httpx/_models.py index 3755c2548c..341b28ee01 100644 --- a/httpx/_models.py +++ b/httpx/_models.py @@ -1585,7 +1585,7 @@ def iter_bytes(self, chunk_size: int = None) -> typing.Iterator[bytes]: yield chunk decoded = decoder.flush() for chunk in chunker.decode(decoded): - yield chunk + yield chunk # pragma: nocover for chunk in chunker.flush(): yield chunk @@ -1683,7 +1683,7 @@ async def aiter_bytes(self, chunk_size: int = None) -> typing.AsyncIterator[byte yield chunk decoded = decoder.flush() for chunk in chunker.decode(decoded): - yield chunk + yield chunk # pragma: nocover for chunk in chunker.flush(): yield chunk diff --git a/tests/models/test_responses.py b/tests/models/test_responses.py index 942231eed4..8a7e7e1aa8 100644 --- a/tests/models/test_responses.py +++ b/tests/models/test_responses.py @@ -396,6 +396,19 @@ def test_iter_raw_with_chunksize(): assert parts == [b"Hello, world!"] +def test_iter_raw_doesnt_return_empty_chunks(): + def streaming_body_with_empty_chunks(): + yield b"Hello, " + yield b"" + yield b"world!" + yield b"" + + response = httpx.Response(200, content=streaming_body_with_empty_chunks()) + + parts = [part for part in response.iter_raw()] + assert parts == [b"Hello, ", b"world!"] + + def test_iter_raw_on_iterable(): response = httpx.Response( 200, @@ -526,6 +539,19 @@ def test_iter_bytes_with_empty_response(): assert parts == [] +def test_iter_bytes_doesnt_return_empty_chunks(): + def streaming_body_with_empty_chunks(): + yield b"Hello, " + yield b"" + yield b"world!" + yield b"" + + response = httpx.Response(200, content=streaming_body_with_empty_chunks()) + + parts = [part for part in response.iter_bytes()] + assert parts == [b"Hello, ", b"world!"] + + @pytest.mark.asyncio async def test_aiter_bytes(): response = httpx.Response(