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

Method changes on redirect #319

Open
OJFord opened this issue Feb 29, 2020 · 12 comments
Open

Method changes on redirect #319

OJFord opened this issue Feb 29, 2020 · 12 comments

Comments

@OJFord
Copy link

OJFord commented Feb 29, 2020

If the redirect policy allows redirection, and the request method was initially POST; on the redirected request it's no longer POST, and the response may be 405 Method Not Allowed (very confusing if the logs aren't showing that redirection happened!) or an unexpected response/effect in the event that the method is allowed.

@jeevatkm
Copy link
Member

jeevatkm commented Mar 2, 2020

@OJFord I think you can take full control of all redirect(s) via policy. By default resty does not assign any redirect policy to the client.

@OJFord
Copy link
Author

OJFord commented Mar 2, 2020

@jeevatkm I'm not sure I understand - would it ever be desirable that a POST resulting in a redirect ends up being a GET on the redirected-to resource?

The behaviour I saw by default (not specifying a redirect policy) was the same as when I supplied one that allowed the redirect (DomainCheckRedirectPolicy) - but it wasn't POSTed and as a result I noticed the error because the server responded 405, since it only allowed POST on that endpoint.

@jeevatkm
Copy link
Member

jeevatkm commented Mar 3, 2020

would it ever be desirable that a POST resulting in a redirect ends up being a GET on the redirected-to resource?

@OJFord It certainly possible. Because on the server-side if they redirect POST to GET then HTTP clients simply going to follow the redirects. So the client is not going to take a decision on its own.

Define a custom redirect policy on your client to investigate it.

client.SetRedirectPolicy(RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
	// log all the info you want for the investigation       
	return nil
}))

If you do not want to follow the redirect kindly use client.SetRedirectPolicy(NoRedirectPolicy())

@OJFord
Copy link
Author

OJFord commented Mar 3, 2020

The redirect response is 301, methods are not supposed to change, but MDN notes:

there are existing user agents that do change their method. 308 was created to remove the ambiguity of the behavior when using non-GET methods.

The response is just:

$ curl --head --request POST "$host/blah"
HTTP/2 301
server: nginx
date: Tue, 03 Mar 2020 10:56:18 GMT
content-type: text/html; charset=utf-8
content-length: 0
location: /blah/
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
vary: Origin
strict-transport-security: max-age=15768000; includeSubDomains

I do want to follow the redirect, I just don't want the method to change.

@jeevatkm
Copy link
Member

jeevatkm commented Apr 6, 2020

@OJFord will check it again in Resty. Just want to clarify, you're using Resty v2 correct?

@OJFord
Copy link
Author

OJFord commented Apr 20, 2020

Sorry for the delay - v2, yes.

@MrNocTV
Copy link

MrNocTV commented Mar 29, 2023

I have the same problem, I send a POST request and it returns 405 because it is changed to GET upon redirect.

@OJFord
Copy link
Author

OJFord commented Mar 29, 2023

@MrNocTV Yep, as far as I recall I just got around this by not having using the redirected endpoint in the end. Not as easy it sounds because of some other issue with trailing slashes or something (which was why it was redirecting), but that was easier to solve in the end.

@MrNocTV
Copy link

MrNocTV commented Apr 3, 2023

@OJFord Can you please share an example :D ?

@OJFord
Copy link
Author

OJFord commented Apr 14, 2023

@MrNocTV Depends on the API you're using, try in the browser or with curl, check the redirect Location, and use that in your code instead of the one that gets redirected. This assumes it's a static/deterministic-in-known-way redirect though; again, depends on API and why it's redirecting.

@jeevatkm jeevatkm added this to the v3.0.0 Milestone milestone Oct 1, 2023
@henrybarreto
Copy link

I was struggling with a similar problem, until I noticed that that method change seems to be the right behavior, depending on the server's status code.

According to Go's net/http docs:

If the server replies with a redirect, the Client first uses the CheckRedirect function to determine whether the redirect should be followed. If permitted, a 301, 302, or 303 redirect causes subsequent requests to use HTTP method GET (or HEAD if the original request was HEAD), with no body. A 307 or 308 redirect preserves the original HTTP method and body, provided that the Request.GetBody function is defined. The NewRequest function automatically sets GetBody for common standard library body types.

We've just changed the method from 301 to 308 and the issue had its solution.

golang/go#60769 (comment)

Maybe It isn't the same problem, but I think it could help in some way.

@OJFord
Copy link
Author

OJFord commented Oct 19, 2023

Oh interesting, thanks for that. I suppose that explains it then - but frustrating if you're working with a third-party API that behaves differently, even if that isn't RFC compliant.

... Actually though RFC2616 implies that the method should be retained ('when automatically redirecting a POST request'); what it does say - and I wonder if the docs quoted above are perhaps a misreading of this? - is that the user agent must not follow the redirect without confirmation, unless it's GET or HEAD. (In the context of a programming library user agent, I suppose 'user confirmation' is something like setting a followRedirects=True flag from its false default.)

Edit: there is also this note:

Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, most
existing user agent implementations treat 302 as if it were a 303
response, performing a GET on the Location field-value regardless
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.

But I think that's been misapplied to 301.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants