-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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: verify method is a string #10111
Conversation
if (_method !== undefined && _method !== null | ||
&& typeof _method !== 'string') { | ||
throw new TypeError('Method must be a string'); | ||
} |
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.
For the best backwards compatibility (and to emulate the method value selection behavior below the typeof
check), I think the undefined
/null
check should be removed and just test for truthiness:
if (options.method && typeof options.method !== 'string') {
throw new TypeError('Method must be a string');
}
The reason being that options.method
could be one of several non-truthy values, such as 0
and false
.
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 this case if options.method
is set to 0
results in a falsy value which is going to default the method to GET
in the following check.
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.
@mscdex that would not fix the non-truthy
values, confusing the defaulting of 0
values to GET
.
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.
Well, it's a difference between semver-ness. This change is definitely going to be semver-major as-is, but it could be semver-patch with the check I suggested. It's up to you.
const assert = require('assert'); | ||
const http = require('http'); | ||
|
||
const expectedSuccesses = { |
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.
Only the keys seem to be used. This could probably be an array...
http.request({ method: method, port: server.address().port }).end(); | ||
} | ||
|
||
ok(undefined); |
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.
... and then you can loop over the array here. Right now, the number of times ok()
is called is independent of methods
.
function fail(input) { | ||
assert.throws(() => { | ||
http.request({ method: input, path: '/' }, common.fail); | ||
}, /Method must be a string/); |
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 want to be really strict, this could be /^TypeError: Method must be a string$/
.
@@ -68,6 +68,11 @@ function ClientRequest(options, cb) { | |||
self.socketPath = options.socketPath; | |||
self.timeout = options.timeout; | |||
|
|||
const _method = options.method; | |||
if (_method !== undefined && _method !== null |
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 can be written as:
if (_method != null && typeof _method !== 'string')
If you don't choose to rewrite like that, the &&
should be moved to the previous line, and the second line should be lined up. I'm surprised the linter doesn't complain.
CI: https://ci.nodejs.org/job/node-test-pull-request/5251/ UPDATE: Another try - https://ci.nodejs.org/job/node-test-pull-request/5252/ |
const _method = options.method; | ||
if (_method != null && typeof _method !== 'string') { | ||
throw new TypeError('Method must be a string'); | ||
} | ||
var method = self.method = (options.method || 'GET').toUpperCase(); |
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.
We should probably use options.method
or _method
consistently. Right now it's a mix.
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 common._checkIsHttpToken()
check on line 77 already includes a test to ensure method
is a string.
One CI failure looks unrelated. |
Is this really semver-major? Wouldn't node have thrown an unexpected internal type error when it tried to use the method as a String, even though it wasn't? I understand when text of warning messages are changed it can break user-space, but user-space depending on something like Just asking for clarification here. |
@sam-github See mscdex's comment here: #10111 (comment) |
I think this is the correct thing to do moving forward. A second PR that is more backwards compatible might be good for Node 7 and earlier. |
While I appreciate the new test, the |
@jasnell The issue though is that that |
In addition to what @mscdex said, if the method is not a string and is truthy, then an exception is thrown: |
ok.. works for me :-) |
@@ -68,7 +68,11 @@ function ClientRequest(options, cb) { | |||
self.socketPath = options.socketPath; | |||
self.timeout = options.timeout; | |||
|
|||
var method = self.method = (options.method || 'GET').toUpperCase(); | |||
const _method = options.method; |
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 we can just move the var method
declaration up here and re-assign on line 75, that way we don't have a second variable for the same thing?
@@ -68,7 +68,11 @@ function ClientRequest(options, cb) { | |||
self.socketPath = options.socketPath; | |||
self.timeout = options.timeout; | |||
|
|||
var method = self.method = (options.method || 'GET').toUpperCase(); | |||
let method = options.method; |
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 keep var
. We haven't really made the switch to let
in lib/
code for performance reasons.
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.
LGTM. Another CI: https://ci.nodejs.org/job/node-test-pull-request/5289/
Landed in df39784. Thanks! |
Prior to this commit, it was possible to pass a truthy non-string value as the HTTP method to the HTTP client, resulting in an exception being thrown. This commit adds validation to the method. PR-URL: #10111 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
Prior to this commit, it was possible to pass a truthy non-string value as the HTTP method to the HTTP client, resulting in an exception being thrown. This commit adds validation to the method. PR-URL: nodejs#10111 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
Checklist
Affected core subsystem(s)
http
Description of change
Added strict check for http request
method
to be astring
. Ifmethod
is not a string (orundefined
ornull
) aTypeError
exceptions is thrown.The
method
value is still defaulted toGET
in the following cases:method
isundefined
method
isnull
This fixes the
http-client
to crash ifoptions.method
inhttp.request
was set to a number not equal to 0.