def _receive_frame(self, frame): """ Handle a frame received on the connection. .. versionchanged:: 2.0.0 Removed from the public API. """ try: # I don't love using __class__ here, maybe reconsider it. frames, events = self._frame_dispatch_table[frame.__class__](frame) except StreamClosedError as e: # We need to send a RST_STREAM frame on behalf of the stream. # The frame the stream wants to emit is already present in the # exception. # This does not require re-raising: it's an expected behaviour. f = RstStreamFrame(e.stream_id) f.error_code = e.error_code self._prepare_for_sending([f]) events = e._events except KeyError as e: # We don't have a function for handling this frame. Let's call this # a PROTOCOL_ERROR and exit. raise UnsupportedFrameError("Unexpected frame: %s" % frame) else: self._prepare_for_sending(frames) return events
def build_rst_stream_frame(self, stream_id, error_code=0): """ Builds a single RST_STREAM frame. """ f = RstStreamFrame(stream_id) f.error_code = error_code return f
def build_rst_stream_frame(self, stream_id, error_code=0): """ Builds a single RST_STREAM frame. """ f = RstStreamFrame(stream_id) f.error_code = error_code return f
def _receive_frame(self, frame): """ Handle a frame received on the connection. .. versionchanged:: 2.0.0 Removed from the public API. """ try: # I don't love using __class__ here, maybe reconsider it. frames, events = self._frame_dispatch_table[frame.__class__](frame) except StreamClosedError as e: # We need to send a RST_STREAM frame on behalf of the stream. # The frame the stream wants to emit is already present in the # exception. # This does not require re-raising: it's an expected behaviour. f = RstStreamFrame(e.stream_id) f.error_code = e.error_code self._prepare_for_sending([f]) events = e._events except KeyError as e: # We don't have a function for handling this frame. Let's call this # a PROTOCOL_ERROR and exit. raise UnsupportedFrameError("Unexpected frame: %s" % frame) else: self._prepare_for_sending(frames) return events
def reset_stream(self, error_code=0): """ Close the stream locally. Reset the stream with an error code. """ self.state_machine.process_input(StreamInputs.SEND_RST_STREAM) rsf = RstStreamFrame(self.stream_id) rsf.error_code = error_code return [rsf]
def reset_stream(self, error_code=0): """ Close the stream locally. Reset the stream with an error code. """ self.state_machine.process_input(StreamInputs.SEND_RST_STREAM) rsf = RstStreamFrame(self.stream_id) rsf.error_code = error_code return [rsf]
def _receive_push_promise_frame(self, frame): """ Receive a push-promise frame on the connection. """ if not self.local_settings.enable_push: raise ProtocolError("Received pushed stream") pushed_headers = self.decoder.decode(frame.data) events = self.state_machine.process_input( ConnectionInputs.RECV_PUSH_PROMISE ) try: stream = self._get_stream_by_id(frame.stream_id) except NoSuchStreamError: # We need to check if the parent stream was reset by us. If it was # then we presume that the PUSH_PROMISE was in flight when we reset # the parent stream. Rather than accept the new stream, just reset # it. # # If this was closed naturally, however, we should call this a # PROTOCOL_ERROR: pushing a stream on a naturally closed stream is # a real problem because it creates a brand new stream that the # remote peer now believes exists. if frame.stream_id in self._reset_streams: f = RstStreamFrame(frame.promised_stream_id) f.error_code = REFUSED_STREAM return [f], events raise ProtocolError("Attempted to push on closed stream.") # We need to prevent peers pushing streams in response to streams that # they themselves have already pushed: see #163 and RFC 7540 ยง 6.6. The # easiest way to do that is to assert that the stream_id is not even: # this shortcut works because only servers can push and the state # machine will enforce this. if (frame.stream_id % 2) == 0: raise ProtocolError("Cannot recursively push streams.") frames, stream_events = stream.receive_push_promise_in_band( frame.promised_stream_id, pushed_headers, ) new_stream = self._begin_new_stream( frame.promised_stream_id, AllowedStreamIDs.EVEN ) self.streams[frame.promised_stream_id] = new_stream new_stream.remotely_pushed() return frames, events + stream_events
def test_reset_pushed_streams_when_push_disabled(self): self.add_push_frame(1, 2, [(':method', 'GET'), (':path', '/'), (':authority', 'www.google.com'), (':scheme', 'https'), ('accept-encoding', 'gzip')]) self.add_headers_frame(1, [(':status', '200'), ('content-type', 'text/html')]) self.request() self.conn._enable_push = False self.conn.get_response() f = RstStreamFrame(2) f.error_code = 7 assert self.conn._sock.queue[-1] == f.serialize()
def test_cancel_push(self): self.add_push_frame(1, 2, [(':method', 'GET'), (':path', '/'), (':authority', 'www.google.com'), (':scheme', 'https'), ('accept-encoding', 'gzip')]) self.add_headers_frame(1, [(':status', '200'), ('content-type', 'text/html')]) self.request() self.conn.get_response() list(self.conn.get_pushes())[0].cancel() f = RstStreamFrame(2) f.error_code = 8 assert self.conn._sock.queue[-1] == f.serialize()
def _receive_frame(self, frame): """ Handle a frame received on the connection. .. versionchanged:: 2.0.0 Removed from the public API. """ try: # I don't love using __class__ here, maybe reconsider it. frames, events = self._frame_dispatch_table[frame.__class__](frame) except StreamClosedError as e: # We need to send a RST_STREAM frame on behalf of the stream. # The frame the stream wants to emit is already present in the # exception. # This does not require re-raising: it's an expected behaviour. The # only time we don't do that is if this is a stream the user # manually reset. if frame.stream_id not in self._reset_streams: f = RstStreamFrame(e.stream_id) f.error_code = e.error_code self._prepare_for_sending([f]) events = e._events else: events = [] except StreamIDTooLowError as e: # The stream ID seems invalid. This is unlikely, so it's probably # the case that this frame is actually for a stream that we've # already reset and removed the state for. If it is, just swallow # the error. If we didn't do that, re-raise. if frame.stream_id not in self._reset_streams: raise events = [] except KeyError as e: # We don't have a function for handling this frame. Let's call this # a PROTOCOL_ERROR and exit. raise UnsupportedFrameError("Unexpected frame: %s" % frame) else: self._prepare_for_sending(frames) return events
def test_reset_pushed_streams_when_push_disabled(self): self.add_push_frame( 1, 2, [ (':method', 'GET'), (':path', '/'), (':authority', 'www.google.com'), (':scheme', 'https'), ('accept-encoding', 'gzip') ] ) self.add_headers_frame( 1, [(':status', '200'), ('content-type', 'text/html')] ) self.request() self.conn._enable_push = False self.conn.get_response() f = RstStreamFrame(2) f.error_code = 7 assert self.conn._sock.queue[-1] == f.serialize()
def test_cancel_push(self): self.add_push_frame( 1, 2, [ (':method', 'GET'), (':path', '/'), (':authority', 'www.google.com'), (':scheme', 'https'), ('accept-encoding', 'gzip') ] ) self.add_headers_frame( 1, [(':status', '200'), ('content-type', 'text/html')] ) self.request() self.conn.get_response() list(self.conn.get_pushes())[0].cancel() f = RstStreamFrame(2) f.error_code = 8 assert self.conn._sock.queue[-1] == f.serialize()
def test_rst_stream_frame_serializes_properly(self): f = RstStreamFrame(1) f.error_code = 420 s = f.serialize() assert s == b'\x00\x00\x04\x03\x00\x00\x00\x00\x01\x00\x00\x01\xa4'
def test_rst_stream_frame_serializes_properly(self): f = RstStreamFrame(1) f.error_code = 420 s = f.serialize() assert s == b'\x00\x00\x04\x03\x00\x00\x00\x00\x01\x00\x00\x01\xa4'
def test_repr(self): f = RstStreamFrame(1) assert repr(f).endswith("error_code=0") f.error_code = 420 assert repr(f).endswith("error_code=420")