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

Commit a370261

Browse files
committed
Merge branch 'jdecuyper-goaway-frames' into development
2 parents 86bd531 + 21f6110 commit a370261

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

hyper/http20/connection.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from .stream import Stream
1919
from .response import HTTP20Response, HTTP20Push
2020
from .window import FlowControlManager
21-
from .exceptions import ConnectionError
21+
from .exceptions import ConnectionError, ProtocolError
2222
from . import errors
2323

2424
import errno
@@ -240,9 +240,17 @@ def close(self):
240240
241241
:returns: Nothing.
242242
"""
243-
# Todo: we should actually clean ourselves up if possible by sending
244-
# GoAway frames and closing all outstanding streams. For now this will
245-
# do.
243+
# Close all streams
244+
for stream in list(self.streams.values()):
245+
log.debug("Close stream %d" % stream.stream_id)
246+
stream.close()
247+
248+
# Send GoAway frame to the server
249+
try:
250+
self._send_cb(GoAwayFrame(0), True)
251+
except Exception as e:
252+
log.warn("GoAway frame could not be sent: %s" % e)
253+
246254
if self._sock is not None:
247255
self._sock.close()
248256
self.__init_state()
@@ -580,7 +588,17 @@ def _consume_frame_payload(self, frame, data):
580588

581589
# Work out to whom this frame should go.
582590
if frame.stream_id != 0:
583-
self.streams[frame.stream_id].receive_frame(frame)
591+
try:
592+
self.streams[frame.stream_id].receive_frame(frame)
593+
except KeyError:
594+
# If we receive an unexpected stream identifier then we
595+
# cancel the stream with an error of type PROTOCOL_ERROR
596+
f = RstStreamFrame(frame.stream_id)
597+
f.error_code = 1 # PROTOCOL_ERROR
598+
self._send_cb(f)
599+
log.warning(
600+
"Unexpected stream identifier %d" % (frame.stream_id)
601+
)
584602
else:
585603
self.receive_frame(frame)
586604

hyper/http20/errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
the array.
99
1010
The current registry is available at:
11-
https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-11.4
11+
https://tools.ietf.org/html/rfc7540#section-11.4
1212
"""
1313

1414
NO_ERROR = {'Name': 'NO_ERROR',

test/test_hyper.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,28 @@ def test_goaway_frame_invalid_error_code(self):
12611261
assert 'data about non existing error code' in err_msg
12621262
assert str(f.error_code) in err_msg
12631263

1264+
def test_receive_unexpected_stream_id(self):
1265+
frames = []
1266+
1267+
def data_callback(frame):
1268+
frames.append(frame)
1269+
1270+
c = HTTP20Connection('www.google.com')
1271+
c._send_cb = data_callback
1272+
1273+
f = DataFrame(2)
1274+
data = memoryview(b"hi there sir")
1275+
c._consume_frame_payload(f, data)
1276+
1277+
# If we receive an unexpected stream id then we cancel the stream
1278+
# by sending a reset stream that contains the protocol error code (1)
1279+
f = frames[0]
1280+
assert len(frames) == 1
1281+
assert f.stream_id == 2
1282+
assert isinstance(f, RstStreamFrame)
1283+
assert f.error_code == 1 # PROTOCOL_ERROR
1284+
1285+
12641286
# Some utility classes for the tests.
12651287
class NullEncoder(object):
12661288
@staticmethod

test/test_integration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,14 @@ def socket_handler(listener):
233233
sock.send(f.serialize())
234234

235235
send_event.wait()
236+
sock.recv(65535)
236237
sock.close()
237238

238239
self._start_server(socket_handler)
239240
with self.get_connection() as conn:
240241
conn.connect()
241-
send_event.set()
242+
243+
send_event.set()
242244

243245
# Check that we closed the connection.
244246
assert conn._sock == None

0 commit comments

Comments
 (0)