From 9cb390d8991978ceeaee4c7a80289f56a030aa00 Mon Sep 17 00:00:00 2001 From: Weijia Wang <381152119@qq.com> Date: Thu, 13 Jul 2017 07:58:59 +0800 Subject: [PATCH] errors: migrate dns to use internal/errors PR-URL: https://github.com/nodejs/node/pull/14212 Refs: https://github.com/nodejs/node/issues/11273 Reviewed-By: James M Snell Reviewed-By: Khaidi Chu Reviewed-By: Refael Ackermann Reviewed-By: Matteo Collina --- doc/api/errors.md | 8 ++ lib/dns.js | 33 +++---- lib/internal/errors.js | 3 + test/parallel/test-c-ares.js | 20 +++-- test/parallel/test-dns-lookup.js | 28 ++++-- test/parallel/test-dns-regress-7070.js | 13 ++- test/parallel/test-dns.js | 90 +++++++++++++------ .../parallel/test-net-connect-options-port.js | 8 +- 8 files changed, 147 insertions(+), 56 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index 2d4f3f02e94e79..7225e8417f4fb5 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -596,6 +596,10 @@ Used when `Console` is instantiated without `stdout` stream or when `stdout` or Used when the native call from `process.cpuUsage` cannot be processed properly. + + +Used when `c-ares` failed to set the DNS server. + ### ERR_FALSY_VALUE_REJECTION @@ -685,6 +689,10 @@ Used when an attempt is made to send an unsupported "handle" over an IPC communication channel to a child process. See [`child.send()`] and [`process.send()`] for more information. + + +Used when an IP address is not valid. + ### ERR_INVALID_OPT_VALUE diff --git a/lib/dns.js b/lib/dns.js index 877dc6218a09f7..4e39cfe49e18c2 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -27,6 +27,7 @@ const cares = process.binding('cares_wrap'); const uv = process.binding('uv'); const internalNet = require('internal/net'); const { customPromisifyArgs } = require('internal/util'); +const errors = require('internal/errors'); const GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap; const GetNameInfoReqWrap = cares.GetNameInfoReqWrap; @@ -126,13 +127,13 @@ function lookup(hostname, options, callback) { // Parse arguments if (hostname && typeof hostname !== 'string') { - throw new TypeError('Invalid arguments: ' + - 'hostname must be a string or falsey'); + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'hostname', + ['string', 'falsey'], hostname); } else if (typeof options === 'function') { callback = options; family = 0; } else if (typeof callback !== 'function') { - throw new TypeError('Invalid arguments: callback must be passed'); + throw new errors.TypeError('ERR_INVALID_CALLBACK'); } else if (options !== null && typeof options === 'object') { hints = options.hints >>> 0; family = options.family >>> 0; @@ -142,14 +143,14 @@ function lookup(hostname, options, callback) { hints !== cares.AI_ADDRCONFIG && hints !== cares.AI_V4MAPPED && hints !== (cares.AI_ADDRCONFIG | cares.AI_V4MAPPED)) { - throw new TypeError('Invalid argument: hints must use valid flags'); + throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'hints', hints); } } else { family = options >>> 0; } if (family !== 0 && family !== 4 && family !== 6) - throw new TypeError('Invalid argument: family must be 4 or 6'); + throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'family', family); if (!hostname) { if (all) { @@ -200,16 +201,16 @@ function onlookupservice(err, host, service) { // lookupService(address, port, callback) function lookupService(host, port, callback) { if (arguments.length !== 3) - throw new Error('Invalid arguments'); + throw new errors.TypeError('ERR_MISSING_ARGS', 'host', 'port', 'callback'); if (isIP(host) === 0) - throw new TypeError('"host" argument needs to be a valid IP address'); + throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'host', host); if (!isLegalPort(port)) - throw new TypeError(`"port" should be >= 0 and < 65536, got "${port}"`); + throw new errors.RangeError('ERR_SOCKET_BAD_PORT'); if (typeof callback !== 'function') - throw new TypeError('"callback" argument must be a function'); + throw new errors.TypeError('ERR_INVALID_CALLBACK'); port = +port; @@ -250,9 +251,10 @@ function resolver(bindingName) { } if (typeof name !== 'string') { - throw new Error('"name" argument must be a string'); + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'name', + 'string', name); } else if (typeof callback !== 'function') { - throw new Error('"callback" argument must be a function'); + throw new errors.TypeError('ERR_INVALID_CALLBACK'); } var req = new QueryReqWrap(); @@ -290,13 +292,14 @@ function resolve(hostname, rrtype, callback) { resolver = resolveMap.A; callback = rrtype; } else { - throw new TypeError('"rrtype" argument must be a string'); + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'rrtype', + 'string', rrtype); } if (typeof resolver === 'function') { return resolver(hostname, callback); } else { - throw new Error(`Unknown type "${rrtype}"`); + throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'rrtype', rrtype); } } @@ -344,7 +347,7 @@ function setServers(servers) { return newSet.push([ipVersion, s, parseInt(p)]); } - throw new Error(`IP address is not properly formatted: ${serv}`); + throw new errors.Error('ERR_INVALID_IP_ADDRESS', serv); }); const errorNumber = cares.setServers(newSet); @@ -354,7 +357,7 @@ function setServers(servers) { cares.setServers(orig.join(',')); var err = cares.strerror(errorNumber); - throw new Error(`c-ares failed to set servers: "${err}" [${servers}]`); + throw new errors.Error('ERR_DNS_SET_SERVERS_FAILED', err, servers); } } diff --git a/lib/internal/errors.js b/lib/internal/errors.js index a85a730e1563e8..aa5e4ca1b342e6 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -106,6 +106,8 @@ E('ERR_CHILD_CLOSED_BEFORE_REPLY', 'Child closed before reply received'); E('ERR_CONSOLE_WRITABLE_STREAM', 'Console expects a writable stream instance for %s'); E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s'); +E('ERR_DNS_SET_SERVERS_FAILED', (err, servers) => + `c-ares failed to set servers: "${err}" [${servers}]`); E('ERR_FALSY_VALUE_REJECTION', 'Promise was rejected with falsy value'); E('ERR_HTTP_HEADERS_SENT', 'Cannot render headers after they are sent to the client'); @@ -129,6 +131,7 @@ E('ERR_INVALID_FILE_URL_HOST', 'File URL host must be "localhost" or empty on %s'); E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s'); E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent'); +E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s'); E('ERR_INVALID_OPT_VALUE', (name, value) => { return `The value "${String(value)}" is invalid for option "${name}"`; diff --git a/test/parallel/test-c-ares.js b/test/parallel/test-c-ares.js index 6a8b08fd2064bb..8ba221ca99ee4b 100644 --- a/test/parallel/test-c-ares.js +++ b/test/parallel/test-c-ares.js @@ -46,11 +46,21 @@ dns.lookup('::1', common.mustCall((error, result, addressType) => { assert.strictEqual(6, addressType); })); -// Try calling resolve with an unsupported type. -assert.throws(() => dns.resolve('www.google.com', 'HI'), /Unknown type/); - -// Try calling resolve with an unsupported type that's an object key -assert.throws(() => dns.resolve('www.google.com', 'toString'), /Unknown type/); +[ + // Try calling resolve with an unsupported type. + 'HI', + // Try calling resolve with an unsupported type that's an object key + 'toString' +].forEach((val) => { + common.expectsError( + () => dns.resolve('www.google.com', val), + { + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: `The value "${val}" is invalid for option "rrtype"` + } + ); +}); // Windows doesn't usually have an entry for localhost 127.0.0.1 in // C:\Windows\System32\drivers\etc\hosts diff --git a/test/parallel/test-dns-lookup.js b/test/parallel/test-dns-lookup.js index a1fad873e33f37..52c0a7d2955ecc 100644 --- a/test/parallel/test-dns-lookup.js +++ b/test/parallel/test-dns-lookup.js @@ -9,15 +9,25 @@ cares.getaddrinfo = () => process.binding('uv').UV_ENOENT; assert.throws(() => { dns.lookup(1, {}); -}, /^TypeError: Invalid arguments: hostname must be a string or falsey$/); +}, common.expectsError({ + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: /^The "hostname" argument must be one of type string or falsey/ +})); assert.throws(() => { dns.lookup(false, 'cb'); -}, /^TypeError: Invalid arguments: callback must be passed$/); +}, common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError +})); assert.throws(() => { dns.lookup(false, 'options', 'cb'); -}, /^TypeError: Invalid arguments: callback must be passed$/); +}, common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError +})); assert.throws(() => { dns.lookup(false, { @@ -25,7 +35,11 @@ assert.throws(() => { family: 0, all: false }, common.mustNotCall()); -}, /^TypeError: Invalid argument: hints must use valid flags$/); +}, common.expectsError({ + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: 'The value "100" is invalid for option "hints"' +})); assert.throws(() => { dns.lookup(false, { @@ -33,7 +47,11 @@ assert.throws(() => { family: 20, all: false }, common.mustNotCall()); -}, /^TypeError: Invalid argument: family must be 4 or 6$/); +}, common.expectsError({ + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: 'The value "20" is invalid for option "family"' +})); assert.doesNotThrow(() => { dns.lookup(false, { diff --git a/test/parallel/test-dns-regress-7070.js b/test/parallel/test-dns-regress-7070.js index 1082a0ce699671..f0e6554fdc7edf 100644 --- a/test/parallel/test-dns-regress-7070.js +++ b/test/parallel/test-dns-regress-7070.js @@ -20,12 +20,19 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const dns = require('dns'); // Should not raise assertion error. Issue #7070 assert.throws(() => dns.resolveNs([]), // bad name - /^Error: "name" argument must be a string$/); + common.expectsError({ + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: /^The "name" argument must be of type string/ + })); assert.throws(() => dns.resolveNs(''), // bad callback - /^Error: "callback" argument must be a function$/); + common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError + })); diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js index 8041587677a8db..ba905d7490d1e9 100644 --- a/test/parallel/test-dns.js +++ b/test/parallel/test-dns.js @@ -68,10 +68,16 @@ const goog = [ ]; assert.doesNotThrow(() => dns.setServers(goog)); assert.deepStrictEqual(dns.getServers(), goog); -assert.throws(() => dns.setServers(['foobar']), - /^Error: IP address is not properly formatted: foobar$/); -assert.throws(() => dns.setServers(['127.0.0.1:va']), - /^Error: IP address is not properly formatted: 127\.0\.0\.1:va$/); +assert.throws(() => dns.setServers(['foobar']), common.expectsError({ + code: 'ERR_INVALID_IP_ADDRESS', + type: Error, + message: 'Invalid IP address: foobar' +})); +assert.throws(() => dns.setServers(['127.0.0.1:va']), common.expectsError({ + code: 'ERR_INVALID_IP_ADDRESS', + type: Error, + message: 'Invalid IP address: 127.0.0.1:va' +})); assert.deepStrictEqual(dns.getServers(), goog); const goog6 = [ @@ -105,12 +111,20 @@ assert.deepStrictEqual(dns.getServers(), []); assert.throws(() => { dns.resolve('example.com', [], common.mustNotCall()); -}, /^TypeError: "rrtype" argument must be a string$/); +}, common.expectsError({ + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "rrtype" argument must be of type string. ' + + 'Received type object' +})); // dns.lookup should accept only falsey and string values { - const errorReg = - /^TypeError: Invalid arguments: hostname must be a string or falsey$/; + const errorReg = common.expectsError({ + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: /^The "hostname" argument must be one of type string or falsey/ + }, 5); assert.throws(() => dns.lookup({}, common.mustNotCall()), errorReg); @@ -156,13 +170,21 @@ assert.throws(() => { assert.throws(() => { dns.lookup('nodejs.org', { hints: (dns.V4MAPPED | dns.ADDRCONFIG) + 1 }, common.mustNotCall()); -}, /^TypeError: Invalid argument: hints must use valid flags$/); - -assert.throws(() => dns.lookup('nodejs.org'), - /^TypeError: Invalid arguments: callback must be passed$/); - -assert.throws(() => dns.lookup('nodejs.org', 4), - /^TypeError: Invalid arguments: callback must be passed$/); +}, common.expectsError({ + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: /The value "\d+" is invalid for option "hints"/ +})); + +assert.throws(() => dns.lookup('nodejs.org'), common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError +})); + +assert.throws(() => dns.lookup('nodejs.org', 4), common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError +})); assert.doesNotThrow(() => dns.lookup('', { family: 4, hints: 0 }, common.mustCall())); @@ -183,25 +205,43 @@ assert.doesNotThrow(() => { }, common.mustCall()); }); -assert.throws(() => dns.lookupService('0.0.0.0'), - /^Error: Invalid arguments$/); - -assert.throws(() => dns.lookupService('fasdfdsaf', 0, common.mustNotCall()), - /^TypeError: "host" argument needs to be a valid IP address$/); +assert.throws(() => dns.lookupService('0.0.0.0'), common.expectsError({ + code: 'ERR_MISSING_ARGS', + type: TypeError, + message: 'The "host", "port", and "callback" arguments must be specified' +})); +const invalidHost = 'fasdfdsaf'; +assert.throws(() => { + dns.lookupService(invalidHost, 0, common.mustNotCall()); +}, common.expectsError({ + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: `The value "${invalidHost}" is invalid for option "host"` +})); + +const badPortMsg = common.expectsError({ + code: 'ERR_SOCKET_BAD_PORT', + type: RangeError, + message: 'Port should be > 0 and < 65536' +}, 4); assert.throws(() => dns.lookupService('0.0.0.0', null, common.mustNotCall()), - /^TypeError: "port" should be >= 0 and < 65536, got "null"$/); + badPortMsg); assert.throws( () => dns.lookupService('0.0.0.0', undefined, common.mustNotCall()), - /^TypeError: "port" should be >= 0 and < 65536, got "undefined"$/ + badPortMsg ); assert.throws(() => dns.lookupService('0.0.0.0', 65538, common.mustNotCall()), - /^TypeError: "port" should be >= 0 and < 65536, got "65538"$/); + badPortMsg); assert.throws(() => dns.lookupService('0.0.0.0', 'test', common.mustNotCall()), - /^TypeError: "port" should be >= 0 and < 65536, got "test"$/); + badPortMsg); -assert.throws(() => dns.lookupService('0.0.0.0', 80, null), - /^TypeError: "callback" argument must be a function$/); +assert.throws(() => { + dns.lookupService('0.0.0.0', 80, null); +}, common.expectsError({ + code: 'ERR_INVALID_CALLBACK', + type: TypeError +})); diff --git a/test/parallel/test-net-connect-options-port.js b/test/parallel/test-net-connect-options-port.js index bc9e76df6546ee..9e4d5991fd62dd 100644 --- a/test/parallel/test-net-connect-options-port.js +++ b/test/parallel/test-net-connect-options-port.js @@ -60,14 +60,16 @@ const net = require('net'); // Test invalid hints { - const regexp = /^TypeError: Invalid argument: hints must use valid flags$/; // connect({hint}, cb) and connect({hint}) const hints = (dns.ADDRCONFIG | dns.V4MAPPED) + 42; const hintOptBlocks = doConnect([{ hints: hints }], () => common.mustNotCall()); for (const block of hintOptBlocks) { - assert.throws(block, regexp, - `${block.name}({hints: ${hints})`); + assert.throws(block, common.expectsError({ + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, + message: /The value "\d+" is invalid for option "hints"/ + })); } }