示例#1
0
 def __init__(self, request, code, headers=None, buffer=None,
              effective_url=None, error=None, request_time=None,
              time_info=None, reason=None):
     if isinstance(request, _RequestProxy):
         self.request = request.request
     else:
         self.request = request
     self.code = code
     self.reason = reason or httputil.responses.get(code, "Unknown")
     if headers is not None:
         self.headers = headers
     else:
         self.headers = httputil.HTTPHeaders()
     self.buffer = buffer
     self._body = None
     if effective_url is None:
         self.effective_url = request.url
     else:
         self.effective_url = effective_url
     if error is None:
         if self.code < 200 or self.code >= 300:
             self.error = HTTPError(self.code, message=self.reason,
                                    response=self)
         else:
             self.error = None
     else:
         self.error = error
     self.request_time = request_time
     self.time_info = time_info or {}
示例#2
0
    def fetch(self, request, callback=None, raise_error=True, **kwargs):
        """Executes a request, asynchronously returning an `HTTPResponse`.

        The request may be either a string URL or an `HTTPRequest` object.
        If it is a string, we construct an `HTTPRequest` using any additional
        kwargs: ``HTTPRequest(request, **kwargs)``

        This method returns a `.Future` whose result is an
        `HTTPResponse`. By default, the ``Future`` will raise an
        `HTTPError` if the request returned a non-200 response code
        (other errors may also be raised if the server could not be
        contacted). Instead, if ``raise_error`` is set to False, the
        response will always be returned regardless of the response
        code.

        If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
        In the callback interface, `HTTPError` is not automatically raised.
        Instead, you must check the response's ``error`` attribute or
        call its `~HTTPResponse.rethrow` method.
        """
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        else:
            if kwargs:
                raise ValueError("kwargs can't be used if request is an HTTPRequest object")
        # We may modify this (to add Host, Accept-Encoding, etc),
        # so make sure we don't modify the caller's object.  This is also
        # where normal dicts get converted to HTTPHeaders objects.
        request.headers = httputil.HTTPHeaders(request.headers)
        request = _RequestProxy(request, self.defaults)
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                exc = future.exception()
                if isinstance(exc, HTTPError) and exc.response is not None:
                    response = exc.response
                elif exc is not None:
                    response = HTTPResponse(
                        request, 599, error=exc,
                        request_time=time.time() - request.start_time)
                else:
                    response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        def handle_response(response):
            if raise_error and response.error:
                future.set_exception(response.error)
            else:
                future.set_result(response)
        self.fetch_impl(request, handle_response)
        return future
示例#3
0
def websocket_connect(url,
                      io_loop=None,
                      callback=None,
                      connect_timeout=None,
                      on_message_callback=None,
                      compression_options=None):
    """Client-side websocket support.

    Takes a url and returns a Future whose result is a
    `WebSocketClientConnection`.

    ``compression_options`` is interpreted in the same way as the
    return value of `.WebSocketHandler.get_compression_options`.

    The connection supports two styles of operation. In the coroutine
    style, the application typically calls
    `~.WebSocketClientConnection.read_message` in a loop::

        conn = yield websocket_connect(url)
        while True:
            msg = yield conn.read_message()
            if msg is None: break
            # Do something with msg

    In the callback style, pass an ``on_message_callback`` to
    ``websocket_connect``. In both styles, a message of ``None``
    indicates that the connection has been closed.

    .. versionchanged:: 3.2
       Also accepts ``HTTPRequest`` objects in place of urls.

    .. versionchanged:: 4.1
       Added ``compression_options`` and ``on_message_callback``.
       The ``io_loop`` argument is deprecated.
    """
    if io_loop is None:
        io_loop = IOLoop.current()
    if isinstance(url, httpclient.HTTPRequest):
        assert connect_timeout is None
        request = url
        # Copy and convert the headers dict/object (see comments in
        # AsyncHTTPClient.fetch)
        request.headers = httputil.HTTPHeaders(request.headers)
    else:
        request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout)
    request = httpclient._RequestProxy(request,
                                       httpclient.HTTPRequest._DEFAULTS)
    conn = WebSocketClientConnection(io_loop,
                                     request,
                                     on_message_callback=on_message_callback,
                                     compression_options=compression_options)
    if callback is not None:
        io_loop.add_future(conn.connect_future, callback)
    return conn.connect_future
