diff --git a/lib/core/dnscache_httpclient.js b/lib/core/dnscache_httpclient.js index 04dc1f91e1..b23506dd3f 100644 --- a/lib/core/dnscache_httpclient.js +++ b/lib/core/dnscache_httpclient.js @@ -2,9 +2,9 @@ const dns = require('mz/dns'); const LRU = require('ylru'); -const urlparse = require('url').parse; const HttpClient = require('./httpclient'); const utility = require('utility'); +const utils = require('./utils'); const IP_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; const DNSLOOKUP = Symbol('DNSCacheHttpClient#dnslookup'); @@ -44,7 +44,14 @@ class DNSCacheHttpClient extends HttpClient { } async [DNSLOOKUP](url, args) { - const parsed = typeof url === 'string' ? urlparse(url) : url; + let parsed; + if (typeof url === 'string') { + parsed = utils.safeParseURL(url); + // invalid url or relative url + if (!parsed) return { url, args }; + } else { + parsed = url; + } // hostname must exists const hostname = parsed.hostname; diff --git a/lib/core/utils.js b/lib/core/utils.js index 3f30c3cbeb..9c215c7fdc 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -2,9 +2,11 @@ const util = require('util'); const is = require('is-type-of'); +const URL = require('url').URL; module.exports = { convertObject, + safeParseURL, }; function convertObject(obj, ignore) { @@ -60,3 +62,11 @@ function convertValue(key, value, ignore) { /* istanbul ignore next */ return util.format(value); } + +function safeParseURL(url) { + try { + return new URL(url); + } catch (err) { + return null; + } +} diff --git a/test/lib/core/utils.test.js b/test/lib/core/utils.test.js index 30220f4528..623e9c2697 100644 --- a/test/lib/core/utils.test.js +++ b/test/lib/core/utils.test.js @@ -4,125 +4,139 @@ const assert = require('assert'); const utils = require('../../../lib/core/utils'); describe('test/lib/core/utils.test.js', () => { - it('should convert primitive', () => { - const s = Symbol('symbol'); - const obj = { - string$: 'string', - number$: 1, - null$: null, - undefined$: undefined, - boolean$: true, - symbol$: s, - }; - utils.convertObject(obj); - assert(obj.string$ === 'string'); - assert(obj.number$ === 1); - assert(obj.null$ === null); - assert(obj.undefined$ === undefined); - assert(obj.boolean$ === true); - assert(obj.symbol$ === 'Symbol(symbol)'); - }); + describe('convertObject()', () => { + it('should convert primitive', () => { + const s = Symbol('symbol'); + const obj = { + string$: 'string', + number$: 1, + null$: null, + undefined$: undefined, + boolean$: true, + symbol$: s, + }; + utils.convertObject(obj); + assert(obj.string$ === 'string'); + assert(obj.number$ === 1); + assert(obj.null$ === null); + assert(obj.undefined$ === undefined); + assert(obj.boolean$ === true); + assert(obj.symbol$ === 'Symbol(symbol)'); + }); - it('should convert regexp', () => { - const obj = { - regexp$: /^a$/g, - }; - utils.convertObject(obj); - assert(obj.regexp$ === '/^a$/g'); - }); + it('should convert regexp', () => { + const obj = { + regexp$: /^a$/g, + }; + utils.convertObject(obj); + assert(obj.regexp$ === '/^a$/g'); + }); - it('should convert date', () => { - const obj = { - date$: new Date(), - }; - utils.convertObject(obj); - assert(obj.date$ === ''); - }); + it('should convert date', () => { + const obj = { + date$: new Date(), + }; + utils.convertObject(obj); + assert(obj.date$ === ''); + }); - it('should convert function', () => { - const obj = { - function$: function a() { console.log(a); }, - arrowFunction$: a => { console.log(a); }, - /* eslint object-shorthand: 0 */ - anonymousFunction$: function(a) { console.log(a); }, - generatorFunction$: function* a(a) { console.log(a); }, - asyncFunction$: async function a(a) { console.log(a); }, - }; - utils.convertObject(obj); - assert(obj.function$ === ''); - assert(obj.arrowFunction$ === ''); - assert(obj.anonymousFunction$ === ''); - assert(obj.generatorFunction$ === ''); - assert(obj.asyncFunction$ === ''); - }); + it('should convert function', () => { + const obj = { + function$: function a() { console.log(a); }, + arrowFunction$: a => { console.log(a); }, + /* eslint object-shorthand: 0 */ + anonymousFunction$: function(a) { console.log(a); }, + generatorFunction$: function* a(a) { console.log(a); }, + asyncFunction$: async function a(a) { console.log(a); }, + }; + utils.convertObject(obj); + assert(obj.function$ === ''); + assert(obj.arrowFunction$ === ''); + assert(obj.anonymousFunction$ === ''); + assert(obj.generatorFunction$ === ''); + assert(obj.asyncFunction$ === ''); + }); - it('should convert error', () => { - class TestError extends Error {} - const obj = { - errorClass$: Error, - errorClassExtend$: TestError, - error$: new Error('a'), - errorExtend$: new TestError('a'), - }; - utils.convertObject(obj); - assert(obj.errorClass$ === ''); - assert(obj.errorClassExtend$ === ''); - assert(obj.error$ === ''); - assert(obj.errorExtend$ === ''); - }); + it('should convert error', () => { + class TestError extends Error { } + const obj = { + errorClass$: Error, + errorClassExtend$: TestError, + error$: new Error('a'), + errorExtend$: new TestError('a'), + }; + utils.convertObject(obj); + assert(obj.errorClass$ === ''); + assert(obj.errorClassExtend$ === ''); + assert(obj.error$ === ''); + assert(obj.errorExtend$ === ''); + }); - it('should convert class', () => { - class BaseClass {} - class Class extends BaseClass {} - const obj = { - class$: BaseClass, - classExtend$: Class, - }; - utils.convertObject(obj); - assert(obj.class$ === ''); - assert(obj.classExtend$ === ''); - }); + it('should convert class', () => { + class BaseClass { } + class Class extends BaseClass { } + const obj = { + class$: BaseClass, + classExtend$: Class, + }; + utils.convertObject(obj); + assert(obj.class$ === ''); + assert(obj.classExtend$ === ''); + }); - it('should convert buffer', () => { - class SlowBuffer extends Buffer {} - const obj = { - bufferClass$: Buffer, - bufferClassExtend$: SlowBuffer, - buffer$: Buffer.from('123'), - bufferExtend$: new SlowBuffer('123'), - }; - utils.convertObject(obj); - assert(obj.bufferClass$ === ''); - assert(obj.bufferClassExtend$ === ''); - assert(obj.buffer$ === ''); - assert(obj.bufferExtend$ === ''); + it('should convert buffer', () => { + class SlowBuffer extends Buffer { } + const obj = { + bufferClass$: Buffer, + bufferClassExtend$: SlowBuffer, + buffer$: Buffer.from('123'), + bufferExtend$: new SlowBuffer('123'), + }; + utils.convertObject(obj); + assert(obj.bufferClass$ === ''); + assert(obj.bufferClassExtend$ === ''); + assert(obj.buffer$ === ''); + assert(obj.bufferExtend$ === ''); + }); + + it('should convert ignore', () => { + const s = Symbol('symbol'); + const obj = { + string$: 'string', + number$: 1, + null$: null, + undefined$: undefined, + boolean$: true, + symbol$: s, + regexp$: /^a$/g, + }; + utils.convertObject(obj, [ + 'string$', + 'number$', + 'null$', + 'undefined$', + 'boolean$', + 'symbol$', + 'regexp$', + ]); + assert(obj.string$ === ''); + assert(obj.number$ === ''); + assert(obj.null$ === null); + assert(obj.undefined$ === undefined); + assert(obj.boolean$ === ''); + assert(obj.symbol$ === ''); + }); }); - it('should convert ignore', () => { - const s = Symbol('symbol'); - const obj = { - string$: 'string', - number$: 1, - null$: null, - undefined$: undefined, - boolean$: true, - symbol$: s, - regexp$: /^a$/g, - }; - utils.convertObject(obj, [ - 'string$', - 'number$', - 'null$', - 'undefined$', - 'boolean$', - 'symbol$', - 'regexp$', - ]); - assert(obj.string$ === ''); - assert(obj.number$ === ''); - assert(obj.null$ === null); - assert(obj.undefined$ === undefined); - assert(obj.boolean$ === ''); - assert(obj.symbol$ === ''); + describe('safeParseURL()', () => { + it('should return null if url invalid', () => { + assert(utils.safeParseURL('https://eggjs.org%0a.com') === null); + assert(utils.safeParseURL('/path/for') === null); + }); + + it('should return parsed url', () => { + assert(utils.safeParseURL('https://eggjs.org').hostname === 'eggjs.org'); + assert(utils.safeParseURL('https://eggjs.org!.foo.com').hostname === 'eggjs.org!.foo.com'); + }); }); });