Skip to content

Commit 95b45d1

Browse files
committed
Better handling of unknown frame types
(cherry picked from commit 563e5c6)
1 parent 92372c9 commit 95b45d1

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

h2/connection.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828
from .exceptions import (
2929
ProtocolError, NoSuchStreamError, FlowControlError, FrameTooLargeError,
3030
TooManyStreamsError, StreamClosedError, StreamIDTooLowError,
31-
NoAvailableStreamIDError, UnsupportedFrameError, RFC1122Error,
32-
DenialOfServiceError
31+
NoAvailableStreamIDError, RFC1122Error, DenialOfServiceError
3332
)
3433
from .frame_buffer import FrameBuffer
3534
from .settings import (
@@ -49,6 +48,15 @@ class OversizedHeaderListError(Exception):
4948
pass
5049

5150

51+
try:
52+
from hyperframe.frame import ExtensionFrame
53+
except ImportError: # Platform-specific: Hyperframe < 5.0.0
54+
# If the frame doesn't exist, that's just fine: we'll define it ourselves
55+
# and the method will just never be called.
56+
class ExtensionFrame(object):
57+
pass
58+
59+
5260
class ConnectionState(Enum):
5361
IDLE = 0
5462
CLIENT_OPEN = 1
@@ -403,6 +411,7 @@ def __init__(self, client_side=True, header_encoding='utf-8', config=None):
403411
GoAwayFrame: self._receive_goaway_frame,
404412
ContinuationFrame: self._receive_naked_continuation,
405413
AltSvcFrame: self._receive_alt_svc_frame,
414+
ExtensionFrame: self._receive_unknown_frame
406415
}
407416

408417
def _prepare_for_sending(self, frames):
@@ -1491,10 +1500,6 @@ def _receive_frame(self, frame):
14911500
if frame.stream_id not in self._reset_streams:
14921501
raise
14931502
events = []
1494-
except KeyError as e: # pragma: no cover
1495-
# We don't have a function for handling this frame. Let's call this
1496-
# a PROTOCOL_ERROR and exit.
1497-
raise UnsupportedFrameError("Unexpected frame: %s" % frame)
14981503
else:
14991504
self._prepare_for_sending(frames)
15001505

@@ -1829,6 +1834,18 @@ def _receive_alt_svc_frame(self, frame):
18291834

18301835
return frames, events
18311836

1837+
def _receive_unknown_frame(self, frame):
1838+
"""
1839+
We have received a frame that we do not understand. This is almost
1840+
certainly an extension frame, though it's impossible to be entirely
1841+
sure.
1842+
1843+
RFC 7540 § 5.5 says that we MUST ignore unknown frame types: so we
1844+
do.
1845+
"""
1846+
# We don't do anything here.
1847+
return [], []
1848+
18321849
def _local_settings_acked(self):
18331850
"""
18341851
Handle the local settings being ACKed, update internal state.

h2/frame_buffer.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ def _parse_frame_header(self, data):
6565
"""
6666
try:
6767
frame, length = Frame.parse_frame_header(data[:9])
68-
except UnknownFrameError as e:
68+
except UnknownFrameError as e: # Platform-specific: Hyperframe < 5.0
6969
# Here we do something a bit odd. We want to consume the frame data
7070
# as consistently as possible, but we also don't ever want to yield
7171
# None. Instead, we make sure that, if there is no frame, we
7272
# recurse into ourselves.
73+
# This can only happen now on older versions of hyperframe.
74+
# TODO: Remove in 3.0
7375
length = e.length
7476
frame = None
7577
except ValueError as e:

0 commit comments

Comments
 (0)