Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
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)
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_INFORMATIONAL_HEADERS):
(H2StreamStateMachine.send_informational_response,
StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_ALTERNATIVE_SERVICE):
(H2StreamStateMachine.send_alt_svc, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_ALTERNATIVE_SERVICE):
(H2StreamStateMachine.recv_alt_svc, StreamState.HALF_CLOSED_REMOTE),
# State: half-closed local
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.response_received,
StreamState.HALF_CLOSED_LOCAL),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_DATA):
(H2StreamStateMachine.data_received, StreamState.HALF_CLOSED_LOCAL),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_END_STREAM):
(H2StreamStateMachine.stream_ended, StreamState.CLOSED),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.SEND_WINDOW_UPDATE):
(None, StreamState.HALF_CLOSED_LOCAL),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_WINDOW_UPDATE):
(H2StreamStateMachine.window_updated, StreamState.HALF_CLOSED_LOCAL),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.SEND_RST_STREAM):
(H2StreamStateMachine.send_reset_stream, StreamState.CLOSED),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_RST_STREAM):
(H2StreamStateMachine.stream_reset, StreamState.CLOSED),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.recv_push_promise,
StreamState.HALF_CLOSED_LOCAL),
(StreamState.HALF_CLOSED_LOCAL, StreamInputs.RECV_INFORMATIONAL_HEADERS):
(H2StreamStateMachine.recv_informational_response,
StreamState.HALF_CLOSED_LOCAL),
(H2StreamStateMachine.response_sent, StreamState.OPEN),
(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),
)
# This is all the state machines we currently know about and will render.
# If any new state machines are added, they should be inserted here.
STATE_MACHINES = [
StateMachine(
fqdn='h2.connection.H2ConnectionStateMachine',
machine=h2.connection.H2ConnectionStateMachine,
states=h2.connection.ConnectionState,
inputs=h2.connection.ConnectionInputs,
transitions=h2.connection.H2ConnectionStateMachine._transitions,
),
StateMachine(
fqdn='h2.stream.H2StreamStateMachine',
machine=h2.stream.H2StreamStateMachine,
states=h2.stream.StreamState,
inputs=h2.stream.StreamInputs,
transitions=h2.stream._transitions,
),
]
def quote(s):
return '"{}"'.format(s.replace('"', r'\"'))
def html(s):
return '<{}>'.format(s)
def element(name, *children, **attrs):
def __init__(self,
stream_id,
config,
inbound_window_size,
outbound_window_size):
self.state_machine = H2StreamStateMachine(stream_id)
self.stream_id = stream_id
self.max_outbound_frame_size = None
self.request_method = None
# The current value of the outbound stream flow control window
self.outbound_flow_control_window = outbound_window_size
# The flow control manager.
self._inbound_window_manager = WindowManager(inbound_window_size)
# The expected content length, if any.
self._expected_content_length = None
# The actual received content length. Always tracked.
self._actual_content_length = 0
# two streams.
#
# The _transitions dictionary contains a mapping of tuples of
# (state, input) to tuples of (side_effect_function, end_state). This
# map contains all allowed transitions: anything not in this map is
# invalid and immediately causes a transition to ``closed``.
_transitions = {
# 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):
(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: half-closed remote
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.response_sent, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_DATA):
(None, StreamState.HALF_CLOSED_REMOTE),
# > END_STREAM flag is sent, as instructed in RFC 7540 Section 5.1. But we
# > don't have access to a clock so we just always allow it.
(StreamState.CLOSED, StreamInputs.RECV_WINDOW_UPDATE):
(None, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.RECV_RST_STREAM):
(None, StreamState.CLOSED),
# > A receiver MUST treat the receipt of a PUSH_PROMISE on a stream that is
# > neither "open" nor "half-closed (local)" as a connection error of type
# > PROTOCOL_ERROR.
(StreamState.CLOSED, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.recv_push_on_closed_stream, StreamState.CLOSED),
# Also, users should be forbidden from sending on closed streams.
(StreamState.CLOSED, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.send_on_closed_stream, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.SEND_PUSH_PROMISE):
(H2StreamStateMachine.send_push_on_closed_stream, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.SEND_RST_STREAM):
(H2StreamStateMachine.send_on_closed_stream, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.SEND_DATA):
(H2StreamStateMachine.send_on_closed_stream, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.SEND_WINDOW_UPDATE):
(H2StreamStateMachine.send_on_closed_stream, StreamState.CLOSED),
(StreamState.CLOSED, StreamInputs.SEND_END_STREAM):
(H2StreamStateMachine.send_on_closed_stream, StreamState.CLOSED),
}
class H2Stream(object):
"""
A low-level HTTP/2 stream object. This handles building and receiving
(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: half-closed remote
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.response_sent, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_DATA):
(None, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_DATA):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_END_STREAM):
(H2StreamStateMachine.send_end_stream, StreamState.CLOSED),
(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: half-closed remote
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_HEADERS):
(H2StreamStateMachine.response_sent, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_HEADERS):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_DATA):
(None, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_DATA):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_END_STREAM):
(H2StreamStateMachine.send_end_stream, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_WINDOW_UPDATE):
(None, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_WINDOW_UPDATE):
(H2StreamStateMachine.window_updated, StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_RST_STREAM):
(H2StreamStateMachine.send_reset_stream, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_RST_STREAM):
(H2StreamStateMachine.stream_reset, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_PUSH_PROMISE):
(H2StreamStateMachine.send_push_promise,
StreamState.HALF_CLOSED_REMOTE),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.RECV_PUSH_PROMISE):
(H2StreamStateMachine.reset_stream_on_error, StreamState.CLOSED),
(StreamState.HALF_CLOSED_REMOTE, StreamInputs.SEND_INFORMATIONAL_HEADERS):
(H2StreamStateMachine.send_informational_response,
StreamState.HALF_CLOSED_REMOTE),