Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/internal/dns/utils.js67
-rw-r--r--lib/internal/main/mksnapshot.js2
-rw-r--r--src/cares_wrap.cc36
-rw-r--r--src/cares_wrap.h3
-rw-r--r--src/node_external_reference.h1
-rw-r--r--test/common/snapshot.js66
-rw-r--r--test/fixtures/snapshot/dns-lookup.js39
-rw-r--r--test/fixtures/snapshot/dns-resolve.js59
-rw-r--r--test/internet/test-snapshot-dns-lookup.js34
-rw-r--r--test/internet/test-snapshot-dns-resolve.js36
-rw-r--r--test/parallel/test-snapshot-dns-lookup-localhost-promise.js35
-rw-r--r--test/parallel/test-snapshot-dns-lookup-localhost.js35
-rw-r--r--test/parallel/test-snapshot-dns-resolve-localhost-promise.js34
-rw-r--r--test/parallel/test-snapshot-dns-resolve-localhost.js34
14 files changed, 474 insertions, 7 deletions
diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js
index f895a46c1a0..511d857b591 100644
--- a/lib/internal/dns/utils.js
+++ b/lib/internal/dns/utils.js
@@ -10,6 +10,7 @@ const {
RegExpPrototypeExec,
RegExpPrototypeSymbolReplace,
ObjectCreate,
+ Symbol,
} = primordials;
const errors = require('internal/errors');
@@ -35,6 +36,12 @@ const {
ERR_INVALID_IP_ADDRESS,
} = errors.codes;
+const {
+ addSerializeCallback,
+ addDeserializeCallback,
+ isBuildingSnapshot,
+} = require('v8').startupSnapshot;
+
function validateTimeout(options) {
const { timeout = -1 } = { ...options };
validateInt32(timeout, 'options.timeout', -1);
@@ -47,12 +54,27 @@ function validateTries(options) {
return tries;
}
+const kSerializeResolver = Symbol('dns:resolver:serialize');
+const kDeserializeResolver = Symbol('dns:resolver:deserialize');
+const kSnapshotStates = Symbol('dns:resolver:config');
+const kInitializeHandle = Symbol('dns:resolver:initializeHandle');
+const kSetServersInteral = Symbol('dns:resolver:setServers');
+
// Resolver instances correspond 1:1 to c-ares channels.
class ResolverBase {
constructor(options = undefined) {
const timeout = validateTimeout(options);
const tries = validateTries(options);
+ // If we are building snapshot, save the states of the resolver along
+ // the way.
+ if (isBuildingSnapshot()) {
+ this[kSnapshotStates] = { timeout, tries };
+ }
+ this[kInitializeHandle](timeout, tries);
+ }
+
+ [kInitializeHandle](timeout, tries) {
const { ChannelWrap } = lazyBinding();
this._handle = new ChannelWrap(timeout, tries);
}
@@ -77,9 +99,7 @@ class ResolverBase {
// Cache the original servers because in the event of an error while
// setting the servers, c-ares won't have any servers available for
// resolution.
- const orig = this._handle.getServers() || [];
const newSet = [];
-
ArrayPrototypeForEach(servers, (serv, index) => {
validateString(serv, `servers[${index}]`);
let ipVersion = isIP(serv);
@@ -118,6 +138,11 @@ class ResolverBase {
throw new ERR_INVALID_IP_ADDRESS(serv);
});
+ this[kSetServersInteral](newSet, servers);
+ }
+
+ [kSetServersInteral](newSet, servers) {
+ const orig = this._handle.getServers() || [];
const errorNumber = this._handle.setServers(newSet);
if (errorNumber !== 0) {
@@ -127,8 +152,13 @@ class ResolverBase {
const err = strerror(errorNumber);
throw new ERR_DNS_SET_SERVERS_FAILED(err, servers);
}
+
+ if (isBuildingSnapshot()) {
+ this[kSnapshotStates].servers = newSet;
+ }
}
+
setLocalAddress(ipv4, ipv6) {
validateString(ipv4, 'ipv4');
@@ -137,6 +167,31 @@ class ResolverBase {
}
this._handle.setLocalAddress(ipv4, ipv6);
+
+ if (isBuildingSnapshot()) {
+ this[kSnapshotStates].localAddress = { ipv4, ipv6 };
+ }
+ }
+
+ // TODO(joyeecheung): consider exposing this if custom DNS resolvers
+ // end up being useful for snapshot users.
+ [kSerializeResolver]() {
+ this._handle = null; // We'll restore it during deserialization.
+ addDeserializeCallback(function deserializeResolver(resolver) {
+ resolver[kDeserializeResolver]();
+ }, this);
+ }
+
+ [kDeserializeResolver]() {
+ const { timeout, tries, localAddress, servers } = this[kSnapshotStates];
+ this[kInitializeHandle](timeout, tries);
+ if (localAddress) {
+ const { ipv4, ipv6 } = localAddress;
+ this._handle.setLocalAddress(ipv4, ipv6);
+ }
+ if (servers) {
+ this[kSetServersInteral](servers, servers);
+ }
}
}
@@ -151,6 +206,14 @@ function initializeDns() {
// Allow the deserialized application to override order from CLI.
dnsOrder = orderFromCLI;
}
+
+ if (!isBuildingSnapshot()) {
+ return;
+ }
+
+ addSerializeCallback(() => {
+ defaultResolver?.[kSerializeResolver]();
+ });
}
const resolverKeys = [
diff --git a/lib/internal/main/mksnapshot.js b/lib/internal/main/mksnapshot.js
index 4add00e13c1..d7ad9324114 100644
--- a/lib/internal/main/mksnapshot.js
+++ b/lib/internal/main/mksnapshot.js
@@ -49,7 +49,7 @@ const supportedModules = new SafeSet(new SafeArrayIterator([
'crypto',
// 'dgram',
'diagnostics_channel',
- // 'dns',
+ 'dns',
// 'dns/promises',
// 'domain',
'events',
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index d19705f94e7..eb3ebceeca6 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -19,18 +19,19 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+#include "cares_wrap.h"
#include "async_wrap-inl.h"
-#include "base_object-inl.h"
#include "base64-inl.h"
-#include "cares_wrap.h"
+#include "base_object-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node.h"
#include "node_errors.h"
+#include "node_external_reference.h"
#include "req_wrap-inl.h"
#include "util-inl.h"
-#include "v8.h"
#include "uv.h"
+#include "v8.h"
#include <cerrno>
#include <cstring>
@@ -1955,7 +1956,36 @@ void Initialize(Local<Object> target,
SetConstructorFunction(context, target, "ChannelWrap", channel_wrap);
}
+void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
+ registry->Register(GetAddrInfo);
+ registry->Register(GetNameInfo);
+ registry->Register(CanonicalizeIP);
+ registry->Register(StrError);
+ registry->Register(ChannelWrap::New);
+
+ registry->Register(Query<QueryAnyWrap>);
+ registry->Register(Query<QueryAWrap>);
+ registry->Register(Query<QueryAaaaWrap>);
+ registry->Register(Query<QueryCaaWrap>);
+ registry->Register(Query<QueryCnameWrap>);
+ registry->Register(Query<QueryMxWrap>);
+ registry->Register(Query<QueryNsWrap>);
+ registry->Register(Query<QueryTxtWrap>);
+ registry->Register(Query<QuerySrvWrap>);
+ registry->Register(Query<QueryPtrWrap>);
+ registry->Register(Query<QueryNaptrWrap>);
+ registry->Register(Query<QuerySoaWrap>);
+ registry->Register(Query<GetHostByAddrWrap>);
+
+ registry->Register(GetServers);
+ registry->Register(SetServers);
+ registry->Register(SetLocalAddress);
+ registry->Register(Cancel);
+}
+
} // namespace cares_wrap
} // namespace node
NODE_MODULE_CONTEXT_AWARE_INTERNAL(cares_wrap, node::cares_wrap::Initialize)
+NODE_MODULE_EXTERNAL_REFERENCE(cares_wrap,
+ node::cares_wrap::RegisterExternalReferences)
diff --git a/src/cares_wrap.h b/src/cares_wrap.h
index 60f99e65edf..ea339b77399 100644
--- a/src/cares_wrap.h
+++ b/src/cares_wrap.h
@@ -9,8 +9,9 @@
#include "base_object.h"
#include "env.h"
#include "memory_tracker.h"
-#include "util.h"
#include "node.h"
+#include "node_internals.h"
+#include "util.h"
#include "ares.h"
#include "v8.h"
diff --git a/src/node_external_reference.h b/src/node_external_reference.h
index a77c1ab14ee..9dc85d1b19a 100644
--- a/src/node_external_reference.h
+++ b/src/node_external_reference.h
@@ -62,6 +62,7 @@ class ExternalReferenceRegistry {
V(blob) \
V(buffer) \
V(builtins) \
+ V(cares_wrap) \
V(contextify) \
V(credentials) \
V(env_var) \
diff --git a/test/common/snapshot.js b/test/common/snapshot.js
new file mode 100644
index 00000000000..97367c05656
--- /dev/null
+++ b/test/common/snapshot.js
@@ -0,0 +1,66 @@
+'use strict';
+
+const tmpdir = require('../common/tmpdir');
+const { spawnSync } = require('child_process');
+const path = require('path');
+const fs = require('fs');
+const assert = require('assert');
+
+function buildSnapshot(entry, env) {
+ const child = spawnSync(process.execPath, [
+ '--snapshot-blob',
+ path.join(tmpdir.path, 'snapshot.blob'),
+ '--build-snapshot',
+ entry,
+ ], {
+ cwd: tmpdir.path,
+ env: {
+ ...process.env,
+ ...env,
+ },
+ });
+
+ const stderr = child.stderr.toString();
+ const stdout = child.stdout.toString();
+ console.log('[stderr]');
+ console.log(stderr);
+ console.log('[stdout]');
+ console.log(stdout);
+
+ assert.strictEqual(child.status, 0);
+
+ const stats = fs.statSync(path.join(tmpdir.path, 'snapshot.blob'));
+ assert(stats.isFile());
+
+ return { child, stderr, stdout };
+}
+
+function runWithSnapshot(entry, env) {
+ const args = ['--snapshot-blob', path.join(tmpdir.path, 'snapshot.blob')];
+ if (entry !== undefined) {
+ args.push(entry);
+ }
+ const child = spawnSync(process.execPath, args, {
+ cwd: tmpdir.path,
+ env: {
+ ...process.env,
+ ...env,
+ }
+ });
+
+ const stderr = child.stderr.toString();
+ const stdout = child.stdout.toString();
+ console.log('[stderr]');
+ console.log(stderr);
+ console.log('[stdout]');
+ console.log(stdout);
+
+ assert.strictEqual(child.status, 0);
+
+ return { child, stderr, stdout };
+}
+
+module.exports = {
+ buildSnapshot,
+ runWithSnapshot,
+};
diff --git a/test/fixtures/snapshot/dns-lookup.js b/test/fixtures/snapshot/dns-lookup.js
new file mode 100644
index 00000000000..773b508f7cb
--- /dev/null
+++ b/test/fixtures/snapshot/dns-lookup.js
@@ -0,0 +1,39 @@
+'use strict';
+const dns = require('dns');
+const assert = require('assert');
+
+assert(process.env.NODE_TEST_HOST);
+
+const {
+ setDeserializeMainFunction,
+} = require('v8').startupSnapshot;
+
+function onError(err) {
+ console.error('error:', err);
+}
+
+function onLookup(address, family) {
+ console.log(`address: ${JSON.stringify(address)}`);
+ console.log(`family: ${JSON.stringify(family)}`);
+}
+
+function query() {
+ const host = process.env.NODE_TEST_HOST;
+ if (process.env.NODE_TEST_PROMISE === 'true') {
+ dns.promises.lookup(host, { family: 4 }).then(
+ ({address, family}) => onLookup(address, family),
+ onError);
+ } else {
+ dns.lookup(host, { family: 4 }, (err, address, family) => {
+ if (err) {
+ onError(err);
+ } else {
+ onLookup(address, family);
+ }
+ });
+ }
+}
+
+query();
+
+setDeserializeMainFunction(query);
diff --git a/test/fixtures/snapshot/dns-resolve.js b/test/fixtures/snapshot/dns-resolve.js
new file mode 100644
index 00000000000..6a776f29704
--- /dev/null
+++ b/test/fixtures/snapshot/dns-resolve.js
@@ -0,0 +1,59 @@
+'use strict';
+const dns = require('dns');
+const assert = require('assert');
+
+assert(process.env.NODE_TEST_HOST);
+
+const {
+ setDeserializeMainFunction,
+} = require('v8').startupSnapshot;
+
+function onError(err) {
+ console.error('error:', err);
+}
+
+function onResolve(addresses) {
+ console.log(`addresses: ${JSON.stringify(addresses)}`);
+}
+
+function onReverse(hostnames) {
+ console.log(`hostnames: ${JSON.stringify(hostnames)}`);
+}
+
+function query() {
+ if (process.env.NODE_TEST_DNS) {
+ dns.setServers([process.env.NODE_TEST_DNS])
+ }
+
+ const host = process.env.NODE_TEST_HOST;
+ if (process.env.NODE_TEST_PROMISE === 'true') {
+ dns.promises.resolve4(host).then(onResolve, onError);
+ } else {
+ dns.resolve4(host, (err, addresses) => {
+ if (err) {
+ onError(err);
+ } else {
+ onResolve(addresses);
+ }
+ });
+ }
+
+ const ip = process.env.NODE_TEST_IP;
+ if (ip) {
+ if (process.env.NODE_TEST_PROMISE === 'true') {
+ dns.promises.reverse(ip).then(onReverse, onError);
+ } else {
+ dns.reverse(ip, (err, hostnames) => {
+ if (err) {
+ onError(err);
+ } else {
+ onReverse(hostnames);
+ }
+ });
+ }
+ }
+}
+
+query();
+
+setDeserializeMainFunction(query);
diff --git a/test/internet/test-snapshot-dns-lookup.js b/test/internet/test-snapshot-dns-lookup.js
new file mode 100644
index 00000000000..842e73e0568
--- /dev/null
+++ b/test/internet/test-snapshot-dns-lookup.js
@@ -0,0 +1,34 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+const {
+ addresses: { INET4_HOST },
+} = require('../common/internet');
+
+const entry = fixtures.path('snapshot', 'dns-lookup.js');
+const env = {
+ NODE_TEST_HOST: INET4_HOST,
+ NODE_TEST_PROMISE: 'false',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ assert(stdout.match(stdout, /address: "\d+\.\d+\.\d+\.\d+"/));
+ assert(stdout.match(stdout, /family: 4/));
+ assert.strictEqual(stdout.trim().split('\n').length, 2);
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
diff --git a/test/internet/test-snapshot-dns-resolve.js b/test/internet/test-snapshot-dns-resolve.js
new file mode 100644
index 00000000000..6efea9b4f74
--- /dev/null
+++ b/test/internet/test-snapshot-dns-resolve.js
@@ -0,0 +1,36 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+const {
+ addresses: { DNS4_SERVER, INET4_IP, INET4_HOST },
+} = require('../common/internet');
+
+const entry = fixtures.path('snapshot', 'dns-resolve.js');
+const env = {
+ NODE_TEST_IP: INET4_IP,
+ NODE_TEST_HOST: INET4_HOST,
+ NODE_TEST_DNS: DNS4_SERVER,
+ NODE_TEST_PROMISE: 'false',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ assert(stdout.includes('hostnames: ['));
+ assert(stdout.includes('addresses: ['));
+ assert.strictEqual(stdout.trim().split('\n').length, 2);
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
diff --git a/test/parallel/test-snapshot-dns-lookup-localhost-promise.js b/test/parallel/test-snapshot-dns-lookup-localhost-promise.js
new file mode 100644
index 00000000000..d19488a716a
--- /dev/null
+++ b/test/parallel/test-snapshot-dns-lookup-localhost-promise.js
@@ -0,0 +1,35 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+
+const entry = fixtures.path('snapshot', 'dns-lookup.js');
+const env = {
+ NODE_TEST_HOST: 'localhost',
+ NODE_TEST_PROMISE: 'true',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ // We allow failures as it's not always possible to resolve localhost.
+ // Functional tests are done in test/internet instead.
+ if (!stderr.startsWith('error:')) {
+ assert(stdout.match(stdout, /address: "\d+\.\d+\.\d+\.\d+"/));
+ assert(stdout.match(stdout, /family: 4/));
+ assert.strictEqual(stdout.trim().split('\n').length, 2);
+ }
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
diff --git a/test/parallel/test-snapshot-dns-lookup-localhost.js b/test/parallel/test-snapshot-dns-lookup-localhost.js
new file mode 100644
index 00000000000..af00480bcca
--- /dev/null
+++ b/test/parallel/test-snapshot-dns-lookup-localhost.js
@@ -0,0 +1,35 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+
+const entry = fixtures.path('snapshot', 'dns-lookup.js');
+const env = {
+ NODE_TEST_HOST: 'localhost',
+ NODE_TEST_PROMISE: 'false',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ // We allow failures as it's not always possible to resolve localhost.
+ // Functional tests are done in test/internet instead.
+ if (!stderr.startsWith('error:')) {
+ assert(stdout.match(stdout, /address: "\d+\.\d+\.\d+\.\d+"/));
+ assert(stdout.match(stdout, /family: 4/));
+ assert.strictEqual(stdout.trim().split('\n').length, 2);
+ }
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
diff --git a/test/parallel/test-snapshot-dns-resolve-localhost-promise.js b/test/parallel/test-snapshot-dns-resolve-localhost-promise.js
new file mode 100644
index 00000000000..cca86007f16
--- /dev/null
+++ b/test/parallel/test-snapshot-dns-resolve-localhost-promise.js
@@ -0,0 +1,34 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+
+const entry = fixtures.path('snapshot', 'dns-resolve.js');
+const env = {
+ NODE_TEST_HOST: 'localhost',
+ NODE_TEST_PROMISE: 'true',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ // We allow failures as it's not always possible to resolve localhost.
+ // Functional tests are done in test/internet instead.
+ if (!stderr.startsWith('error:')) {
+ assert(stdout.includes('addresses: ['));
+ assert.strictEqual(stdout.trim().split('\n').length, 1);
+ }
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
diff --git a/test/parallel/test-snapshot-dns-resolve-localhost.js b/test/parallel/test-snapshot-dns-resolve-localhost.js
new file mode 100644
index 00000000000..af4576bcc3e
--- /dev/null
+++ b/test/parallel/test-snapshot-dns-resolve-localhost.js
@@ -0,0 +1,34 @@
+'use strict';
+
+// This tests support for the dns module in snapshot.
+
+require('../common');
+const assert = require('assert');
+const tmpdir = require('../common/tmpdir');
+const fixtures = require('../common/fixtures');
+const { buildSnapshot, runWithSnapshot } = require('../common/snapshot');
+
+const entry = fixtures.path('snapshot', 'dns-resolve.js');
+const env = {
+ NODE_TEST_HOST: 'localhost',
+ NODE_TEST_PROMISE: 'false',
+};
+
+tmpdir.refresh();
+function checkOutput(stderr, stdout) {
+ // We allow failures as it's not always possible to resolve localhost.
+ // Functional tests are done in test/internet instead.
+ if (!stderr.startsWith('error:')) {
+ assert(stdout.includes('addresses: ['));
+ assert.strictEqual(stdout.trim().split('\n').length, 1);
+ }
+}
+{
+ const { stderr, stdout } = buildSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}
+
+{
+ const { stderr, stdout } = runWithSnapshot(entry, env);
+ checkOutput(stderr, stdout);
+}