From deef31ef1def21862a8b35a327f5726998fd10da Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Fri, 7 Apr 2023 20:50:30 +0200 Subject: [PATCH] fetch: fix leak Fixes: https://github.com/nodejs/undici/issues/1823 --- lib/fetch/request.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/fetch/request.js b/lib/fetch/request.js index 080a5d7bfa3..93365c8fae5 100644 --- a/lib/fetch/request.js +++ b/lib/fetch/request.js @@ -34,6 +34,7 @@ const { setMaxListeners, getEventListeners, defaultMaxListeners } = require('eve let TransformStream = globalThis.TransformStream const kInit = Symbol('init') +const kAbortController = Symbol('abortController') const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { signal.removeEventListener('abort', abort) @@ -354,8 +355,14 @@ class Request { if (signal.aborted) { ac.abort(signal.reason) } else { + // Keep a strong ref to ac while request object + // is alive. This is needed to prevent AbortController + // from being prematurely garbage collected. + this[kAbortController] = ac + + const weakAc = new WeakRef(ac) const abort = function () { - ac.abort(this.reason) + weakAc.deref()?.abort(this.reason) } // Third-party AbortControllers may not work with these. @@ -367,7 +374,7 @@ class Request { } catch {} signal.addEventListener('abort', abort, { once: true }) - requestFinalizer.register(this, { signal, abort }) + requestFinalizer.register(ac, { signal, abort }) } }