-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use node 7+ WHATWG parser for hostname, fixes #1002 #1004
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1004 +/- ##
======================================
Coverage 100% 100%
======================================
Files 5 5
Lines 356 366 +10
======================================
+ Hits 356 366 +10
Continue to review full report at Codecov.
|
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought about destructing here (const { format: stringify, URL } = require('url')
),
though I'm not seeing it elsewhere so assumed it was taboo in koajs/koa.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fl0w i think we didn't add it for node v4 support previously
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should change node's engines in package.json to 7.0.0.
@abouthiroppy that will mess with users who transpile Koa down to e.g. node 6. |
lib/request.js
Outdated
@@ -242,9 +243,12 @@ module.exports = { | |||
*/ | |||
|
|||
get hostname() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs some adjusting - the code path is weird and for some reason I'm not using host
whilst also assigning const host = this.host
(relic from the past). I'll clean this up later today.
lib/request.js
Outdated
if (!this.parsedUrl) { | ||
const host = this.host; | ||
if (!host) return ''; | ||
this.parsedUrl = new URL(`${this.protocol}://${this.host}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about the performance? Slow down or faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use WHATWG parser for hostname when host
start with [
, otherwise keep the old way to get high performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind sharing your bench src?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like a potential module to me :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jonathanong the hostname validation or bench src? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider performance before merge.
@fengmk2 @jonathanong The naming might be conflicting with I'll add docs and tests for |
lib/request.js
Outdated
const protocol = this.protocol; | ||
const host = this.host; | ||
const originalUrl = this.originalUrl || ''; // avoid undefined in template string | ||
this.memoizedURL = new URL(`${protocol}://${host}${originalUrl}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL will throw TypeError if something's off.
Koa generally has value || ''
type of solutions in most cases.
Maybe wrap this in a try-catch and memoize empty object so that this.URL.hostname
when malformed does not throw/crash the entire app?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A try-catch shouldn't deopt since node 7.x (v8/v8@9aac80f)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe wrap this in a try-catch and memoize empty object so that this.URL.hostname when malformed does not throw/crash the entire app?
+1
lib/request.js
Outdated
@@ -244,10 +245,29 @@ module.exports = { | |||
get hostname() { | |||
const host = this.host; | |||
if (!host) return ''; | |||
if ('[' == host[0]) return this.URL.hostname; // IPv6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.URL
can be an empty object, return this.URL.hostname || ''
here
I am not sure if this is a fortunate solution. |
Yes, this is a side effect I've been pondering about. As a quick solution, you can simply clear memoization by setting This was done because the parse felt quite costly (as noted by fengmk2). edit
This was my initial proposition, but currently it seems to be hitting performance with significance. This was in comparison to request.host, not sure about the actual implications on a real world application. |
@urugator though correct me if I'm wrong - this should only be of concern when hostname is called with an IPv6 host? As far as inconsistencies, memoization could be removed but it would still require one to fetch a new URL object every time |
@fl0w The concern is that code behaves differently based on the hostname format. Actually I would say that simply stating that Ipv6 hostname is not supported is a more acceptable solution, because seems easier to reason about. However I still wonder whether the WHATWG parser is really neccessary for this.
It has to be kept in sync manually, but not re-constructed: const newHost = "myLittleHost"
request.headers["host"] = newHost;
request.URL.host = newHost; |
@jonathanong
Well, there's the node 7+ WHATWG compliant url.URL, which could potentially help Koa "de-depend" parseurl and querystring as well (I think).
This PR could be expanded to substitute public API for host/hostname/query and maybe a few more.(performance impacted to heavily)There would be some minor adjustments to output like
URL.port
returning''
when :80 or :443 is provided (special scheme ports).I'm also assuming
url.URL
would come with someminormajor performance hit.notice that all port 80 returns empty string, as http and https are special scheme, thus parsed implicitly