Example #1
0
    def _consume_frame_payload(self, frame, data):
        frame.parse_body(data)

        if self.config.http2_show_debug:
            self.logger.debug("h2 %s Recv:%s", self.ip_str, str(frame))

        # Maintain our flow control window. We do this by delegating to the
        # chosen WindowManager.
        if frame.type == DataFrame.type:

            size = frame.flow_controlled_length
            increment = self.local_window_manager._handle_frame(size)

            if increment < 0:
                self.logger.warn("increment:%d", increment)
            elif increment:
                #self.logger.debug("%s frame size:%d increase win:%d", self.ip, size, increment)
                w = WindowUpdateFrame(0)
                w.window_increment = increment
                self._send_cb(w)

        elif frame.type == PushPromiseFrame.type:
            self.logger.error("%s receive push frame", self.ip_str, )

        # Work out to whom this frame should go.
        if frame.stream_id != 0:
            try:
                stream = self.streams[frame.stream_id]
                stream.receive_frame(frame)
            except KeyError as e:
                if frame.type not in [WindowUpdateFrame.type]:
                    self.logger.warn("%s Unexpected stream identifier %d, frame.type:%s e:%r",
                                          self.ip_str, frame.stream_id, frame, e)
        else:
            self.receive_frame(frame)
Example #2
0
        def socket_handler(listener):
            sock = listener.accept()[0]

            # Dispose of the first packet.
            sock.recv(65535)

            # Send a Settings frame that reduces the flow-control window to
            # 64 bytes.
            f = SettingsFrame(0)
            f.settings[SettingsFrame.INITIAL_WINDOW_SIZE] = 64
            sock.send(f.serialize())

            # Grab three frames, the settings ACK, the initial headers frame,
            # and the first data frame.
            for x in range(0, 3):
                data.append(sock.recv(65535))

            # Send a WindowUpdate giving more window room to the stream.
            f = WindowUpdateFrame(1)
            f.window_increment = 64
            sock.send(f.serialize())

            # Send one that gives more room to the connection.
            f = WindowUpdateFrame(0)
            f.window_increment = 64
            sock.send(f.serialize())

            # Reeive the remaining frame.
            data.append(sock.recv(65535))
            send_event.set()

            # We're done.
            sock.close()
 def build_window_update_frame(self, stream_id, increment):
     """
     Builds a single WindowUpdate frame.
     """
     f = WindowUpdateFrame(stream_id)
     f.window_increment = increment
     return f
Example #4
0
    def increment_flow_control_window(self, increment, stream_id=None):
        """
        Increment a flow control window, optionally for a single stream. Allows
        the remote peer to send more data.

        .. versionchanged:: 2.0.0
           Rejects attempts to increment the flow control window by out of
           range values with a ``ValueError``.

        :param increment: The amount ot increment the flow control window by.
        :type increment: ``int``
        :param stream_id: (optional) The ID of the stream that should have its
            flow control window opened. If not present or ``None``, the
            connection flow control window will be opened instead.
        :type stream_id: ``int`` or ``None``
        :returns: Nothing
        :raises: ``ValueError``
        """
        if not (1 <= increment <= self.MAX_WINDOW_INCREMENT):
            raise ValueError("Flow control increment must be between 1 and %d" % self.MAX_WINDOW_INCREMENT)

        self.state_machine.process_input(ConnectionInputs.SEND_WINDOW_UPDATE)

        if stream_id is not None:
            stream = self.streams[stream_id]
            frames = stream.increase_flow_control_window(increment)
            stream.inbound_flow_control_window = guard_increment_window(stream.inbound_flow_control_window, increment)
        else:
            f = WindowUpdateFrame(0)
            f.window_increment = increment
            self.inbound_flow_control_window = guard_increment_window(self.inbound_flow_control_window, increment)
            frames = [f]

        self._prepare_for_sending(frames)
Example #5
0
 def build_window_update_frame(self, stream_id, increment):
     """
     Builds a single WindowUpdate frame.
     """
     f = WindowUpdateFrame(stream_id)
     f.window_increment = increment
     return f
Example #6
0
 def increase_flow_control_window(self, increment):
     """
     Increase the size of the flow control window for the remote side.
     """
     self.state_machine.process_input(StreamInputs.SEND_WINDOW_UPDATE)
     wuf = WindowUpdateFrame(self.stream_id)
     wuf.window_increment = increment
     return [wuf]
