seanmonstar / reqwest

An easy and powerful Rust HTTP Client
https://docs.rs/reqwest
Apache License 2.0
9.9k stars 1.12k forks source link

HTTP method changed after redirect #1777

Open roman-r-m opened 1 year ago

roman-r-m commented 1 year ago

I am trying to use reqwest for WebDAV and facing an issue with redirects. I am using

reqwest = { version = "0.11", features = ["blocking", "json"] }

First I am making a PROPFIND call to Apache server with WebDAV enabled:

PROPFIND /webdav/foo/bar HTTP/1.1

Apparently Apache requires the URL to have the trailing slash to it replies with HTTP 301:

HTTP/1.1 301 Moved Permanently
Date: Tue, 14 Mar 2023 22:21:13 GMT
Server: Apache/2.4.54 (Raspbian)
Location: http://host:8080/webdav/foo/bar/

At this point reqwest does a GET call instead of PROPFIND:

GET /webdav/foo/bar/ HTTP/1.1
referer: http://host:8080/webdav/foo/bar

I believe redirect should not change the method and this is a bug.

roman-r-m commented 1 year ago

I looked at redirect policy in hope that I could somehow use it to restore the original method but it does not look to be possible.

seanmonstar commented 1 year ago

This behavior is based on this point in RFC 9110:

For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request. If this behavior is undesired, the 308 (Permanent Redirect) status code can be used instead.

So, I suppose the question I'm now wondering, is does that note suggest that only POST would be changed? Or that anything not GET?

roman-r-m commented 1 year ago

So, I suppose the question I'm now wondering, is does that note suggest that only POST would be changed? Or that anything not GET?

To me it reads like it's only POST. MDN is also ambiguous on this (https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections#permanent_redirections):

GET methods unchanged. Others may or may not be changed to GET. [1]

In any case I have found a workaround (setting trailing slash on the URL prevents Apache from redirecting) so feel free to close this if you prefer.

joshhansen commented 2 months ago

I'm running into this issue myself - PROPFIND is being 301 redirected, but the request then becomes a GET which does something very different in a WebDAV / CalDAV context.

If there's no desire to change the existing behavior, perhaps the redirect::Attempt::follow method could be augmented to allow specification of the HTTP method used when following the redirect, which would make this a situation that clients could handle themselves.

seanmonstar commented 2 months ago

On re-reading again, I'd be open to two changes (both even):

konstin commented 1 month ago

For us, it would be great if it would be possible to set the redirect policy so that we don't redirect POST requests at all (we're POSTing to any API, not a form, while sharing the client with GET requests); Currently, reqwest::redirect::Attempt doesn't expose the method.

lucab commented 1 month ago

For reference, this is the JS fetch() behavior from specs (point 12 of https://fetch.spec.whatwg.org/#http-redirect-fetch):

If one of the following is true
    status is 301 or 302 and request’s method is `POST`
    status is 303 and request’s method is not `GET` or `HEAD`
then:
    Set request’s method to `GET` and request’s body to null.
    For each headerName of request-body-header name, delete headerName from request’s header list.