@@ -928,56 +928,77 @@ def on_disconnect(self) -> bytes:
928
928
929
929
raise ClientDisconnected ()
930
930
931
- def exhaust (self , chunk_size : int = 1024 * 64 ) -> None :
932
- """Exhaust the stream. This consumes all the data left until the
933
- limit is reached.
931
+ def _exhaust_chunks (self , chunk_size : int = 1024 * 64 ) -> t .Iterator [bytes ]:
932
+ """Exhaust the stream by reading until the limit is reached or the client
933
+ disconnects, yielding each chunk.
934
+
935
+ :param chunk_size: How many bytes to read at a time.
936
+
937
+ :meta private:
934
938
935
- :param chunk_size: the size for a chunk. It will read the chunk
936
- until the stream is exhausted and throw away
937
- the results.
939
+ .. versionadded:: 2.2.3
938
940
"""
939
941
to_read = self .limit - self ._pos
940
- chunk = chunk_size
942
+
941
943
while to_read > 0 :
942
- chunk = min (to_read , chunk )
943
- self . read ( chunk )
944
- to_read -= chunk
945
-
946
- def exhaust_into (self , buf : bytearray , chunk_size : int = 1024 * 64 ) -> None :
947
- """Exhaust the stream. This consumes all the data left until the
948
- limit is reached, and writes the result into the given buffer .
949
-
950
- :param buf: the buffer to read the result into .
951
- :param chunk_size: the size for a chunk. It will read the chunk
952
- until the stream is exhausted and write it into
953
- the buffer .
944
+ chunk = self . read ( min (to_read , chunk_size ) )
945
+ yield chunk
946
+ to_read -= len ( chunk )
947
+
948
+ def exhaust (self , chunk_size : int = 1024 * 64 ) -> None :
949
+ """Exhaust the stream by reading until the limit is reached or the client
950
+ disconnects, discarding the data .
951
+
952
+ :param chunk_size: How many bytes to read at a time .
953
+
954
+ .. versionchanged:: 2.2.3
955
+ Handle case where wrapped stream returns fewer bytes than requested .
954
956
"""
955
- to_read = self .limit - self ._pos
956
- chunk = chunk_size
957
- while to_read > 0 :
958
- chunk = min (to_read , chunk )
959
- data = self .read (chunk )
960
- buf .extend (data )
961
- to_read -= len (data )
957
+ for _ in self ._exhaust_chunks (chunk_size ):
958
+ pass
962
959
963
960
def read (self , size : t .Optional [int ] = None ) -> bytes :
964
- """Read `size` bytes or if size is not provided everything is read.
961
+ """Read up to ``size`` bytes from the underlying stream. If size is not
962
+ provided, read until the limit.
965
963
966
- :param size: the number of bytes read.
964
+ If the limit is reached, :meth:`on_exhausted` is called, which returns empty
965
+ bytes.
966
+
967
+ If no bytes are read and the limit is not reached, or if an error occurs during
968
+ the read, :meth:`on_disconnect` is called, which raises
969
+ :exc:`.ClientDisconnected`.
970
+
971
+ :param size: The number of bytes to read. ``None``, default, reads until the
972
+ limit is reached.
973
+
974
+ .. versionchanged:: 2.2.3
975
+ Handle case where wrapped stream returns fewer bytes than requested.
967
976
"""
968
977
if self ._pos >= self .limit :
969
978
return self .on_exhausted ()
970
- if size is None or size == - 1 : # -1 is for consistence with file
979
+
980
+ if size is None or size == - 1 : # -1 is for consistency with file
981
+ # Keep reading from the wrapped stream until the limit is reached. Can't
982
+ # rely on stream.read(size) because it's not guaranteed to return size.
971
983
buf = bytearray ()
972
- self .exhaust_into (buf )
984
+
985
+ for chunk in self ._exhaust_chunks ():
986
+ buf .extend (chunk )
987
+
973
988
return bytes (buf )
989
+
974
990
to_read = min (self .limit - self ._pos , size )
991
+
975
992
try :
976
993
read = self ._read (to_read )
977
994
except (OSError , ValueError ):
978
995
return self .on_disconnect ()
996
+
979
997
if to_read and not len (read ):
998
+ # If no data was read, treat it as a disconnect. As long as some data was
999
+ # read, a subsequent call can still return more before reaching the limit.
980
1000
return self .on_disconnect ()
1001
+
981
1002
self ._pos += len (read )
982
1003
return read
983
1004
0 commit comments