Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 167
HTTP client: Preserve request method and body for 307 Temporary Redirect and 308 Permanent Redirect#442
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
Uh oh!
There was an error while loading. Please reload this page.
Conversation
SimonFrings commented Feb 14, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Hey @dinooo13 , thanks for looking into this one 👍 This is an interesting topic and the approach looks nice. It may not seem like it but I think this not only fixes some stuff but also breaks some (for example the new request doesn't contain a body, so when redirecting a POST there is no data). It fixes the problem addressed in #409 but I also think it overloads this PR to use this new rule on every 300 status code (except 303). I also looked a bit deeper into the HTTP specification. For the majority of the 300 status codes, it says that the request method may change when redirecting, which depends a bit on the use case and who you're talking to. Because of all of this, I think it's best that this PR only focuses on the 307 (and 308) for now and that we tackle the remaining status codes in a following one (if necessary). Additionally, the specification says, that the method for 303 should always be a GET when redirecting. You already covered this in your current PR but I was thinking: What if the original method was HEAD. The HEAD and GET methods are very similar to each other, the only difference is that the HEAD method doesn't request the body. If I use a HEAD method now and this changes into a GET when redirecting, I'm receiving more data than I originally wanted. I am curious what your thoughts on this are! Should we add some kind of functionality that HEAD will stay the same when receiving a 303 (which is not explicitly mentioned inside the RFC)? |
dinooo13 commented Feb 15, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Okay I will update to only handle 307/308, yes it's better to address these when they actually become problems (YAGNI again 😄 ). Actually I found this in the RFC regarding 303 HEAD requests:
|
dinooo13 commented Jun 24, 2022
Updated this PR to only handle 303, 307 and 308. 303 will be converted to GET. 307 and 308 will preserve their methods and body. All others should have the same behavior as before. |
SimonFrings commented Jun 28, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@dinooo13 Looking good, but I still think the logic for 303 should use the default behavior (HEAD stays HEAD and GET stays GET). The logic behind your code works great, I am not quite sure if we're introducing to much complexity by adding two new methods. I came up with a shorter version of your code, still the same logic: privatefunctiononResponseRedirect(ResponseInterface$response, RequestInterface$request, Deferred$deferred, ClientRequestState$state){// resolve location relative to last request URI$location = Uri::resolve($request->getUri(), $response->getHeaderLine('Location')); $request = $this->makeRedirectRequest($request, $location, $response->getStatusCode()); $this->progress('redirect', array($request)); if ($state->numRequests >= $this->maxRedirects){thrownew \RuntimeException('Maximum number of redirects (' . $this->maxRedirects . ') exceeded')} return$this->next($request, $deferred, $state)}The first code block shows the privatefunctionmakeRedirectRequest(RequestInterface$request, UriInterface$location, Int$statusCode){$originalHost = $request->getUri()->getHost(); $request = $request->withoutHeader('Host'); if ($statusCode !== 307 || $statusCode !== 308){$request = $request ->withoutHeader('Content-Type') ->withoutHeader('Content-Length')} // Remove authorization if changing hostnames (but not if just changing ports or protocols).if ($location->getHost() !== $originalHost){$request = $request->withoutHeader('Authorization')} $body = null; if ($statusCode === 307 || $statusCode === 308){$method = $request->getMethod(); $body = $request->getBody()} else{// naïve approach..$method = ($request->getMethod() === 'HEAD') ? 'HEAD' : 'GET'} returnnewRequest($method, $location, $request->getHeaders(), $body)}The second block shows the The only thing I don't know how to handle yet are streaming bodies. The original request would send the whole body before the redirect response arrives. This means the new request can't contain the same body (data is already sent). What are your thoughts on this? |
dinooo13 commented Jun 28, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Nice yes I think this really simplifies it. I found this about how Chrome handles this with the fetch API:
https://web.dev/fetch-upload-streaming/#restricted-redirects I think this sums it up pretty good, it just makes no sense to redirect a stream. |
SimonFrings commented Jun 29, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Seems like this is the way to go then 👍 I also found this inside the Guzzle documentation, throwing an exception in this case could be the answer for this ticket too. They're also using some kind of repeatable streams, this could be something for a follow up PR maybe ^^ |
dinooo13 commented Jul 1, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Hey I updated the PR with your suggestions and added an exception and a test. Please have a close look at the new test I'm not 100% sure if it's correct. I'm also curious what you think about adding an exception with basically only a default message and a name should we even bother then? I think a hint in the documentation on reactphp.org would also be good to have. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
dinooo13 commented Jul 23, 2022
I'm not sure if the re-request review button worked you may now have no or quite a few requests 🤣 |
WyriHaximus commented Aug 10, 2022
Looks like even I can't re-request @SimonFrings' review 😱 |
WyriHaximus left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
SimonFrings commented Aug 12, 2022 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@WyriHaximus Could be a sign, but I am here anyway ^^ @dinooo13 Changes are looking great, the last thing I want to mention is the amount of commits for this. I don't think it is necessary to have 10 commits for this, can you squash them together into one? After that this is ready to be merged! 👍 |
dinooo13 commented Aug 12, 2022
Can u maybe enable this on the repo or am I just not seeing this option? This would make it way easier to merge PRs. But I can also squash manually in the evening I think. |
c4fdb04 to 48fa053Comparedinooo13 commented Aug 12, 2022
Everything squashed 😄 |
SimonFrings left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one 👍
SimonFrings commented Sep 14, 2022
Ping @clue, this is ready for review 👍 |
clue left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dinooo13 Some good progress, would love to get this in! 👍 See minor remarks below, otherwise LGTM 👍
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
010a828 to f56c1fdCompare
SimonFrings left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
230c60d to b1102dcComparedinooo13 commented Sep 16, 2022
LGTM! I applied your suggestions 👍🏼 |
SimonFrings commented Sep 19, 2022
@dinooo13 Nice, now you only need to squash your commits ;) |
7afa045 to c259432Comparedinooo13 commented Sep 19, 2022
Oh I think I messed something up squashing I will fix this in the evening |
dinooo13 commented Sep 19, 2022
Or not as it seems 😆 thought the checks failed but looks good |
clue left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dinooo13 Thanks for the update! Changes LGTM, but perhaps we can add some additional tests like suggested below?
Also, the documentation currently says "If the original request contained a request body, this request body will never be passed to the redirected request. Accordingly, each redirected request will remove any Content-Length and Content-Type request headers.", should we update this as part of this PR?
Keep it up! 👍
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
c259432 to 6d8ad82Comparedinooo13 commented Sep 28, 2022
Added asserts for the headers in the tests as suggested and 🔥'd the whitespace |
SimonFrings commented Sep 29, 2022
Nice one 👍 Have you also seen @clue's comment regarding the
|
dinooo13 commented Sep 29, 2022
Ahh I thought this was about checking the headers have been removed in the test with See Other as status code. I will update the Readme! |
6d8ad82 to 2290723Compare307 Temporary Redirect and 308 Permanent Redirect
clue left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dinooo13 Thank you very much for looking into this, changes LGTM! Keep it up! ![]()
Should close#409
303 See Other should change the method to GET all other redirects should leave it unchanged
(Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages)
I think there are some specialties for 300 and 304 which I ignored for now, but I could look further into it if you wish.