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

Seemingly incorrect relocation after HTTP/1.1 302 Found #4859

Closed
merkys opened this issue Jan 28, 2020 · 9 comments
Closed

Seemingly incorrect relocation after HTTP/1.1 302 Found #4859

merkys opened this issue Jan 28, 2020 · 9 comments
Labels

Comments

@merkys
Copy link

merkys commented Jan 28, 2020

I came upon a strange behavior of relocation. I believe it to be a bug, as this behavior seems to contradict the one described in the manual, as well as the debug print of curl itself.

I did this

Issued a HTTP/1.1 PUT request with --header 'Content-Type: application/json' -d @sample.json and --location. The site responded with HTTP/1.1 302 Found with Location header, which is an expected response.

curl redid the request to the new location with the following debug print:

* Issue another request to this URL: <URL omitted for brevity>
* Switch from POST to GET
* Found bundle for host <HOST omitted for brevity>
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host <HOST omitted for brevity>
* Connected to <HOST omitted for brevity>
> PUT <URL omitted for brevity> HTTP/1.1
> Host: <HOST omitted for brevity>
> User-Agent: curl/7.67.0
> Accept: */*
> Content-Type: application/json

I expected the following

As per curl's manpage in Debian,

When curl follows a redirect and the request is not a plain GET (for example POST or PUT), it will do the following request with a GET if the HTTP response was 301, 302, or 303.

Also, the debug print line:

  • Switch from POST to GET

I have expected a GET request to be made. However, a PUT request was made with Content-Type: application/json and empty content. The remote site responded with HTTP/1.1 400 Bad Request telling that empty JSON file is a malformed JSON file.

curl/libcurl version

curl 7.67.0 (x86_64-pc-linux-gnu) libcurl/7.67.0 OpenSSL/1.1.1d zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.20.2 (+libidn2/2.0.5) libssh2/1.8.0 nghttp2/1.40.0 librtmp/2.3
Release-Date: 2019-11-06
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets

Got the same with curl 7.58.0 (x86_64-pc-linux-gnu) too.

operating system

Debian unstable as of 2020-01-28 03:15:57-05:00

@bagder bagder added the HTTP label Jan 28, 2020
@bagder
Copy link
Member

bagder commented Jan 28, 2020

You're not telling us the whole story. You started saying you used --header 'Content-Type: application/json' -d @sample.json --location which would do a POST.

Further down you then say "a PUT request was made", which implies you used more options to get that effect but didn't tell us how.

  1. That other option is probably what made the redirect not work the way you intended
  2. A HTTP 302 responses is only expected to change exactly POST to a GET in a redirect, it is not supposed to change PUT or any other method. (RFC 7231 Section 6.4.3)

@merkys
Copy link
Author

merkys commented Jan 28, 2020

You're not telling us the whole story. You started saying you used --header 'Content-Type: application/json' -d @sample.json --location which would do a POST.

OK; I've explicitly ordered PUT with -X PUT.

Further down you then say "a PUT request was made", which implies you used more options to get that effect but didn't tell us how.

By "a PUT request was made" I meant "curl made a PUT request", see the curl's debug print.

1. That other option is probably what made the redirect not work the way you intended

The full command line was

curl --config curl-config.cf -X PUT -d @sample.json \
    --header 'Content-Type: application/json' \
    --dump-header /dev/tty <URL omitted for brevity> -L -k -v

Configuration file contains only directives to set the client's SSL certificate.

2. A HTTP 302 responses is _only_ expected to change exactly `POST` to a `GET` in a redirect, it is not supposed to change `PUT` or any other method. ([RFC 7231 Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3))

While I agree that curl's behavior is consistent with RFC 7231, it is completely different from what is written in the manpage, which tells that curl responds to HTTP 302 with GET no matter which method was used before.

@bagder
Copy link
Member

bagder commented Jan 28, 2020

Yes, the documentation isn't as accurate as it should be (I would not call it "completely different" though)

Still, that doesn't matter to your case since you override that decision with -X.

bagder added a commit that referenced this issue Jan 28, 2020
Not from generic non-GET to GET.

Ref: #4859
@merkys
Copy link
Author

merkys commented Jan 28, 2020

Right, -X overrides the request method, this is already written in the option description. My bad.

However, substituting -X PUT -d @sample.json with -T sample.json (seemingly the only other way to instruct curl to use PUT, at least per manpage) again results in a PUT after HTTP 302. Nevertheless, #4861 makes the description of -L consistent with curl's behavior.

bagder added a commit that referenced this issue Jan 28, 2020
Not from generic non-GET to GET.

Reported-by: Andrius Merkys
Ref: #4859
Closes #4861
@bagder
Copy link
Member

bagder commented Jan 28, 2020

There's no HTTP redirect response code to tell a client to change from PUT to GET. A client that sends a PUT should sent a PUT again after a 302 when following a redirect. If the server doesn't want/support this, then it should probably not redirect the PUT to begin with!

@merkys
Copy link
Author

merkys commented Jan 28, 2020

I am not talking about the server at all. I am talking about curl's documentation, which until 7929550 said that redirects after non-GET requests (PUT included) result in curl making a GET.

@bagder
Copy link
Member

bagder commented Jan 28, 2020

I am not talking about the server at all

Sorry, I thought the issue was the originally shown command line and how curl behaved on that server response. With the update docs I think this case is closed.

@merkys
Copy link
Author

merkys commented Jan 28, 2020

With the update docs I think this case is closed.

I agree. Thanks for prompt response.

@bagder
Copy link
Member

bagder commented Jan 28, 2020

Thanks, closing!

@bagder bagder closed this as completed Jan 28, 2020
@lock lock bot locked as resolved and limited conversation to collaborators May 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

2 participants