Beispiel #1
0
    def fetch(
        self,
        request: Union[str, "HTTPRequest"],
        raise_error: bool = True,
        **kwargs: Any
    ) -> Awaitable["HTTPResponse"]:
        """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.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed. Use the returned
           `.Future` instead.

           The ``raise_error=False`` argument only affects the
           `HTTPError` raised when a non-200 response code is used,
           instead of suppressing all errors.
        """
        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_proxy = _RequestProxy(request, self.defaults)
        future = Future()  # type: Future[HTTPResponse]

        def handle_response(response: "HTTPResponse") -> None:
            if response.error:
                if raise_error or not response._error_is_response_code:
                    future_set_exception_unless_cancelled(future, response.error)
                    return
            future_set_result_unless_cancelled(future, response)

        self.fetch_impl(cast(HTTPRequest, request_proxy), handle_response)
        return future
Beispiel #2
0
    def _process_queue(self) -> None:
        while True:
            started = 0
            while self._free_list and self._requests:
                started += 1
                curl = self._free_list.pop()
                (request, callback,
                 queue_start_time) = self._requests.popleft()
                # TODO: Don't smuggle extra data on an attribute of the Curl object.
                curl.info = {  # type: ignore
                    "headers": httputil.HTTPHeaders(),
                    "buffer": BytesIO(),
                    "request": request,
                    "callback": callback,
                    "queue_start_time": queue_start_time,
                    "curl_start_time": time.time(),
                    "curl_start_ioloop_time": self.io_loop.current().time(),
                }
                try:
                    self._curl_setup_request(
                        curl,
                        request,
                        curl.info["buffer"],  # type: ignore
                        curl.info["headers"],  # type: ignore
                    )
                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
Beispiel #3
0
 def __init__(
     self,
     request: HTTPRequest,
     code: int,
     headers: Optional[httputil.HTTPHeaders] = None,
     buffer: Optional[BytesIO] = None,
     effective_url: Optional[str] = None,
     error: Optional[BaseException] = None,
     request_time: Optional[float] = None,
     time_info: Optional[Dict[str, float]] = None,
     reason: Optional[str] = None,
     start_time: Optional[float] = None,
 ) -> 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  # type: Optional[bytes]
     if effective_url is None:
         self.effective_url = request.url
     else:
         self.effective_url = effective_url
     self._error_is_response_code = False
     if error is None:
         if self.code < 200 or self.code >= 300:
             self._error_is_response_code = True
             self.error = HTTPError(self.code, message=self.reason, response=self)
         else:
             self.error = None
     else:
         self.error = error
     self.start_time = start_time
     self.request_time = request_time
     self.time_info = time_info or {}
Beispiel #4
0
 def finish(self) -> None:
     self.connection.write_headers(
         httputil.ResponseStartLine("HTTP/1.1", 404, "Not Found"),
         httputil.HTTPHeaders(),
     )
     self.connection.finish()
Beispiel #5
0
 def headers(self, value: Union[Dict[str, str], httputil.HTTPHeaders]) -> None:
     if value is None:
         self._headers = httputil.HTTPHeaders()
     else:
         self._headers = value  # type: ignore