http: verify method is a string#10111
http: verify method is a string#10111lucamaraschi wants to merge 5 commits intonodejs:masterfrom lucamaraschi:master
Conversation
| if (_method !== undefined && _method !== null | ||
| && typeof _method !== 'string') { | ||
| throw new TypeError('Method must be a string'); | ||
| } |
There was a problem hiding this comment.
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.
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.
@mscdex that would not fix the non-truthy values, confusing the defaulting of 0 values to GET.
There was a problem hiding this comment.
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.
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.
... 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.
If you want to be really strict, this could be /^TypeError: Method must be a string$/.
lib/_http_client.js
Outdated
| self.timeout = options.timeout; | ||
|
|
||
| const _method = options.method; | ||
| if (_method !== undefined && _method !== null |
There was a problem hiding this comment.
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/ |
lib/_http_client.js
Outdated
| 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.
We should probably use options.method or _method consistently. Right now it's a mix.
There was a problem hiding this comment.
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 :-) |
lib/_http_client.js
Outdated
| self.timeout = options.timeout; | ||
|
|
||
| var method = self.method = (options.method || 'GET').toUpperCase(); | ||
| const _method = options.method; |
There was a problem hiding this comment.
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?
lib/_http_client.js
Outdated
| self.timeout = options.timeout; | ||
|
|
||
| var method = self.method = (options.method || 'GET').toUpperCase(); | ||
| let method = options.method; |
There was a problem hiding this comment.
Can you keep var. We haven't really made the switch to let in lib/ code for performance reasons.
cjihrig
left a comment
There was a problem hiding this comment.
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
methodto be astring. Ifmethodis not a string (orundefinedornull) aTypeErrorexceptions is thrown.The
methodvalue is still defaulted toGETin the following cases:methodisundefinedmethodisnullThis fixes the
http-clientto crash ifoptions.methodinhttp.requestwas set to a number not equal to 0.