Skip to content

Commit c5d962a

Browse files
authored
bump hyperframe and fix protocol error (#1238)
1 parent e91f2f6 commit c5d962a

File tree

5 files changed

+22
-35
lines changed

5 files changed

+22
-35
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
'Programming Language :: Python :: Implementation :: PyPy',
5656
],
5757
install_requires=[
58-
'hyperframe>=5.2.0,<6',
58+
'hyperframe>=6.0,<7',
5959
'hpack>=4.0,<5',
6060
],
6161
)

src/h2/connection.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,12 +1721,8 @@ def _receive_window_update_frame(self, frame):
17211721
"""
17221722
Receive a WINDOW_UPDATE frame on the connection.
17231723
"""
1724-
# Validate the frame.
1725-
if not (1 <= frame.window_increment <= self.MAX_WINDOW_INCREMENT):
1726-
raise ProtocolError(
1727-
"Flow control increment must be between 1 and %d, received %d"
1728-
% (self.MAX_WINDOW_INCREMENT, frame.window_increment)
1729-
)
1724+
# hyperframe will take care of validating the window_increment.
1725+
# If we reach in here, we can assume a valid value.
17301726

17311727
events = self.state_machine.process_input(
17321728
ConnectionInputs.RECV_WINDOW_UPDATE

src/h2/exceptions.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class FrameTooLargeError(ProtocolError):
2626
"""
2727
The frame that we tried to send or that we received was too large.
2828
"""
29-
#: This error code that corresponds to this kind of Protocol Error.
29+
#: The error code corresponds to this kind of Protocol Error.
3030
error_code = h2.errors.ErrorCodes.FRAME_SIZE_ERROR
3131

3232

@@ -36,7 +36,7 @@ class FrameDataMissingError(ProtocolError):
3636
3737
.. versionadded:: 2.0.0
3838
"""
39-
#: The error code that corresponds to this kind of Protocol Error
39+
#: The error code corresponds to this kind of Protocol Error.
4040
error_code = h2.errors.ErrorCodes.FRAME_SIZE_ERROR
4141

4242

@@ -52,8 +52,7 @@ class FlowControlError(ProtocolError):
5252
"""
5353
An attempted action violates flow control constraints.
5454
"""
55-
#: The error code that corresponds to this kind of
56-
#: :class:`ProtocolError <h2.exceptions.ProtocolError>`
55+
#: The error code corresponds to this kind of Protocol Error.
5756
error_code = h2.errors.ErrorCodes.FLOW_CONTROL_ERROR
5857

5958

@@ -94,7 +93,7 @@ class NoSuchStreamError(ProtocolError):
9493
<h2.exceptions.ProtocolError>`
9594
"""
9695
def __init__(self, stream_id):
97-
#: The stream ID that corresponds to the non-existent stream.
96+
#: The stream ID corresponds to the non-existent stream.
9897
self.stream_id = stream_id
9998

10099

@@ -106,7 +105,7 @@ class StreamClosedError(NoSuchStreamError):
106105
stream has been removed.
107106
"""
108107
def __init__(self, stream_id):
109-
#: The stream ID that corresponds to the nonexistent stream.
108+
#: The stream ID corresponds to the nonexistent stream.
110109
self.stream_id = stream_id
111110

112111
#: The relevant HTTP/2 error code.
@@ -145,13 +144,15 @@ def __str__(self):
145144
)
146145

147146

148-
class UnsupportedFrameError(ProtocolError, KeyError):
147+
class UnsupportedFrameError(ProtocolError):
149148
"""
150149
The remote peer sent a frame that is unsupported in this context.
151150
152151
.. versionadded:: 2.1.0
152+
153+
.. versionchanged:: 4.0.0
154+
Removed deprecated KeyError parent class.
153155
"""
154-
# TODO: Remove the KeyError in 3.0.0
155156
pass
156157

157158

@@ -181,6 +182,6 @@ class DenialOfServiceError(ProtocolError):
181182
182183
.. versionadded:: 2.5.0
183184
"""
184-
#: The error code that corresponds to this kind of
185+
#: The error code corresponds to this kind of
185186
#: :class:`ProtocolError <h2.exceptions.ProtocolError>`
186187
error_code = h2.errors.ErrorCodes.ENHANCE_YOUR_CALM

src/h2/frame_buffer.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
A data structure that provides a way to iterate over a byte buffer in terms of
77
frames.
88
"""
9-
from hyperframe.exceptions import InvalidFrameError
9+
from hyperframe.exceptions import InvalidFrameError, InvalidDataError
1010
from hyperframe.frame import (
1111
Frame, HeadersFrame, ContinuationFrame, PushPromiseFrame
1212
)
@@ -57,20 +57,6 @@ def add_data(self, data):
5757

5858
self.data += data
5959

60-
def _parse_frame_header(self, data):
61-
"""
62-
Parses the frame header from the data. Either returns a tuple of
63-
(frame, length), or throws an exception. The returned frame may be None
64-
if the frame is of unknown type.
65-
"""
66-
try:
67-
frame, length = Frame.parse_frame_header(data[:9])
68-
except ValueError as e:
69-
# The frame header is invalid. This is a ProtocolError
70-
raise ProtocolError("Invalid frame header received: %s" % str(e))
71-
72-
return frame, length
73-
7460
def _validate_frame_length(self, length):
7561
"""
7662
Confirm that the frame is an appropriate length.
@@ -137,9 +123,11 @@ def __next__(self):
137123
raise StopIteration()
138124

139125
try:
140-
f, length = self._parse_frame_header(self.data)
141-
except InvalidFrameError: # pragma: no cover
142-
raise ProtocolError("Received frame with invalid frame header.")
126+
f, length = Frame.parse_frame_header(self.data[:9])
127+
except (InvalidDataError, InvalidFrameError) as e: # pragma: no cover
128+
raise ProtocolError(
129+
"Received frame with invalid header: %s" % str(e)
130+
)
143131

144132
# Next, check that we have enough length to parse the frame body. If
145133
# not, bail, leaving the frame header data in the buffer for next time.
@@ -152,6 +140,8 @@ def __next__(self):
152140
# Try to parse the frame body
153141
try:
154142
f.parse_body(memoryview(self.data[9:9+length]))
143+
except InvalidDataError:
144+
raise ProtocolError("Received frame with non-compliant data")
155145
except InvalidFrameError:
156146
raise FrameDataMissingError("Frame data missing or invalid")
157147

test/test_invalid_frame_sequences.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def test_invalid_frame_headers_are_protocol_errors(self, frame_factory):
278278
with pytest.raises(h2.exceptions.ProtocolError) as e:
279279
c.receive_data(frame_data)
280280

281-
assert "Stream ID must be non-zero" in str(e.value)
281+
assert "Received frame with invalid header" in str(e.value)
282282

283283
def test_data_before_headers(self, frame_factory):
284284
"""

0 commit comments

Comments
 (0)