def read_chunked(self, amt=None): # FIXME: Rewrite this method and make it a class with # a better structured logic. if not self.chunked: raise ResponseNotChunked( "Response is not chunked. " "Header 'transfer-encoding: chunked' is missing.") while True: # First, we'll figure out length of a chunk and then # we'll try to read it from socket. if self.chunk_left is None: line = self._fp.fp.readline() line = line.decode() # See RFC 7230: Chunked Transfer Coding. i = line.find(';') if i >= 0: line = line[:i] # Strip chunk-extensions. try: self.chunk_left = int(line, 16) except ValueError: # Invalid chunked protocol response, abort. self.close() raise httplib.IncompleteRead(''.join(line)) if self.chunk_left == 0: break if amt is None: chunk = self._fp._safe_read(self.chunk_left) yield chunk self._fp._safe_read( 2) # Toss the CRLF at the end of the chunk. self.chunk_left = None elif amt < self.chunk_left: value = self._fp._safe_read(amt) self.chunk_left = self.chunk_left - amt yield value elif amt == self.chunk_left: value = self._fp._safe_read(amt) self._fp._safe_read( 2) # Toss the CRLF at the end of the chunk. self.chunk_left = None yield value else: # amt > self.chunk_left yield self._fp._safe_read(self.chunk_left) self._fp._safe_read( 2) # Toss the CRLF at the end of the chunk. self.chunk_left = None # Chunk content ends with \r\n: discard it. while True: line = self._fp.fp.readline() if not line: # Some sites may not end with '\r\n'. break if line == b'\r\n': break # We read everything; close the "file". self.release_conn()
def _update_chunk_length(self): # First, we'll figure out length of a chunk and then # we'll try to read it from socket. if self.chunk_left is not None: return line = self._fp.fp.readline() line = line.split(b';', 1)[0] try: self.chunk_left = int(line, 16) except ValueError: # Invalid chunked protocol response, abort. self.close() raise httplib.IncompleteRead(line)