* Use node 7+ WHATWG parser for hostname, fixes #1002 * only use URL if host is IPv6, expose parsed URL * catch invalid URLs, memoize empty obj * hostname returns empty string when URL throws
This commit is contained in:
parent
012587889d
commit
327b65cb6b
5 changed files with 91 additions and 0 deletions
|
@ -99,6 +99,14 @@ ctx.request.href
|
|||
Get hostname when present. Supports `X-Forwarded-Host`
|
||||
when `app.proxy` is __true__, otherwise `Host` is used.
|
||||
|
||||
If host is IPv6, Koa delegates parsing to
|
||||
[WHATWG URL API](https://nodejs.org/dist/latest-v8.x/docs/api/url.html#url_the_whatwg_url_api),
|
||||
*Note* This may impact performance.
|
||||
|
||||
### request.URL
|
||||
|
||||
Get WHATWG parsed URL object.
|
||||
|
||||
### request.type
|
||||
|
||||
Get request `Content-Type` void of parameters such as "charset".
|
||||
|
|
|
@ -198,6 +198,7 @@ delegate(proto, 'request')
|
|||
.getter('protocol')
|
||||
.getter('host')
|
||||
.getter('hostname')
|
||||
.getter('URL')
|
||||
.getter('header')
|
||||
.getter('headers')
|
||||
.getter('secure')
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Module dependencies.
|
||||
*/
|
||||
|
||||
const URL = require('url').URL;
|
||||
const net = require('net');
|
||||
const contentType = require('content-type');
|
||||
const stringify = require('url').format;
|
||||
|
@ -264,9 +265,32 @@ module.exports = {
|
|||
get hostname() {
|
||||
const host = this.host;
|
||||
if (!host) return '';
|
||||
if ('[' == host[0]) return this.URL.hostname || ''; // IPv6
|
||||
return host.split(':')[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Get WHATWG parsed URL.
|
||||
* Lazily memoized.
|
||||
*
|
||||
* @return {URL|Object}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
get URL() {
|
||||
if (!this.memoizedURL) {
|
||||
const protocol = this.protocol;
|
||||
const host = this.host;
|
||||
const originalUrl = this.originalUrl || ''; // avoid undefined in template string
|
||||
try {
|
||||
this.memoizedURL = new URL(`${protocol}://${host}${originalUrl}`);
|
||||
} catch (err) {
|
||||
this.memoizedURL = Object.create(null);
|
||||
}
|
||||
}
|
||||
return this.memoizedURL;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the request is fresh, aka
|
||||
* Last-Modified and/or the ETag
|
||||
|
|
|
@ -18,6 +18,38 @@ describe('req.hostname', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with IPv6 in host', () => {
|
||||
it('should parse localhost void of port', () => {
|
||||
const req = request();
|
||||
req.header.host = '[::1]';
|
||||
assert.equal(req.hostname, '[::1]');
|
||||
});
|
||||
|
||||
it('should parse localhost with port 80', () => {
|
||||
const req = request();
|
||||
req.header.host = '[::1]:80';
|
||||
assert.equal(req.hostname, '[::1]');
|
||||
});
|
||||
|
||||
it('should parse localhost with non special schema port', () => {
|
||||
const req = request();
|
||||
req.header.host = '[::1]:1337';
|
||||
assert.equal(req.hostname, '[::1]');
|
||||
});
|
||||
|
||||
it('should reduce IPv6 with non special schema port, as hostname', () => {
|
||||
const req = request();
|
||||
req.header.host = '[2001:cdba:0000:0000:0000:0000:3257:9652]:1337';
|
||||
assert.equal(req.hostname, '[2001:cdba::3257:9652]');
|
||||
});
|
||||
|
||||
it('should return empty string when invalid', () => {
|
||||
const req = request();
|
||||
req.header.host = '[invalidIPv6]';
|
||||
assert.equal(req.hostname, '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when X-Forwarded-Host is present', () => {
|
||||
describe('and proxy is not trusted', () => {
|
||||
it('should be ignored', () => {
|
||||
|
|
26
test/request/whatwg-url.js
Normal file
26
test/request/whatwg-url.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const request = require('../helpers/context').request;
|
||||
const assert = require('assert');
|
||||
|
||||
describe('req.URL', () => {
|
||||
describe('should not throw when', () => {
|
||||
it('host is void', () => {
|
||||
const req = request();
|
||||
assert.doesNotThrow(() => req.URL, TypeError);
|
||||
});
|
||||
|
||||
it('header.host is invalid', () => {
|
||||
const req = request();
|
||||
req.header.host = 'invalid host';
|
||||
assert.doesNotThrow(() => req.URL, TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty object when invalid', () => {
|
||||
const req = request();
|
||||
req.header.host = 'invalid host';
|
||||
assert.deepStrictEqual(req.URL, Object.create(null));
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue