diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts index b8eb3be842..f407c9186e 100644 --- a/cli/tests/unit/http_test.ts +++ b/cli/tests/unit/http_test.ts @@ -2762,6 +2762,39 @@ for (const compression of [true, false]) { }); } +Deno.test({ + name: "request signal is aborted when response errors", + permissions: { net: true }, + async fn() { + let httpConn: Deno.HttpConn; + const promise = (async () => { + const listener = Deno.listen({ port: 4501 }); + const conn = await listener.accept(); + listener.close(); + httpConn = Deno.serveHttp(conn); + const ev = await httpConn.nextRequest(); + const { request, respondWith } = ev!; + + await delay(300); + await assertRejects(() => respondWith(new Response("Hello World"))); + assert(request.signal.aborted); + })(); + + const abortController = new AbortController(); + + fetch("http://127.0.0.1:4501/", { + signal: abortController.signal, + }).catch(() => { + // ignore + }); + + await delay(100); + abortController.abort(); + await promise; + httpConn!.close(); + }, +}); + function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader { // Based on https://tools.ietf.org/html/rfc2616#section-19.4.6 const tp = new TextProtoReader(r); diff --git a/ext/http/01_http.js b/ext/http/01_http.js index fee30f7f0e..7e648017bf 100644 --- a/ext/http/01_http.js +++ b/ext/http/01_http.js @@ -18,7 +18,7 @@ import { fromInnerRequest, newInnerRequest, } from "ext:deno_fetch/23_request.js"; -import * as abortSignal from "ext:deno_web/03_abort_signal.js"; +import { AbortController } from "ext:deno_web/03_abort_signal.js"; import { _eventLoop, _idleTimeoutDuration, @@ -135,10 +135,10 @@ class HttpConn { body !== null ? new InnerBody(body) : null, false, ); - const signal = abortSignal.newSignal(); + const abortController = new AbortController(); const request = fromInnerRequest( innerRequest, - signal, + abortController.signal, "immutable", false, ); @@ -149,6 +149,7 @@ class HttpConn { request, this.#remoteAddr, this.#localAddr, + abortController, ); return { request, respondWith }; @@ -185,6 +186,7 @@ function createRespondWith( request, remoteAddr, localAddr, + abortController, ) { return async function respondWith(resp) { try { @@ -381,6 +383,9 @@ function createRespondWith( } ws[_serverHandleIdleTimeout](); } + } catch (error) { + abortController.abort(error); + throw error; } finally { if (SetPrototypeDelete(httpConn.managedResources, streamRid)) { core.close(streamRid);