def init_request_handler(self, rh_cls, view_type): global app if view_type == 'list': rq = rh_cls.as_list() elif view_type == 'detail': rq = rh_cls.as_detail() # compose a fake incoming request fake_connection = None # after tornado 4.1, it's not allowed to build a RequestHandler without a connection. if _newer_or_equal_((4, 0, 0, 0)): ios = IOStream(socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)) context = None # there is a bug in these 2 version that would fail when # context is None if _equal_((4, 0, 1)) or _equal_((4, 0, 2)): context = httpserver._HTTPRequestContext(ios, None, None) fake_connection = HTTP1Connection(ios, False, context=context) fake_request = httpserver.HTTPRequest('GET', '/fake', body='test123', connection=fake_connection) self.new_handler = rq(app, fake_request)
def test_no_connection_reuse_with_connection_close(server, io_stream): '''Sends '/ping' request to the server with 'Connection: Close' and validate that the connection is closed by the server. To check that the server closes the connection, read all the data from the socket. If the server fails to close the socket, the test will hang for the specified async_test's timeout. Args: server: an instance of `Server`. io_stream: an instance of `tornado.iostream.IOStream`. ''' yield io_stream.connect(('localhost', server.opts['port'])) start_line = RequestStartLine(method='GET', path='/ping', version='HTTP/1.1') headers = HTTPHeaders({'Connection': 'Close'}) connection = HTTP1Connection(io_stream, is_client=True) yield connection.write_headers(start_line, headers) connection.finish() response = PingResponseHandler() yield connection.read_response(response) assert response.start_line.code == requests.codes.ok # read all remaining data from the connection and validate it (there should be no data) remaining_data = yield io_stream.read_until_close() assert len(remaining_data) == 0
def test_http10_no_content_length(self): # Regression test for a bug in which can_keep_alive would crash # for an HTTP/1.0 (not 1.1) response with no content-length. conn = HTTP1Connection(self.client_stream, True) self.server_stream.write(b"HTTP/1.0 200 Not Modified\r\n\r\nhello") self.server_stream.close() event = Event() test = self body = [] class Delegate(HTTPMessageDelegate): def headers_received(self, start_line, headers): test.code = start_line.code def data_received(self, data): body.append(data) def finish(self): event.set() yield conn.read_response(Delegate()) yield event.wait() self.assertEqual(self.code, 200) self.assertEqual(b''.join(body), b'hello')
def test_connection_reuse_for_HTTP_1_1(server, io_stream, num_requests): '''Sends multiple '/ping' requests to the server using the same connection. The ok handler that just responds with 200 is used for serving requests. Keep-Alive is assumed by default for each request as it's HTTP/1.1. Args: server: an instance of `Server`. io_stream: an instance of `tornado.iostream.IOStream` that is used for consecutive requests. ''' yield io_stream.connect(('localhost', server.opts['port'])) # common request start line and headers for all ping requests start_line = RequestStartLine(method='GET', path='/ping', version='HTTP/1.1') headers = HTTPHeaders() for request in range(num_requests): connection = HTTP1Connection(io_stream, is_client=True) yield connection.write_headers(start_line, headers) connection.finish() response = PingResponseHandler() yield connection.read_response(response) assert response.start_line.code == requests.codes.ok
async def main(stream): print(stream) chunks = [] class Delegate(HTTPMessageDelegate): def headers_received(self, start_line, headers): self.headers = headers self.start_line = start_line print('headers_received') def data_received(self, chunk): chunks.append(chunk) print('data_received') def finish(self): conn.detach() # type: ignore print('finish') stream = IOStream(stream) #print('ideme connect') #await stream.connect(("example.com", 80)) print('await stream.connect(("example.com", 80))') await stream.write(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n") print('await stream.write(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")') conn = HTTP1Connection(stream, True) delegate = Delegate() await conn.read_response(delegate) print(delegate.start_line, delegate.headers, b"".join(chunks))
def _create_connection(self, stream): stream.set_nodelay(True) connection = HTTP1Connection( stream, True, HTTP1ConnectionParameters( no_keep_alive=True, max_header_size=self.max_header_size, decompress=self.request.decompress_response), self._sockaddr) return connection
def http_connection(request, io_stream): '''Create an instance of the `tornado.http1connection.HTTP1Connection`. `io_stream` fixture will be used for the connection. ''' opts = request.node.get_marker('http_connection_options') opts = opts.kwargs if opts else {} params = HTTP1ConnectionParameters(**opts) return HTTP1Connection( io_stream, is_client=True, params=params, )
def read_stream_body(stream, callback): """Reads an HTTP response from `stream` and runs callback with its headers and body.""" chunks = [] class Delegate(HTTPMessageDelegate): def headers_received(self, start_line, headers): self.headers = headers def data_received(self, chunk): chunks.append(chunk) def finish(self): callback((self.headers, b''.join(chunks))) conn = HTTP1Connection(stream, True) conn.read_response(Delegate())
def handle_stream(self, ssl_stream, address): try: yield ssl_stream.wait_for_handshake() except SSLErrorHTTPRequest: stream = IOStream(ssl_stream.socket._sock) conn = HTTP1Connection(stream, is_client=False) try: yield self.handle_http_connection(conn) except Exception: logger.exception("Failed to process HTTP request:") finally: stream.close() except StreamClosedError: logger.debug("Stream closed by client during handshake. Skipping.") return else: super(AutoHTTPSServer, self).handle_stream(ssl_stream, address)
async def read_stream_body(stream): """Reads an HTTP response from `stream` and returns a tuple of its start_line, headers and body.""" chunks = [] class Delegate(HTTPMessageDelegate): def headers_received(self, start_line, headers): self.headers = headers self.start_line = start_line def data_received(self, chunk): chunks.append(chunk) def finish(self): conn.detach() # type: ignore conn = HTTP1Connection(stream, True) delegate = Delegate() await conn.read_response(delegate) return delegate.start_line, delegate.headers, b"".join(chunks)
def handle_stream(self, ssl_stream, address): try: yield ssl_stream.wait_for_handshake() except SSLErrorHTTPRequest: stream = make_iostream(ssl_stream) conn = HTTP1Connection(stream, is_client=False) try: yield self.handle_http_connection(conn) except Exception: logger.exception("Failed to process HTTP request:") finally: stream.close() except ssl.SSLError as e: logger.error("SSLError: %s", e) except (OSError, StreamClosedError) as e: logger.debug("Error during SSL handshake: %s %s", e.__class__.__name__, getattr(e, "strerror", str(e))) logger.debug("Stream closed by client during handshake. Skipping.") return else: super(AutoHTTPSServer, self).handle_stream(ssl_stream, address)
def setUp(self): super(TestWebSocketBase, self).setUp() self.application = Application() self.server = HTTPServer(self.application) self.socket, self.port = testing.bind_unused_port() self.server.add_socket(self.socket) self.instance = WebSocketBase( self.application, HTTPServerRequest( method="GET", uri='/', version="HTTP/1.0", headers=HTTPHeaders(), body=BytesIO(), host=None, files=None, connection=HTTP1Connection(stream=IOStream(socket.socket()), is_client=False), start_line=RequestStartLine(method='GET', path='/', version='HTTP/1.1'), )) self.instance.open()
async def read_stream_body(stream): """Reads an HTTP response from `stream` and returns a tuple of its start_line, headers and body.""" chunks = [] class Delegate(HTTPMessageDelegate): def headers_received(self, start_line, headers): self.headers = headers self.start_line = start_line print('headers_received') def data_received(self, chunk): chunks.append(chunk) print('data_received') def finish(self): conn.detach() # type: ignore print('finish') conn = HTTP1Connection(stream, True) print('conn = HTTP1Connection(stream, True)') delegate = Delegate() print('delegate = Delegate()')
def __init__(self, host, port): self._sock = socket() self._sock.connect((host, port)) self._stream = IOStream(self._sock) self._connection = HTTP1Connection(self._stream, True)
def __init__(self, stream, params=None): HTTP1Connection.__init__(self, stream, True, params)
def __init__(self, stream): self.stream = stream self.connection = HTTP1Connection(stream, is_client=True) self.response_start_line = None self.response_headers = None
def _on_connect(self, stream): if self.final_callback is None: # final_callback is cleared if we've hit our timeout. stream.close() return self.stream = stream self.stream.set_close_callback(self._on_close) self._remove_timeout() if self.final_callback is None: return if self.request.request_timeout: self._timeout = self.io_loop.add_timeout( self.start_time + self.request.request_timeout, stack_context.wrap(self._on_timeout)) if (self.request.method not in self._SUPPORTED_METHODS and not self.request.allow_nonstandard_methods): raise KeyError("unknown method %s" % self.request.method) for key in ('network_interface', 'proxy_host', 'proxy_port', 'proxy_username', 'proxy_password'): if getattr(self.request, key, None): raise NotImplementedError('%s not supported' % key) if "Connection" not in self.request.headers: self.request.headers["Connection"] = "close" if "Host" not in self.request.headers: if '@' in self.parsed.netloc: self.request.headers["Host"] = self.parsed.netloc.rpartition( '@')[-1] else: self.request.headers["Host"] = self.parsed.netloc username, password = None, None if self.parsed.username is not None: username, password = self.parsed.username, self.parsed.password elif self.request.auth_username is not None: username = self.request.auth_username password = self.request.auth_password or '' if username is not None: if self.request.auth_mode not in (None, "basic"): raise ValueError("unsupported auth_mode %s", self.request.auth_mode) auth = utf8(username) + b":" + utf8(password) self.request.headers["Authorization"] = (b"Basic " + base64.b64encode(auth)) if self.request.user_agent: self.request.headers["User-Agent"] = self.request.user_agent if not self.request.allow_nonstandard_methods: if self.request.method in ("POST", "PATCH", "PUT"): if (self.request.body is None and self.request.body_producer is None): raise AssertionError( 'Body must not be empty for "%s" request' % self.request.method) else: if (self.request.body is not None or self.request.body_producer is not None): raise AssertionError( 'Body must be empty for "%s" request' % self.request.method) if self.request.expect_100_continue: self.request.headers["Expect"] = "100-continue" if self.request.body is not None: # When body_producer is used the caller is responsible for # setting Content-Length (or else chunked encoding will be used). self.request.headers["Content-Length"] = str(len( self.request.body)) if (self.request.method == "POST" and "Content-Type" not in self.request.headers): self.request.headers[ "Content-Type"] = "application/x-www-form-urlencoded" if self.request.decompress_response: self.request.headers["Accept-Encoding"] = "gzip" req_path = ((self.parsed.path or '/') + (('?' + self.parsed.query) if self.parsed.query else '')) self.stream.set_nodelay(True) self.connection = HTTP1Connection( self.stream, True, HTTP1ConnectionParameters( no_keep_alive=True, max_header_size=self.max_header_size, decompress=self.request.decompress_response), self._sockaddr) start_line = httputil.RequestStartLine(self.request.method, req_path, 'HTTP/1.1') self.connection.write_headers(start_line, self.request.headers) if self.request.expect_100_continue: self._read_response() else: self._write_body(True)
def create_qactuar_handler(self, scope: Scope) -> RequestHandler: # noinspection PyAbstractClass,PyMethodParameters class QactuarHandler(self.handler_type): # type: ignore def __init__( inner_self, tornado_application: Application, tornado_request: HTTPServerRequest, logger: Logger, **kwargs: Dict[Any, Any], ) -> None: super().__init__(tornado_application, tornado_request, **kwargs) inner_self._qactuar_body: List[bytes] = [] inner_self._qactuar_headers: Headers = [] inner_self._logger = logger def write(inner_self, chunk: Union[str, bytes, dict]) -> None: super().write(chunk) inner_self._qactuar_body.append(to_bytes(chunk)) def add_header(inner_self, name: str, value: _HeaderTypes) -> None: super().add_header(name, value) inner_self._qactuar_headers.append( (to_bytes(name), to_bytes(value))) def set_header(inner_self, name: str, value: _HeaderTypes) -> None: super().set_header(name, value) inner_self._qactuar_headers.append( (to_bytes(name), to_bytes(value))) if self.request_message and "body" in self.request_message: body = self.request_message["body"] else: body = b"" if self.request_message and "headers" in self.request_message: headers = scope["headers"] else: headers = [] headers = HTTPHeaders({ header[0].decode("utf-8"): header[1].decode("utf-8") for header in headers }) request_start_line = RequestStartLine(scope["method"], scope["path"], scope["http_version"]) # noinspection PyTypeChecker http_connection = HTTP1Connection(QactuarStream(), False) http_connection._request_start_line = request_start_line http_connection._request_headers = headers request = HTTPServerRequest( method=scope["method"], uri=scope["path"], version=scope["http_version"], headers=headers, body=body, host=scope["server"][0], connection=http_connection, start_line=request_start_line, ) handler = QactuarHandler(Application(), request, self.child_log) handler._transforms = [] handler.application.transforms = [] return handler