Skip to content

Commit

Permalink
dns: add a cancel() method to the promise Resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak committed Nov 11, 2020
1 parent 35274cb commit a0408fc
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 9 deletions.
8 changes: 8 additions & 0 deletions doc/api/dns.md
Expand Up @@ -730,6 +730,14 @@ The following methods from the `dnsPromises` API are available:
* [`resolver.reverse()`][`dnsPromises.reverse()`]
* [`resolver.setServers()`][`dnsPromises.setServers()`]

### `resolver.cancel()`
<!-- YAML
added: REPLACEME
-->

Cancel all outstanding DNS queries made by this resolver. The corresponding
promises will be rejected with an error with code `ECANCELLED`.

### `dnsPromises.getServers()`
<!-- YAML
added: v10.6.0
Expand Down
1 change: 1 addition & 0 deletions lib/internal/dns/promises.js
Expand Up @@ -217,6 +217,7 @@ class Resolver {

Resolver.prototype.getServers = CallbackResolver.prototype.getServers;
Resolver.prototype.setServers = CallbackResolver.prototype.setServers;
Resolver.prototype.cancel = CallbackResolver.prototype.cancel;
Resolver.prototype.setLocalAddress = CallbackResolver.prototype.setLocalAddress;
Resolver.prototype.resolveAny = resolveMap.ANY = resolver('queryAny');
Resolver.prototype.resolve4 = resolveMap.A = resolver('queryA');
Expand Down
71 changes: 71 additions & 0 deletions test/parallel/test-dns-channel-cancel-promise.js
@@ -0,0 +1,71 @@
'use strict';
const common = require('../common');
const dnstools = require('../common/dns');
const { promises: dnsPromises } = require('dns');
const assert = require('assert');
const dgram = require('dgram');

const server = dgram.createSocket('udp4');
const resolver = new dnsPromises.Resolver();

const receivedDomains = [];
const expectedDomains = [];

server.bind(0, common.mustCall(async () => {
resolver.setServers([`127.0.0.1:${server.address().port}`]);

// Single promise
{
const hostname = 'example0.org';
expectedDomains.push(hostname);

await assert.rejects(
resolver.resolve4(hostname),
{
code: 'ECANCELLED',
syscall: 'queryA',
hostname: 'example0.org'
}
);
}

// Multiple promises
{
const assertions = [];
const assertionCount = 10;

for (let i = 1; i <= assertionCount; i++) {
const hostname = `example${i}.org`;

expectedDomains.push(hostname);

assertions.push(
assert.rejects(
resolver.resolve4(hostname),
{
code: 'ECANCELLED',
syscall: 'queryA',
hostname: hostname
}
)
);
}

await Promise.all(assertions);
}

assert.deepStrictEqual(expectedDomains.sort(), receivedDomains.sort());

server.close();
}));

server.on('message', (msg, { address, port }) => {
const parsed = dnstools.parseDNSPacket(msg);

for (const question of parsed.questions) {
receivedDomains.push(question.domain);
}

// Do not send a reply.
resolver.cancel();
});
46 changes: 37 additions & 9 deletions test/parallel/test-dns-channel-cancel.js
Expand Up @@ -8,21 +8,49 @@ const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const resolver = new Resolver();

server.bind(0, common.mustCall(() => {
const expectedDomains = [];
const receivedDomains = [];
const desiredQueries = 11;
let finishedQueries = 0;

server.bind(0, common.mustCall(async () => {
resolver.setServers([`127.0.0.1:${server.address().port}`]);
resolver.resolve4('example.org', common.mustCall((err, res) => {

const callback = common.mustCall((err, res) => {
assert.strictEqual(err.code, 'ECANCELLED');
assert.strictEqual(err.syscall, 'queryA');
assert.strictEqual(err.hostname, 'example.org');
server.close();
}));
assert.strictEqual(err.hostname, `example${finishedQueries}.org`);

finishedQueries++;
if (finishedQueries === desiredQueries) {
assert.deepStrictEqual(expectedDomains.sort(), receivedDomains.sort());
server.close();
}
}, desiredQueries);

const next = (...args) => {
callback(...args);

// Multiple queries
for (let i = 1; i < desiredQueries; i++) {
const domain = `example${i}.org`;
expectedDomains.push(domain);
resolver.resolve4(domain, callback);
}
};

// Single query
expectedDomains.push('example0.org');
resolver.resolve4('example0.org', next);
}));

server.on('message', common.mustCall((msg, { address, port }) => {
server.on('message', (msg, { address, port }) => {
const parsed = dnstools.parseDNSPacket(msg);
const domain = parsed.questions[0].domain;
assert.strictEqual(domain, 'example.org');

for (const question of parsed.questions) {
receivedDomains.push(question.domain);
}

// Do not send a reply.
resolver.cancel();
}));
});

0 comments on commit a0408fc

Please sign in to comment.