Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active March 11, 2025 02:24
Show Gist options
  • Save guest271314/c56d769bca04d92dc941c04d9ac40ba5 to your computer and use it in GitHub Desktop.
Save guest271314/c56d769bca04d92dc941c04d9ac40ba5 to your computer and use it in GitHub Desktop.
HTTP/2 server using Node.js builtins and WHATWG Streams
import { createSecureServer } from "node:http2";
import { createWriteStream, readFileSync } from "node:fs";
import { open, stat } from "node:fs/promises";
import { Readable, Writable } from "node:stream";
import process from "node:process";
const stdout = Writable.toWeb(process.stdout);
const encoder = new TextEncoder();
const headers = {
"Cache-Control": "no-cache",
"Content-Type": "text/plain; charset=UTF-8",
"Cross-Origin-Opener-Policy": "unsafe-none",
"Cross-Origin-Embedder-Policy": "unsafe-none",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Private-Network": "true",
"Access-Control-Allow-Headers": "Access-Control-Request-Private-Network",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET,HEAD,QUERY,query",
};
const key = readFileSync(
`${import.meta.dirname}/certificate.key`,
);
const cert = readFileSync(
`${import.meta.dirname}/certificate.pem`,
);
let controller;
const requestStream = new ReadableStream({
start(_) {
return (controller = _);
},
});
// https://nodejs.org/api/http2.html#compatibility-api
async function onRequestHandler(request, response) {
controller.enqueue({ request, response });
}
const server = createSecureServer({
key,
cert,
}, onRequestHandler);
server.listen(8443);
(async () => {
for await (const { request, response } of requestStream) {
if (request.method === "OPTIONS") {
response.writeHead(204, headers);
continue;
}
if (request.method === "POST" || /query/i.test(request.method)) {
response.writeHead(200, headers);
}
const readable = Readable.toWeb(request);
const writable = Writable.toWeb(response);
try {
const stream = await readable
.pipeThrough(new TextDecoderStream())
.pipeThrough(
new TransformStream({
start(c) {
console.log(c);
},
transform(value, c) {
console.log(value);
c.enqueue(value.toUpperCase());
},
async flush() {
console.log("flush");
},
}),
).pipeThrough(new TextEncoderStream())
.pipeTo(writable).catch((e) => {
throw e;
});
} catch (e) {
console.log(e);
continue;
}
continue;
}
})().catch((e) => {
console.log(e);
process.exit();
});
@guest271314
Copy link
Author

// NODE_TLS_REJECT_UNAUTHORIZED=0 node --no-warnings http2-client.js
// deno -A --unsafely-ignore-certificate-errors --unstable-node-globals http2-client.js
// NODE_TLS_REJECT_UNAUTHORIZED=0 bun http2-client.js
var { readable, writable } = new TransformStream();
(async () => {
  (await fetch("https://localhost:8443", {
    method: "post",
    body: readable,
    duplex: "half",
  })).body
    .pipeThrough(new TextDecoderStream())
    .pipeTo(
      new WritableStream({
        write(v) {
          console.log(v);
        },
        close() {
          console.log("Stream closed.");
        },
      }),
    );
})();
var write = async (str, preventClose = true) =>
  await new Response(str).body.pipeTo(writable, { preventClose });
await write("a");
await write("b");
await write("c");
await write("d");
await write("e");
await write("f");
await write("g", false);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment