diff options
author | Tobias Kölling <tobi@die70.de> | 2020-12-09 12:25:41 +0100 |
---|---|---|
committer | Tobias Kölling <tobi@die70.de> | 2020-12-09 12:25:41 +0100 |
commit | cbaa5fa864c0e8f15ba079124a4c42565601200c (patch) | |
tree | cddc44ce36d490c2ca66185b3847bda8b7121e9b | |
parent | 536df8686cc815f0e0ed22e6a7402b83dbec5a00 (diff) | |
download | webob-cbaa5fa864c0e8f15ba079124a4c42565601200c.tar.gz |
deflate'd response: use RFC compliant decompression by default
[RFC7230](https://tools.ietf.org/html/rfc7230#section-4.2.2) specifies
that
> The "deflate" coding is a "zlib" data format [RFC1950](https://tools.ietf.org/html/rfc1950) containing a
> "deflate" compressed data stream [RFC1951](https://tools.ietf.org/html/rfc1951) that uses a combination of
> the Lempel-Ziv (LZ77) compression algorithm and Huffman coding.
but also
> Note: Some non-conformant implementations send the "deflate"
> compressed data without the zlib wrapper.
Thus deflate coded data should be expected to be received within a
"zlib" container, however if no container is present, the data shouldn't
be rejected.
This patch tries to decode that data using RFC7230 conformant decoding
and falls back to unwrapped decoding only if the previous attempt didn't
work.
-rw-r--r-- | src/webob/response.py | 11 | ||||
-rw-r--r-- | tests/test_response.py | 13 |
2 files changed, 22 insertions, 2 deletions
diff --git a/src/webob/response.py b/src/webob/response.py index e02de87..51d6c89 100644 --- a/src/webob/response.py +++ b/src/webob/response.py @@ -1322,8 +1322,15 @@ class Response: self.content_encoding = None gzip_f.close() else: - # Weird feature: http://bugs.python.org/issue5784 - self.body = zlib.decompress(self.body, -15) + try: + # RFC7230 section 4.2.2 specifies that the body should be wrapped + # inside a ZLIB (RFC1950) container ... + self.body = zlib.decompress(self.body) + except zlib.error: + # ... but there are nonconformant implementations around which send + # the data without the ZLIB container, so we use maximum window size + # decompression without header check (the - sign) + self.body = zlib.decompress(self.body, -15) self.content_encoding = None def md5_etag(self, body=None, set_content_md5=False): diff --git a/tests/test_response.py b/tests/test_response.py index 7f76bbe..ed2b7f1 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -425,6 +425,19 @@ def test_decode_content_with_deflate(): assert res.content_encoding is None +def test_decode_content_with_deflate_and_zlib_header(): + res = Response() + body = b"Hey Hey Hey" + # don't chop off the zlib container + # https://tools.ietf.org/html/rfc7230#section-4.2.2 says + # that chopping it exists but is non-conformant + res.body = zlib.compress(body) + res.content_encoding = "deflate" + res.decode_content() + assert res.body == body + assert res.content_encoding is None + + def test_content_length(): r0 = Response("x" * 10, content_length=10) |