def send_duplicate_push (self, stream_id, push_id): assert not self._is_client, "Only servers may send a duplicate push." assert push_id < self._max_push_id, "Given push ID is never sent" assert ( push_id not in self._canceled_push_ids ), "Given push ID is canceled by client" self._quic.send_stream_data (stream_id, encode_frame(FrameType.DUPLICATE_PUSH, encode_uint_var(push_id)), True)
def shutdown (self, last_stream_id = None): assert not self._is_client, "Client must not send a goaway frame" if last_stream_id is None: last_stream_id = self._max_client_bidi_stream_id else: if last_stream_id == -1: last_stream_id = -4 assert last_stream_id % 4 == 0 and (-4 <= last_stream_id <= self._max_client_bidi_stream_id), "Unissued request stream" frame = encode_frame(FrameType.GOAWAY, encode_uint_var(last_stream_id + 4)) self._quic.send_stream_data (self._local_control_stream_id, frame)
def test_handle_request_frame_bad_headers(self): """ We should not receive HEADERS which cannot be decoded. """ quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_server = H3Connection(quic_server) h3_server.handle_event( StreamDataReceived(stream_id=0, data=encode_frame(FrameType.HEADERS, b""), end_stream=False)) self.assertEqual(quic_server.closed, (ErrorCode.HTTP_QPACK_DECOMPRESSION_FAILED, ""))
def send_push_promise (self, stream_id, headers): assert not self._is_client, "Only servers may send a push promise." if self._max_push_id is None or self._next_push_id >= self._max_push_id: raise NoAvailablePushIDError push_id = self._next_push_id self._next_push_id += 1 frame = encode_frame (FrameType.PUSH_PROMISE, encode_uint_var(push_id) + self._encode_headers(stream_id, headers)) self._quic.send_stream_data (stream_id, frame) push_stream_id = self._create_uni_stream (StreamType.PUSH) self._quic.send_stream_data (push_stream_id, encode_uint_var(push_id)) self._push_map [push_stream_id] = push_id return push_stream_id
def test_handle_request_frame_wrong_frame_type(self): quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_server = H3Connection(quic_server) h3_server.handle_event( StreamDataReceived( stream_id=0, data=encode_frame(FrameType.SETTINGS, b""), end_stream=False, )) self.assertEqual( quic_server.closed, (ErrorCode.HTTP_FRAME_UNEXPECTED, "Invalid frame type on request stream"), )
def test_handle_request_frame_push_promise_from_client(self): """ A server should not receive PUSH_PROMISE on a request stream. """ quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_server = H3Connection(quic_server) h3_server.handle_event( StreamDataReceived( stream_id=0, data=encode_frame(FrameType.PUSH_PROMISE, b""), end_stream=False, )) self.assertEqual( quic_server.closed, (ErrorCode.HTTP_FRAME_UNEXPECTED, "Clients must not send PUSH_PROMISE"), )
def test_handle_request_frame_data_before_headers(self): """ We should not receive DATA before receiving headers. """ quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_server = H3Connection(quic_server) h3_server.handle_event( StreamDataReceived(stream_id=0, data=encode_frame(FrameType.DATA, b""), end_stream=False)) self.assertEqual( quic_server.closed, ( ErrorCode.HTTP_FRAME_UNEXPECTED, "DATA frame is not allowed in this state", ), )
def test_handle_control_frame_max_push_id_from_server(self): """ A client should not receive MAX_PUSH_ID on the control stream. """ quic_client = FakeQuicConnection(configuration=QuicConfiguration( is_client=True)) h3_client = H3Connection(quic_client) h3_client.handle_event( StreamDataReceived( stream_id=3, data=encode_uint_var(StreamType.CONTROL) + encode_frame(FrameType.MAX_PUSH_ID, b""), end_stream=False, )) self.assertEqual( quic_client.closed, (ErrorCode.HTTP_FRAME_UNEXPECTED, "Servers must not send MAX_PUSH_ID"), )
def test_handle_control_frame_headers(self): """ We should not receive HEADERS on the control stream. """ quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_server = H3Connection(quic_server) h3_server.handle_event( StreamDataReceived( stream_id=2, data=encode_uint_var(StreamType.CONTROL) + encode_frame(FrameType.HEADERS, b""), end_stream=False, )) self.assertEqual( quic_server.closed, (ErrorCode.HTTP_FRAME_UNEXPECTED, "Invalid frame type on control stream"), )
def test_handle_push_frame_wrong_frame_type(self): """ We should not received SETTINGS on a push stream. """ quic_client = FakeQuicConnection(configuration=QuicConfiguration( is_client=True)) h3_client = H3Connection(quic_client) h3_client.handle_event( StreamDataReceived( stream_id=15, data=encode_uint_var(StreamType.PUSH) + encode_uint_var(0) # push ID + encode_frame(FrameType.SETTINGS, b""), end_stream=False, )) self.assertEqual( quic_client.closed, (ErrorCode.HTTP_FRAME_UNEXPECTED, "Invalid frame type on push stream"), )
def test_handle_request_frame_headers_after_trailers(self): """ We should not receive HEADERS after receiving trailers. """ quic_client = FakeQuicConnection(configuration=QuicConfiguration( is_client=True)) quic_server = FakeQuicConnection(configuration=QuicConfiguration( is_client=False)) h3_client = H3Connection(quic_client) h3_server = H3Connection(quic_server) stream_id = quic_client.get_next_available_stream_id() h3_client.send_headers( stream_id=stream_id, headers=[ (b":method", b"GET"), (b":scheme", b"https"), (b":authority", b"localhost"), (b":path", b"/"), ], ) h3_client.send_headers(stream_id=stream_id, headers=[(b"x-some-trailer", b"foo")], end_stream=True) h3_transfer(quic_client, h3_server) h3_server.handle_event( StreamDataReceived(stream_id=0, data=encode_frame(FrameType.HEADERS, b""), end_stream=False)) self.assertEqual( quic_server.closed, ( ErrorCode.HTTP_FRAME_UNEXPECTED, "HEADERS frame is not allowed in this state", ), )
def cancel_push (self, push_id): self._canceled_push_ids.add (push_id) self._quic.send_stream_data (self._local_control_stream_id, encode_frame(FrameType.CANCEL_PUSH, encode_uint_var(push_id)))