|
18 | 18 | from .stream import Stream |
19 | 19 | from .response import HTTP20Response, HTTP20Push |
20 | 20 | from .window import FlowControlManager |
21 | | -from .exceptions import ConnectionError |
| 21 | +from .exceptions import ConnectionError, ProtocolError |
22 | 22 | from . import errors |
23 | 23 |
|
24 | 24 | import errno |
@@ -240,9 +240,17 @@ def close(self): |
240 | 240 |
|
241 | 241 | :returns: Nothing. |
242 | 242 | """ |
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 | + |
246 | 254 | if self._sock is not None: |
247 | 255 | self._sock.close() |
248 | 256 | self.__init_state() |
@@ -580,7 +588,17 @@ def _consume_frame_payload(self, frame, data): |
580 | 588 |
|
581 | 589 | # Work out to whom this frame should go. |
582 | 590 | 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 | + ) |
584 | 602 | else: |
585 | 603 | self.receive_frame(frame) |
586 | 604 |
|
|
0 commit comments