Skip to content

HTTP 307 redirects break when normalizing URLs #9350

Description

@lxhom

Describe the bug

HTTP 307 description if you're not familiar with it

HTTP 307 Temporary Redirect redirect status response code indicates that the resource requested has been temporarily moved to the URL given by the Location headers.

The method and the body of the original request are reused to perform the redirected request. In the cases where you want the method used to be changed to GET, use 303 See Other instead. This is useful when you want to give an answer to a PUT method that is not the uploaded resources, but a confirmation message (like "You successfully uploaded XYZ").

(from MDN: HTTP 307 Temporary Redirect)

My use case is a bit complicated, but I need to redirect a POST request like this:

POST server1.com/path -> HTTP 307, Location: server2.com/path
POST server2.com/path -> HTTP 200

This works with SvelteKit, except when it normalizes paths:

POST server1.com/path/ -> HTTP 307, Location: server2.com/path/
POST server2.com/path/ -> HTTP 301, Location: server2.com/path, X-SvelteKit-Normalize: 1
GET  server2.com/path  -> HTTP 405

This is due to this condition:

if (normalized !== url.pathname && !state.prerendering?.fallback) {
return new Response(undefined, {
status: 301,
headers: {
'x-sveltekit-normalize': '1',
location:
// ensure paths starting with '//' are not treated as protocol-relative
(normalized.startsWith('//') ? url.origin + normalized : normalized) +
(url.search === '?' ? '' : url.search)
}
});
}

This should check if the original request is a 307, and use 307 too if that is the case.

Reproduction

Without normalization:

❯ curl -Lvd "a" localhost:3000/from
> POST /from HTTP/1.1
> Host: localhost:3000
> 
< HTTP/1.1 307 Temporary Redirect
< location: http://localhost:3000/to
< 
* Issue another request to this URL: 'http://localhost:3000/to'
> POST /to HTTP/1.1
> Host: localhost:3000
> 
< HTTP/1.1 200 OK
< 
Posted!

With normalization:

❯ curl -Lvd "a" localhost:3000/from/
> POST /from/ HTTP/1.1
> Host: localhost:3000
> 
< HTTP/1.1 301 Moved Permanently
< location: /from
< x-sveltekit-normalize: 1
< 
* Issue another request to this URL: 'http://localhost:3000/from'
* Switch from POST to GET
> GET /from HTTP/1.1
> Host: localhost:3000
> 
< HTTP/1.1 405 Method Not Allowed
< 
GET method not allowed    

For example code see lxhom/sk-307-demo@f8d580e (the commit only includes the changed files from a base SK project)

Logs

No response

System Info

System:
    OS: Linux 6.1 Arch Linux (btw)
    CPU: (4) x64 AMD A8-7410 APU with AMD Radeon R5 Graphics
    Memory: 818.83 MB / 6.74 GB
    Container: Yes
    Shell: 5.8 - /usr/local/bin/zsh
  Binaries:
    Node: 19.4.0 - ~/.nvm/versions/node/v19.4.0/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 9.2.0 - ~/.nvm/versions/node/v19.4.0/bin/npm
  Browsers:
    Firefox: 109.0
    Chrome: 110

Severity

serious, but I can work around it

Additional Information

I'd submit this as a PR (because this seems really easy), but I'm rather new to SK and I don't know if this would break other stuff.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions