예제 #1
0
    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)
예제 #2
0
    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]),
예제 #3
0
 def test_pull_uint32_truncated(self):
     buf = Buffer(capacity=3)
     with self.assertRaises(BufferReadError):
         buf.pull_uint32()
     self.assertEqual(buf.tell(), 0)
예제 #4
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)