Skip to content

Commit 562b7d4

Browse files
End CRT stream when source is empty
1 parent 1de61a1 commit 562b7d4

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

packages/smithy-http/src/smithy_http/aio/crt.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ async def _consume_body_async(
337337
) -> None:
338338
async for chunk in source:
339339
dest.write(chunk)
340+
dest.end_stream()
340341

341342
def __deepcopy__(self, memo: Any) -> "AWSCRTHTTPClient":
342343
return AWSCRTHTTPClient(
@@ -354,30 +355,38 @@ def __init__(self) -> None:
354355
# will be much more efficient than a list.
355356
self._chunks: deque[bytes] = deque()
356357
self._closed = False
358+
self._done = False
357359

358360
def read(self, size: int | None = -1) -> bytes:
359361
if self._closed:
360362
return b""
361363

362364
if len(self._chunks) == 0:
365+
if self._done:
366+
self._closed = True
367+
return b""
368+
363369
# When the CRT recieves this, it'll try again later.
364370
raise BlockingIOError("read")
365371

366-
chunk = self._chunks.popleft()
367-
if size is None or size < 1:
368-
# We could compile all the chunks here instead of just returning
369-
# the one, BUT the CRT will keep calling read until empty bytes
370-
# are returned. So it's actually better to just return one chunk
371-
# since combining them would have some potentially bad memory
372-
# usage issues.
373-
return chunk
374-
else:
375-
result = chunk[:size]
376-
remainder = chunk[size:]
372+
# We could compile all the chunks here instead of just returning
373+
# the one, BUT the CRT will keep calling read until empty bytes
374+
# are returned. So it's actually better to just return one chunk
375+
# since combining them would have some potentially bad memory
376+
# usage issues.
377+
result = self._chunks.popleft()
378+
if size is not None and size > 0:
379+
remainder = result[size:]
380+
result = result[:size]
377381
if remainder:
378382
self._chunks.appendleft(remainder)
379383
return result
380384

385+
if self._done and len(self._chunks) == 0:
386+
self.close()
387+
388+
return result
389+
381390
def read1(self, size: int = -1) -> bytes:
382391
return self.read(size)
383392

@@ -410,6 +419,10 @@ def closed(self) -> bool:
410419

411420
def close(self) -> None:
412421
self._closed = True
422+
self._done = True
413423

414424
# Clear out the remaining chunks so that they don't sit around in memory.
415425
self._chunks.clear()
426+
427+
def end_stream(self) -> None:
428+
self._done = True

packages/smithy-http/tests/unit/aio/test_crt.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,13 @@ def test_stream_readinto_bytearray() -> None:
9191
stream.write(b"foobar")
9292
stream.readinto(buffer)
9393
assert bytes(buffer) == b"foo"
94+
95+
96+
def test_end_stream() -> None:
97+
stream = BufferableByteStream()
98+
stream.write(b"foo")
99+
stream.end_stream()
100+
101+
assert not stream.closed
102+
assert stream.read() == b"foo"
103+
assert stream.closed

0 commit comments

Comments
 (0)