node/lib/internal/dns/callback_resolver.js
Joyee Cheung 12fb94c78c
dns: refactor default resolver
This patch refactors the DNS default resolver code to make it
easier to be included in a snapshot:

- The code specific for the callback-based DNS resolver are not
  in a separate module to make the dependency clearer (it's not
  actually needed if the user only ever loads `dns/promises`)
- The common part of the callback-based resolver and the promise-
  based resolver is now ResolverBase. The other two user-facing
  resolvers are now subclasses of ResolverBase. The default
  Resolver is constructed with just ResolverBase. This would
  be fine as the default resolver is never actually exposed
  to the user-land and it has been working using duck-typing anyway.
- Move the construction of Resolver subclasses into a common
  method `createResolverClass()` to reduce code duplication.
  The two subclasses now also share the same base constructor.
  This would make it possible for them to also share code
  for snapshot support later.
- `--dns-result-order` is now queried and refreshed during
  pre-execution. To avoid loading the cares_wrap binding unnecessarily
  the loading of the binding is also made lazy.

PR-URL: https://github.com/nodejs/node/pull/44541
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
2022-09-13 13:36:08 +00:00

117 lines
2.8 KiB
JavaScript

'use strict';
const {
ObjectDefineProperty,
ReflectApply,
ArrayPrototypeMap,
Symbol
} = primordials;
const { toASCII } = require('internal/idna');
const {
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
},
dnsException
} = require('internal/errors');
const {
createResolverClass,
} = require('internal/dns/utils');
const {
validateFunction,
validateString,
} = require('internal/validators');
const {
QueryReqWrap,
} = internalBinding('cares_wrap');
const {
hasObserver,
startPerf,
stopPerf,
} = require('internal/perf/observe');
const kPerfHooksDnsLookupResolveContext = Symbol('kPerfHooksDnsLookupResolveContext');
function onresolve(err, result, ttls) {
if (ttls && this.ttl)
result = ArrayPrototypeMap(
result, (address, index) => ({ address, ttl: ttls[index] }));
if (err)
this.callback(dnsException(err, this.bindingName, this.hostname));
else {
this.callback(null, result);
if (this[kPerfHooksDnsLookupResolveContext] && hasObserver('dns')) {
stopPerf(this, kPerfHooksDnsLookupResolveContext, { detail: { result } });
}
}
}
function resolver(bindingName) {
function query(name, /* options, */ callback) {
let options;
if (arguments.length > 2) {
options = callback;
callback = arguments[2];
}
validateString(name, 'name');
validateFunction(callback, 'callback');
const req = new QueryReqWrap();
req.bindingName = bindingName;
req.callback = callback;
req.hostname = name;
req.oncomplete = onresolve;
req.ttl = !!(options && options.ttl);
const err = this._handle[bindingName](req, toASCII(name));
if (err) throw dnsException(err, bindingName, name);
if (hasObserver('dns')) {
startPerf(req, kPerfHooksDnsLookupResolveContext, {
type: 'dns',
name: bindingName,
detail: {
host: name,
ttl: req.ttl,
},
});
}
return req;
}
ObjectDefineProperty(query, 'name', { __proto__: null, value: bindingName });
return query;
}
// This is the callback-based resolver. There is another similar
// resolver in dns/promises.js with resolve methods that are based
// on promises instead.
const { Resolver, resolveMap } = createResolverClass(resolver);
Resolver.prototype.resolve = resolve;
function resolve(hostname, rrtype, callback) {
let resolver;
if (typeof rrtype === 'string') {
resolver = resolveMap[rrtype];
} else if (typeof rrtype === 'function') {
resolver = resolveMap.A;
callback = rrtype;
} else {
throw new ERR_INVALID_ARG_TYPE('rrtype', 'string', rrtype);
}
if (typeof resolver === 'function') {
return ReflectApply(resolver, this, [hostname, callback]);
}
throw new ERR_INVALID_ARG_VALUE('rrtype', rrtype);
}
module.exports = {
Resolver
};