2025-01-01 04:12:39 +09:00
|
|
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
2024-12-20 13:48:48 +01:00
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
import { assert, assertEquals } from "./test_util.ts";
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
const cert = Deno.readTextFileSync("tests/testdata/tls/localhost.crt");
|
|
|
|
const key = Deno.readTextFileSync("tests/testdata/tls/localhost.key");
|
|
|
|
const caCerts = [Deno.readTextFileSync("tests/testdata/tls/RootCA.pem")];
|
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
interface Pair {
|
|
|
|
server: Deno.QuicConn;
|
|
|
|
client: Deno.QuicConn;
|
|
|
|
endpoint: Deno.QuicEndpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function pair(opt?: Deno.QuicTransportOptions): Promise<Pair> {
|
|
|
|
const endpoint = new Deno.QuicEndpoint({ hostname: "localhost" });
|
|
|
|
const listener = endpoint.listen({
|
2024-12-20 13:48:48 +01:00
|
|
|
cert,
|
|
|
|
key,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
...opt,
|
|
|
|
});
|
2025-01-06 15:24:59 +01:00
|
|
|
assertEquals(endpoint, listener.endpoint);
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
const [server, client] = await Promise.all([
|
|
|
|
listener.accept(),
|
|
|
|
Deno.connectQuic({
|
|
|
|
hostname: "localhost",
|
2025-01-06 15:24:59 +01:00
|
|
|
port: endpoint.addr.port,
|
2024-12-20 13:48:48 +01:00
|
|
|
caCerts,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
...opt,
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
|
|
|
|
assertEquals(server.protocol, "deno-test");
|
|
|
|
assertEquals(client.protocol, "deno-test");
|
2025-01-06 15:24:59 +01:00
|
|
|
assertEquals(client.remoteAddr, endpoint.addr);
|
|
|
|
assertEquals(server.serverName, "localhost");
|
2024-12-20 13:48:48 +01:00
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
return { server, client, endpoint };
|
2024-12-20 13:48:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Deno.test("bidirectional stream", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const { server, client, endpoint } = await pair();
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
const encoded = (new TextEncoder()).encode("hi!");
|
|
|
|
|
|
|
|
{
|
|
|
|
const bi = await server.createBidirectionalStream({ sendOrder: 42 });
|
|
|
|
assertEquals(bi.writable.sendOrder, 42);
|
|
|
|
bi.writable.sendOrder = 0;
|
|
|
|
assertEquals(bi.writable.sendOrder, 0);
|
|
|
|
await bi.writable.getWriter().write(encoded);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const { value: bi } = await client.incomingBidirectionalStreams
|
|
|
|
.getReader()
|
|
|
|
.read();
|
|
|
|
const { value: data } = await bi!.readable.getReader().read();
|
|
|
|
assertEquals(data, encoded);
|
|
|
|
}
|
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
client.close();
|
|
|
|
endpoint.close();
|
2024-12-20 13:48:48 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("unidirectional stream", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const { server, client, endpoint } = await pair();
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
const encoded = (new TextEncoder()).encode("hi!");
|
|
|
|
|
|
|
|
{
|
|
|
|
const uni = await server.createUnidirectionalStream({ sendOrder: 42 });
|
|
|
|
assertEquals(uni.sendOrder, 42);
|
|
|
|
uni.sendOrder = 0;
|
|
|
|
assertEquals(uni.sendOrder, 0);
|
|
|
|
await uni.getWriter().write(encoded);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const { value: uni } = await client.incomingUnidirectionalStreams
|
|
|
|
.getReader()
|
|
|
|
.read();
|
|
|
|
const { value: data } = await uni!.getReader().read();
|
|
|
|
assertEquals(data, encoded);
|
|
|
|
}
|
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
endpoint.close();
|
|
|
|
client.close();
|
2024-12-20 13:48:48 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("datagrams", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const { server, client, endpoint } = await pair();
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
const encoded = (new TextEncoder()).encode("hi!");
|
|
|
|
|
|
|
|
await server.sendDatagram(encoded);
|
|
|
|
|
|
|
|
const data = await client.readDatagram();
|
|
|
|
assertEquals(data, encoded);
|
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
endpoint.close();
|
|
|
|
client.close();
|
2024-12-20 13:48:48 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("closing", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const { server, client } = await pair();
|
2024-12-20 13:48:48 +01:00
|
|
|
|
|
|
|
server.close({ closeCode: 42, reason: "hi!" });
|
|
|
|
|
|
|
|
assertEquals(await client.closed, { closeCode: 42, reason: "hi!" });
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("max concurrent streams", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const { server, client, endpoint } = await pair({
|
2024-12-20 13:48:48 +01:00
|
|
|
maxConcurrentBidirectionalStreams: 1,
|
|
|
|
maxConcurrentUnidirectionalStreams: 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
{
|
|
|
|
await server.createBidirectionalStream();
|
|
|
|
await server.createBidirectionalStream()
|
|
|
|
.then(() => {
|
|
|
|
throw new Error("expected failure");
|
|
|
|
}, () => {
|
|
|
|
// success!
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
await server.createUnidirectionalStream();
|
|
|
|
await server.createUnidirectionalStream()
|
|
|
|
.then(() => {
|
|
|
|
throw new Error("expected failure");
|
|
|
|
}, () => {
|
|
|
|
// success!
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
endpoint.close();
|
|
|
|
client.close();
|
2024-12-20 13:48:48 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("incoming", async () => {
|
2025-01-06 15:24:59 +01:00
|
|
|
const endpoint = new Deno.QuicEndpoint({ hostname: "localhost" });
|
|
|
|
const listener = endpoint.listen({
|
2024-12-20 13:48:48 +01:00
|
|
|
cert,
|
|
|
|
key,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
});
|
|
|
|
|
|
|
|
const connect = () =>
|
|
|
|
Deno.connectQuic({
|
|
|
|
hostname: "localhost",
|
2025-01-06 15:24:59 +01:00
|
|
|
port: endpoint.addr.port,
|
2024-12-20 13:48:48 +01:00
|
|
|
caCerts,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
});
|
|
|
|
|
|
|
|
const c1p = connect();
|
|
|
|
const i1 = await listener.incoming();
|
|
|
|
const server = await i1.accept();
|
|
|
|
const client = await c1p;
|
|
|
|
|
|
|
|
assertEquals(server.protocol, "deno-test");
|
|
|
|
assertEquals(client.protocol, "deno-test");
|
2025-01-06 15:24:59 +01:00
|
|
|
assertEquals(client.remoteAddr, endpoint.addr);
|
|
|
|
|
|
|
|
endpoint.close();
|
|
|
|
client.close();
|
|
|
|
});
|
|
|
|
|
|
|
|
Deno.test("0rtt", async () => {
|
|
|
|
const sEndpoint = new Deno.QuicEndpoint({ hostname: "localhost" });
|
|
|
|
const listener = sEndpoint.listen({
|
|
|
|
cert,
|
|
|
|
key,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
});
|
|
|
|
|
|
|
|
(async () => {
|
|
|
|
while (true) {
|
|
|
|
let incoming;
|
|
|
|
try {
|
|
|
|
incoming = await listener.incoming();
|
|
|
|
} catch (e) {
|
|
|
|
if (e instanceof Deno.errors.BadResource) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
const conn = incoming.accept({ zeroRtt: true });
|
|
|
|
conn.handshake.then(() => {
|
|
|
|
conn.close();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
|
|
const endpoint = new Deno.QuicEndpoint();
|
|
|
|
|
|
|
|
const c1 = await Deno.connectQuic({
|
|
|
|
hostname: "localhost",
|
|
|
|
port: sEndpoint.addr.port,
|
|
|
|
caCerts,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
endpoint,
|
|
|
|
});
|
|
|
|
|
|
|
|
await c1.closed;
|
|
|
|
|
|
|
|
const c2 = Deno.connectQuic({
|
|
|
|
hostname: "localhost",
|
|
|
|
port: sEndpoint.addr.port,
|
|
|
|
caCerts,
|
|
|
|
alpnProtocols: ["deno-test"],
|
|
|
|
zeroRtt: true,
|
|
|
|
endpoint,
|
|
|
|
});
|
|
|
|
|
|
|
|
assert(!(c2 instanceof Promise), "0rtt should be accepted");
|
|
|
|
|
|
|
|
await c2.closed;
|
2024-12-20 13:48:48 +01:00
|
|
|
|
2025-01-06 15:24:59 +01:00
|
|
|
sEndpoint.close();
|
|
|
|
endpoint.close();
|
2024-12-20 13:48:48 +01:00
|
|
|
});
|