-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Force GET Redirect on PUT and POST on HTTP Status Code 300-303 #28998
Comments
Is there an HTTP-related specification somewhere that dictates that? |
We generally follow RFC 7231. Section 6.4 covers behaviors for redirection: https://tools.ietf.org/html/rfc7231.html#section-6.4 |
RFC 7231 describes the behavior for POST redirects and indicates it should transform to GET.
However, there are no described behaviors in the RFC for transforming PUT or DELETE. If RestSharp is doing that, then it is inventing a new behavior. What do browsers do in these cases? |
Alright. You are right the RFC's are not clear. I tried tools like postman that did the mapping to GET even for PUT and DELETE. My understanding is that due to the confusion 307 and 308 were made to ensure request method are not rewritten. For 301 and 302 the behavior varies across tools. 303 maps to GET in most cases even for PUT and DELETE. https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections#Temporary_redirections. For 303 the rewriting should happen in my opinion. 301 and 302 are debatable. |
It should be noted that forcing a GET on 303 for a PUT is the behavior of System.Net.Http in .NET Framework from what I can tell. |
Triage: We should match .NET Framework in cases where RFC is not clear. |
Is this stackoverflow answer wrong?
I just converted a utility from Net Framework to Net 5.0, and the results were not pretty. I'm doing a PUT to In Net Framework, the retry does a GET on In Net 5.0, the retry does another PUT to I'm not clear on what use case this is desirable behaviour. Since I didn't want to completely disable retries for my GETs, too, the smallest way to compensate seemed to be to set MaxAutomaticRedirections = 1 then manually handle the 303 for the PUT. |
Here's my take on the RFC language, taken from https://tools.ietf.org/html/rfc7231#section-6.4
So I think our current behavior here (only change POST) is correct.
So, I think we should change the behavior for 303 to change the method to GET for all methods (not just PUT). I believe this matches both .NET Framework behavior and common practice. @scalablecory @stephentoub Any concerns here? |
Is there a place I can check the Net Framework code to make sure the behaviour is matching? |
If it brings us better in line with the spec and netfx, sounds good. |
@TimothyByrd best option is to write a test for each case and try it out. Code is here: https://referencesource.microsoft.com/
That is our high-level desire as well -- see #28998 (comment). |
Fair enough. I have updated the PR such that:
@karelz @stephentoub Is that what you meant? |
Why not all methods? I think special casing HEAD is probably reasonable; HEAD is sort of a special case of GET, and if you did a HEAD in the first place it's pretty weird for that to result in a response body. But for other methods, including OPTIONS and any unrecognized method, the RFC seems pretty clear that 303 applies to this. The server chose to send a 303. That means it wants the client to follow the redirect. |
Well, we know the RFC is unclear, and that since HEAD stays HEAD, "all" doesn't really mean "all". (This paragraph is how I was imagining things.) POST/PUT/PATCH all create/update a resource, so having a redirect to a GET makes sense for the case where assembling the resource is expensive. OPTIONS sounds like it retrieves metadata about a resource, which makes it seem more like HEAD in a way. To figure things out, I took a brute force approach and checked what Firefox, Edge/Chrome and Net Framework do. It looks like the only major discrepancy is that Net Framework changes "all" methods (except HEAD) to GET when redirecting on a 300, and doesn't follow the redirect on a 308. I don't suggest doing that, but I do think it should be documented as change between Net Framework and Net. And I've updated the pull request to change all methods (except HEAD) to GET. |
It seems like compatibility with Framework could be useful if RFC is ambiguous. Would it make sense to add AppContext switch @geoffkizer for legacy behavior? |
You mean, to match current behavior? I think our current behavior here is pretty broken, so I don't think there's a need for a compat switch. |
So to conclude the discussion, here's where we have landed: (1) 303 should change all methods to GET, except HEAD. This matches .NET Framework and common browser behavior. If anything looks wrong, please yell now. |
BTW @TimothyByrd thanks for doing the research re browser behavior here, that's very helpful. |
* Make 303 redirects do GET like Net Framework In Net Framework, PUT redirects on a 303 do a GET. Net 5.0 breaks compatibility with this. See #28998 This commit causes redirects of a 303 to do a GET for all methods except HEAD. Co-authored-by: Timothy Byrd <timothy.byrd@laserfiche.com>
Currently, GET request is just forced for POST requests with a 300-303 response. This behavior should also be in place for PUT and DELETE considering they are not safe functions either. RestSharp does it like that.
If not, I couldn't even figure out a way to keep the current behavior and just handling it differently for these methods. From the looks of it, I'll have to implement the complete redirection logic to achieve the desired behavior.
The text was updated successfully, but these errors were encountered: