Skip to content

Commit dad6a91

Browse files
committed
Fix infinite loop when retrying with request.options in afterResponse hook
Fixes #2414
1 parent b581a0a commit dad6a91

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

source/core/options.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,10 @@ export default class Options {
10341034
}
10351035

10361036
if (options instanceof Options) {
1037-
for (const init of options._init) {
1037+
// Create a copy of the _init array to avoid infinite loop
1038+
// when merging an Options instance with itself
1039+
const initArray = [...options._init];
1040+
for (const init of initArray) {
10381041
this.merge(init);
10391042
}
10401043

test/infinite-loop-issue.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import test from 'ava';
2+
import withServer from './helpers/with-server.js';
3+
4+
// Test for issue #2414: Endless recurrent loop upon retry in options.js
5+
// https://github.com/sindresorhus/got/issues/2414
6+
test('does not cause infinite loop when retrying with request.options', withServer, async (t, server, got) => {
7+
server.get('/', (_request, response) => {
8+
response.statusCode = 401;
9+
response.end();
10+
});
11+
12+
let isCalled = false;
13+
14+
await got({
15+
hooks: {
16+
afterResponse: [
17+
(response, retry) => {
18+
if (!isCalled) {
19+
isCalled = true;
20+
// This used to cause an infinite loop in versions 12-14
21+
return retry(response.request.options);
22+
}
23+
24+
return response;
25+
},
26+
],
27+
},
28+
throwHttpErrors: false,
29+
retry: {
30+
limit: 0,
31+
},
32+
});
33+
34+
t.true(isCalled);
35+
});

0 commit comments

Comments
 (0)