summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/node/polyfills/http.ts4
-rw-r--r--tests/unit_node/http_test.ts80
2 files changed, 83 insertions, 1 deletions
diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts
index f4126241e..e0ddedef8 100644
--- a/ext/node/polyfills/http.ts
+++ b/ext/node/polyfills/http.ts
@@ -1642,7 +1642,9 @@ export class IncomingMessageForServer extends NodeReadable {
}
},
destroy: (err, cb) => {
- reader?.cancel().finally(() => cb(err));
+ reader?.cancel().catch(() => {
+ // Don't throw error - it's propagated to the user via 'error' event.
+ }).finally(nextTick(onError, this, err, cb));
},
});
// TODO(@bartlomieju): consider more robust path extraction, e.g:
diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts
index d4cf5941f..3d53e09f9 100644
--- a/tests/unit_node/http_test.ts
+++ b/tests/unit_node/http_test.ts
@@ -1308,6 +1308,86 @@ Deno.test("[node/http] client closing a streaming response doesn't terminate ser
clearInterval(interval!);
});
+Deno.test("[node/http] client closing a streaming request doesn't terminate server", async () => {
+ let interval: number;
+ let uploadedData = "";
+ let requestError: Error | null = null;
+ const server = http.createServer((req, res) => {
+ res.writeHead(200, { "Content-Type": "text/plain" });
+ interval = setInterval(() => {
+ res.write("Hello, world!\n");
+ }, 100);
+ req.on("data", (chunk) => {
+ uploadedData += chunk.toString();
+ });
+ req.on("end", () => {
+ clearInterval(interval);
+ });
+ req.on("error", (err) => {
+ requestError = err;
+ clearInterval(interval);
+ res.end();
+ });
+ });
+
+ const deferred1 = Promise.withResolvers<void>();
+ server.listen(0, () => {
+ // deno-lint-ignore no-explicit-any
+ const port = (server.address() as any).port;
+
+ // Create a client connection to the server
+ const client = net.createConnection({ port }, () => {
+ const headers = [
+ "POST /upload HTTP/1.1",
+ "Host: localhost",
+ "Content-Type: text/plain",
+ "Transfer-Encoding: chunked",
+ "",
+ "",
+ ].join("\r\n");
+
+ client.write(headers);
+
+ const chunk = "A".repeat(100);
+ let sentChunks = 0;
+
+ function writeChunk() {
+ const chunkHeader = `${chunk.length.toString(16)}\r\n`;
+ client.write(chunkHeader);
+ client.write(chunk);
+ client.write("\r\n");
+ sentChunks++;
+
+ if (sentChunks >= 3) {
+ client.destroy();
+ setTimeout(() => {
+ deferred1.resolve();
+ }, 40);
+ } else {
+ setTimeout(writeChunk, 10);
+ }
+ }
+ writeChunk();
+ });
+ });
+
+ await deferred1.promise;
+ assert(requestError !== null, "Server should have received an error");
+ assert(
+ (requestError! as Error)?.name === "Http",
+ `Expected Http error, got ${(requestError! as Error)?.name}`,
+ );
+ assert(
+ (requestError! as Error)?.message.includes(
+ "error reading a body from connection",
+ ),
+ );
+ assertEquals(server.listening, true);
+ server.close();
+ assertEquals(server.listening, false);
+ clearInterval(interval!);
+});
+
Deno.test("[node/http] http.request() post streaming body works", async () => {
const server = http.createServer((req, res) => {
if (req.method === "POST") {