def _receive_data_on_session_stream(self, data: bytes, fin: bool) -> None: self._capsule_decoder_for_session_stream.append(data) if fin: self._capsule_decoder_for_session_stream.final() for capsule in self._capsule_decoder_for_session_stream: if capsule.type in { CapsuleType.DATAGRAM, CapsuleType.REGISTER_DATAGRAM_CONTEXT, CapsuleType.CLOSE_DATAGRAM_CONTEXT }: raise ProtocolError( f"Unimplemented capsule type: {capsule.type}") if capsule.type in { CapsuleType.REGISTER_DATAGRAM_NO_CONTEXT, CapsuleType.CLOSE_WEBTRANSPORT_SESSION }: # We'll handle this case below. pass else: # We should ignore unknown capsules. continue if self._close_info is not None: raise ProtocolError( ("Receiving a capsule with type = {} after receiving " + "CLOSE_WEBTRANSPORT_SESSION").format(capsule.type)) if capsule.type == CapsuleType.REGISTER_DATAGRAM_NO_CONTEXT: buffer = Buffer(data=capsule.data) format_type = buffer.pull_uint_var() # https://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#name-datagram-format-type WEBTRANPORT_FORMAT_TYPE = 0xff7c00 if format_type != WEBTRANPORT_FORMAT_TYPE: raise ProtocolError( "Unexpected datagram format type: {}".format( format_type)) self._allow_datagrams = True elif capsule.type == CapsuleType.CLOSE_WEBTRANSPORT_SESSION: buffer = Buffer(data=capsule.data) code = buffer.pull_uint32() # 4 bytes for the uint32. reason = buffer.pull_bytes(len(capsule.data) - 4) # TODO(yutakahirano): Make sure `reason` is a UTF-8 text. self._close_info = (code, reason) if fin: self._call_session_closed(self._close_info, abruptly=False)
def test_pull_version_negotiation(self): buf = Buffer(data=load("version_negotiation.bin")) header = pull_quic_header(buf, host_cid_length=8) self.assertTrue(header.is_long_header) self.assertEqual(header.version, QuicProtocolVersion.NEGOTIATION) self.assertEqual(header.packet_type, None) self.assertEqual(header.destination_cid, binascii.unhexlify("9aac5a49ba87a849")) self.assertEqual(header.source_cid, binascii.unhexlify("f92f4336fa951ba1")) self.assertEqual(header.token, b"") self.assertEqual(header.integrity_tag, b"") self.assertEqual(header.rest_length, 8) self.assertEqual(buf.tell(), 23) versions = [] while not buf.eof(): versions.append(buf.pull_uint32()) self.assertEqual(versions, [0x45474716, QuicProtocolVersion.VERSION_1]),
def test_pull_uint32_truncated(self): buf = Buffer(capacity=3) with self.assertRaises(BufferReadError): buf.pull_uint32() self.assertEqual(buf.tell(), 0)
def test_pull_uint32(self): buf = Buffer(data=b"\x08\x07\x06\x05\x04\x03\x02\x01") self.assertEqual(buf.pull_uint32(), 0x08070605) self.assertEqual(buf.tell(), 4)