Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
h2.stream.StreamInputs.SEND_WINDOW_UPDATE,
h2.stream.StreamInputs.SEND_END_STREAM,
]
)
def test_cannot_send_on_closed_streams(self, input_):
"""
Sending anything but a PRIORITY frame is forbidden on closed streams.
"""
c = h2.stream.H2StreamStateMachine(stream_id=1)
c.state = h2.stream.StreamState.CLOSED
expected_error = (
h2.exceptions.ProtocolError
if input_ == h2.stream.StreamInputs.SEND_PUSH_PROMISE
else h2.exceptions.StreamClosedError
)
input_=sampled_from(h2.stream.StreamInputs))
def test_state_transitions(self, state, input_):
s = h2.stream.H2StreamStateMachine(stream_id=1)
s.state = state
try:
s.process_input(input_)
except h2.exceptions.StreamClosedError:
# This can only happen for streams that started in the closed
# state OR where the input was RECV_DATA and the state was not
# OPEN or HALF_CLOSED_LOCAL OR where the state was
# HALF_CLOSED_REMOTE and a frame was received.
if state == h2.stream.StreamState.CLOSED:
assert s.state == h2.stream.StreamState.CLOSED
elif input_ == h2.stream.StreamInputs.RECV_DATA:
assert s.state == h2.stream.StreamState.CLOSED
assert state not in (
def test_stream_state_machine_forbids_sending_pushes_from_clients(self):
"""
Streams where this peer is a client do not allow sending pushed frames.
"""
s = h2.stream.H2StreamStateMachine(stream_id=1)
s.process_input(h2.stream.StreamInputs.SEND_HEADERS)
with pytest.raises(h2.exceptions.ProtocolError):
s.process_input(h2.stream.StreamInputs.SEND_PUSH_PROMISE)
# This can only happen for streams that started in the closed
# state OR where the input was RECV_DATA and the state was not
# OPEN or HALF_CLOSED_LOCAL OR where the state was
# HALF_CLOSED_REMOTE and a frame was received.
if state == h2.stream.StreamState.CLOSED:
assert s.state == h2.stream.StreamState.CLOSED
elif input_ == h2.stream.StreamInputs.RECV_DATA:
assert s.state == h2.stream.StreamState.CLOSED
assert state not in (
h2.stream.StreamState.OPEN,
h2.stream.StreamState.HALF_CLOSED_LOCAL,
)
elif state == h2.stream.StreamState.HALF_CLOSED_REMOTE:
assert input_ in (
h2.stream.StreamInputs.RECV_HEADERS,
h2.stream.StreamInputs.RECV_PUSH_PROMISE,
h2.stream.StreamInputs.RECV_DATA,
h2.stream.StreamInputs.RECV_CONTINUATION,
)
except h2.exceptions.ProtocolError:
assert s.state == h2.stream.StreamState.CLOSED
else:
assert s.state in h2.stream.StreamState
h2.stream.StreamInputs.SEND_DATA,
h2.stream.StreamInputs.SEND_WINDOW_UPDATE,
h2.stream.StreamInputs.SEND_END_STREAM,
]
)
def test_cannot_send_on_closed_streams(self, input_):
"""
Sending anything but a PRIORITY frame is forbidden on closed streams.
"""
c = h2.stream.H2StreamStateMachine(stream_id=1)
c.state = h2.stream.StreamState.CLOSED
expected_error = (
h2.exceptions.ProtocolError
if input_ == h2.stream.StreamInputs.SEND_PUSH_PROMISE
else h2.exceptions.StreamClosedError
)
def test_stream_state_machine_forbids_sending_pushes_from_clients(self):
"""
Streams where this peer is a client do not allow sending pushed frames.
"""
s = h2.stream.H2StreamStateMachine(stream_id=1)
s.process_input(h2.stream.StreamInputs.SEND_HEADERS)
with pytest.raises(h2.exceptions.ProtocolError):
s.process_input(h2.stream.StreamInputs.SEND_PUSH_PROMISE)
def receive_headers(self, headers, end_stream, header_encoding):
"""
Receive a set of headers (or trailers).
"""
if is_informational_response(headers):
if end_stream:
raise ProtocolError(
"Cannot set END_STREAM on informational responses"
)
input_ = StreamInputs.RECV_INFORMATIONAL_HEADERS
else:
input_ = StreamInputs.RECV_HEADERS
events = self.state_machine.process_input(input_)
if end_stream:
es_events = self.state_machine.process_input(
StreamInputs.RECV_END_STREAM
)
events[0].stream_ended = es_events[0]
events += es_events
self._initialize_content_length(headers)
if isinstance(events[0], TrailersReceived):
if not end_stream:
(StreamState.OPEN, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.response_received, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.SEND_DATA):
(None, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.RECV_DATA):
(H2StreamStateMachine.data_received, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.SEND_END_STREAM):
(None, StreamState.HALF_CLOSED_LOCAL),
(StreamState.OPEN, StreamInputs.RECV_END_STREAM):
(H2StreamStateMachine.stream_half_closed,
StreamState.HALF_CLOSED_REMOTE),
(StreamState.OPEN, StreamInputs.SEND_WINDOW_UPDATE):
(None, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.RECV_WINDOW_UPDATE):
(H2StreamStateMachine.window_updated, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.SEND_RST_STREAM):
(H2StreamStateMachine.send_reset_stream, StreamState.CLOSED),
(StreamState.OPEN, StreamInputs.RECV_RST_STREAM):
(H2StreamStateMachine.stream_reset, StreamState.CLOSED),
(StreamState.OPEN, StreamInputs.SEND_PUSH_PROMISE):
(H2StreamStateMachine.send_push_promise, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.recv_push_promise, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.SEND_INFORMATIONAL_HEADERS):
(H2StreamStateMachine.send_informational_response, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.RECV_INFORMATIONAL_HEADERS):
(H2StreamStateMachine.recv_informational_response, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.SEND_ALTERNATIVE_SERVICE):
(H2StreamStateMachine.send_alt_svc, StreamState.OPEN),
(StreamState.OPEN, StreamInputs.RECV_ALTERNATIVE_SERVICE):
(H2StreamStateMachine.recv_alt_svc, StreamState.OPEN),
# State: idle
(StreamState.IDLE, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.request_sent, StreamState.OPEN),
(StreamState.IDLE, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.request_received, StreamState.OPEN),
(StreamState.IDLE, StreamInputs.RECV_DATA):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.IDLE, StreamInputs.SEND_PUSH_PROMISE):
(H2StreamStateMachine.send_new_pushed_stream,
StreamState.RESERVED_LOCAL),
(StreamState.IDLE, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.recv_new_pushed_stream,
StreamState.RESERVED_REMOTE),
(StreamState.IDLE, StreamInputs.RECV_ALTERNATIVE_SERVICE):
(None, StreamState.IDLE),
(StreamState.IDLE, StreamInputs.UPGRADE_CLIENT):
(H2StreamStateMachine.request_sent, StreamState.HALF_CLOSED_LOCAL),
(StreamState.IDLE, StreamInputs.UPGRADE_SERVER):
(H2StreamStateMachine.request_received,
StreamState.HALF_CLOSED_REMOTE),
# State: reserved local
(StreamState.RESERVED_LOCAL, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.response_sent, StreamState.HALF_CLOSED_REMOTE),
(StreamState.RESERVED_LOCAL, StreamInputs.RECV_DATA):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.RESERVED_LOCAL, StreamInputs.SEND_WINDOW_UPDATE):
(None, StreamState.RESERVED_LOCAL),
(StreamState.RESERVED_LOCAL, StreamInputs.RECV_WINDOW_UPDATE):
(H2StreamStateMachine.window_updated, StreamState.RESERVED_LOCAL),
(StreamState.RESERVED_LOCAL, StreamInputs.SEND_RST_STREAM):
(H2StreamStateMachine.send_reset_stream, StreamState.CLOSED),
# Because encoding headers makes an irreversible change to the header
# compression context, we make the state transition before we encode
# them.
# First, check if we're a client. If we are, no problem: if we aren't,
# we need to scan the header block to see if this is an informational
# response.
input_ = StreamInputs.SEND_HEADERS
if ((not self.state_machine.client) and
is_informational_response(headers)):
if end_stream:
raise ProtocolError(
"Cannot set END_STREAM on informational responses."
)
input_ = StreamInputs.SEND_INFORMATIONAL_HEADERS
events = self.state_machine.process_input(input_)
hf = HeadersFrame(self.stream_id)
hdr_validation_flags = self._build_hdr_validation_flags(events)
frames = self._build_headers_frames(
headers, encoder, hf, hdr_validation_flags
)
if end_stream:
# Not a bug: the END_STREAM flag is valid on the initial HEADERS
# frame, not the CONTINUATION frames that follow.
self.state_machine.process_input(StreamInputs.SEND_END_STREAM)
frames[0].flags.add('END_STREAM')
if self.state_machine.trailers_sent and not end_stream: