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

Commit 40d65b5

Browse files
committed
Fixed to read out all data from socket when Data Frame payload is quite large like SETTINGS_MAX_FRAME_SIZE
1 parent 7978b2a commit 40d65b5

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

Diff for: hyper/http20/connection.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,30 @@ def _consume_single_frame(self):
483483
frame, length = Frame.parse_frame_header(header)
484484

485485
# Read the remaining data from the socket.
486-
if length:
486+
data = self._recv_payload(length)
487+
self._consume_frame_payload(frame, data)
488+
489+
def _recv_payload(self, length):
490+
if not length:
491+
return memoryview(b'')
492+
493+
buffer = bytearray(length)
494+
buffer_view = memoryview(buffer)
495+
index = 0
496+
data_length = -1
497+
# _sock.recv(length) might not read out all data if the given length
498+
# is very large. So it should be to retrieve from socket repeatedly.
499+
while length and data_length:
487500
data = self._sock.recv(length)
488-
else:
489-
data = memoryview(b'')
501+
data_length = len(data)
502+
end = index + data_length
503+
buffer_view[index:end] = data[:]
504+
length -= data_length
505+
index = end
506+
507+
return buffer_view[:end]
490508

509+
def _consume_frame_payload(self, frame, data):
491510
frame.parse_body(data)
492511

493512
log.info(

Diff for: test/test_hyper.py

+26
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,23 @@ def test_we_can_read_from_the_socket(self):
10721072
s = c.recent_stream
10731073
assert s.data == [b'testdata']
10741074

1075+
def test_we_can_read_fitfully_from_the_socket(self):
1076+
sock = DummyFitfullySocket()
1077+
sock.buffer = BytesIO(
1078+
b'\x00\x00\x18\x00\x01\x00\x00\x00\x01'
1079+
b'testdata'
1080+
b'+payload'
1081+
)
1082+
1083+
c = HTTP20Connection('www.google.com')
1084+
c._sock = sock
1085+
c.putrequest('GET', '/')
1086+
c.endheaders()
1087+
c._recv_cb()
1088+
1089+
s = c.recent_stream
1090+
assert s.data == [b'testdata+payload']
1091+
10751092
def test_putrequest_sends_data(self):
10761093
sock = DummySocket()
10771094

@@ -2045,6 +2062,15 @@ def recv(self, l):
20452062
def close(self):
20462063
pass
20472064

2065+
2066+
class DummyFitfullySocket(DummySocket):
2067+
def recv(self, l):
2068+
length = l
2069+
if l != 9 and l >= 4:
2070+
length = int(round(l / 2))
2071+
return memoryview(self.buffer.read(length))
2072+
2073+
20482074
class DummyStream(object):
20492075
def __init__(self, data, trailers=None):
20502076
self.data = data

0 commit comments

Comments
 (0)