From: Ben Darnell Date: Mon, 3 Mar 2014 02:26:15 +0000 (-0500) Subject: Move gzip decompression from simple_httpclient to http1connection. X-Git-Tag: v4.0.0b1~91^2~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a47e500d3e74034127ffc23b2d203bb3281d1891;p=thirdparty%2Ftornado.git Move gzip decompression from simple_httpclient to http1connection. --- diff --git a/tornado/http1connection.py b/tornado/http1connection.py index 8f78e8266..cc14379fd 100644 --- a/tornado/http1connection.py +++ b/tornado/http1connection.py @@ -23,6 +23,7 @@ from tornado import httputil from tornado import iostream from tornado.log import gen_log from tornado import stack_context +from tornado.util import GzipDecompressor class HTTP1Connection(object): @@ -68,7 +69,9 @@ class HTTP1Connection(object): if not ret: return - def read_response(self, delegate, method): + def read_response(self, delegate, method, use_gzip=False): + if use_gzip: + delegate = _GzipMessageDelegate(delegate) return self._read_message(delegate, True, method=method) @gen.coroutine @@ -247,3 +250,33 @@ class HTTP1Connection(object): def _read_body_until_close(self, delegate): body = yield self.stream.read_until_close() delegate.data_received(body) + + +class _GzipMessageDelegate(httputil.HTTPMessageDelegate): + """Wraps an `HTTPMessageDelegate` to decode ``Content-Encoding: gzip``. + """ + def __init__(self, delegate): + self._delegate = delegate + self._decompressor = None + + def headers_received(self, start_line, headers): + if headers.get("Content-Encoding") == "gzip": + self._decompressor = GzipDecompressor() + return self._delegate.headers_received(start_line, headers) + + def data_received(self, chunk): + if self._decompressor: + chunk = self._decompressor.decompress(chunk) + return self._delegate.data_received(chunk) + + def finish(self): + if self._decompressor is not None: + tail = self._decompressor.flush() + if tail: + # I believe the tail will always be empty (i.e. + # decompress will return all it can). The purpose + # of the flush call is to detect errors such + # as truncated input. But in case it ever returns + # anything, treat it as an extra chunk + self._delegate.data_received(tail) + return self._delegate.finish() diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index 0b837369c..acc898439 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -9,7 +9,6 @@ from tornado.iostream import IOStream, SSLIOStream, StreamClosedError from tornado.netutil import Resolver, OverrideResolver from tornado.log import gen_log from tornado import stack_context -from tornado.util import GzipDecompressor import base64 import collections @@ -341,7 +340,8 @@ class _HTTPConnection(httputil.HTTPMessageDelegate): # Ensure that any exception raised in read_response ends up in our # stack context. self.io_loop.add_future( - self.connection.read_response(self, method=self.request.method), + self.connection.read_response(self, method=self.request.method, + use_gzip=self.request.use_gzip), lambda f: f.result()) def _release(self): @@ -421,23 +421,7 @@ class _HTTPConnection(httputil.HTTPMessageDelegate): raise ValueError("Response with code %d should not have body" % self.code) - if (self.request.use_gzip and - self.headers.get("Content-Encoding") == "gzip"): - self._decompressor = GzipDecompressor() - def finish(self): - if self._decompressor is not None: - tail = self._decompressor.flush() - if tail: - # I believe the tail will always be empty (i.e. - # decompress will return all it can). The purpose - # of the flush call is to detect errors such - # as truncated input. But in case it ever returns - # anything, treat it as an extra chunk - if self.request.streaming_callback is not None: - self.request.streaming_callback(tail) - else: - self.chunks.append(tail) data = b''.join(self.chunks) self._remove_timeout() original_request = getattr(self.request, "original_request", @@ -491,8 +475,6 @@ class _HTTPConnection(httputil.HTTPMessageDelegate): self.stream.close() def data_received(self, chunk): - if self._decompressor: - chunk = self._decompressor.decompress(chunk) if self.request.streaming_callback is not None: self.request.streaming_callback(chunk) else: