class ClientResponse: # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase cookies = None # Response cookies (Set-Cookie) content = None # Payload stream headers = None # Response headers, CIMultiDictProxy raw_headers = None # Response raw headers, a sequence of pairs _connection = None # current connection flow_control_class = FlowControlStreamReader # reader flow control _reader = None # input stream _response_parser = aiohttp.HttpResponseParser() _source_traceback = None # setted up by ClientRequest after ClientResponse object creation # post-init stage allows to not change ctor signature _loop = None _closed = True # to allow __del__ for non-initialized properly response def __init__(self, method, url, host='', *, writer=None, continue100=None, timeout=5 * 60): super().__init__() self.method = method self.url = url self.host = host self._content = None self._writer = writer self._continue = continue100 self._closed = False self._should_close = True # override by message.should_close later self._history = () self._timeout = timeout def _post_init(self, loop): self._loop = loop if loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) def __del__(self, _warnings=warnings): if self._loop is None: return # not started if self._closed: return self.close() _warnings.warn("Unclosed response {!r}".format(self), ResourceWarning) context = {'client_response': self, 'message': 'Unclosed response'} if self._source_traceback: context['source_traceback'] = self._source_traceback self._loop.call_exception_handler(context) def __repr__(self): out = io.StringIO() ascii_encodable_url = self.url.encode('ascii', 'backslashreplace') \ .decode('ascii') if self.reason: ascii_encodable_reason = self.reason.encode('ascii', 'backslashreplace') \ .decode('ascii') else: ascii_encodable_reason = self.reason print('<ClientResponse({}) [{} {}]>'.format(ascii_encodable_url, self.status, ascii_encodable_reason), file=out) print(self.headers, file=out) return out.getvalue() @property def connection(self): return self._connection @property def history(self): """A sequence of of responses, if redirects occured.""" return self._history def waiting_for_continue(self): return self._continue is not None def _setup_connection(self, connection): self._reader = connection.reader self._connection = connection self.content = self.flow_control_class(connection.reader, loop=connection.loop, timeout=self._timeout) def _need_parse_response_body(self): return (self.method.lower() != 'head' and self.status not in [204, 304]) @asyncio.coroutine def start(self, connection, read_until_eof=False): """Start response processing.""" self._setup_connection(connection) while True: httpstream = self._reader.set_parser(self._response_parser) # read response with Timeout(self._timeout, loop=self._loop): message = yield from httpstream.read() if message.code != 100: break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = message.version self.status = message.code self.reason = message.reason self._should_close = message.should_close # headers self.headers = CIMultiDictProxy(message.headers) self.raw_headers = tuple(message.raw_headers) # payload rwb = self._need_parse_response_body() self._reader.set_parser( aiohttp.HttpPayloadParser(message, readall=read_until_eof, response_with_body=rwb), self.content) # cookies self.cookies = http.cookies.SimpleCookie() if hdrs.SET_COOKIE in self.headers: for hdr in self.headers.getall(hdrs.SET_COOKIE): try: self.cookies.load(hdr) except http.cookies.CookieError as exc: client_logger.warning('Can not load response cookies: %s', exc) return self def close(self): if self._closed: return self._closed = True if self._loop is None or self._loop.is_closed(): return if self._connection is not None: self._connection.close() self._connection = None self._cleanup_writer() @asyncio.coroutine def release(self): if self._closed: return try: content = self.content if content is not None and not content.at_eof(): chunk = yield from content.readany() while chunk is not EOF_MARKER or chunk: chunk = yield from content.readany() except Exception: self._connection.close() self._connection = None raise finally: self._closed = True if self._connection is not None: self._connection.release() if self._reader is not None: self._reader.unset_parser() self._connection = None self._cleanup_writer() def raise_for_status(self): if 400 <= self.status: raise aiohttp.HttpProcessingError(code=self.status, message=self.reason) def _cleanup_writer(self): if self._writer is not None and not self._writer.done(): self._writer.cancel() self._writer = None @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None yield from self.release() @asyncio.coroutine def read(self): """Read response payload.""" if self._content is None: try: self._content = yield from self.content.read() except: self.close() raise else: yield from self.release() return self._content def _get_encoding(self): ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() mtype, stype, _, params = helpers.parse_mimetype(ctype) encoding = params.get('charset') if not encoding: encoding = chardet.detect(self._content)['encoding'] if not encoding: encoding = 'utf-8' return encoding @asyncio.coroutine def text(self, encoding=None): """Read response payload and decode.""" if self._content is None: yield from self.read() if encoding is None: encoding = self._get_encoding() return self._content.decode(encoding) @asyncio.coroutine def json(self, *, encoding=None, loads=json.loads): """Read and decodes JSON response.""" if self._content is None: yield from self.read() ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() if 'json' not in ctype: client_logger.warning( 'Attempt to decode JSON with unexpected mimetype: %s', ctype) stripped = self._content.strip() if not stripped: return None if encoding is None: encoding = self._get_encoding() return loads(stripped.decode(encoding)) if PY_35: @asyncio.coroutine def __aenter__(self): return self @asyncio.coroutine def __aexit__(self, exc_type, exc_val, exc_tb): if exc_type is None: yield from self.release() else: self.close()
class ClientResponse: message = None # RawResponseMessage object # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase cookies = None # Response cookies (Set-Cookie) content = None # Payload stream _connection = None # current connection flow_control_class = FlowControlStreamReader # reader flow control _reader = None # input stream _response_parser = aiohttp.HttpResponseParser() _source_traceback = None # setted up by ClientRequest after ClientResponse object creation # post-init stage allows to not change ctor signature _loop = None _closed = True # to allow __del__ for non-initialized properly response def __init__(self, method, url, host='', *, writer=None, continue100=None): super().__init__() self.method = method self.url = url self.host = host self.headers = None self._content = None self._writer = writer self._continue = continue100 self._closed = False def _post_init(self, loop): self._loop = loop if loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) if PY_341: def __del__(self): if self._closed: return self.close() warnings.warn("Unclosed response {!r}".format(self), ResourceWarning) context = {'client_response': self, 'message': 'Unclosed response'} if self._source_traceback: context['source_traceback'] = self._source_traceback self._loop.call_exception_handler(context) def __repr__(self): out = io.StringIO() print('<ClientResponse({}) [{} {}]>'.format(self.url, self.status, self.reason), file=out) print(self.headers, file=out) return out.getvalue() @property def connection(self): return self._connection def waiting_for_continue(self): return self._continue is not None def _setup_connection(self, connection): self._reader = connection.reader self._connection = connection self.content = self.flow_control_class(connection.reader, loop=connection.loop) @asyncio.coroutine def start(self, connection, read_until_eof=False): """Start response processing.""" self._setup_connection(connection) while True: httpstream = self._reader.set_parser(self._response_parser) # read response self.message = yield from httpstream.read() if self.message.code != 100: break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = self.message.version self.status = self.message.code self.reason = self.message.reason # headers self.headers = CIMultiDictProxy(self.message.headers) # payload response_with_body = self.method.lower() != 'head' self._reader.set_parser( aiohttp.HttpPayloadParser(self.message, readall=read_until_eof, response_with_body=response_with_body), self.content) # cookies self.cookies = http.cookies.SimpleCookie() if hdrs.SET_COOKIE in self.headers: for hdr in self.headers.getall(hdrs.SET_COOKIE): try: self.cookies.load(hdr) except http.cookies.CookieError as exc: client_logger.warning('Can not load response cookies: %s', exc) return self def close(self, force=False): if self._closed: return self._closed = True if hasattr(self._loop, 'is_closed'): if self._loop.is_closed(): return if self._connection is not None: if self.content and not self.content.at_eof(): force = True if force: self._connection.close() else: self._connection.release() if self._reader is not None: self._reader.unset_parser() self._connection = None if self._writer is not None and not self._writer.done(): self._writer.cancel() self._writer = None @asyncio.coroutine def release(self): try: chunk = yield from self.content.readany() while chunk is not EOF_MARKER or chunk: chunk = yield from self.content.readany() finally: self.close() @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None self.close() @asyncio.coroutine def read(self, decode=False): """Read response payload.""" if self._content is None: try: self._content = yield from self.content.read() except: self.close(True) raise else: self.close() data = self._content if decode: warnings.warn('.read(True) is deprecated. use .json() instead', DeprecationWarning) return (yield from self.json()) return data @asyncio.coroutine def read_and_close(self, decode=False): """Read response payload and then close response.""" warnings.warn('read_and_close is deprecated, use .read() instead', DeprecationWarning) return (yield from self.read(decode)) def _get_encoding(self): ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() mtype, stype, _, params = helpers.parse_mimetype(ctype) encoding = params.get('charset') if not encoding: encoding = chardet.detect(self._content)['encoding'] if not encoding: encoding = 'utf-8' return encoding @asyncio.coroutine def text(self, encoding=None): """Read response payload and decode.""" if self._content is None: yield from self.read() if encoding is None: encoding = self._get_encoding() return self._content.decode(encoding) @asyncio.coroutine def json(self, *, encoding=None, loads=json.loads): """Read and decodes JSON response.""" if self._content is None: yield from self.read() ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() if 'json' not in ctype: client_logger.warning( 'Attempt to decode JSON with unexpected mimetype: %s', ctype) if not self._content.strip(): return None if encoding is None: encoding = self._get_encoding() return loads(self._content.decode(encoding))
class ClientResponse: message = None # RawResponseMessage object # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase cookies = None # Response cookies (Set-Cookie) content = None # Payload stream connection = None # current connection flow_control_class = FlowControlStreamReader # reader flow control _reader = None # input stream _response_parser = aiohttp.HttpResponseParser() _connection_wr = None # weakref to self for releasing connection on del _writer_wr = None # weakref to self for cancelling writer on del def __init__(self, method, url, host='', *, writer=None, continue100=None): super().__init__() self.method = method self.url = url self.host = host self.headers = None self._content = None self._writer = writer if writer is not None: self._writer_wr = weakref.ref(self, lambda wr: writer.cancel()) self._continue = continue100 def __repr__(self): out = io.StringIO() print('<ClientResponse({}) [{} {}]>'.format(self.url, self.status, self.reason), file=out) print(self.headers, file=out) return out.getvalue() __str__ = __repr__ def waiting_for_continue(self): return self._continue is not None def _setup_connection(self, connection): self._reader = connection.reader self.connection = connection self.content = self.flow_control_class(connection.reader, loop=connection.loop) msg = ('ClientResponse has to be closed explicitly! {}:{}:{}'.format( self.method, self.host, self.url)) def _do_close_connection(wr, connection=connection, msg=msg): warnings.warn(msg, ResourceWarning) connection.close() self._connection_wr = weakref.ref(self, _do_close_connection) @asyncio.coroutine def start(self, connection, read_until_eof=False): """Start response processing.""" self._setup_connection(connection) while True: httpstream = self._reader.set_parser(self._response_parser) # read response self.message = yield from httpstream.read() if self.message.code != 100: break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = self.message.version self.status = self.message.code self.reason = self.message.reason # headers self.headers = CaseInsensitiveMultiDict( self.message.headers.items(getall=True)) # payload response_with_body = self.method.lower() != 'head' self._reader.set_parser( aiohttp.HttpPayloadParser(self.message, readall=read_until_eof, response_with_body=response_with_body), self.content) # cookies self.cookies = http.cookies.SimpleCookie() if 'SET-COOKIE' in self.headers: for hdr in self.headers.getall('SET-COOKIE'): try: self.cookies.load(hdr) except http.cookies.CookieError as exc: client_logger.warning('Can not load response cookies: %s', exc) connection.share_cookies(self.cookies) return self def close(self, force=False): if self.connection is not None: if self.content and not self.content.at_eof(): force = True if force: self.connection.close() else: self.connection.release() self.connection = None self._connection_wr = None if self._writer is not None and not self._writer.done(): self._writer.cancel() self._writer = None self._writer_wr = None @asyncio.coroutine def release(self): try: chunk = yield from self.content.readany() while chunk is not EOF_MARKER or chunk: chunk = yield from self.content.readany() finally: self.close() @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None self._writer_wr = None self.close() @asyncio.coroutine def read(self, decode=False): """Read response payload.""" if self._content is None: try: self._content = yield from self.content.read() except: self.close(True) raise else: self.close() data = self._content if decode: warnings.warn('.read(True) is deprecated. use .json() instead', DeprecationWarning) return (yield from self.json()) return data @asyncio.coroutine def read_and_close(self, decode=False): """Read response payload and then close response.""" warnings.warn('read_and_close is deprecated, use .read() instead', DeprecationWarning) return (yield from self.read(decode)) def _get_encoding(self, encoding): ctype = self.headers.get('CONTENT-TYPE', '').lower() mtype, stype, _, params = helpers.parse_mimetype(ctype) if not encoding: encoding = params.get('charset') if not encoding and chardet: encoding = chardet.detect(self._content)['encoding'] if not encoding: # pragma: no cover encoding = 'utf-8' return encoding @asyncio.coroutine def text(self, encoding=None): """Read response payload and decode.""" if self._content is None: yield from self.read() return self._content.decode(self._get_encoding(encoding)) @asyncio.coroutine def json(self, *, encoding=None, loads=json.loads): """Reads and decodes JSON response.""" if self._content is None: yield from self.read() ctype = self.headers.get('CONTENT-TYPE', '').lower() if 'json' not in ctype: client_logger.warning( 'Attempt to decode JSON with unexpected mimetype: %s', ctype) if not self._content.strip(): return None return loads(self._content.decode(self._get_encoding(encoding)))
class ClientResponse(HeadersMixin): # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase content = None # Payload stream headers = None # Response headers, CIMultiDictProxy raw_headers = None # Response raw headers, a sequence of pairs _connection = None # current connection flow_control_class = FlowControlStreamReader # reader flow control _reader = None # input stream _response_parser = aiohttp.HttpResponseParser() _source_traceback = None # setted up by ClientRequest after ClientResponse object creation # post-init stage allows to not change ctor signature _loop = None _closed = True # to allow __del__ for non-initialized properly response def __init__(self, method, url, *, writer=None, continue100=None, timer=None): assert isinstance(url, URL) self.method = method self._url_obj = url self._content = None self._writer = writer self._continue = continue100 self._closed = False self._should_close = True # override by message.should_close later self._history = () self._timer = timer if timer is not None else _TimeServiceTimeoutNoop() self.cookies = SimpleCookie() @property def url_obj(self): return self._url_obj @property def url(self): warnings.warn("Deprecated, use .url_obj", DeprecationWarning, stacklevel=2) return str(self._url_obj) @property def host(self): warnings.warn("Deprecated, use .url_obj.host", DeprecationWarning, stacklevel=2) return self._url_obj.host def _post_init(self, loop): self._loop = loop if loop.get_debug(): self._source_traceback = traceback.extract_stack(sys._getframe(1)) def __del__(self, _warnings=warnings): if self._loop is None: return # not started if self._closed: return self.close() _warnings.warn("Unclosed response {!r}".format(self), ResourceWarning) context = {'client_response': self, 'message': 'Unclosed response'} if self._source_traceback: context['source_traceback'] = self._source_traceback self._loop.call_exception_handler(context) def __repr__(self): out = io.StringIO() ascii_encodable_url = str(self.url) if self.reason: ascii_encodable_reason = self.reason.encode('ascii', 'backslashreplace') \ .decode('ascii') else: ascii_encodable_reason = self.reason print('<ClientResponse({}) [{} {}]>'.format(ascii_encodable_url, self.status, ascii_encodable_reason), file=out) print(self.headers, file=out) return out.getvalue() @property def connection(self): return self._connection @property def history(self): """A sequence of of responses, if redirects occurred.""" return self._history @asyncio.coroutine def start(self, connection, read_until_eof=False): """Start response processing.""" self._protocol = connection.protocol self._connection = connection connection.protocol.set_response_params( timer=self._timer, skip_payload=self.method.lower() == 'head', skip_status_codes=(204, 304), read_until_eof=read_until_eof) with self._timer: while True: # read response (message, payload) = yield from self._protocol.read() if (message.code < 100 or message.code > 199 or message.code == 101): break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = message.version self.status = message.code self.reason = message.reason self._should_close = message.should_close # headers self.headers = CIMultiDictProxy(message.headers) self.raw_headers = tuple(message.raw_headers) # payload self.content = payload # cookies for hdr in self.headers.getall(hdrs.SET_COOKIE, ()): try: self.cookies.load(hdr) except CookieError as exc: client_logger.warning('Can not load response cookies: %s', exc) return self def close(self): if self._closed: return self._closed = True if self._loop is None or self._loop.is_closed(): return if self._connection is not None: self._connection.close() self._connection = None self._cleanup_writer() self._notify_content() @asyncio.coroutine def release(self, *, consume=False): if self._closed: return try: content = self.content if content is not None: if consume: while not content.at_eof(): yield from content.readany() else: close = False if content.exception() is not None: close = True else: content.read_nowait() if not content.at_eof(): close = True if close: self.close() except Exception: self._connection.close() self._connection = None raise finally: self._closed = True if self._connection is not None: self._connection.release() self._connection = None self._cleanup_writer() self._notify_content() def raise_for_status(self): if 400 <= self.status: raise aiohttp.HttpProcessingError(code=self.status, message=self.reason) def _cleanup_writer(self): if self._writer is not None and not self._writer.done(): self._writer.cancel() self._writer = None def _notify_content(self): content = self.content if content and content.exception() is None and not content.is_eof(): content.set_exception( aiohttp.ClientDisconnectedError('Connection closed')) @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None yield from self.release() @asyncio.coroutine def read(self): """Read response payload.""" if self._content is None: try: self._content = yield from self.content.read() except: self.close() raise else: yield from self.release() return self._content def _get_encoding(self): ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() mtype, stype, _, params = helpers.parse_mimetype(ctype) encoding = params.get('charset') if not encoding: if mtype == 'application' and stype == 'json': # RFC 7159 states that the default encoding is UTF-8. encoding = 'utf-8' else: encoding = chardet.detect(self._content)['encoding'] if not encoding: encoding = 'utf-8' return encoding @asyncio.coroutine def text(self, encoding=None, errors='strict'): """Read response payload and decode.""" if self._content is None: yield from self.read() if encoding is None: encoding = self._get_encoding() return self._content.decode(encoding, errors=errors) @asyncio.coroutine def json(self, *, encoding=None, loads=json.loads): """Read and decodes JSON response.""" if self._content is None: yield from self.read() ctype = self.headers.get(hdrs.CONTENT_TYPE, '').lower() if 'json' not in ctype: client_logger.warning( 'Attempt to decode JSON with unexpected mimetype: %s', ctype) stripped = self._content.strip() if not stripped: return None if encoding is None: encoding = self._get_encoding() return loads(stripped.decode(encoding)) if PY_35: @asyncio.coroutine def __aenter__(self): return self @asyncio.coroutine def __aexit__(self, exc_type, exc_val, exc_tb): # similar to _RequestContextManager, we do not need to check # for exceptions, response object can closes connection # is state is broken yield from self.release()
class HttpResponse(http.client.HTTPMessage): message = None # RawResponseMessage object # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase cookies = None # Response cookies (Set-Cookie) content = None # Payload stream _reader = None # input stream _connection = None # current connection _response_parser = aiohttp.HttpResponseParser() def __init__(self, method, url, host='', *, writer=None, continue100=None): super().__init__() self.method = method self.url = url self.host = host self._content = None self._writer = writer self._continue = continue100 def __del__(self): if self._connection is not None: logging.warn('HttpResponse has to be closed explicitly! %s:%s:%s', self.method, self.host, self.url) self.close(True) def __repr__(self): out = io.StringIO() print('<HttpResponse({}{}) [{} {}]>'.format( self.host, self.url, self.status, self.reason), file=out) print(super().__str__(), file=out) return out.getvalue() __str__ = __repr__ def waiting_for_continue(self): return self._continue is not None def start(self, connection, read_until_eof=False): """Start response processing.""" self._reader = connection.reader self._connection = connection while True: httpstream = self._reader.set_parser(self._response_parser) # read response self.message = yield from httpstream.read() if self.message.code != 100: break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = self.message.version self.status = self.message.code self.reason = self.message.reason # headers for hdr, val in self.message.headers: self.add_header(hdr, val) # payload self.content = self._reader.set_parser( aiohttp.HttpPayloadParser(self.message, readall=read_until_eof)) # cookies self.cookies = http.cookies.SimpleCookie() if 'Set-Cookie' in self: for hdr in self.get_all('Set-Cookie'): try: self.cookies.load(hdr) except http.cookies.CookieError as exc: logging.warn('Can not load response cookies: %s', exc) return self def close(self, force=False): if self._connection is not None: if force: self._connection.close() else: self._connection.release() self._connection = None if (self._writer is not None) and not self._writer.done(): self._writer.cancel() self._writer = None @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None self.close() @asyncio.coroutine def read(self, decode=False): """Read response payload. Decode known types of content.""" if self._content is None: buf = [] total = 0 try: while True: chunk = yield from self.content.read() size = len(chunk) buf.append((chunk, size)) total += size except aiohttp.EofStream: pass self._content = bytearray(total) idx = 0 content = memoryview(self._content) for chunk, size in buf: content[idx:idx+size] = chunk idx += size data = self._content if decode: ct = self.get('content-type', '').lower() if ct == 'application/json': data = json.loads(data.decode('utf-8')) return data @asyncio.coroutine def read_and_close(self, decode=False): """Read response payload and then close response.""" try: payload = yield from self.read(decode) return payload finally: self.close()
class ClientResponse: message = None # RawResponseMessage object # from the Status-Line of the response version = None # HTTP-Version status = None # Status-Code reason = None # Reason-Phrase cookies = None # Response cookies (Set-Cookie) content = None # Payload stream connection = None # current connection _reader = None # input stream _response_parser = aiohttp.HttpResponseParser() _connection_wr = None # weakref to self for releasing connection on del _writer_wr = None # weakref to self for cancelling writer on del def __init__(self, method, url, host='', *, writer=None, continue100=None): super().__init__() self.method = method self.url = url self.host = host self.headers = None self._content = None self._writer = writer if writer is not None: self._writer_wr = weakref.ref(self, lambda wr: writer.cancel()) self._continue = continue100 def __repr__(self): out = io.StringIO() print('<ClientResponse({}{}) [{} {}]>'.format(self.host, self.url, self.status, self.reason), file=out) print(self.headers, file=out) return out.getvalue() __str__ = __repr__ def waiting_for_continue(self): return self._continue is not None def _setup_connection(self, connection): self._reader = connection.reader self.connection = connection msg = ('ClientResponse has to be closed explicitly! {}:{}:{}'.format( self.method, self.host, self.url)) def _do_close_connection(wr, connection=connection, msg=msg): warnings.warn(msg, ResourceWarning) connection.close() self._connection_wr = weakref.ref(self, _do_close_connection) @asyncio.coroutine def start(self, connection, read_until_eof=False): """Start response processing.""" self._setup_connection(connection) while True: httpstream = self._reader.set_parser(self._response_parser) # read response self.message = yield from httpstream.read() if self.message.code != 100: break if self._continue is not None and not self._continue.done(): self._continue.set_result(True) self._continue = None # response status self.version = self.message.version self.status = self.message.code self.reason = self.message.reason # headers self.headers = CaseInsensitiveMultiDict( self.message.headers.items(getall=True)) # payload self.content = self._reader.set_parser( aiohttp.HttpPayloadParser(self.message, readall=read_until_eof)) # cookies self.cookies = http.cookies.SimpleCookie() if 'SET-COOKIE' in self.headers: for hdr in self.headers.getall('SET-COOKIE'): try: self.cookies.load(hdr) except http.cookies.CookieError as exc: logging.warn('Can not load response cookies: %s', exc) return self def close(self, force=False): if self.connection is not None: if force: self.connection.close() else: self.connection.release() self.connection = None self._connection_wr = None if self._writer is not None and not self._writer.done(): self._writer.cancel() self._writer = None self._writer_wr = None @asyncio.coroutine def wait_for_close(self): if self._writer is not None: try: yield from self._writer finally: self._writer = None self._writer_wr = None self.close() @asyncio.coroutine def read(self, decode=False): """Read response payload. Decode known types of content.""" if self._content is None: buf = [] total = 0 try: while True: chunk = yield from self.content.read() size = len(chunk) buf.append((chunk, size)) total += size except aiohttp.EofStream: pass self._content = bytearray(total) idx = 0 content = memoryview(self._content) for chunk, size in buf: content[idx:idx + size] = chunk idx += size data = self._content if decode: ct = self.headers.get('CONTENT-TYPE', '').lower() if ct == 'application/json': data = json.loads(data.decode('utf-8')) return data @asyncio.coroutine def read_and_close(self, decode=False): """Read response payload and then close response.""" try: payload = yield from self.read(decode) except: self.close(True) raise else: self.close() return payload