Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active March 11, 2025 03:07
Show Gist options
  • Save guest271314/c1974f24fff86fe4708f901651be8079 to your computer and use it in GitHub Desktop.
Save guest271314/c1974f24fff86fe4708f901651be8079 to your computer and use it in GitHub Desktop.
Deno HTTP/3 WebTransport server
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// https://raw.githubusercontent.com/denoland/deno/dce204af32e4b56681be4f9a034256d979a3ce4b/tests/specs/run/webtransport/main.ts
const cert = Deno.readTextFileSync("./certificate.pem");
const key = Deno.readTextFileSync("./certificate.key");
const certBase64 = cert.split("\n").slice(1, -2).join("");
const certBytes =
await (await fetch(`data:application/octet-stream;base64,${certBase64}`))
.bytes();
const certHash = await crypto.subtle.digest("SHA-256", certBytes);
const server = new Deno.QuicEndpoint({
hostname: "localhost",
port: 4433,
});
const listener = server.listen({
cert,
key,
alpnProtocols: ["h3"],
});
let requests = 0;
async function handle(wt) {
try {
console.log(wt);
const encoder = new TextEncoder();
await wt.ready;
for await (
const { readable, writable } of wt.incomingBidirectionalStreams
) {
for await (const value of readable.pipeThrough(new TextDecoderStream())) {
console.log(value);
await new Response(value.toUpperCase()).body
.pipeTo(writable, { preventClose: true });
}
await writable.close().then(() => console.log("writable close"));
console.log(writable);
await new Promise((r) => setTimeout(r));
wt.close();
break;
}
} catch (e) {
console.log(e);
console.trace();
} finally {
return wt.closed.then(() => ({
code: 0,
reason: `Done streaming request ${requests++}`,
}));
}
}
for await (const conn of listener) {
const wt = await Deno.upgradeWebTransport(conn);
try {
handle(wt)
.then((session) => console.log(session))
.catch((e) => console.log(e));
} catch (e) {
console.log(e);
} finally {
continue;
}
}
server.close();
const client = new WebTransport(
`https://localhost:4433/path`,
/*
{
serverCertificateHashes: [{
algorithm: "sha-256",
value: certHash,
}],
},
*/
);
await client.ready;
const encoder = new TextEncoder();
const { readable, writable } = await client.createBidirectionalStream();
const stream = readable.pipeThrough(new TextDecoderStream())
.pipeTo(
new WritableStream({
write(value, controller) {
console.log(value);
},
close() {
console.log("WritableStream close");
},
abort(reason) {
console.log({ reason });
},
}),
).catch((e) => e.message);
const write = async (encoded, preventClose = true) =>
await new Response(encoded).body
.pipeTo(writable, { preventClose });
let str = "abcdefghijklmnopqrstuvwxyz";
for (let i = 0; i < 26; i++) {
let preventClose = i < str.length - 1;
await write(encoder.encode(str.at(i)), preventClose);
}
if (!navigator.userAgent.includes("Deno")) {
await Promise.allSettled([client.closed, stream])
.then(console.log);
} else {
if (navigator.userAgent.includes("Deno")) {
// Deno doesn't close on writer.close()
await new Promise((r) => setTimeout(r, 5));
client.close();
await Promise.allSettled([client.closed, stream])
.then(console.log);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment