From 14fa2b1abef4ada9fc3c32f07c7596b0a3aa898b Mon Sep 17 00:00:00 2001 From: aleister1102 Date: Thu, 11 Jun 2026 14:15:40 +0700 Subject: [PATCH 1/2] fix(batch): add missing early return in nodeHttpBatchRpcResponse on non-POST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without response.end() and return, a non-POST request would write the 405 status line then fall through into the full RPC pipeline. This caused the subsequent writeHead(200) to throw ERR_HTTP_HEADERS_SENT, left the TCP connection open (response.end never called), and — when the caller uses the documented try/catch pattern — caused a second writeHead(500) to throw uncaught, terminating the Node.js process. Co-Authored-By: Claude Sonnet 4.6 --- src/batch.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/batch.ts b/src/batch.ts index 4f423c7..85d1a10 100644 --- a/src/batch.ts +++ b/src/batch.ts @@ -179,6 +179,8 @@ export async function nodeHttpBatchRpcResponse( }): Promise { if (request.method !== "POST") { response.writeHead(405, "This endpoint only accepts POST requests."); + response.end(); + return; } let body = await new Promise((resolve, reject) => { From f684df8c85401038020c3e2980790bd158ced555 Mon Sep 17 00:00:00 2001 From: aleister1102 Date: Thu, 11 Jun 2026 23:36:53 +0700 Subject: [PATCH 2/2] test(batch): add 405 regression test for non-POST requests Add changeset for nodeHttpBatchRpcResponse early-return fix. --- .changeset/non-post-early-return.md | 6 ++++++ __tests__/index.test.ts | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 .changeset/non-post-early-return.md diff --git a/.changeset/non-post-early-return.md b/.changeset/non-post-early-return.md new file mode 100644 index 0000000..739b11c --- /dev/null +++ b/.changeset/non-post-early-return.md @@ -0,0 +1,6 @@ +--- +"capnweb": patch +--- + +Fix nodeHttpBatchRpcResponse leaving the connection open and crashing with +ERR_HTTP_HEADERS_SENT on non-POST requests. It now returns 405 immediately. diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index fdf41b3..7ab5145 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1935,6 +1935,12 @@ describe("HTTP requests", () => { expect(await Promise.all([promise1, promise2, promise3])) .toStrictEqual([36, 5, 9]); }); + + it("rejects non-POST requests with 405", async () => { + let response = await fetch(`http://${inject("testServerHost")}`, { method: "GET" }); + expect(response.status).toBe(405); + await response.text(); + }); }); describe("WebSockets", () => {