Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

nfriedly
Copy link
Contributor

@nfriedly nfriedly commented Oct 11, 2016

Checklist
  • make -j8 test (UNIX), or vcbuild test nosign (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected 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:

  • Any otherwise-valid string: '200' previously was accepted, it throws a TypeError with this change
  • Numbers with decimals: 200.6 was previously accepted (and silently coerced to 200), it throws a RangeError with this change.

All non-number values will now get a TypeError instead of a RangeError.

Fixes #9027

@nodejs-github-bot nodejs-github-bot added the http Issues or PRs related to the http subsystem. label Oct 11, 2016
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) {
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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).

@mscdex mscdex added the semver-major PRs that contain breaking changes and should be released in the next major version. label Oct 11, 2016
nfriedly added a commit to nfriedly/node that referenced this pull request Oct 11, 2016
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
@nfriedly nfriedly force-pushed the issue-9027 branch 3 times, most recently from 0910731 to 10702ba Compare October 11, 2016 20:28
nfriedly added a commit to nfriedly/node that referenced this pull request Oct 11, 2016
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
@nfriedly nfriedly force-pushed the issue-9027 branch 2 times, most recently from 2047e28 to 7cf406e Compare October 11, 2016 21:05
@nfriedly
Copy link
Contributor Author

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 :/

@jasnell jasnell changed the title Fix error message for invalid httm status code, fix tests. Fix error message for invalid http status code, fix tests. Oct 11, 2016
@rvagg rvagg force-pushed the master branch 2 times, most recently from c133999 to 83c7a88 Compare October 18, 2016 17:02
@targos targos added this to the 8.0.0 milestone Jan 8, 2017
@@ -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}`);
Copy link
Member

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?

Copy link
Member

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

Copy link
Member

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.

Copy link
Contributor Author

@nfriedly nfriedly Jan 11, 2017

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?

Copy link
Member

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.

@nfriedly nfriedly changed the title Fix error message for invalid http status code, fix tests. Fix error message for invalid http status code Jan 11, 2017
@nfriedly
Copy link
Contributor Author

nfriedly commented Jan 16, 2017

I just rebased this against master, and ended up making some changes. I couldn't just use this.statusCode anymore because the range check is now the first thing that happens in writeHead(). So, instead, I just made the validation more strict so that statusCode is never modified.

This leads to two changes:

  • String input is not accepted anymore: '200' previously worked but now throws. This could lead to a pretty confusing error message, so I think I may need to put some more work in here. Fixed - I added a type check first.
  • Numbers with decimals are not accepted anymore - before, 200.6 was silently floored to 200, now it throws.

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 nfriedly changed the title Fix error message for invalid http status code http: more strict statusCode validation Jan 17, 2017
@jasnell
Copy link
Member

jasnell commented Mar 1, 2017

@nfriedly ... is this still something you want to pursue

@nodejs/http

@jasnell jasnell added the stalled Issues and PRs that are stalled. label Mar 1, 2017
@cjihrig
Copy link
Contributor

cjihrig commented Mar 1, 2017

Closing per #9027 (comment)

@cjihrig cjihrig closed this Mar 1, 2017
@nfriedly
Copy link
Contributor Author

nfriedly commented Mar 1, 2017

@jasnell It looks like a4bb9fd fixed the original issue, so I'm content with closing this PR and calling it good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem. semver-major PRs that contain breaking changes and should be released in the next major version. stalled Issues and PRs that are stalled.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants