Skip to content

Commit 6349b1d

Browse files
szmarczakcodebytere
authored andcommitted
dns: add a cancel() method to the promise Resolver
PR-URL: #33099 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 9405cdd commit 6349b1d

File tree

4 files changed

+110
-13
lines changed

4 files changed

+110
-13
lines changed

doc/api/dns.md

+8
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,14 @@ The following methods from the `dnsPromises` API are available:
730730
* [`resolver.reverse()`][`dnsPromises.reverse()`]
731731
* [`resolver.setServers()`][`dnsPromises.setServers()`]
732732

733+
### `resolver.cancel()`
734+
<!-- YAML
735+
added: REPLACEME
736+
-->
737+
738+
Cancel all outstanding DNS queries made by this resolver. The corresponding
739+
promises will be rejected with an error with code `ECANCELLED`.
740+
733741
### `dnsPromises.getServers()`
734742
<!-- YAML
735743
added: v10.6.0

lib/internal/dns/promises.js

+1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class Resolver {
217217

218218
Resolver.prototype.getServers = CallbackResolver.prototype.getServers;
219219
Resolver.prototype.setServers = CallbackResolver.prototype.setServers;
220+
Resolver.prototype.cancel = CallbackResolver.prototype.cancel;
220221
Resolver.prototype.setLocalAddress = CallbackResolver.prototype.setLocalAddress;
221222
Resolver.prototype.resolveAny = resolveMap.ANY = resolver('queryAny');
222223
Resolver.prototype.resolve4 = resolveMap.A = resolver('queryA');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
const common = require('../common');
3+
const { promises: dnsPromises } = require('dns');
4+
const assert = require('assert');
5+
const dgram = require('dgram');
6+
7+
const server = dgram.createSocket('udp4');
8+
const resolver = new dnsPromises.Resolver();
9+
10+
const addMessageListener = () => {
11+
server.removeAllListeners('message');
12+
13+
server.once('message', () => {
14+
server.once('message', common.mustNotCall);
15+
16+
resolver.cancel();
17+
});
18+
};
19+
20+
server.bind(0, common.mustCall(async () => {
21+
resolver.setServers([`127.0.0.1:${server.address().port}`]);
22+
23+
addMessageListener();
24+
25+
// Single promise
26+
{
27+
const hostname = 'example0.org';
28+
29+
await assert.rejects(
30+
resolver.resolve4(hostname),
31+
{
32+
code: 'ECANCELLED',
33+
syscall: 'queryA',
34+
hostname
35+
}
36+
);
37+
}
38+
39+
addMessageListener();
40+
41+
// Multiple promises
42+
{
43+
const assertions = [];
44+
const assertionCount = 10;
45+
46+
for (let i = 1; i <= assertionCount; i++) {
47+
const hostname = `example${i}.org`;
48+
49+
assertions.push(
50+
assert.rejects(
51+
resolver.resolve4(hostname),
52+
{
53+
code: 'ECANCELLED',
54+
syscall: 'queryA',
55+
hostname: hostname
56+
}
57+
)
58+
);
59+
}
60+
61+
await Promise.all(assertions);
62+
}
63+
64+
server.close();
65+
}));
+36-13
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,51 @@
11
'use strict';
22
const common = require('../common');
3-
const dnstools = require('../common/dns');
43
const { Resolver } = require('dns');
54
const assert = require('assert');
65
const dgram = require('dgram');
76

87
const server = dgram.createSocket('udp4');
98
const resolver = new Resolver();
109

11-
server.bind(0, common.mustCall(() => {
10+
const desiredQueries = 11;
11+
let finishedQueries = 0;
12+
13+
const addMessageListener = () => {
14+
server.removeAllListeners('message');
15+
16+
server.once('message', () => {
17+
server.once('message', common.mustNotCall);
18+
19+
resolver.cancel();
20+
});
21+
};
22+
23+
server.bind(0, common.mustCall(async () => {
1224
resolver.setServers([`127.0.0.1:${server.address().port}`]);
13-
resolver.resolve4('example.org', common.mustCall((err, res) => {
25+
26+
const callback = common.mustCall((err, res) => {
1427
assert.strictEqual(err.code, 'ECANCELLED');
1528
assert.strictEqual(err.syscall, 'queryA');
16-
assert.strictEqual(err.hostname, 'example.org');
17-
server.close();
18-
}));
19-
}));
29+
assert.strictEqual(err.hostname, `example${finishedQueries}.org`);
30+
31+
finishedQueries++;
32+
if (finishedQueries === desiredQueries) {
33+
server.close();
34+
}
35+
}, desiredQueries);
36+
37+
const next = (...args) => {
38+
callback(...args);
39+
40+
addMessageListener();
2041

21-
server.on('message', common.mustCall((msg, { address, port }) => {
22-
const parsed = dnstools.parseDNSPacket(msg);
23-
const domain = parsed.questions[0].domain;
24-
assert.strictEqual(domain, 'example.org');
42+
// Multiple queries
43+
for (let i = 1; i < desiredQueries; i++) {
44+
resolver.resolve4(`example${i}.org`, callback);
45+
}
46+
};
2547

26-
// Do not send a reply.
27-
resolver.cancel();
48+
// Single query
49+
addMessageListener();
50+
resolver.resolve4('example0.org', next);
2851
}));

0 commit comments

Comments
 (0)