示例#4
0
    def __call__(self, request):
        data = {}
        response = []

        def start_response(status, response_headers, exc_info=None):
            data["status"] = status
            data["headers"] = response_headers
            return response.append

        app_response = self.wsgi_application(WSGIContainer.environ(request),
                                             start_response)
        try:
            response.extend(app_response)
            body = b"".join(response)
        finally:
            if hasattr(app_response, "close"):
                app_response.close()
        if not data:
            raise Exception("WSGI app did not call start_response")

        status_code, reason = data["status"].split(' ', 1)
        status_code = int(status_code)
        headers = data["headers"]
        header_set = set(k.lower() for (k, v) in headers)
        body = escape.utf8(body)
        if status_code != 304:
            if "content-length" not in header_set:
                headers.append(("Content-Length", str(len(body))))
            if "content-type" not in header_set:
                headers.append(("Content-Type", "text/html; charset=UTF-8"))
        if "server" not in header_set:
            headers.append(
                ("Server", "TornadoServer/%s" % censiotornado.version))

        start_line = httputil.ResponseStartLine("HTTP/1.1", status_code,
                                                reason)
        header_obj = httputil.HTTPHeaders()
        for key, value in headers:
            header_obj.add(key, value)
        request.connection.write_headers(start_line, header_obj, chunk=body)
        request.connection.finish()
        self._log(status_code, request)
示例#5
0
 def __call__(self, environ, start_response):
     method = environ["REQUEST_METHOD"]
     uri = urllib_parse.quote(from_wsgi_str(environ.get("SCRIPT_NAME", "")))
     uri += urllib_parse.quote(from_wsgi_str(environ.get("PATH_INFO", "")))
     if environ.get("QUERY_STRING"):
         uri += "?" + environ["QUERY_STRING"]
     headers = httputil.HTTPHeaders()
     if environ.get("CONTENT_TYPE"):
         headers["Content-Type"] = environ["CONTENT_TYPE"]
     if environ.get("CONTENT_LENGTH"):
         headers["Content-Length"] = environ["CONTENT_LENGTH"]
     for key in environ:
         if key.startswith("HTTP_"):
             headers[key[5:].replace("_", "-")] = environ[key]
     if headers.get("Content-Length"):
         body = environ["wsgi.input"].read(int(headers["Content-Length"]))
     else:
         body = b""
     protocol = environ["wsgi.url_scheme"]
     remote_ip = environ.get("REMOTE_ADDR", "")
     if environ.get("HTTP_HOST"):
         host = environ["HTTP_HOST"]
     else:
         host = environ["SERVER_NAME"]
     connection = _WSGIConnection(method, start_response,
                                  _WSGIRequestContext(remote_ip, protocol))
     request = httputil.HTTPServerRequest(method,
                                          uri,
                                          "HTTP/1.1",
                                          headers=headers,
                                          body=body,
                                          host=host,
                                          connection=connection)
     request._parse_body()
     self.application(request)
     if connection._error:
         raise connection._error
     if not connection._finished:
         raise Exception("request did not finish synchronously")
     return connection._write_buffer
示例#6
0
    def _process_queue(self):
        with stack_context.NullContext():
            while True:
                started = 0
                while self._free_list and self._requests:
                    started += 1
                    curl = self._free_list.pop()
                    (request, callback) = self._requests.popleft()
                    curl.info = {
                        "headers": httputil.HTTPHeaders(),
                        "buffer": BytesIO(),
                        "request": request,
                        "callback": callback,
                        "curl_start_time": time.time(),
                    }
                    try:
                        self._curl_setup_request(curl, request,
                                                 curl.info["buffer"],
                                                 curl.info["headers"])
                    except Exception as e:
                        # If there was an error in setup, pass it on
                        # to the callback. Note that allowing the
                        # error to escape here will appear to work
                        # most of the time since we are still in the
                        # caller's original stack frame, but when
                        # _process_queue() is called from
                        # _finish_pending_requests the exceptions have
                        # nowhere to go.
                        self._free_list.append(curl)
                        callback(
                            HTTPResponse(request=request, code=599, error=e))
                    else:
                        self._multi.add_handle(curl)

                if not started:
                    break
示例#7
0
 def headers(self, value):
     if value is None:
         self._headers = httputil.HTTPHeaders()
     else:
         self._headers = value