summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-08-29 14:13:58 +0200
committerGitHub <noreply@github.com>2023-08-29 12:13:58 +0000
commit2929313652a9d7fb3a26ad7f754deaeb03435e10 (patch)
treecd6e08ae77e255f956b448b50463cf549d63a30a
parentc31c93ce70c1147872d911c4a05c808d4078339b (diff)
fix(node/http): don't leak resources on destroyed request (#20040)
Closes https://github.com/denoland/deno/issues/19828
-rw-r--r--cli/tests/unit_node/http_test.ts34
-rw-r--r--ext/node/polyfills/http.ts7
2 files changed, 41 insertions, 0 deletions
diff --git a/cli/tests/unit_node/http_test.ts b/cli/tests/unit_node/http_test.ts
index 9feee0272..825815ae6 100644
--- a/cli/tests/unit_node/http_test.ts
+++ b/cli/tests/unit_node/http_test.ts
@@ -777,3 +777,37 @@ Deno.test("[node/http] server emits error if addr in use", async () => {
`Wrong error: ${err.message}`,
);
});
+
+Deno.test(
+ "[node/http] client destroy doesn't leak",
+ { permissions: { net: true } },
+ async () => {
+ const ac = new AbortController();
+ let timerId;
+
+ const server = Deno.serve(
+ { port: 5929, signal: ac.signal },
+ async (_req) => {
+ await new Promise((resolve) => {
+ timerId = setTimeout(resolve, 5000);
+ });
+ return new Response("hello");
+ },
+ );
+ const promise = deferred();
+
+ const request = http.request("http://localhost:5929/");
+ request.on("error", promise.reject);
+ request.on("close", () => {});
+ request.end();
+ setTimeout(() => {
+ request.destroy(new Error());
+ promise.resolve();
+ }, 100);
+
+ await promise;
+ clearTimeout(timerId);
+ ac.abort();
+ await server.finished;
+ },
+);
diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts
index 1103e93c3..ae670d5f0 100644
--- a/ext/node/polyfills/http.ts
+++ b/ext/node/polyfills/http.ts
@@ -787,6 +787,13 @@ class ClientRequest extends OutgoingMessage {
}
this.destroyed = true;
+ const rid = this._client?.rid;
+ if (rid) {
+ core.tryClose(rid);
+ }
+ if (this._req.cancelHandleRid !== null) {
+ core.tryClose(this._req.cancelHandleRid);
+ }
// If we're aborting, we don't care about any more response data.
if (this.res) {
this.res._dump();