예제 #1
0
def client_and_server(
    client_options={},
    client_patch=lambda x: None,
    server_options={},
    server_patch=lambda x: None,
    transport_options={},
):
    client = QuicConnection(
        configuration=QuicConfiguration(is_client=True, **client_options))
    client._ack_delay = 0
    client_patch(client)

    server = QuicConnection(
        configuration=QuicConfiguration(is_client=False,
                                        certificate=SERVER_CERTIFICATE,
                                        private_key=SERVER_PRIVATE_KEY,
                                        **server_options))
    server._ack_delay = 0
    server_patch(server)

    # perform handshake
    client.connect(SERVER_ADDR, now=time.time())
    for i in range(3):
        roundtrip(client, server)

    yield client, server

    # close
    client.close()
    server.close()
예제 #2
0
def create_standalone_client(self):
    client = QuicConnection(configuration=QuicConfiguration(is_client=True))
    client._ack_delay = 0

    # kick-off handshake
    client.connect(SERVER_ADDR, now=time.time())
    self.assertEqual(drop(client), 1)

    return client
예제 #3
0
def create_standalone_client():
    client = QuicConnection(configuration=QuicConfiguration(is_client=True))
    client_transport = FakeTransport(CLIENT_ADDR, loss=0)

    # kick-off handshake
    client.connection_made(client_transport)
    client.connect(SERVER_ADDR)

    return client, client_transport
예제 #4
0
def run(url: str) -> None:
    # parse URL
    parsed = urlparse(url)
    assert parsed.scheme == "https", "Only HTTPS URLs are supported."
    if ":" in parsed.netloc:
        server_name, port_str = parsed.netloc.split(":")
        port = int(port_str)
    else:
        server_name = parsed.netloc
        port = 443

    # prepare socket
    server_addr = (socket.gethostbyname(server_name), port)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # prepare QUIC connection
    quic = QuicConnection(configuration=QuicConfiguration(
        alpn_protocols=["h3-20"],
        is_client=True,
        secrets_log_file=open("/tmp/ssl.log", "w"),
        server_name=server_name,
    ))
    quic.connect(server_addr, now=time.time())

    # send request
    http = H3Connection(quic)
    stream_id = quic.get_next_available_stream_id()
    http.send_headers(
        stream_id=stream_id,
        headers=[
            (b":method", b"GET"),
            (b":scheme", parsed.scheme.encode("utf8")),
            (b":authority", parsed.netloc.encode("utf8")),
            (b":path", parsed.path.encode("utf8")),
        ],
    )
    http.send_data(stream_id=stream_id, data=b"", end_stream=True)
    for data, addr in quic.datagrams_to_send(now=time.time()):
        sock.sendto(data, addr)

    # handle events
    stream_ended = False
    while not stream_ended:
        data, addr = sock.recvfrom(2048)
        quic.receive_datagram(data, addr, now=time.time())
        for event in http.handle_events():
            print(event)
            if isinstance(event, (DataReceived, ResponseReceived)):
                stream_ended = event.stream_ended

        for data, addr in quic.datagrams_to_send(now=time.time()):
            sock.sendto(data, addr)
예제 #5
0
    def test_connection_lost_with_exception(self):
        client = QuicConnection(is_client=True)
        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )

        # perform handshake
        client_transport, server_transport = create_transport(client, server)
        self.assertEqual(client_transport.sent, 4)
        self.assertEqual(server_transport.sent, 4)
        run(client.connect())

        # send data over stream
        client_reader, client_writer = client.create_stream()
        client_writer.write(b"ping")
        run(asyncio.sleep(0))
        self.assertEqual(client_transport.sent, 5)
        self.assertEqual(server_transport.sent, 5)

        # break connection
        exc = Exception("some error")
        client.connection_lost(exc)
        with self.assertRaises(Exception) as cm:
            run(client_reader.read())
        self.assertEqual(cm.exception, exc)
예제 #6
0
    def _test_connect_with_version(self, client_versions, server_versions):
        client = QuicConnection(is_client=True)
        client.supported_versions = client_versions

        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )
        server.supported_versions = server_versions

        # perform handshake
        client_transport, server_transport = create_transport(client, server)
        self.assertEqual(client_transport.sent, 4)
        self.assertEqual(server_transport.sent, 4)
        run(client.connect())

        # send data over stream
        client_reader, client_writer = client.create_stream()
        client_writer.write(b"ping")
        run(asyncio.sleep(0))
        self.assertEqual(client_transport.sent, 5)
        self.assertEqual(server_transport.sent, 5)

        # FIXME: needs an API
        server_reader, server_writer = (
            server.streams[0].reader,
            server.streams[0].writer,
        )
        self.assertEqual(run(server_reader.read(1024)), b"ping")
        server_writer.write(b"pong")
        run(asyncio.sleep(0))
        self.assertEqual(client_transport.sent, 6)
        self.assertEqual(server_transport.sent, 6)

        # client receives pong
        self.assertEqual(run(client_reader.read(1024)), b"pong")

        # client writes EOF
        client_writer.write_eof()
        run(asyncio.sleep(0))
        self.assertEqual(client_transport.sent, 7)
        self.assertEqual(server_transport.sent, 7)

        # server receives EOF
        self.assertEqual(run(server_reader.read()), b"")
예제 #7
0
    def test_connection_lost(self):
        client = QuicConnection(is_client=True)
        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )

        # perform handshake
        client_transport, server_transport = create_transport(client, server)
        self.assertEqual(client_transport.sent, 4)
        self.assertEqual(server_transport.sent, 4)
        run(client.connect())

        # send data over stream
        client_reader, client_writer = client.create_stream()
        client_writer.write(b"ping")
        run(asyncio.sleep(0))
        self.assertEqual(client_transport.sent, 5)
        self.assertEqual(server_transport.sent, 5)

        # break connection
        client.connection_lost(None)
        self.assertEqual(run(client_reader.read()), b"")