def read_stream_body(self, delegate, chunk_size=1, stream_callback=None): _delegate, delegate = self._parse_delegate(delegate) remain_content = False need_delegate_close = True if not _delegate.skip_body: try: body_future = self._read_stream_body(chunk_size, delegate) if body_future is not None: remain_content = yield body_future need_delegate_close = False if not remain_content: self._read_finished = True if (not self._finish_future.done() and self.stream is not None and not self.stream.closed()): self.stream.set_close_callback( self._on_connection_close) yield self._finish_future if self._disconnect_on_finish: self.close() except HTTPInputError as e: gen_log.info("Malformed HTTP message from %s: %s", self.context, e) self.close() remain_content = False finally: if need_delegate_close: with _ExceptionLoggingContext(app_log): delegate.on_connection_close(self.stream.error) if not remain_content: self._clear_callbacks() raise gen.Return(remain_content)
def request_received(self, event, delegate, data): self.event = event self.stream_id = event.stream_id log.debug("_request_received: {}".format(self.stream_id)) if event.headers: with _ExceptionLoggingContext(app_log): hd = {k: v for k, v in event.headers} start_line = httputil.RequestStartLine( method=hd[':method'], path=hd[':path'], version='HTTP/2.0') header_future = delegate.headers_received( start_line, httputil.HTTPHeaders(hd) ) if header_future is not None: yield header_future delegate.data_received(data) with _ExceptionLoggingContext(app_log): delegate.finish() raise gen.Return(True)
def read_headers(self, delegate): try: _delegate, delegate = self._parse_delegate(delegate) header_future = self.stream.read_until_regex( b"\r?\n\r?\n", max_bytes=self.params.max_header_size) header_data = yield header_future start_line, headers = self._parse_headers(header_data) start_line = parse_response_start_line(start_line) self._response_start_line = start_line self._disconnect_on_finish = not self._can_keep_alive( start_line, headers) with _ExceptionLoggingContext(app_log): header_future = delegate.headers_received(start_line, headers) if header_future is not None: yield header_future if self.stream is None: # We've been detached. raise gen.Return(False) # determine body skip #TODO: 100 <= code < 200 if (self._request_start_line is not None and self._request_start_line.method == 'HEAD'): _delegate.skip_body = True code = start_line.code if code == 304: # 304 responses may include the content-length header # but do not actually have a body. # http://tools.ietf.org/html/rfc7230#section-3.3 _delegate.skip_body = True if code >= 100 and code < 200: # 1xx responses should never indicate the presence of # a body. if ('Content-Length' in headers or 'Transfer-Encoding' in headers): raise HTTPInputError("Response code %d cannot have body" % code) # TODO: client delegates will get headers_received twice # in the case of a 100-continue. Document or change? yield self.read_headers(delegate) except HTTPInputError as e: gen_log.info("Malformed HTTP message from %s: %s", self.context, e) self.close() self._clear_callbacks() raise gen.Return(False) finally: header_future = None raise gen.Return(True)
def read_body(self, delegate): _delegate, delegate = self._parse_delegate(delegate) need_delegate_close = True if not _delegate.skip_body: try: body_future = self._read_body(_delegate.code, _delegate.headers, delegate) if body_future is not None: if self._body_timeout is None: yield body_future else: try: yield gen.with_timeout( self.stream.io_loop.time() + self._body_timeout, body_future, quiet_exceptions=StreamClosedError) except gen.TimeoutError: gen_log.info("Timeout reading body from %s", self.context) self.stream.close() raise gen.Return(False) self._read_finished = True need_delegate_close = False # If we're waiting for the application to produce an asynchronous # response, and we're not detached, register a close callback # on the stream (we didn't need one while we were reading) if (not self._finish_future.done() and self.stream is not None and not self.stream.closed()): self.stream.set_close_callback(self._on_connection_close) yield self._finish_future if self._disconnect_on_finish: self.close() if self.stream is None: raise gen.Return(False) except HTTPInputError as e: gen_log.info("Malformed HTTP message from %s: %s", self.context, e) self.close() raise gen.Return(False) finally: if need_delegate_close: with _ExceptionLoggingContext(app_log): delegate.on_connection_close(self.stream.error) self._clear_callbacks() raise gen.Return(True)
def _read_stream_body(self, content_length, delegate): while 0 < content_length: try: body = yield self.stream.read_bytes( min(self.params.chunk_size, content_length), partial=True) except StreamClosedError: # with partial stream will update close status after receiving # the last chunk, so we catch StreamClosedError instead raise gen.Return(False) content_length -= len(body) if not self._write_finished or self.is_client: with _ExceptionLoggingContext(app_log): ret = delegate.data_received(body) if ret is not None: yield ret raise gen.Return(True)
def _read_message(self, delegate): try: while True: message_future = self.stream.read_until(b"\r\n") if self.timeout is None: message_data = yield message_future else: try: message_data = yield gen.with_timeout( self.stream.io_loop.time() + self.timeout, message_future, io_loop=self.stream.io_loop, quiet_exceptions=iostream.StreamClosedError) except gen.TimeoutError: self.close() raise gen.Return(False) with _ExceptionLoggingContext(app_log): data = delegate.data_received(message_data) self.stream.write(data) finally: self._clear_callbacks()
def _read_body_until_close(self, delegate): body = yield self.stream.read_until_close() self._read_finished = True if not self._write_finished or self.is_client: with _ExceptionLoggingContext(app_log): delegate.data_received(body)
def _read_message(self, delegate): need_delegate_close = False try: '''header_future = self.stream.read_until_regex( "\x00", max_bytes=3) if self.params.header_timeout is None: header_data = yield header_future else: try: header_data = yield gen.with_timeout( self.stream.io_loop.time() + self.params.header_timeout, header_future, io_loop=self.stream.io_loop, quiet_exceptions=iostream.StreamClosedError) except gen.TimeoutError: self.close() raise gen.Return(False)''' """start_line, headers = self._parse_headers(header_data) if self.is_client: start_line = httputil.parse_response_start_line(start_line) self._response_start_line = start_line else: start_line = httputil.parse_request_start_line(start_line) self._request_start_line = start_line self._request_headers = headers self._disconnect_on_finish = not self._can_keep_alive( start_line, headers) """ yield self._read_body_until_close(delegate) need_delegate_close = True '''with _ExceptionLoggingContext(app_log): header_future = delegate.headers_received(start_line, headers) if header_future is not None: yield header_future if self.stream is None: # We've been detached. need_delegate_close = False raise gen.Return(False) skip_body = False if self.is_client: if (self._request_start_line is not None and self._request_start_line.method == 'HEAD'): skip_body = True code = start_line.code if code == 304: # 304 responses may include the content-length header # but do not actually have a body. # http://tools.ietf.org/html/rfc7230#section-3.3 skip_body = True if code >= 100 and code < 200: # 1xx responses should never indicate the presence of # a body. if ('Content-Length' in headers or 'Transfer-Encoding' in headers): raise httputil.HTTPInputError( "Response code %d cannot have body" % code) # TODO: client delegates will get headers_received twice # in the case of a 100-continue. Document or change? yield self._read_message(delegate) else: if (headers.get("Expect") == "100-continue" and not self._write_finished): self.stream.write(b"HTTP/1.1 100 (Continue)\r\n\r\n") if not skip_body: body_future = self._read_body( start_line.code if self.is_client else 0, headers, delegate) if body_future is not None: if self._body_timeout is None: yield body_future else: try: yield gen.with_timeout( self.stream.io_loop.time() + self._body_timeout, body_future, self.stream.io_loop, quiet_exceptions=iostream.StreamClosedError) except gen.TimeoutError: gen_log.info("Timeout reading body from %s", self.context) self.stream.close() raise gen.Return(False)''' #self._read_finished = True if not self._write_finished or self.is_client: need_delegate_close = False with _ExceptionLoggingContext(app_log): delegate.finish() # If we're waiting for the application to produce an asynchronous # response, and we're not detached, register a close callback # on the stream (we didn't need one while we were reading) if (not self._finish_future.done() and self.stream is not None and not self.stream.closed()): self.stream.set_close_callback(self._on_connection_close) yield self._finish_future if self.is_client and self._disconnect_on_finish: self.close() if self.stream is None: raise gen.Return(False) except httputil.HTTPInputError as e: gen_log.info("Malformed HTTP message from %s: %s", self.context, e) self.close() raise gen.Return(False) finally: if need_delegate_close: with _ExceptionLoggingContext(app_log): delegate.on_connection_close() self._clear_callbacks() raise gen.Return(True)