Skip to content

Commit 4035c48

Browse files
committed
fix: handle stream error to prevent uncaught DOMException and consume body if not used (per <https://github.com/nodejs/undici/issues/3353\#issuecomment-2184635954>)
1 parent 20bcf27 commit 4035c48

File tree

6 files changed

+60
-30
lines changed

6 files changed

+60
-30
lines changed

benchmarks/lookup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Tangerine = require('..');
44

55
const opts = { timeout: 5000, tries: 1 };
66

7+
// eslint-disable-next-line n/prefer-promises/dns
78
dns.setServers(['1.1.1.1', '1.0.0.1']);
89

910
const resolver = new dns.promises.Resolver(opts);

benchmarks/resolve.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Tangerine = require('..');
44

55
const opts = { timeout: 5000, tries: 1 };
66

7+
// eslint-disable-next-line n/prefer-promises/dns
78
dns.setServers(['1.1.1.1', '1.0.0.1']);
89

910
const resolver = new dns.promises.Resolver(opts);

benchmarks/reverse.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Tangerine = require('..');
44

55
const opts = { timeout: 5000, tries: 1 };
66

7+
// eslint-disable-next-line n/prefer-promises/dns
78
dns.setServers(['1.1.1.1', '1.0.0.1']);
89

910
const resolver = new dns.promises.Resolver(opts);

index.js

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const autoBind = require('auto-bind');
1111
const getStream = require('get-stream');
1212
const hostile = require('hostile');
1313
const ipaddr = require('ipaddr.js');
14+
const isStream = require('is-stream');
1415
const mergeOptions = require('merge-options');
1516
const pMap = require('p-map');
1617
const pTimeout = require('p-timeout');
@@ -702,8 +703,8 @@ class Tangerine extends dns.promises.Resolver {
702703

703704
// safeguard (matches c-ares)
704705
if (lower === 'localhost' || lower === 'localhost.') {
705-
if (!resolve4) resolve4 = ['127.0.0.1'];
706-
if (!resolve6) resolve6 = ['::1'];
706+
resolve4 ||= ['127.0.0.1'];
707+
resolve6 ||= ['::1'];
707708
}
708709

709710
if (isIPv4(name)) {
@@ -1128,22 +1129,41 @@ class Tangerine extends dns.promises.Resolver {
11281129
const statusCode = response.status || response.statusCode;
11291130
debug('response', { statusCode, headers });
11301131

1132+
// <https://github.com/nodejs/undici/issues/3353#issuecomment-2184635954>
1133+
// eslint-disable-next-line max-depth
1134+
if (body && isStream(body) && typeof body.on === 'function')
1135+
body.on('error', (err) => {
1136+
this.options.logger.error(err, { response });
1137+
});
1138+
11311139
// eslint-disable-next-line max-depth
11321140
if (body && statusCode >= 200 && statusCode < 300) {
1141+
// <https://sindresorhus.com/blog/goodbye-nodejs-buffer>
11331142
buffer = Buffer.isBuffer(body)
11341143
? body
11351144
: // eslint-disable-next-line no-await-in-loop
11361145
await getStream.buffer(body);
1146+
// <https://github.com/nodejs/undici/issues/3353>
1147+
// eslint-disable-next-line no-await-in-loop, max-depth
1148+
if (body && typeof body.dump === 'function') await body.dump();
11371149
// eslint-disable-next-line max-depth
11381150
if (!abortController.signal.aborted) abortController.abort();
11391151
break;
11401152
}
11411153

1154+
// <https://github.com/nodejs/undici/issues/3353>
1155+
// eslint-disable-next-line no-await-in-loop, max-depth
1156+
if (body && typeof body.dump === 'function') await body.dump();
1157+
1158+
// <https://github.com/nodejs/undici/blob/00dfd0bd41e73782452aecb728395f354585ca94/lib/core/errors.js#L47-L58>
11421159
const message =
11431160
http.STATUS_CODES[statusCode] ||
11441161
this.options.defaultHTTPErrorMessage;
11451162
const err = new Error(message);
1163+
err.body = body;
1164+
err.status = statusCode;
11461165
err.statusCode = statusCode;
1166+
err.headers = headers;
11471167
throw err;
11481168
}
11491169
} catch (err) {
@@ -1202,6 +1222,12 @@ class Tangerine extends dns.promises.Resolver {
12021222
// that one or more dns servers have persistent issues
12031223
if (errors.length > 0)
12041224
this.options.logger.error(this.constructor.combineErrors(errors));
1225+
1226+
//
1227+
// NOTE: dns-packet does not yet support Uint8Array
1228+
// (however undici does have body.arrayBuffer() method)
1229+
//
1230+
// https://github.com/mafintosh/dns-packet/issues/72
12051231
return packet.decode(buffer);
12061232
} catch (_err) {
12071233
if (!abortController.signal.aborted) abortController.abort();
@@ -1886,8 +1912,8 @@ class Tangerine extends dns.promises.Resolver {
18861912
Buffer.isBuffer(a.data)
18871913
? a.data.toString()
18881914
: Array.isArray(a.data)
1889-
? a.data.map((d) => (Buffer.isBuffer(d) ? d.toString() : d))
1890-
: a.data
1915+
? a.data.map((d) => (Buffer.isBuffer(d) ? d.toString() : d))
1916+
: a.data
18911917
];
18921918
});
18931919
}

package.json

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,50 @@
1212
"dependencies": {
1313
"@ungap/structured-clone": "^1.2.0",
1414
"auto-bind": "4",
15-
"dns-packet": "^5.6.0",
15+
"dns-packet": "^5.6.1",
1616
"dohdec": "^5.0.3",
1717
"get-stream": "6",
18-
"hostile": "^1.3.3",
19-
"ipaddr.js": "^2.0.1",
18+
"hostile": "^1.4.0",
19+
"ipaddr.js": "^2.2.0",
20+
"is-stream": "2.0.1",
2021
"merge-options": "3.0.4",
2122
"p-map": "4",
2223
"p-timeout": "4",
2324
"p-wait-for": "3",
2425
"port-numbers": "6.0.1",
25-
"private-ip": "^3.0.0",
26-
"punycode": "^2.3.0",
27-
"semver": "^7.5.1"
26+
"private-ip": "^3.0.2",
27+
"punycode": "^2.3.1",
28+
"semver": "^7.6.3"
2829
},
2930
"devDependencies": {
30-
"@commitlint/cli": "^17.6.3",
31-
"@commitlint/config-conventional": "^17.6.3",
31+
"@commitlint/cli": "^19.3.0",
32+
"@commitlint/config-conventional": "^19.2.2",
3233
"ava": "^5.2.0",
33-
"axios": "^1.4.0",
34+
"axios": "^1.7.3",
3435
"benchmark": "^2.1.4",
3536
"cross-env": "^7.0.3",
36-
"eslint": "^8.34.0",
37+
"eslint": "^9.8.0",
3738
"eslint-config-xo-lass": "^2.0.1",
38-
"fetch-mock": "^9.11.0",
39+
"fetch-mock": "^10.1.1",
3940
"fixpack": "^4.0.0",
4041
"got": "11",
41-
"husky": "^8.0.3",
42-
"ioredis": "^5.3.2",
43-
"ioredis-mock": "^8.7.0",
42+
"husky": "^9.1.4",
43+
"ioredis": "^5.4.1",
44+
"ioredis-mock": "^8.9.0",
4445
"is-ci": "^3.0.1",
45-
"lint-staged": "^13.2.2",
46+
"lint-staged": "^15.2.8",
4647
"lodash": "^4.17.21",
47-
"nock": "^13.3.1",
48+
"nock": "^13.5.4",
4849
"node-fetch": "2",
49-
"nyc": "^15.1.0",
50-
"phin": "^3.7.0",
51-
"remark-cli": "^11.0.0",
50+
"nyc": "^17.0.0",
51+
"phin": "^3.7.1",
52+
"remark-cli": "11.0.0",
5253
"remark-preset-github": "^4.0.4",
5354
"request": "^2.88.2",
5455
"sort-keys": "4.2.0",
55-
"superagent": "^8.0.9",
56-
"undici": "^5.22.1",
57-
"xo": "^0.54.2"
56+
"superagent": "^9.0.2",
57+
"undici": "^6.19.5",
58+
"xo": "^0.58.0"
5859
},
5960
"engines": {
6061
"node": ">=16"

test/test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,13 @@ function compareResults(t, type, r1, r2) {
227227
_.isError(r1)
228228
? r1
229229
: Array.isArray(r1) && r1.every((s) => _.isString(s))
230-
? r1.sort()
231-
: sortKeys(r1),
230+
? r1.sort()
231+
: sortKeys(r1),
232232
_.isError(r2)
233233
? r2
234234
: Array.isArray(r2) && r2.every((s) => _.isString(s))
235-
? r2.sort()
236-
: sortKeys(r2)
235+
? r2.sort()
236+
: sortKeys(r2)
237237
);
238238
}
239239
}

0 commit comments

Comments
 (0)