-
Notifications
You must be signed in to change notification settings - Fork 30k
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
esm: treat 307
and 308
as redirects in HTTPS imports
#43689
Conversation
Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: #43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238
Review requested:
|
if (res.statusCode > 303 || res.statusCode < 200) { | ||
if ( | ||
( | ||
res.statusCode > 303 && | ||
res.statusCode !== 307 && | ||
res.statusCode !== 308 | ||
) || res.statusCode < 200) { |
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 part makes me wonder if original flow is correct. If the response isRedirect && !hasLocation
, shouldn't we throw? Especially if we deal with 300 Multiple Choices
.
This concern is not blocking and can be addressed separately, the change itself LGTM.
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 think if the server returns 300 Multiple Choices and no Location
, it should be treated as unresolvable/fail (or follow the Location
if provided).
Perhaps a custom loader should be used deal with Multiple Choices.
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.
To be fair, I'm not even sure if there are reasonable use cases to import a body of response with any 2xx
code other than 200
.
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 often get the body from a 201 as "a representation of the thing that was created".
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.
From a GET
request? May I ask in which scenario it's required or has high probability of happening?
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.
oh true, i wouldn't expect a 201 from a GET request :-) a 204 (no body) or 206 (partial body) maybe, though
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.
206
probably shouldn't happen there (i.e. we don't send any Range
so partial body is not what should be expected), 204
restricts having a body at all... Although yes, technically we can import {} from 'https://example.com/204-no-content.mjs';
and there's nothing really wrong about that. 😄
if ((res.statusCode > 303 && !isRedirect(res.statusCode)) || | ||
res.statusCode < 200) { |
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 original code was intending to catch all status codes in the 1xx, 4xx and 5xx ranges. The author didn’t realize that there were valid redirect codes higher than 303; a better version would just start at 400:
if ((res.statusCode > 303 && !isRedirect(res.statusCode)) || | |
res.statusCode < 200) { | |
if (res.statusCode < 200 || res.statusCode >= 400) { |
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.
Thanks for explaining, this code always looks awkward to me, but I did not change it in order to be cautious.
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 like to point out that 3xx
codes are not only redirects: for example, there is 304 Not Modified
.
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.
Sorry, I should correct myself: that was my assumption as to what the original code was intending. @JakobJingleheimer perhaps you can confirm? Should this condition catch 304 and/or any of the other 3xx codes?
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 don't know why Bradley did not include them (he wrote this part). Perhaps it has to do with the subtle differences/specifics in 307 and 308?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
307
This has the same semantics as the302
Found HTTP response code, with the exception that the user agent must not change the HTTP method used: if aPOST
was used in the first request, aPOST
must be used in the second request.
(308 is the same, but relative to 301)
I'd need to check through the other code to see if it even supports changing the method during a redirect—I don't recall it supporting that. If it can't, I see no reason to not include 307 and 308.
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 nuances between 301/302 and 307/308 is unrelated here since it is only doing GET
.
But upon taking a close look I feel this is throwing an inappropriate error. If the status code is < 200 or >= 400, why would the code expect it to have a oops, I think I almost said the same thing as #43689 (comment)location
header? It probably should be something like ERR_NETWORK_STATUS_NOT_ALLOWED
.
Maybe we need some tests ? |
I didn't add tests because this is simply expanding existing check and should be covered by existing tests like: node/test/es-module/test-http-imports.mjs Lines 104 to 117 in b985ad5
Probably don't need a test for every response code. |
boo on the switch :-) an array can be made multiline with comments just as easily. |
* https://datatracker.ietf.org/doc/html/rfc7231#section-6.4 | ||
* and RFC 7238: | ||
* https://datatracker.ietf.org/doc/html/rfc7238 | ||
* @param {number} 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.
* @param {number} statusCode | |
* See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Status | |
* @param {number} 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.
* @param {number} statusCode | |
* @param {number} statusCode | |
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status |
case 301: // Moved Permanently | ||
case 302: // Found | ||
case 303: // See Other | ||
case 307: // Temporary Redirect |
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 think we should include a comment noting that leaving out 304 is a deliberate choice.
case 307: // Temporary Redirect | |
// Skipping 304: Not Modified | |
case 307: // Temporary Redirect |
I’m also fine with this being a SafeSet
defined outside of the function if that seems more readable to everyone. I don’t have a preference between one or the other.
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.
+1 for the comment about explicitly skipping 304 🙂
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.
-1 for the comment about 304
because the next steps are commenting 305
and 306
.
I agree with author's #43689 (comment) that http codes are well-known and there already is a link. I don't think extra verbosity is useful here.
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.
304 is commonly used whereas 305 and 306 basically don't exist. I think it's worth calling out that we intended to treat 304 differently, so that no one comes by later and opens a PR to add it here—like this PR is doing. It's not about explaining what 304 is, but that this code intentionally excludes it from the "treat as redirect" set.
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 agree with @GeoffreyBooth that it's worth noting. I am the primary maintainer and I know my future self would appreciate the comment.
I'll add it in a follow-up PR and we can debate it there (along with a bugfix for the wrong error type he found in the original implementation).
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.
CI hasn’t run yet for this PR, I think there’s no reason to wait for a follow-up to add a comment.
@@ -127,7 +148,7 @@ function fetchWithRedirects(parsed) { | |||
err.message = `Cannot find module '${parsed.href}', HTTP 404`; | |||
throw err; | |||
} | |||
if (res.statusCode > 303 || res.statusCode < 200) { | |||
if (res.statusCode < 200 || res.statusCode >= 400) { |
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.
Should this also include 304, as in (res.statusCode < 200 || res.statusCode === 304 || res.statusCode >= 400)
? @JakobJingleheimer? I feel like we should never get a 304 in Node because we’re not maintaining a cache in the way browsers are?
Also what is this error 'cannot redirect to non-network location'
referring to? If the status code is 500, this seems a weird error to throw.
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 would just switch this to the new isRedirect()
helper
I feel like we should never get a 304 in Node because we’re not maintaining a cache in the way browsers are?
We maintain a cache, and I think there are designs (perhaps only in people's heads at the moment?) for a write-to-disk cache in future (at which point a 304 would be very valid). I'd say account for it now whilst we're thinking of it (especially because it's trivial) rather than get bitten by it later.
Also what is this error 'cannot redirect to non-network location' referring to?
This is when a remote module tries to access a local module (eg fs
), which is forbidden.
If the status code is 500, this seems a weird error to throw.
Sorry, where are you seeing a 500
?
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.
Sorry, where are you seeing a
500
?
500 >= 400
so it would throw here if the server responds with this code.
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.
Oh! Yes, indeed it should not throw disallowed network import for a 500.
@aduh95 I see you just approved; I'm thinking this should be consider a blocker (it introduces a bug). The rest can be addressed in a follow-up.
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.
Wrong error is not introduced in this PR, it's a part of original code.
What this PR in its current state changes here is behaviour for 303 < statusCode < 400
(for 307 and 308, only if no Location provided), importing body instead of throwing "non-network location" error. Which can be addressed in a follow-up, but is still in line with logic of old code (it did the same for 300~303
).
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 see you just approved; I'm thinking this should be consider a blocker
Livia said it all, if there's a bug let's fix it in its own PR. This PR does a great job at adding support for 307 and 308, it wouldn't be fait to block it on a bug (or maybe not bug?) of the existing implementation.
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 before it's derailed too much. 😄
The fix is correct; issues of original code (both functional and stylistic) can be addressed by follow-up PRs.
Commit Queue failed- Loading data for nodejs/node/pull/43689 ✔ Done loading data for nodejs/node/pull/43689 ----------------------------------- PR info ------------------------------------ Title esm: treat `307` and `308` as redirects in HTTPS imports (#43689) ⚠ Could not retrieve the email or name of the PR author's from user's GitHub profile! Branch kidonng:fetch_module-3xx -> nodejs:main Labels esm, author ready, needs-ci, commit-queue-squash Commits 4 - esm: treat `307` and `308` as redirects in HTTPS imports - Split `isRedirect` into its own function per review - Apply review suggestions - Use a switch Committers 1 - GitHub PR-URL: https://github.com/nodejs/node/pull/43689 Fixes: https://github.com/nodejs/node/issues/43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 Reviewed-By: Geoffrey Booth Reviewed-By: Zijian Liu Reviewed-By: LiviaMedeiros Reviewed-By: Antoine du Hamel Reviewed-By: Jacob Smith ------------------------------ Generated metadata ------------------------------ PR-URL: https://github.com/nodejs/node/pull/43689 Fixes: https://github.com/nodejs/node/issues/43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 Reviewed-By: Geoffrey Booth Reviewed-By: Zijian Liu Reviewed-By: LiviaMedeiros Reviewed-By: Antoine du Hamel Reviewed-By: Jacob Smith -------------------------------------------------------------------------------- ℹ This PR was created on Tue, 05 Jul 2022 14:17:54 GMT ✔ Approvals: 5 ✔ - Geoffrey Booth (@GeoffreyBooth) (TSC): https://github.com/nodejs/node/pull/43689#pullrequestreview-1030971473 ✔ - Zijian Liu (@Lxxyx): https://github.com/nodejs/node/pull/43689#pullrequestreview-1030853737 ✔ - LiviaMedeiros (@LiviaMedeiros): https://github.com/nodejs/node/pull/43689#pullrequestreview-1031160705 ✔ - Antoine du Hamel (@aduh95) (TSC): https://github.com/nodejs/node/pull/43689#pullrequestreview-1031177455 ✔ - Jacob Smith (@JakobJingleheimer): https://github.com/nodejs/node/pull/43689#pullrequestreview-1031313255 ✖ This PR needs to wait 3 more hours to land ✔ Last GitHub CI successful ✖ No Jenkins CI runs detected -------------------------------------------------------------------------------- ✔ Aborted `git node land` session in /home/runner/work/node/node/.ncuhttps://github.com/nodejs/node/actions/runs/2629054923 |
We also need a CI run (Jenkins, not GitHub), but it's on lockdown right now. |
Oh, I thought it was only locked til yesterday. Sit tight. Rodger 👍 |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Landed in 3d575a4 |
Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: #43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 PR-URL: #43689 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Zijian Liu <[email protected]> Reviewed-By: LiviaMedeiros <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Treat redirects without Location and other 3xx responses as errors PR-URL: nodejs#43742 Refs: nodejs#43689 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: #43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 PR-URL: #43689 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Zijian Liu <[email protected]> Reviewed-By: LiviaMedeiros <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Treat redirects without Location and other 3xx responses as errors PR-URL: #43742 Refs: #43689 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: #43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 PR-URL: #43689 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Zijian Liu <[email protected]> Reviewed-By: LiviaMedeiros <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Treat redirects without Location and other 3xx responses as errors PR-URL: #43742 Refs: #43689 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: nodejs/node#43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 PR-URL: nodejs/node#43689 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Zijian Liu <[email protected]> Reviewed-By: LiviaMedeiros <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Treat redirects without Location and other 3xx responses as errors PR-URL: nodejs/node#43742 Refs: nodejs/node#43689 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
Per RFC 7231 and 7238, HTTP
307
and308
status code are also forredirect responses.
Fixes: #43679
Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7
Refs: https://datatracker.ietf.org/doc/html/rfc7238