-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
Ensure IPv6 hostname is enclosed within square brackets in Host header #5314
Conversation
It looks like the file permissions for |
Thank you for noticing, and I apologize for the mistake. Not sure how that happened, but I'll update the PR with the permissions change reverted. |
c3faa8d
to
0f7bf56
Compare
// For the Host header, ensure that IPv6 addresses are enclosed | ||
// in square brackets, as defined by URI formatting | ||
// https://tools.ietf.org/html/rfc3986#section-3.2.2 | ||
if ('[' !== hostHeader[0] && -1 !== hostHeader.indexOf(':')) { |
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 use net.isIPv6(hostHeader)
here instead?
// in square brackets, as defined by URI formatting | ||
// https://tools.ietf.org/html/rfc3986#section-3.2.2 | ||
if (net.isIPv6(hostHeader)) { | ||
hostHeader = '[' + hostHeader + ']'; |
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.
very minor nit... these can use template strings now.. [${hostHeader}]
... not critical tho :-)
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.
Isn't string concatenation faster than template strings?
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 want to say that some benchmarks have shown that template strings do not introduce any performance issues, maybe even improve performance. Will have to look and see if I can find them though.
LGTM |
req.end(); | ||
} | ||
|
||
server = http.createServer(function(req, res) { |
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.
if you wrap this in a common.mustCall(function(req, res) { })
, then the hadRequest
can be be totally removed. It doesn't look like hadError
is used at all, so that can be removed. With those two gone, we can also remove the process.on('exit')
listener.
If you can address the nits that both myself and @jasnell have mentioned, LGTM. Once that is done, we can run the CI and make sure everything is passing. Thanks for the contribution! |
// For the Host header, ensure that IPv6 addresses are enclosed | ||
// in square brackets, as defined by URI formatting | ||
// https://tools.ietf.org/html/rfc3986#section-3.2.2 | ||
if (net.isIPv6(hostHeader)) { |
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.
isn't this too heavyweight?
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.
In my initial PR, IPv6 checking was done by hostHeader.indexOf(':')
, just as you also suggested in #5308
However, now I agree that net.isIPv6()
is a much more reliable way of testing for IPv6.
I don't necessarily think it's too heavyweight, since it relies on uv_inet_pton
. I guess it's slightly slower than indexOf
, but since it also checks for valid characters inside the string, I believe it's worth the extra cycles.
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 were no check for correctness here before, so I assume that there are two possibilities:
- Host is check before and is valid at this point, so if there is
:
then it can only possibly be IPv6 address. - Host isn't checked before, so it might be invalid. If it has
:
then it is either IPv6 or invalid. If we wrap invalid host in brackets it would still be invalid, so it doesn't really matter.
isIPv6
involves calling C++ code and also checking if argument is IPv4 before checking if it's 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.
Host value doesn't pass through proper validation. It actually relies on either url.parse()
to produce a host value, or simply takes options.hostname
|| options.host
. At this stage, especially if options
object is passed to the request()
, hostHeader
could even be www.domain.tld:3000
, before reaching my code; (which is not wrong, only unsupported atm). In this case, a simple :
check would yield an invalid Host header [www.domain.tld:3000]
.
Secondly, the RFC says that if (IP is IPv6) then [IP]
, which in my view makes it mandatory to make absolutely sure that whatever I enclose within square brackets, is an IPv6 address and not anything else (even if invalid).
I've been considering all of the above right from my initial PR, including the fact that indexOf
is faster than isIPv6
. However, since all points of view express advantages and disadvantages, I also opted for net.isIPv6
in the end, because that allows my fix to avoid type assumptions and ultimately make the code terse, and enforces the RFC statement.
While the above explains my preference for net.isIPv6
, if there's consensus on reverting it back to :
matching, I'll happily do it.
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.
Secondly, the RFC says that if (IP is IPv6) then [IP], which in my view makes it mandatory to make absolutely sure that whatever I enclose within square bracket
It doesn't say that wrapping invalid host with brackets makes it more invalid, that's all I'm saying.
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.
Doing a quick scan for two :
's may be a simple workaround here. I agree that dropping down to the native code to check is a bit overweight for this.
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.
Yea, I agree. Just ran some benchmarks and net.isIPv6
runs about 3-6 times slower than an indexOf
check here.
I've just pushed two commits with the following:
|
Still LGTM. @nodejs/http @nodejs/ctc |
@evanlucas ... does this LGTY? |
LGTM |
req.end(); | ||
} | ||
|
||
server = http.createServer(common.mustCall(function(req, res) { |
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.
nit: would just make this const server
CI is green, added a small nit. |
bc7d9ca
to
6634168
Compare
Modified to use |
New CI after the rebase: https://ci.nodejs.org/job/node-test-pull-request/2021/ |
Apparently CI failed on "node-test-binary-arm » 3,pi1-raspbian-wheezy" https://ci.nodejs.org/job/node-test-binary-arm/1448//console |
No, we've been seeing an increase in random flakiness with tests on the pi devices. I don't think the failure is related. /cc @nodejs/testing |
Can I ask you to please squash the commits down into one commit now? Thank you! |
3ff813d
to
7dc4d06
Compare
Sure, done. |
@mpotra to clarify, the tests that live in |
cebe453
to
f311efd
Compare
Thanks, and sorry for having it under |
No problem at all. Sorry for just noticing :] I've started another CI run: https://ci.nodejs.org/job/node-test-pull-request/2063/ |
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. test: add test for IPv6 hostname conformance in Host header http: Ensure IPv6 is enclosed within square brackets in Host header http: use net.isIPv6 in ClientRequest test: update test with const instead of var test: use common.mustCall and cleanup http: ClientRequest, drop isIPv6() in favor of indexOf() checks http: ClientRequest, replace concatenation with string literal test: use const test: clean-up test: move test to parallel test: skip if no IPv6 support
Two failures: 1 is
Apparently it cannot bind |
f311efd
to
5132c30
Compare
Updated with IPv6 check, as per nodejs/node-v0.x-archive#7983 |
Everything looks green, except a Let me know if there's anything else I can do. |
LGTM |
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
Landed in dabe1d5 |
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
Notable changes: http: * Enclose IPv6 Host header in square brackets. This will enable proper seperation of the host adress from any port reference (Mihai Potra) #5314 path: * Make win32.isAbsolute more consistent (Brian White) #6028 PR-URL: #6060 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Notable changes: http: * Enclose IPv6 Host header in square brackets. This will enable proper seperation of the host adress from any port reference (Mihai Potra) #5314 path: * Make win32.isAbsolute more consistent (Brian White) #6028 PR-URL: #6060 Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference. PR-URL: #5314 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
Fixes #5308
As per https://tools.ietf.org/html/rfc7230#section-5.4 and https://tools.ietf.org/html/rfc3986#section-3.2.2 IPv6 addresses in Host header (URI), must be enclosed within square brackets, in order to properly separate the host address from any port reference.