Skip to content
This repository was archived by the owner on Jan 13, 2021. It is now read-only.

Commit c47cfd3

Browse files
committed
Support transparent decompressing of responses.
1 parent e0c9893 commit c47cfd3

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

hyper/http20/response.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
Contains the HTTP/2.0 equivalent of the HTTPResponse object defined in
77
httplib/http.client.
88
"""
9+
import zlib
10+
11+
912
class HTTP20Response(object):
1013
"""
1114
An ``HTTP20Response`` wraps the HTTP/2.0 response from the server. It
@@ -36,22 +39,40 @@ def __init__(self, headers, stream):
3639
# may need to buffer some for incomplete reads.
3740
self._data_buffer = b''
3841

39-
def read(self, amt=None):
42+
# This object is used for decompressing gzipped request bodies. Right
43+
# now we only support gzip because that's all the RFC mandates of us.
44+
# Later we'll add support for more encodings.
45+
# This 16 + MAX_WBITS nonsense is to force gzip. See this
46+
# Stack Overflow answer for more:
47+
# http://stackoverflow.com/a/2695466/1401686
48+
self._decompressobj = zlib.decompressobj(16 + zlib.MAX_WBITS)
49+
50+
def read(self, amt=None, decode_content=True):
4051
"""
4152
Reads the response body, or up to the next ``amt`` bytes.
4253
"""
4354
if amt is not None and amt <= len(self._data_buffer):
4455
data = self._data_buffer[:amt]
4556
self._data_buffer = self._data_buffer[amt:]
46-
return data
57+
flush_buffer = False
4758
elif amt is not None:
4859
read_amt = amt - len(self._data_buffer)
4960
self._data_buffer += self._stream._read(read_amt)
5061
data = self._data_buffer[:amt]
5162
self._data_buffer = self._data_buffer[amt:]
52-
return data
63+
flush_buffer = len(data) < amt
5364
else:
54-
return b''.join([self._data_buffer, self._stream._read()])
65+
data = b''.join([self._data_buffer, self._stream._read()])
66+
flush_buffer = True
67+
68+
# We may need to decode the body.
69+
if (decode_content and self.getheader('content-encoding', False)):
70+
data = self._decompressobj.decompress(data)
71+
72+
if flush_buffer:
73+
data += self._decompressobj.flush()
74+
75+
return data
5576

5677
def getheader(self, name, default=None):
5778
"""

test/test_hyper.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,8 +1034,10 @@ def test_status_is_stripped_from_headers(self):
10341034
assert resp.getheaders() == []
10351035

10361036
def test_response_transparently_decrypts(self):
1037-
headers = {':status': '200', 'Content-Encoding': 'gzip'}
1038-
body = zlib.compress(b'this is test data')
1037+
headers = {':status': '200', 'content-encoding': 'gzip'}
1038+
c = zlib.compressobj(wbits=24)
1039+
body = c.compress(b'this is test data')
1040+
body += c.flush()
10391041
resp = HTTP20Response(headers, DummyStream(body))
10401042

10411043
assert resp.read() == b'this is test data'

0 commit comments

Comments
 (0)