Example #1
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 #2
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 #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_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 #9
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 #10
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 #11
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 #12
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()
    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 #14
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 #15
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")