Skip to content

Commit aa864ba

Browse files
cjihrigtargos
authored andcommitted
dns: add promisified dns module
PR-URL: #21264 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent 9cef72d commit aa864ba

16 files changed

+1551
-406
lines changed

doc/api/dns.md

Lines changed: 466 additions & 0 deletions
Large diffs are not rendered by default.

lib/dns.js

Lines changed: 35 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ const { isIP, isIPv4, isLegalPort } = require('internal/net');
2626
const { customPromisifyArgs } = require('internal/util');
2727
const errors = require('internal/errors');
2828
const {
29-
ERR_DNS_SET_SERVERS_FAILED,
29+
bindDefaultResolver,
30+
getDefaultResolver,
31+
setDefaultResolver,
32+
Resolver,
33+
validateHints
34+
} = require('internal/dns/utils');
35+
const {
3036
ERR_INVALID_ARG_TYPE,
3137
ERR_INVALID_CALLBACK,
32-
ERR_INVALID_IP_ADDRESS,
3338
ERR_INVALID_OPT_VALUE,
3439
ERR_MISSING_ARGS,
3540
ERR_SOCKET_BAD_PORT
@@ -39,12 +44,13 @@ const {
3944
GetAddrInfoReqWrap,
4045
GetNameInfoReqWrap,
4146
QueryReqWrap,
42-
ChannelWrap,
4347
} = cares;
4448

45-
const IANA_DNS_PORT = 53;
4649
const dnsException = errors.dnsException;
4750

51+
let promisesWarn = true;
52+
let promises; // Lazy loaded
53+
4854
function onlookup(err, addresses) {
4955
if (err) {
5056
return this.callback(dnsException(err, 'getaddrinfo', this.hostname));
@@ -97,12 +103,7 @@ function lookup(hostname, options, callback) {
97103
all = options.all === true;
98104
verbatim = options.verbatim === true;
99105

100-
if (hints !== 0 &&
101-
hints !== cares.AI_ADDRCONFIG &&
102-
hints !== cares.AI_V4MAPPED &&
103-
hints !== (cares.AI_ADDRCONFIG | cares.AI_V4MAPPED)) {
104-
throw new ERR_INVALID_OPT_VALUE('hints', hints);
105-
}
106+
validateHints(hints);
106107
} else {
107108
family = options >>> 0;
108109
}
@@ -197,17 +198,6 @@ function onresolve(err, result, ttls) {
197198
this.callback(null, result);
198199
}
199200

200-
// Resolver instances correspond 1:1 to c-ares channels.
201-
class Resolver {
202-
constructor() {
203-
this._handle = new ChannelWrap();
204-
}
205-
206-
cancel() {
207-
this._handle.cancel();
208-
}
209-
}
210-
211201
function resolver(bindingName) {
212202
function query(name, /* options, */ callback) {
213203
var options;
@@ -270,101 +260,15 @@ function resolve(hostname, rrtype, callback) {
270260
}
271261
}
272262

273-
274-
Resolver.prototype.getServers = getServers;
275-
function getServers() {
276-
const ret = this._handle.getServers();
277-
return ret.map((val) => {
278-
if (!val[1] || val[1] === IANA_DNS_PORT) return val[0];
279-
280-
const host = isIP(val[0]) === 6 ? `[${val[0]}]` : val[0];
281-
return `${host}:${val[1]}`;
282-
});
283-
}
284-
285-
286-
Resolver.prototype.setServers = setServers;
287-
function setServers(servers) {
288-
// cache the original servers because in the event of an error setting the
289-
// servers cares won't have any servers available for resolution
290-
const orig = this._handle.getServers();
291-
const newSet = [];
292-
const IPv6RE = /^\[([^[\]]*)\]/;
293-
const addrSplitRE = /(^.+?)(?::(\d+))?$/;
294-
295-
servers.forEach((serv) => {
296-
var ipVersion = isIP(serv);
297-
if (ipVersion !== 0)
298-
return newSet.push([ipVersion, serv, IANA_DNS_PORT]);
299-
300-
const match = serv.match(IPv6RE);
301-
// we have an IPv6 in brackets
302-
if (match) {
303-
ipVersion = isIP(match[1]);
304-
if (ipVersion !== 0) {
305-
const port =
306-
parseInt(serv.replace(addrSplitRE, '$2')) ||
307-
IANA_DNS_PORT;
308-
return newSet.push([ipVersion, match[1], port]);
309-
}
310-
}
311-
312-
// addr::port
313-
const addrSplitMatch = serv.match(addrSplitRE);
314-
if (addrSplitMatch) {
315-
const hostIP = addrSplitMatch[1];
316-
const port = addrSplitMatch[2] || IANA_DNS_PORT;
317-
318-
ipVersion = isIP(hostIP);
319-
if (ipVersion !== 0) {
320-
return newSet.push([ipVersion, hostIP, parseInt(port)]);
321-
}
322-
}
323-
324-
throw new ERR_INVALID_IP_ADDRESS(serv);
325-
});
326-
327-
const errorNumber = this._handle.setServers(newSet);
328-
329-
if (errorNumber !== 0) {
330-
// reset the servers to the old servers, because ares probably unset them
331-
this._handle.setServers(orig.join(','));
332-
333-
var err = cares.strerror(errorNumber);
334-
throw new ERR_DNS_SET_SERVERS_FAILED(err, servers);
335-
}
336-
}
337-
338-
let defaultResolver = new Resolver();
339-
340-
const resolverKeys = [
341-
'getServers',
342-
'resolve',
343-
'resolveAny',
344-
'resolve4',
345-
'resolve6',
346-
'resolveCname',
347-
'resolveMx',
348-
'resolveNs',
349-
'resolveTxt',
350-
'resolveSrv',
351-
'resolvePtr',
352-
'resolveNaptr',
353-
'resolveSoa',
354-
'reverse'
355-
];
356-
357-
function setExportsFunctions() {
358-
resolverKeys.forEach((key) => {
359-
module.exports[key] = defaultResolver[key].bind(defaultResolver);
360-
});
361-
}
362-
363263
function defaultResolverSetServers(servers) {
364264
const resolver = new Resolver();
265+
365266
resolver.setServers(servers);
366-
defaultResolver = resolver;
367-
setExportsFunctions();
267+
setDefaultResolver(resolver);
268+
bindDefaultResolver(module.exports, Resolver.prototype);
269+
270+
if (promises !== undefined)
271+
bindDefaultResolver(promises, promises.Resolver.prototype);
368272
}
369273

370274
module.exports = {
@@ -405,4 +309,21 @@ module.exports = {
405309
CANCELLED: 'ECANCELLED'
406310
};
407311

408-
setExportsFunctions();
312+
bindDefaultResolver(module.exports, getDefaultResolver());
313+
314+
Object.defineProperties(module.exports, {
315+
promises: {
316+
configurable: true,
317+
enumerable: false,
318+
get() {
319+
if (promisesWarn) {
320+
promises = require('internal/dns/promises');
321+
promises.setServers = defaultResolverSetServers;
322+
promisesWarn = false;
323+
process.emitWarning('The dns.promises API is experimental',
324+
'ExperimentalWarning');
325+
}
326+
return promises;
327+
}
328+
}
329+
});

0 commit comments

Comments
 (0)