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

Commit 595d27e

Browse files
committed
Support chunked responses with normal reads.
1 parent 4e78258 commit 595d27e

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

hyper/http11/response.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ def __init__(self, code, reason, headers, sock):
7474
else:
7575
self._decompressobj = None
7676

77+
self._buffered_data = b''
78+
self._chunker = None
79+
7780
def read(self, amt=None, decode_content=True):
7881
"""
7982
Reads the response body, or up to the next ``amt`` bytes.
@@ -90,8 +93,32 @@ def read(self, amt=None, decode_content=True):
9093
if self._sock is None:
9194
return b''
9295

93-
# FIXME: Handle chunked transfer encoding
94-
assert not self._chunked
96+
if self._chunked:
97+
# If we're doing a full read, read it as chunked and then just join
98+
# the chunks together!
99+
if amt is None:
100+
return self._buffered_data + b''.join(self.read_chunked())
101+
102+
if self._chunker is None:
103+
self._chunker = self.read_chunked()
104+
105+
# Otherwise, we have a certain amount of data we want to read.
106+
current_amount = len(self._buffered_data)
107+
108+
extra_data = [self._buffered_data]
109+
while current_amount < amt:
110+
try:
111+
chunk = next(self._chunker)
112+
except StopIteration:
113+
self.close()
114+
break
115+
116+
current_amount += len(chunk)
117+
extra_data.append(chunk)
118+
119+
data = b''.join(extra_data)
120+
self._buffered_data = data[amt:]
121+
return data[:amt]
95122

96123
# If we're asked to do a read without a length, we need to read
97124
# everything. That means either the entire content length, or until the

test/test_http11.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,43 @@ def test_response_transparently_decrypts_chunked_gzip(self):
445445

446446
assert received_body == b'this is test data'
447447

448+
def test_chunked_normal_read(self):
449+
d = DummySocket()
450+
r = HTTP11Response(200, 'OK', {b'transfer-encoding': [b'chunked']}, d)
451+
452+
data = (
453+
b'4\r\nwell\r\n'
454+
b'4\r\nwell\r\n'
455+
b'4\r\nwhat\r\n'
456+
b'4\r\nhave\r\n'
457+
b'2\r\nwe\r\n'
458+
b'a\r\nhereabouts\r\n'
459+
b'0\r\n\r\n'
460+
)
461+
d._buffer = BytesIO(data)
462+
463+
assert r.read() == b'wellwellwhathavewehereabouts'
464+
465+
def test_chunk_length_read(self):
466+
d = DummySocket()
467+
r = HTTP11Response(200, 'OK', {b'transfer-encoding': [b'chunked']}, d)
468+
469+
data = (
470+
b'4\r\nwell\r\n'
471+
b'4\r\nwell\r\n'
472+
b'4\r\nwhat\r\n'
473+
b'4\r\nhave\r\n'
474+
b'2\r\nwe\r\n'
475+
b'a\r\nhereabouts\r\n'
476+
b'0\r\n\r\n'
477+
)
478+
d._buffer = BytesIO(data)
479+
480+
assert r.read(5) == b'wellw'
481+
assert r.read(15) == b'ellwhathavewehe'
482+
assert r.read(20) == b'reabouts'
483+
assert r.read() == b''
484+
448485
class DummySocket(object):
449486
def __init__(self):
450487
self.queue = []

0 commit comments

Comments
 (0)