diff --git a/lib/fetch/request.js b/lib/fetch/request.js index c9672cddfaf..080a5d7bfa3 100644 --- a/lib/fetch/request.js +++ b/lib/fetch/request.js @@ -358,9 +358,13 @@ class Request { ac.abort(this.reason) } - if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) { - setMaxListeners(100, signal) - } + // Third-party AbortControllers may not work with these. + // See https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619 + try { + if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) { + setMaxListeners(100, signal) + } + } catch {} signal.addEventListener('abort', abort, { once: true }) requestFinalizer.register(this, { signal, abort }) diff --git a/package.json b/package.json index 76c20a370e4..a49b43fd94b 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "husky": "^8.0.1", "import-fresh": "^3.3.0", "jest": "^29.0.2", + "jsdom": "^21.1.0", "jsfuzz": "^1.0.15", "mocha": "^10.0.0", "p-timeout": "^3.2.0", diff --git a/test/fetch/jsdom-abortcontroller-1910-1464495619.js b/test/fetch/jsdom-abortcontroller-1910-1464495619.js new file mode 100644 index 00000000000..fad1e77c12b --- /dev/null +++ b/test/fetch/jsdom-abortcontroller-1910-1464495619.js @@ -0,0 +1,22 @@ +'use strict' + +const { test } = require('tap') +const { createServer } = require('http') +const { once } = require('events') +const { fetch } = require('../..') +const { JSDOM } = require('jsdom') + +// https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619 +test('third party AbortControllers', async (t) => { + const server = createServer((_, res) => res.end()).listen(0) + + t.teardown(server.close.bind(server)) + await once(server, 'listening') + + const { AbortController } = new JSDOM().window + const controller = new AbortController() + + await t.resolves(fetch(`http://localhost:${server.address().port}`, { + signal: controller.signal + })) +})