Skip to content

Commit

Permalink
Catch when nodejs request is aborted
Browse files Browse the repository at this point in the history
When we receive a request, we start listening to the close event on the
response.
When fired, we check if the request was aborted using `incoming.destroyed`,
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>
  • Loading branch information
M4RC3L05 committed Feb 6, 2024
1 parent 1d75d95 commit 2a75974
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.destroyed) {
req.signal.dispatchEvent(new Event('abort'))
}
})

try {
res = fetchCallback(req, { incoming, outgoing } as HttpBindings) as
| Response
Expand Down
39 changes: 39 additions & 0 deletions test/listener.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(() => {
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()
}
})
})
})

0 comments on commit 2a75974

Please sign in to comment.