File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -448,18 +448,25 @@ def read(self, amt=None):
448448 self ._close_conn ()
449449 return b""
450450
451+ if self .chunked :
452+ return self ._read_chunked (amt )
453+
451454 if amt is not None :
452- # Amount is given, implement using readinto
453- b = bytearray (amt )
454- n = self .readinto (b )
455- return memoryview (b )[:n ].tobytes ()
455+ if self .length is not None and amt > self .length :
456+ # clip the read to the "end of response"
457+ amt = self .length
458+ s = self .fp .read (amt )
459+ if not s and amt :
460+ # Ideally, we would raise IncompleteRead if the content-length
461+ # wasn't satisfied, but it might break compatibility.
462+ self ._close_conn ()
463+ elif self .length is not None :
464+ self .length -= len (s )
465+ if not self .length :
466+ self ._close_conn ()
467+ return s
456468 else :
457469 # Amount is not given (unbounded read) so we must check self.length
458- # and self.chunked
459-
460- if self .chunked :
461- return self ._readall_chunked ()
462-
463470 if self .length is None :
464471 s = self .fp .read ()
465472 else :
@@ -560,15 +567,23 @@ def _get_chunk_left(self):
560567 self .chunk_left = chunk_left
561568 return chunk_left
562569
563- def _readall_chunked (self ):
570+ def _read_chunked (self , amt = None ):
564571 assert self .chunked != _UNKNOWN
565572 value = []
566573 try :
567574 while True :
568575 chunk_left = self ._get_chunk_left ()
569576 if chunk_left is None :
570577 break
578+
579+ if amt is not None and amt <= chunk_left :
580+ value .append (self ._safe_read (amt ))
581+ self .chunk_left = chunk_left - amt
582+ break
583+
571584 value .append (self ._safe_read (chunk_left ))
585+ if amt is not None :
586+ amt -= chunk_left
572587 self .chunk_left = 0
573588 return b'' .join (value )
574589 except IncompleteRead :
Original file line number Diff line number Diff line change @@ -569,6 +569,33 @@ def test_partial_readintos(self):
569569 resp .close ()
570570 self .assertTrue (resp .closed )
571571
572+ def test_partial_reads_past_end (self ):
573+ # if we have Content-Length, clip reads to the end
574+ body = "HTTP/1.1 200 Ok\r \n Content-Length: 4\r \n \r \n Text"
575+ sock = FakeSocket (body )
576+ resp = client .HTTPResponse (sock )
577+ resp .begin ()
578+ self .assertEqual (resp .read (10 ), b'Text' )
579+ self .assertTrue (resp .isclosed ())
580+ self .assertFalse (resp .closed )
581+ resp .close ()
582+ self .assertTrue (resp .closed )
583+
584+ def test_partial_readintos_past_end (self ):
585+ # if we have Content-Length, clip readintos to the end
586+ body = "HTTP/1.1 200 Ok\r \n Content-Length: 4\r \n \r \n Text"
587+ sock = FakeSocket (body )
588+ resp = client .HTTPResponse (sock )
589+ resp .begin ()
590+ b = bytearray (10 )
591+ n = resp .readinto (b )
592+ self .assertEqual (n , 4 )
593+ self .assertEqual (bytes (b )[:4 ], b'Text' )
594+ self .assertTrue (resp .isclosed ())
595+ self .assertFalse (resp .closed )
596+ resp .close ()
597+ self .assertTrue (resp .closed )
598+
572599 def test_partial_reads_no_content_length (self ):
573600 # when no length is present, the socket should be gracefully closed when
574601 # all data was read
Original file line number Diff line number Diff line change 1+ Improve performance of HTTPResponse.read with a given amount. Patch by Bruce Merry.
You can’t perform that action at this time.
0 commit comments