dns: add a cancel() method to the promise Resolver

PR-URL: https://github.com/nodejs/node/pull/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>
This commit is contained in:
Szymon Marczak 2020-11-11 22:22:41 +01:00 committed by Antoine du Hamel
parent d5e4e19470
commit 9ea0fae7ea
4 changed files with 110 additions and 13 deletions

View File

@ -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

View File

@ -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');

View File

@ -0,0 +1,65 @@
'use strict';
const common = require('../common');
const { promises: dnsPromises } = require('dns');
const assert = require('assert');
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const resolver = new dnsPromises.Resolver();
const addMessageListener = () => {
server.removeAllListeners('message');
server.once('message', () => {
server.once('message', common.mustNotCall);
resolver.cancel();
});
};
server.bind(0, common.mustCall(async () => {
resolver.setServers([`127.0.0.1:${server.address().port}`]);
addMessageListener();
// Single promise
{
const hostname = 'example0.org';
await assert.rejects(
resolver.resolve4(hostname),
{
code: 'ECANCELLED',
syscall: 'queryA',
hostname
}
);
}
addMessageListener();
// Multiple promises
{
const assertions = [];
const assertionCount = 10;
for (let i = 1; i <= assertionCount; i++) {
const hostname = `example${i}.org`;
assertions.push(
assert.rejects(
resolver.resolve4(hostname),
{
code: 'ECANCELLED',
syscall: 'queryA',
hostname: hostname
}
)
);
}
await Promise.all(assertions);
}
server.close();
}));

View File

@ -1,6 +1,5 @@
'use strict';
const common = require('../common');
const dnstools = require('../common/dns');
const { Resolver } = require('dns');
const assert = require('assert');
const dgram = require('dgram');
@ -8,21 +7,45 @@ const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const resolver = new Resolver();
server.bind(0, common.mustCall(() => {
const desiredQueries = 11;
let finishedQueries = 0;
const addMessageListener = () => {
server.removeAllListeners('message');
server.once('message', () => {
server.once('message', common.mustNotCall);
resolver.cancel();
});
};
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`);
server.on('message', common.mustCall((msg, { address, port }) => {
const parsed = dnstools.parseDNSPacket(msg);
const domain = parsed.questions[0].domain;
assert.strictEqual(domain, 'example.org');
finishedQueries++;
if (finishedQueries === desiredQueries) {
server.close();
}
}, desiredQueries);
// Do not send a reply.
resolver.cancel();
const next = (...args) => {
callback(...args);
addMessageListener();
// Multiple queries
for (let i = 1; i < desiredQueries; i++) {
resolver.resolve4(`example${i}.org`, callback);
}
};
// Single query
addMessageListener();
resolver.resolve4('example0.org', next);
}));