diff --git a/lib/web/fetch/index.js b/lib/web/fetch/index.js index 56e540d9d88..24d724c2218 100644 --- a/lib/web/fetch/index.js +++ b/lib/web/fetch/index.js @@ -1675,6 +1675,11 @@ async function httpNetworkOrCacheFetch ( // 4. Set the password given request’s current URL and password. // requestCurrentURL(request).password = TODO + + // In browsers, the user will be prompted to enter a username/password before the request + // is re-sent. To prevent an infinite 401 loop, return a network error for now. + // https://github.com/nodejs/undici/pull/4756 + return makeNetworkError() } // 4. Set response to the result of running HTTP-network-or-cache fetch given diff --git a/test/fetch/401-statuscode-no-infinite-loop.js b/test/fetch/401-statuscode-no-infinite-loop.js new file mode 100644 index 00000000000..1c808bb36cb --- /dev/null +++ b/test/fetch/401-statuscode-no-infinite-loop.js @@ -0,0 +1,26 @@ +'use strict' + +const { fetch } = require('../..') +const { createServer } = require('node:http') +const { once } = require('node:events') +const { test } = require('node:test') +const assert = require('node:assert') + +const { closeServerAsPromise } = require('../utils/node-http') + +test('Receiving a 401 status code should not cause infinite retry loop', async (t) => { + let requestCount = 0 + + const server = createServer({ joinDuplicateHeaders: true }, (req, res) => { + requestCount++ + console.log({ requestCount }) + res.statusCode = 401 + res.setHeader('WWW-Authenticate', 'Basic realm="test"') + res.end('Unauthorized') + }).listen(0) + + t.after(closeServerAsPromise(server)) + await once(server, 'listening') + + await assert.rejects(() => fetch(`http://localhost:${server.address().port}`)) +})