From: Ben Darnell Date: Mon, 18 Feb 2013 03:46:52 +0000 (-0500) Subject: Add a future-based interface to AsyncHTTPClient.fetch. X-Git-Tag: v3.0.0~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ba5cdccd607035b97bb337a1ee8b03f15ce4c53;p=thirdparty%2Ftornado.git Add a future-based interface to AsyncHTTPClient.fetch. --- diff --git a/tornado/curl_httpclient.py b/tornado/curl_httpclient.py index 73ecfb0e1..028c80584 100644 --- a/tornado/curl_httpclient.py +++ b/tornado/curl_httpclient.py @@ -88,7 +88,7 @@ class CurlAsyncHTTPClient(AsyncHTTPClient): super(CurlAsyncHTTPClient, self).close() def fetch_impl(self, request, callback): - self._requests.append((request, stack_context.wrap(callback))) + self._requests.append((request, callback)) self._process_queue() self._set_timeout(0) diff --git a/tornado/httpclient.py b/tornado/httpclient.py index 18e53bd22..1b6455049 100644 --- a/tornado/httpclient.py +++ b/tornado/httpclient.py @@ -34,6 +34,7 @@ from __future__ import absolute_import, division, print_function, with_statement import time import weakref +from tornado.concurrent import Future from tornado.escape import utf8 from tornado import httputil, stack_context from tornado.ioloop import IOLoop @@ -159,7 +160,7 @@ class AsyncHTTPClient(Configurable): if self._async_clients().get(self.io_loop) is self: del self._async_clients()[self.io_loop] - def fetch(self, request, callback, **kwargs): + def fetch(self, request, callback=None, **kwargs): """Executes a request, calling callback with an `HTTPResponse`. The request may be either a string URL or an `HTTPRequest` object. @@ -178,7 +179,28 @@ class AsyncHTTPClient(Configurable): # where normal dicts get converted to HTTPHeaders objects. request.headers = httputil.HTTPHeaders(request.headers) request = _RequestProxy(request, self.defaults) - self.fetch_impl(request, callback) + future = Future() + 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 response.error: + future.set_exception(response.error) + else: + future.set_result(response) + self.fetch_impl(request, handle_response) + return future def fetch_impl(self, request, callback): raise NotImplementedError() diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index 01f290c2c..73739ff40 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -78,7 +78,6 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient): self.resolver = OverrideResolver(self.resolver, hostname_mapping) def fetch_impl(self, request, callback): - callback = stack_context.wrap(callback) self.queue.append((request, callback)) self._process_queue() if self.queue: diff --git a/tornado/test/httpclient_test.py b/tornado/test/httpclient_test.py index e04f7c451..039720e2d 100644 --- a/tornado/test/httpclient_test.py +++ b/tornado/test/httpclient_test.py @@ -9,11 +9,11 @@ import functools import sys from tornado.escape import utf8 -from tornado.httpclient import HTTPRequest, HTTPResponse, _RequestProxy +from tornado.httpclient import HTTPRequest, HTTPResponse, _RequestProxy, HTTPError from tornado.iostream import IOStream from tornado import netutil from tornado.stack_context import ExceptionStackContext, NullContext -from tornado.testing import AsyncHTTPTestCase, bind_unused_port +from tornado.testing import AsyncHTTPTestCase, bind_unused_port, gen_test from tornado.test.util import unittest from tornado.util import u, bytes_type from tornado.web import Application, RequestHandler, url @@ -316,6 +316,19 @@ Transfer-Encoding: chunked self.wait() self.assertEqual(exc_info[0][0], ZeroDivisionError) + @gen_test + def test_future_interface(self): + response = yield self.http_client.fetch(self.get_url('/hello')) + self.assertEqual(response.body, b'Hello world!') + + @gen_test + def test_future_http_error(self): + try: + yield self.http_client.fetch(self.get_url('/notfound')) + except HTTPError as e: + self.assertEqual(e.code, 404) + self.assertEqual(e.response.code, 404) + class RequestProxyTest(unittest.TestCase): def test_request_set(self):