From: Ben Darnell Date: Sun, 21 Aug 2011 22:53:00 +0000 (-0700) Subject: When following redirects, release connection resources immediately X-Git-Tag: v2.1.0~39^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=437274accb45b327c50002a9198ba3a4c5967aac;p=thirdparty%2Ftornado.git When following redirects, release connection resources immediately --- diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index c0d76aa66..e1a9ce405 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -110,13 +110,12 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient): key = object() self.active[key] = (request, callback) _HTTPConnection(self.io_loop, self, request, - functools.partial(self._on_fetch_complete, - key, callback), + functools.partial(self._release_fetch, key), + callback, self.max_buffer_size) - def _on_fetch_complete(self, key, callback, response): + def _release_fetch(self, key): del self.active[key] - callback(response) self._process_queue() @@ -124,12 +123,14 @@ class SimpleAsyncHTTPClient(AsyncHTTPClient): class _HTTPConnection(object): _SUPPORTED_METHODS = set(["GET", "HEAD", "POST", "PUT", "DELETE"]) - def __init__(self, io_loop, client, request, callback, max_buffer_size): + def __init__(self, io_loop, client, request, release_callback, + final_callback, max_buffer_size): self.start_time = time.time() self.io_loop = io_loop self.client = client self.request = request - self.callback = callback + self.release_callback = release_callback + self.final_callback = final_callback self.code = None self.headers = None self.chunks = None @@ -269,11 +270,18 @@ class _HTTPConnection(object): self.stream.write(self.request.body) self.stream.read_until(b("\r\n\r\n"), self._on_headers) + def _release(self): + if self.release_callback is not None: + release_callback = self.release_callback + self.release_callback = None + release_callback() + def _run_callback(self, response): - if self.callback is not None: - callback = self.callback - self.callback = None - callback(response) + self._release() + if self.final_callback is not None: + final_callback = self.final_callback + self.final_callback = None + final_callback(response) @contextlib.contextmanager def cleanup(self): @@ -346,9 +354,11 @@ class _HTTPConnection(object): new_request.max_redirects -= 1 del new_request.headers["Host"] new_request.original_request = original_request - callback = self.callback - self.callback = None - self.client.fetch(new_request, callback) + final_callback = self.final_callback + self.final_callback = None + self._release() + self.client.fetch(new_request, final_callback) + self.stream.close() return response = HTTPResponse(original_request, self.code, headers=self.headers, diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 804acdeb3..8ac365e21 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -105,7 +105,8 @@ class HTTPConnectionTest(AsyncHTTPTestCase, LogTrapTestCase): def raw_fetch(self, headers, body): conn = RawRequestHTTPConnection(self.io_loop, self.http_client, httpclient.HTTPRequest(self.get_url("/")), - self.stop, 1024*1024) + None, self.stop, + 1024*1024) conn.set_request( b("\r\n").join(headers + [utf8("Content-Length: %d\r\n" % len(body))]) + diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index bdea4fc70..662806620 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -100,6 +100,15 @@ class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase): self.assertEqual(set(seen), set([0, 1, 2, 3])) self.assertEqual(len(self.triggers), 0) + def test_redirect_connection_limit(self): + # following redirects should not consume additional connections + client = SimpleAsyncHTTPClient(self.io_loop, max_clients=1, + force_instance=True) + client.fetch(self.get_url('/countdown/3'), self.stop, + max_redirects=3) + response = self.wait() + response.rethrow() + def test_default_certificates_exist(self): open(_DEFAULT_CA_CERTS).close()