reqwest icon indicating copy to clipboard operation
reqwest copied to clipboard

HTTP method changed after redirect

Open roman-r-m opened this issue 2 years ago • 7 comments

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 avatar Mar 14 '23 22:03 roman-r-m

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.

roman-r-m avatar Mar 14 '23 22:03 roman-r-m

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?

seanmonstar avatar Mar 15 '23 14:03 seanmonstar

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.

roman-r-m avatar Mar 15 '23 23:03 roman-r-m

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.

joshhansen avatar Aug 22 '24 00:08 joshhansen

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

  • Patch reqwest to only redirect POST, as the RFC mentions, and it seems browsers and curl do this as well.
  • Provide a ClientBuilder option that disables changing the HTTP method on a redirect entirely.

seanmonstar avatar Aug 22 '24 01:08 seanmonstar

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.

konstin avatar Sep 20 '24 09:09 konstin

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.

lucab avatar Sep 20 '24 09:09 lucab