From 49e33a87411b003705e377a8d5ea6d2d1acef108 Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 22 Feb 2024 19:50:59 -0500 Subject: [PATCH] remove all fetchParam event handlers --- lib/web/fetch/index.js | 11 +++++------ test/fetch/issue-1711.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 test/fetch/issue-1711.js diff --git a/lib/web/fetch/index.js b/lib/web/fetch/index.js index f4a6e5e6262..df2f442c647 100644 --- a/lib/web/fetch/index.js +++ b/lib/web/fetch/index.js @@ -81,12 +81,6 @@ class Fetch extends EE { this.connection = null this.dump = false this.state = 'ongoing' - // 2 terminated listeners get added per request, - // but only 1 gets removed. If there are 20 redirects, - // 21 listeners will be added. - // See https://github.com/nodejs/undici/issues/1711 - // TODO (fix): Find and fix root cause for leaked listener. - this.setMaxListeners(21) } terminate (reason) { @@ -1967,6 +1961,7 @@ async function httpNetworkFetch ( // 19. Run these steps in parallel: // 1. Run these steps, but abort when fetchParams is canceled: + fetchParams.controller.onAborted = onAborted fetchParams.controller.on('terminated', onAborted) fetchParams.controller.resume = async () => { // 1. While true @@ -2235,6 +2230,10 @@ async function httpNetworkFetch ( fetchParams.controller.off('terminated', this.abort) } + if (fetchParams.controller.onAborted) { + fetchParams.controller.off('terminated', fetchParams.controller.onAborted) + } + fetchParams.controller.ended = true this.body.push(null) diff --git a/test/fetch/issue-1711.js b/test/fetch/issue-1711.js new file mode 100644 index 00000000000..b024e411195 --- /dev/null +++ b/test/fetch/issue-1711.js @@ -0,0 +1,33 @@ +'use strict' + +const assert = require('node:assert') +const { once } = require('node:events') +const { createServer } = require('node:http') +const { test } = require('node:test') +const { fetch } = require('../..') + +test('Redirecting a bunch does not cause a MaxListenersExceededWarning', async (t) => { + let redirects = 0 + + const server = createServer((req, res) => { + if (redirects === 15) { + res.end('Okay goodbye') + return + } + + res.writeHead(302, { + Location: `/${redirects++}` + }) + res.end() + }).listen(0) + + t.after(server.close.bind(server)) + await once(server, 'listening') + + process.emitWarning = assert.bind(null, false) + + const url = `http://localhost:${server.address().port}` + const response = await fetch(url, { redirect: 'follow' }) + + assert.deepStrictEqual(response.url, `${url}/${redirects - 1}`) +})