Example #7
0
 def increase_flow_control_window(self, increment):
     """
     Increase the size of the flow control window for the remote side.
     """
     self.state_machine.process_input(StreamInputs.SEND_WINDOW_UPDATE)
     wuf = WindowUpdateFrame(self.stream_id)
     wuf.window_increment = increment
     return [wuf]
    def slow_settings(self, conn, h2conn):
        LOGGER.info("SLOW SETTINGS ATTACK============================")
        h2conn.initiate_connection()
        wf = WindowUpdateFrame(0)
        wf.window_increment = WINDOW_SIZE_INCREMENT
        h2conn._data_to_send += wf.serialize()
        conn.sendall(h2conn.data_to_send())

        headers = [(":authority", args.target), (":path", "/"),
                   (":scheme", "http"), (":method", "GET")]
        h2conn.send_headers(1, headers, end_stream=True)
        conn.sendall(h2conn.data_to_send())
Example #9
0
    def test_short_windowupdate_frame_errors(self):
        s = b'\x00\x00\x04\x08\x00\x00\x00\x00\x00\x00\x00\x02'  # -1 byte
        with pytest.raises(InvalidFrameError):
            decode_frame(s)

        s = b'\x00\x00\x05\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02'
        with pytest.raises(InvalidFrameError):
            decode_frame(s)

        with pytest.raises(InvalidDataError):
            decode_frame(WindowUpdateFrame(0).serialize())

        with pytest.raises(InvalidDataError):
            decode_frame(WindowUpdateFrame(2**31).serialize())
Example #10
0
    def acknowledge_received_data(self, acknowledged_size):
        """
        The user has informed us that they've processed some amount of data
        that was received on this stream. Pass that to the window manager and
        potentially return some WindowUpdate frames.
        """
        increment = self._inbound_window_manager.process_bytes(
            acknowledged_size)
        if increment:
            f = WindowUpdateFrame(self.stream_id)
            f.window_increment = increment
            return [f]

        return []
Example #11
0
    def acknowledge_received_data(self, acknowledged_size):
        """
        The user has informed us that they've processed some amount of data
        that was received on this stream. Pass that to the window manager and
        potentially return some WindowUpdate frames.
        """
        increment = self._inbound_window_manager.process_bytes(
            acknowledged_size
        )
        if increment:
            f = WindowUpdateFrame(self.stream_id)
            f.window_increment = increment
            return [f]

        return []
    def slow_headers(self, conn, h2conn, method="GET"):
        LOGGER.info("SLOW HEADERS ATTACK=============================")
        h2conn.initiate_connection()
        wf = WindowUpdateFrame(0)
        wf.window_increment = WINDOW_SIZE_INCREMENT
        h2conn._data_to_send += wf.serialize()
        conn.sendall(h2conn.data_to_send())

        headers = [(":authority", args.target), (":path", "/"),
                   (":scheme", "http"), (":method", method)]
        hf = HeadersFrame(1)
        if method == "GET":
            hf.flags.add("END_STREAM")
        e = Encoder()
        hf.data = e.encode(headers)
        h2conn._data_to_send += hf.serialize()
        conn.sendall(h2conn.data_to_send())
Example #13
0
def attack2(tls_conn, h2_conn):
    h2_conn.initiate_connection()
    wf = WindowUpdateFrame(0)
    wf.window_increment = WINDOW_INCREMENT_SIZE
    h2_conn._data_to_send += wf.serialize()
    tls_conn.sendall(h2_conn.data_to_send())
    headers = [
        (':authority', args.target),
        (':path', '/'),
        (':scheme', 'https'),
        (':method', 'POST'),
    ]
    hf = HeadersFrame(1)
    hf.flags.add('END_HEADERS')
    e = Encoder()
    hf.data = hf.data = e.encode(headers)
    h2_conn._data_to_send += hf.serialize()
    tls_conn.sendall(h2_conn.data_to_send())
