-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
http: more strict statusCode validation #9031
Conversation
test/common.js
Outdated
@@ -402,8 +402,10 @@ function runCallChecks(exitCode) { | |||
} | |||
|
|||
|
|||
exports.mustCall = function(fn, expected) { | |||
if (typeof expected !== 'number') expected = 1; | |||
exports.mustCall = function(fn, expected = 1) { |
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.
The changes in this file should be in a separate PR, as they are unrelated.
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 can move this to it's own PR, and started to in #9035 - but the problem is that the tests then fail without the other changes from that commit. And, then the second commit isn't actually tested without those changes.
So, I can break this up if you really want, but I don't think it makes sense to in this case.
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.
It would really be nice to have the common.mustCall
change in a separate PR (including the fixes to tests that don't pass a number). Then when it lands you can rebase this one.
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.
Ok, that makes sense. Done in #10692
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.
Can you also remove the changes from this PR.
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.
Kind of, although it isn't actually tested unless I at least keep the fixes in test-http-response-statuscode.js. I was thinking I would clean this one up after that one lands like @targos said, so that wouldn't be an issue then.
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.
#10692 is now merged in; I'll rebase this branch soon (probably tomorrow).
Updates expected to use modern default syntax and also validate the value and throw an error rather than silently overwriting invalid arguments. Would prevent issues such as the one fixed in the first commit on nodejs#9031
0910731
to
10702ba
Compare
Updates expected to use modern default syntax and also validate the value and throw an error rather than silently overwriting invalid arguments. Would prevent issues such as the one fixed in the first commit on nodejs#9031
2047e28
to
7cf406e
Compare
Sorry about all of the references here on github - it took me a couple of tries to get things split up in response to @mscdex's comments, and then a couple more to put them back once I realized that it wouldn't work because the tests wouldn't pass :/ |
c133999
to
83c7a88
Compare
lib/_http_server.js
Outdated
@@ -189,7 +189,7 @@ ServerResponse.prototype.writeHead = function(statusCode, reason, obj) { | |||
|
|||
statusCode |= 0; | |||
if (statusCode < 100 || statusCode > 999) | |||
throw new RangeError(`Invalid status code: ${statusCode}`); | |||
throw new RangeError(`Invalid status code: ${this.statusCode}`); |
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.
Why is this change needed?
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.
It will print the actual value before it is converted to an integer
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'd prefer not. The test that leads to this error is being performed on the coerced value. I would rather display the coerced value than the actual value.
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.
Speaking from experience, that's confusing to an end user, because it ends up as 0 for most invalid input. (In my case, someone had been setting error.code to a custom status code, but then an ENOENT error caused this to throw "RangeError: Invalid status code: 0", and I spent a good part of a day tracking it down because I was looking for the wrong thing.)
However, you do have a valid point, so what about a couple of alternatives - either include both the coerced value and the original value in the message, or else have a type check earlier that throws on non-Number input with the original value & type?
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'm not going to object to the change being made, I just don't prefer it.
I just rebased this against master, and ended up making some changes. I couldn't just use This leads to two changes:
|
HTTP ServerResponse.writeHead previously coerced the given statusCode to an integer to validate it, then threw an error with the converted number if it was invalid. This meant that non-numeric input led to confusing error messages. This change makes the input validation more strict, throwing on any non-integer input rather than silently coercing it. Of note: * Strings (e.g. '200') were previously accepted, now they cause a TypeError * Numbers with decimals (e.g. 200.6) were previously floored, now they cause a RangeError (with the original value included in the error message). Fixes nodejs#9027
@nfriedly ... is this still something you want to pursue @nodejs/http |
Closing per #9027 (comment) |
Checklist
make -j8 test
(UNIX), orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
HTTP
Description of change
This removes the http statusCode coercion, and instead performs more strict validation on the original value, either using it unchanged or throwing.
Of note, some values that were previously accepted no longer are:
'200'
previously was accepted, it throws a TypeError with this change200.6
was previously accepted (and silently coerced to200
), it throws a RangeError with this change.All non-number values will now get a TypeError instead of a RangeError.
Fixes #9027