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

esm: treat 307 and 308 as redirects in HTTPS imports #43689

Merged
merged 4 commits into from
Jul 9, 2022
Merged

esm: treat 307 and 308 as redirects in HTTPS imports #43689

merged 4 commits into from
Jul 9, 2022

Conversation

kidonng
Copy link
Contributor

@kidonng kidonng commented Jul 5, 2022

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

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
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/modules

@nodejs-github-bot nodejs-github-bot added esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Jul 5, 2022
Comment on lines 130 to 139
if (res.statusCode > 303 || res.statusCode < 200) {
if (
(
res.statusCode > 303 &&
res.statusCode !== 307 &&
res.statusCode !== 308
) || res.statusCode < 200) {
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Member

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

Copy link
Contributor

@LiviaMedeiros LiviaMedeiros Jul 6, 2022

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?

Copy link
Member

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

Copy link
Contributor

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

lib/internal/modules/esm/fetch_module.js Outdated Show resolved Hide resolved
Comment on lines 141 to 142
if ((res.statusCode > 303 && !isRedirect(res.statusCode)) ||
res.statusCode < 200) {
Copy link
Member

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:

Suggested change
if ((res.statusCode > 303 && !isRedirect(res.statusCode)) ||
res.statusCode < 200) {
if (res.statusCode < 200 || res.statusCode >= 400) {

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Member

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?

Copy link
Member

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 the 302 Found HTTP response code, with the exception that the user agent must not change the HTTP method used: if a POST was used in the first request, a POST 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.

Copy link
Contributor Author

@kidonng kidonng Jul 7, 2022

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 location header? It probably should be something like ERR_NETWORK_STATUS_NOT_ALLOWED. oops, I think I almost said the same thing as #43689 (comment)

@GeoffreyBooth GeoffreyBooth added the request-ci Add this label to start a Jenkins CI on a PR. label Jul 6, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jul 6, 2022
@aduh95 aduh95 added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jul 6, 2022
@hemanth
Copy link
Contributor

hemanth commented Jul 6, 2022

Maybe we need some tests ?

@kidonng
Copy link
Contributor Author

kidonng commented Jul 7, 2022

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:

// Redirects have same import.meta.url but different cache
// entry on Web
const redirect = new URL(url.href);
redirect.searchParams.set('redirect', JSON.stringify({
status: 302,
location: url.href
}));
const redirectedNS = await import(redirect.href);
assert.strict.deepStrictEqual(
Object.keys(redirectedNS),
['default', 'url']
);
assert.strict.notEqual(redirectedNS.default, ns.default);
assert.strict.equal(redirectedNS.url, url.href);

Probably don't need a test for every response code.

@ljharb
Copy link
Member

ljharb commented Jul 7, 2022

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param {number} statusCode
* See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @param {number} statusCode

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @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
Copy link
Member

@GeoffreyBooth GeoffreyBooth Jul 7, 2022

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.

Suggested change
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.

Copy link
Member

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 🙂

Copy link
Contributor

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.

Copy link
Member

@GeoffreyBooth GeoffreyBooth Jul 7, 2022

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.

Copy link
Member

@JakobJingleheimer JakobJingleheimer Jul 7, 2022

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

Copy link
Member

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) {
Copy link
Member

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.

Copy link
Member

@JakobJingleheimer JakobJingleheimer Jul 7, 2022

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?

Copy link
Contributor

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.

Copy link
Member

@JakobJingleheimer JakobJingleheimer Jul 7, 2022

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.

Copy link
Contributor

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

Copy link
Contributor

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.

Copy link
Contributor

@LiviaMedeiros LiviaMedeiros left a 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.

@JakobJingleheimer JakobJingleheimer added commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. commit-queue Add this label to land a pull request using GitHub Actions. labels Jul 7, 2022
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Jul 7, 2022
@nodejs-github-bot
Copy link
Collaborator

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/.ncu
https://github.com/nodejs/node/actions/runs/2629054923

@nodejs-github-bot nodejs-github-bot added the commit-queue-failed An error occurred while landing this pull request using GitHub Actions. label Jul 7, 2022
@JakobJingleheimer
Copy link
Member

JakobJingleheimer commented Jul 7, 2022

Ah, whoops. The PR says 2d, but it's only 45 hours (not 48).

@LiviaMedeiros
Copy link
Contributor

We also need a CI run (Jenkins, not GitHub), but it's on lockdown right now.

@JakobJingleheimer
Copy link
Member

Oh, I thought it was only locked til yesterday. Sit tight. Rodger 👍

@LiviaMedeiros LiviaMedeiros added the request-ci Add this label to start a Jenkins CI on a PR. label Jul 7, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jul 7, 2022
@LiviaMedeiros LiviaMedeiros added the request-ci Add this label to start a Jenkins CI on a PR. label Jul 7, 2022
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jul 7, 2022
@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot

This comment was marked as outdated.

@nodejs-github-bot
Copy link
Collaborator

CI: https://ci.nodejs.org/job/node-test-pull-request/45189/

@LiviaMedeiros LiviaMedeiros added the commit-queue Add this label to land a pull request using GitHub Actions. label Jul 8, 2022
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Jul 9, 2022
@nodejs-github-bot nodejs-github-bot merged commit 3d575a4 into nodejs:main Jul 9, 2022
@nodejs-github-bot
Copy link
Collaborator

Landed in 3d575a4

targos pushed a commit that referenced this pull request Jul 12, 2022
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 <webadmin@geoffreybooth.com>
Reviewed-By: Zijian Liu <lxxyxzj@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
LiviaMedeiros added a commit to LiviaMedeiros/node that referenced this pull request Jul 12, 2022
Treat redirects without Location and other 3xx responses as errors

PR-URL: nodejs#43742
Refs: nodejs#43689
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
targos pushed a commit that referenced this pull request Jul 20, 2022
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 <webadmin@geoffreybooth.com>
Reviewed-By: Zijian Liu <lxxyxzj@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
danielleadams pushed a commit that referenced this pull request Jul 26, 2022
Treat redirects without Location and other 3xx responses as errors

PR-URL: #43742
Refs: #43689
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
targos pushed a commit that referenced this pull request Jul 31, 2022
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 <webadmin@geoffreybooth.com>
Reviewed-By: Zijian Liu <lxxyxzj@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
targos pushed a commit that referenced this pull request Jul 31, 2022
Treat redirects without Location and other 3xx responses as errors

PR-URL: #43742
Refs: #43689
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
guangwong pushed a commit to noslate-project/node that referenced this pull request Oct 10, 2022
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 <webadmin@geoffreybooth.com>
Reviewed-By: Zijian Liu <lxxyxzj@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
guangwong pushed a commit to noslate-project/node that referenced this pull request Oct 10, 2022
Treat redirects without Location and other 3xx responses as errors

PR-URL: nodejs/node#43742
Refs: nodejs/node#43689
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. commit-queue-failed An error occurred while landing this pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Treat 307 and 308 as redirects in HTTPS imports
9 participants