From 4aa31b4435bfe4f05b88faf077b4e34cfbe09518 Mon Sep 17 00:00:00 2001 From: Marcin Jahn <10273406+marcinjahn@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:09:01 +0100 Subject: [PATCH] fix: cancellation of requests with body The current implementation works well only for HTTP methods that do not support request body. For requests like POST, `req`'s 'close' event fires as soon as request body is read (see https://github.com/expressjs/express/issues/6334#issuecomment-2663645929). I changed it to use `res`'s 'close', which works as expected. "finish" fires before "close", so I added `requestFinished` flag to avoid cancellation when the request is already processed. --- src/abort-controller.middleware.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/abort-controller.middleware.ts b/src/abort-controller.middleware.ts index ca3fea2..b559aa0 100644 --- a/src/abort-controller.middleware.ts +++ b/src/abort-controller.middleware.ts @@ -27,13 +27,26 @@ export class AbortControllerMiddleware implements NestMiddleware { req.abortController = controller; req.abortSignal = controller.signal; - req.on('close', () => { + let requestFinished = false; + + res.on('close', () => { + if (requestFinished) { + return; + } + if (enableLogging) { this.logger.debug(LOG_MESSAGES.CLIENT_DISCONNECTED); } controller.abort(); }); + res.on('finish', () => { + requestFinished = true; + if (enableLogging) { + this.logger.debug(LOG_MESSAGES.REQUEST_COMPLETED); + } + }); + if (timeout > 0) { const timeoutId = setTimeout(() => { if (enableLogging) { @@ -42,16 +55,10 @@ export class AbortControllerMiddleware implements NestMiddleware { controller.abort(); }, timeout); - req.on('close', () => clearTimeout(timeoutId)); + res.on('close', () => clearTimeout(timeoutId)); res.on('finish', () => clearTimeout(timeoutId)); } - res.on('finish', () => { - if (enableLogging) { - this.logger.debug(LOG_MESSAGES.REQUEST_COMPLETED); - } - }); - next(); } }