import type { Subprocess } from "bun"; import { afterAll, beforeAll, expect, it } from "bun:test"; import { bunEnv, tls } from "harness"; import type { IncomingMessage } from "http"; import { join } from "path"; let url: URL; let process: Subprocess<"ignore", "pipe", "ignore"> | null = null; beforeAll(async () => { process = Bun.spawn(["node", join(import.meta.dir, "renegotiation-feature.js")], { stdout: "pipe", stderr: "inherit", stdin: "ignore", env: { ...bunEnv, SERVER_CERT: tls.cert, SERVER_KEY: tls.key, }, }); const { value } = await process.stdout.getReader().read(); url = new URL(new TextDecoder().decode(value)); }); afterAll(() => { process?.kill(); }); it("allow renegotiation in fetch", async () => { const body = await fetch(url, { verbose: true, keepalive: false, tls: { rejectUnauthorized: false }, }).then(res => res.text()); expect(body).toBe("Hello World"); }); it("should fail if renegotiation fails using fetch", async () => { try { await fetch(url, { verbose: true, keepalive: false, tls: { rejectUnauthorized: true }, }).then(res => res.text()); expect.unreachable(); } catch (e: any) { expect(e.code).toBe("DEPTH_ZERO_SELF_SIGNED_CERT"); } }); it("allow renegotiation in https module", async () => { const { promise, resolve, reject } = Promise.withResolvers(); const req = require("https").request( { hostname: url.hostname, port: url.port, path: url.pathname, method: "GET", keepalive: false, rejectUnauthorized: false, }, (res: IncomingMessage) => { res.setEncoding("utf8"); let data = ""; res.on("data", (chunk: string) => { data += chunk; }); res.on("error", reject); res.on("end", () => resolve(data)); }, ); req.on("error", reject); req.end(); const body = await promise; expect(body).toBe("Hello World"); }); it("should fail if renegotiation fails using https", async () => { const { promise, resolve, reject } = Promise.withResolvers(); const req = require("https").request( { hostname: url.hostname, port: url.port, path: url.pathname, method: "GET", keepalive: false, rejectUnauthorized: true, }, (res: IncomingMessage) => { res.setEncoding("utf8"); let data = ""; res.on("data", (chunk: string) => { data += chunk; }); res.on("error", reject); res.on("end", () => resolve(data)); }, ); req.on("error", reject); req.end(); try { await promise; expect.unreachable(); } catch (e: any) { expect(e.code).toBe("DEPTH_ZERO_SELF_SIGNED_CERT"); } }); it("allow renegotiation in tls module", async () => { const { promise, resolve, reject } = Promise.withResolvers(); const socket = require("tls").connect({ rejectUnauthorized: false, host: url.hostname, port: url.port, }); let data = ""; socket.on("data", (chunk: Buffer) => { data += chunk.toString(); if (data.indexOf("0\r\n\r\n") !== -1) { const result = data.split("\r\n\r\n")[1].split("\r\n")[1]; resolve(result); } }); socket.on("error", reject); socket.write("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"); const body = await promise; expect(body).toBe("Hello World"); }); it("should fail if renegotiation fails using tls module", async () => { const { promise, resolve, reject } = Promise.withResolvers(); const socket = require("tls").connect({ rejectUnauthorized: true, host: url.hostname, port: url.port, }); let data = ""; socket.on("data", (chunk: Buffer) => { data += chunk.toString(); if (data.indexOf("0\r\n\r\n") !== -1) { const result = data.split("\r\n\r\n")[1].split("\r\n")[1]; resolve(result); } }); socket.on("error", reject); socket.write("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"); try { await promise; expect.unreachable(); } catch (e: any) { expect(e.code).toBe("DEPTH_ZERO_SELF_SIGNED_CERT"); } });