Example #1
0
 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
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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]
Example #6
0
    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]
Example #7
0
    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
Example #8
0
    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()
Example #9
0
    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()
Example #10
0
        def socket_handler(listener):
            sock = listener.accept()[0]

            # We get two messages for the connection open and then a HEADERS
            # frame.
            receive_preamble(sock)
            sock.recv(65535)

            # Now, send two RST_STREAM frames.
            for _ in range(0, 2):
                f = RstStreamFrame(1)
                sock.send(f.serialize())

            # Wait for the message from the main thread.
            recv_event.wait(5)
            sock.close()
Example #11
0
        def socket_handler(listener):
            sock = listener.accept()[0]

            # We get two messages for the connection open and then a HEADERS
            # frame.
            receive_preamble(sock)
            sock.recv(65535)

            # Now, send two RST_STREAM frames.
            for _ in range(0, 2):
                f = RstStreamFrame(1)
                sock.send(f.serialize())

            # Wait for the message from the main thread.
            recv_event.wait(5)
            sock.close()
Example #12
0
    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
Example #13
0
    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()
Example #14
0
    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()
Example #15
0
    def receive_frame(self, frame):
        """
        Handle a frame received on the connection.
        """
        try:
            if frame.body_len > self.max_inbound_frame_size:
                raise ProtocolError(
                    "Received overlong frame: length %d, max %d" %
                    (frame.body_len, self.max_inbound_frame_size))

            # I don't love using __class__ here, maybe reconsider it.
            frames, events = self._frame_dispatch_table[frame.__class__](frame)
        except ProtocolError as e:
            # For whatever reason, receiving the frame caused a protocol error.
            # We should prepare to emit a GoAway frame before throwing the
            # exception up further. No need for an event: the exception will
            # do fine.
            f = GoAwayFrame(0)
            f.last_stream_id = sorted(self.streams.keys())[-1]
            f.error_code = e.error_code
            self.state_machine.process_input(ConnectionInputs.SEND_GOAWAY)
            self._prepare_for_sending([f])
            raise
        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 = []
        else:
            self._prepare_for_sending(frames)

        return events
Example #16
0
 def test_rst_stream_frame_has_no_flags(self):
     f = RstStreamFrame(1)
     flags = f.parse_flags(0xFF)
     assert not flags
     assert isinstance(flags, Flags)
 def test_rst_stream_frame_must_have_body_length_four(self):
     f = RstStreamFrame(1)
     with pytest.raises(ValueError):
         f.parse_body(b'\x01')
    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_has_no_flags(self):
     f = RstStreamFrame(1)
     flags = f.parse_flags(0xFF)
     assert not flags
     assert isinstance(flags, set)
Example #20
0
 def test_rst_stream_frame_must_have_body_length_four(self):
     f = RstStreamFrame(1)
     with pytest.raises(ValueError):
         f.parse_body(b'\x01')
Example #21
0
 def test_rst_stream_frame_comes_on_a_stream(self):
     with pytest.raises(ValueError):
         RstStreamFrame(0)
Example #22
0
    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'
Example #23
0
 def test_rst_stream_frame_comes_on_a_stream(self):
     with pytest.raises(InvalidDataError):
         RstStreamFrame(0)
Example #24
0
 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")