]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add a future-based interface to AsyncHTTPClient.fetch.
authorBen Darnell <ben@bendarnell.com>
Mon, 18 Feb 2013 03:46:52 +0000 (22:46 -0500)
committerBen Darnell <ben@bendarnell.com>
Mon, 18 Feb 2013 03:46:52 +0000 (22:46 -0500)
tornado/curl_httpclient.py
tornado/httpclient.py
tornado/simple_httpclient.py
tornado/test/httpclient_test.py

index 73ecfb0e12a38eb95e80e9e5ac275719305afc9b..028c80584e52cc61d9ccfe9f9990493de423b7e7 100644 (file)
@@ -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)
 
index 18e53bd226ac78d716532d4b946a59cf80cc48c2..1b64550493d5359e2fedb8f3bde3d170710f5870 100644 (file)
@@ -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()
index 01f290c2c02a9e155af88c6799028d03a8b0fa22..73739ff4002b44a01b987778b075c68a62eeb574 100644 (file)
@@ -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:
index e04f7c451c128ce71a9cbe084fe6d38f916f1585..039720e2d2a1f4a8c8ed7616c396a1558b5d81fc 100644 (file)
@@ -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):