Example #14
0
    def increment_flow_control_window(self, increment, stream_id=None):
        """
        Increment a flow control window, optionally for a single stream.
        """
        self.state_machine.process_input(ConnectionInputs.SEND_WINDOW_UPDATE)

        if stream_id is not None:
            stream = self.streams[stream_id]
            frames, events = stream.increase_flow_control_window(increment)
            stream.inbound_flow_control_window += increment
        else:
            f = WindowUpdateFrame(0)
            f.window_increment = increment
            self.inbound_flow_control_window += increment
            frames = [f]
            events = []

        self._prepare_for_sending(frames)
        return events
Example #15
0
    def increment_flow_control_window(self, increment, stream_id=None):
        """
        Increment a flow control window, optionally for a single stream.
        """
        self.state_machine.process_input(ConnectionInputs.SEND_WINDOW_UPDATE)

        if stream_id is not None:
            stream = self.streams[stream_id]
            frames, events = stream.increase_flow_control_window(
                increment
            )
            stream.inbound_flow_control_window += increment
        else:
            f = WindowUpdateFrame(0)
            f.window_increment = increment
            self.inbound_flow_control_window += increment
            frames = [f]
            events = []

        self._prepare_for_sending(frames)
        return events
Example #16
0
    def _send_preamble(self):
        self.send_queue.put(RawFrame(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'))

        f = SettingsFrame(0)
        f.settings[SettingsFrame.ENABLE_PUSH] = 0
        f.settings[SettingsFrame.INITIAL_WINDOW_SIZE] = self.local_settings[SettingsFrame.INITIAL_WINDOW_SIZE]
        f.settings[SettingsFrame.MAX_FRAME_SIZE] = self.local_settings[SettingsFrame.MAX_FRAME_SIZE]
        self._send_cb(f)

        # update local connection windows size
        f = WindowUpdateFrame(0)
        f.window_increment = self.local_connection_initial_windows - DEFAULT_WINDOW_SIZE
        self._send_cb(f)
Example #17
0
    def increment_flow_control_window(self, increment, stream_id=None):
        """
        Increment a flow control window, optionally for a single stream. Allows
        the remote peer to send more data.

        .. versionchanged:: 2.0.0
           Rejects attempts to increment the flow control window by out of
           range values with a ``ValueError``.

        :param increment: The amount ot increment the flow control window by.
        :type increment: ``int``
        :param stream_id: (optional) The ID of the stream that should have its
            flow control window opened. If not present or ``None``, the
            connection flow control window will be opened instead.
        :type stream_id: ``int`` or ``None``
        :returns: Nothing
        :raises: ``ValueError``
        """
        if not (1 <= increment <= self.MAX_WINDOW_INCREMENT):
            raise ValueError(
                "Flow control increment must be between 1 and %d" %
                self.MAX_WINDOW_INCREMENT)

        self.state_machine.process_input(ConnectionInputs.SEND_WINDOW_UPDATE)

        if stream_id is not None:
            stream = self.streams[stream_id]
            frames = stream.increase_flow_control_window(increment)
            stream.inbound_flow_control_window = guard_increment_window(
                stream.inbound_flow_control_window, increment)
        else:
            f = WindowUpdateFrame(0)
            f.window_increment = increment
            self.inbound_flow_control_window = guard_increment_window(
                self.inbound_flow_control_window, increment)
            frames = [f]

        self._prepare_for_sending(frames)
Example #18
0
 def test_repr(self):
     f = WindowUpdateFrame(0)
     assert repr(f).endswith("window_increment=0")
     f.stream_id = 1
     f.window_increment = 512
     assert repr(f).endswith("window_increment=512")
    def test_window_update_serializes_properly(self):
        f = WindowUpdateFrame(0)
        f.window_increment = 512

        s = f.serialize()
        assert s == b'\x00\x00\x04\x08\x00\x00\x00\x00\x00\x00\x00\x02\x00'
    def test_window_update_has_no_flags(self):
        f = WindowUpdateFrame(0)
        flags = f.parse_flags(0xFF)

        assert not flags
        assert isinstance(flags, set)
Example #21
0
    def test_window_update_serializes_properly(self):
        f = WindowUpdateFrame(0)
        f.window_increment = 512

        s = f.serialize()
        assert s == b'\x00\x00\x04\x08\x00\x00\x00\x00\x00\x00\x00\x02\x00'
Example #22
0
    def test_window_update_has_no_flags(self):
        f = WindowUpdateFrame(0)
        flags = f.parse_flags(0xFF)

        assert not flags
        assert isinstance(flags, Flags)
Example #23
0
    def receive_frame(self, frame):
        """
        Handle a frame received on this stream.
        called by connection.
        """
        # self.logger.debug("stream %d recved frame %r", self.stream_id, frame)
        if frame.type == WindowUpdateFrame.type:
            self.remote_window_size += frame.window_increment
            self.send_left_body()
        elif frame.type == HeadersFrame.type:
            # Begin the header block for the response headers.
            #self.response_header_datas = [frame.data]
            self.response_header_datas.append(frame.data)
        elif frame.type == PushPromiseFrame.type:
            self.logger.error("%s receive PushPromiseFrame:%d", self.ip_str,
                              frame.stream_id)
        elif frame.type == ContinuationFrame.type:
            # Continue a header block begun with either HEADERS or PUSH_PROMISE.
            self.response_header_datas.append(frame.data)
        elif frame.type == DataFrame.type:
            # Append the data to the buffer.
            if not self.task.finished:
                self.task.put_data(frame.data)

            if 'END_STREAM' not in frame.flags:
                # Increase the window size. Only do this if the data frame contains
                # actual data.
                # don't do it if stream is closed.
                size = frame.flow_controlled_length
                increment = self.receive_window_manager._handle_frame(size)
                #if increment:
                #    self.logger.debug("stream:%d frame size:%d increase win:%d", self.stream_id, size, increment)

                #content_len = int(self.request_headers.get("Content-Length")[0])
                #self.logger.debug("%s get:%d s:%d", self.ip, self.response_body_len, size)

                if increment and not self._remote_closed:
                    w = WindowUpdateFrame(self.stream_id)
                    w.window_increment = increment
                    self._send_cb(w)

        elif frame.type == RstStreamFrame.type:
            # Rest Frame send from server is not define in RFC
            inactive_time = time.time() - self.connection.last_recv_time
            self.logger.debug(
                "%s Stream %d Rest by server, inactive:%d. error code:%d",
                self.ip_str, self.stream_id, inactive_time, frame.error_code)
            self.connection.close("RESET")
        elif frame.type in FRAMES:
            # This frame isn't valid at this point.
            #raise ValueError("Unexpected frame %s." % frame)
            self.logger.error("%s Unexpected frame %s.", self.ip_str, frame)
        else:  # pragma: no cover
            # Unknown frames belong to extensions. Just drop it on the
            # floor, but log so that users know that something happened.
            self.logger.error("%s Received unknown frame, type %d",
                              self.ip_str, frame.type)
            pass

        if 'END_HEADERS' in frame.flags:
            if self.config.http2_show_debug:
                self.logger.debug("END_HEADERS")

            if self.response_headers is not None:
                raise ProtocolError("Too many header blocks.")

            # Begin by decoding the header block. If this fails, we need to
            # tear down the entire connection.
            if len(self.response_header_datas) == 1:
                header_data = self.response_header_datas[0]
            else:
                header_data = b''.join(self.response_header_datas)

            try:
                headers = self._decoder.decode(header_data)
            except Exception as e:
                self.logger.exception("decode h2 header %s fail:%r",
                                      header_data, e)
                raise e

            self.response_headers = HTTPHeaderMap(headers)

            # We've handled the headers, zero them out.
            self.response_header_datas = None

            self.get_head_time = time.time()

            length = self.response_headers.get("Content-Length", None)
            if isinstance(length, list):
                length = int(length[0])
            if not self.task.finished:
                self.task.content_length = length
                self.task.set_state("h2_get_head")
                self.send_response()

        if 'END_STREAM' in frame.flags:
            if self.config.http2_show_debug:
                self.logger.debug("%s Closing remote side of stream:%d",
                                  self.connection.ssl_sock.ip_str,
                                  self.stream_id)

            time_now = time.time()
            time_cost = time_now - self.get_head_time
            if time_cost > 0 and \
                    isinstance(self.task.content_length, int) and \
                    not self.task.finished:
                speed = self.task.content_length / time_cost
                self.task.set_state("h2_finish[SP:%d]" % speed)

            self._close_remote()

            self.close("end stream")
            if not self.task.finished:
                self.connection.continue_timeout = 0