From 16ef93df763e7c7ac1b13aed4e4295038569ac52 Mon Sep 17 00:00:00 2001 From: m4rc3l05 <15786310+M4RC3L05@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:00:37 +0000 Subject: [PATCH] Catch when nodejs request is aborted When we receive a request, we start listening to the close event. When fired, we check if the request was aborted using `incoming.aborted`, if it was, we dispatch an abort event to the existing request abort signal. Without this, whe the client abortes the request, the signal on the request was not being called with the abort event. Signed-off-by: m4rc3l05 <15786310+M4RC3L05@users.noreply.github.com> --- src/listener.ts | 7 +++++++ test/listener.test.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/listener.ts b/src/listener.ts index 2388344..368c0e6 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -143,6 +143,13 @@ export const getRequestListener = ( // so generate a pseudo Request object with only the minimum required information. const req = newRequest(incoming) + // Detect if request was aborted. + outgoing.on('close', () => { + if (incoming.socket.destroyed) { + req.signal.dispatchEvent(new Event('abort')) + } + }) + try { res = fetchCallback(req, { incoming, outgoing } as HttpBindings) as | Response diff --git a/test/listener.test.ts b/test/listener.test.ts index 5c10d84..8c4c335 100644 --- a/test/listener.test.ts +++ b/test/listener.test.ts @@ -89,3 +89,42 @@ describe('Error handling - async fetchCallback', () => { expect(res.text).toBe('error handler did not return a response') }) }) + +describe('Abort request', () => { + const data: string[] = [] + + const fetchCallback = async (req: { signal: AbortSignal }) => { + await new Promise(() => { + req.signal.addEventListener('abort', () => { + data.push('aborted') + }) + }) + } + + const requestListener = getRequestListener(fetchCallback) + + const server = createServer(async (req, res) => { + await requestListener(req, res) + }) + + beforeEach(() => { + data.length = 0 + }) + + it('should emit an abort event when the nodejs request is aborted', (done) => { + const req = request(server) + .get('/abort') + .end(() => {}) + + setTimeout(() => { + req.abort() + }, 10) + + const interval = setInterval(() => { + if (data.includes('aborted')) { + clearInterval(interval) + done() + } + }) + }) +})