Skip to content

Commit a0408fc

Browse files
committed
dns: add a cancel() method to the promise Resolver
1 parent 35274cb commit a0408fc

File tree

4 files changed

+117
-9
lines changed

4 files changed

+117
-9
lines changed

doc/api/dns.md

Lines changed: 8 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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');
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
const common = require('../common');
3+
const dnstools = require('../common/dns');
4+
const { promises: dnsPromises } = require('dns');
5+
const assert = require('assert');
6+
const dgram = require('dgram');
7+
8+
const server = dgram.createSocket('udp4');
9+
const resolver = new dnsPromises.Resolver();
10+
11+
const receivedDomains = [];
12+
const expectedDomains = [];
13+
14+
server.bind(0, common.mustCall(async () => {
15+
resolver.setServers([`127.0.0.1:${server.address().port}`]);
16+
17+
// Single promise
18+
{
19+
const hostname = 'example0.org';
20+
expectedDomains.push(hostname);
21+
22+
await assert.rejects(
23+
resolver.resolve4(hostname),
24+
{
25+
code: 'ECANCELLED',
26+
syscall: 'queryA',
27+
hostname: 'example0.org'
28+
}
29+
);
30+
}
31+
32+
// Multiple promises
33+
{
34+
const assertions = [];
35+
const assertionCount = 10;
36+
37+
for (let i = 1; i <= assertionCount; i++) {
38+
const hostname = `example${i}.org`;
39+
40+
expectedDomains.push(hostname);
41+
42+
assertions.push(
43+
assert.rejects(
44+
resolver.resolve4(hostname),
45+
{
46+
code: 'ECANCELLED',
47+
syscall: 'queryA',
48+
hostname: hostname
49+
}
50+
)
51+
);
52+
}
53+
54+
await Promise.all(assertions);
55+
}
56+
57+
assert.deepStrictEqual(expectedDomains.sort(), receivedDomains.sort());
58+
59+
server.close();
60+
}));
61+
62+
server.on('message', (msg, { address, port }) => {
63+
const parsed = dnstools.parseDNSPacket(msg);
64+
65+
for (const question of parsed.questions) {
66+
receivedDomains.push(question.domain);
67+
}
68+
69+
// Do not send a reply.
70+
resolver.cancel();
71+
});

test/parallel/test-dns-channel-cancel.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,49 @@ const dgram = require('dgram');
88
const server = dgram.createSocket('udp4');
99
const resolver = new Resolver();
1010

11-
server.bind(0, common.mustCall(() => {
11+
const expectedDomains = [];
12+
const receivedDomains = [];
13+
const desiredQueries = 11;
14+
let finishedQueries = 0;
15+
16+
server.bind(0, common.mustCall(async () => {
1217
resolver.setServers([`127.0.0.1:${server.address().port}`]);
13-
resolver.resolve4('example.org', common.mustCall((err, res) => {
18+
19+
const callback = common.mustCall((err, res) => {
1420
assert.strictEqual(err.code, 'ECANCELLED');
1521
assert.strictEqual(err.syscall, 'queryA');
16-
assert.strictEqual(err.hostname, 'example.org');
17-
server.close();
18-
}));
22+
assert.strictEqual(err.hostname, `example${finishedQueries}.org`);
23+
24+
finishedQueries++;
25+
if (finishedQueries === desiredQueries) {
26+
assert.deepStrictEqual(expectedDomains.sort(), receivedDomains.sort());
27+
server.close();
28+
}
29+
}, desiredQueries);
30+
31+
const next = (...args) => {
32+
callback(...args);
33+
34+
// Multiple queries
35+
for (let i = 1; i < desiredQueries; i++) {
36+
const domain = `example${i}.org`;
37+
expectedDomains.push(domain);
38+
resolver.resolve4(domain, callback);
39+
}
40+
};
41+
42+
// Single query
43+
expectedDomains.push('example0.org');
44+
resolver.resolve4('example0.org', next);
1945
}));
2046

21-
server.on('message', common.mustCall((msg, { address, port }) => {
47+
server.on('message', (msg, { address, port }) => {
2248
const parsed = dnstools.parseDNSPacket(msg);
23-
const domain = parsed.questions[0].domain;
24-
assert.strictEqual(domain, 'example.org');
49+
50+
for (const question of parsed.questions) {
51+
receivedDomains.push(question.domain);
52+
}
2553

2654
// Do not send a reply.
2755
resolver.cancel();
28-
}));
56+
});

0 commit comments

Comments
 (0)