-
Notifications
You must be signed in to change notification settings - Fork 177
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
Redirect 307 / 308 correctly #187
Comments
Thanks for filing, and welcome to the repo! I've been wanting to get this done for a while. It sounds like your proposal has two parts:
Is that right? |
Can we solve this with a buffer of configurable size? (This is an idea @jsha started) The default buffer size would be some multiple of a probable initial TCP window size, meaning the server would have a chance to send the 307/308 response while the client sending more than the buffer size is "held back" by TCP flow control. Obviously probable initial TCP window size is a bit moot, so the user should be able to configure this for In addition, such a buffer could means for small |
A straightforward way could be added. However, I think that all creations of the
I would have replaced the current
This might be a very interesting idea. I'm not too sure about the intricacies of HTTP and if the server must respond with 307 / 308 when only receiving a partial payload, or if it might be allowed to hold back the response until the whole payload is received. I could imagine a reverse proxy like nginx buffering several chunks before forwarding them as a single chunk to the original server. Otherwise I think this could be an interesting idea. |
I suspect that's entirely up to the HTTP server, but it would be kinda awkward to support 307/308 without also considering the case of aborting uploads of large bodies. A related technique that we might want to consider is expect 100-continue. Curl has a default 1 second delay before sending the body, in which the server has a chance to respond with some other code aborting the body send. That's another way to do it, which could be done for 307/308 in addition to buffering.
During steps 3-4 the server can successfully respond with 307/308. |
Part of our user-facing API is:
I'd prefer not to add a
Personally I've never seen any HTTP server do something like this. It would require some fairly custom code in most HTTP server implementations, but more importantly it would require client cooperation. Specifically, the client would have to send some of the body, then do a non-blocking read from the response stream to see if the server responded early. That's pretty unusual - though perhaps more common in the HTTP/2 world? I think algesten's on the right track, that this is the sort of problem One thing that would help us reach a good design: Can you give examples of real-world APIs or websites that return 307 or 308? If we design around making those real use cases work well, I think we'll wind up with something good. |
Expect: 100-continue looks like the correct fix here. And if curl does something, it should be perfect do copy its behaviour. I noticed the missing 308 redirection when making a GET request to the gitlab.com API. If you include a double-slash in the request, e.g. try to request https://gitlab.com/api/v4//groups, it returns a 308 redirecting to the URL without the double-slash. |
Lol.. And here I was thinking that would be the norm, cause how would you otherwise detect "early" response headers? … Any early 3xx, 4xx or 5xx is an opportunity to abort sending a big body. Maybe I'm tainted by h2 :D |
On the flip side (a little off-topic but it's entertaining IMO), there are some servers out there that will send you a response as soon as you connect, without even waiting for a request! This gives up any opportunity to serve different responses for different requests, but the hosts I've seen it on seem to be serving analytics JS at very large scale. It's probably a significant performance win, and they're always only serving the same JS anyhow. |
I'm not sure the current status of this, but deadlinks would like this to avoid having to deal with redirects itself: deadlinks/cargo-deadlinks#110. It would be fine by me to treat it exactly the same as 301/302. |
Note that since #288 307/308 are followed for GET/HEAD, which should help the majority of use cases. For PUT/POST/DELETE you still have to handle the error yourself. |
This feature was already tried to be implemented. However, when sending the request, the body is consumed (due to being
dyn Read
), so it can't be sent again for the 307 or 308 redirect, which requires the same request to be sent again.ureq/src/unit.rs
Lines 237 to 238 in 5b75dec
From what I can tell so far after looking at the source, we can reset any
Payload
back to the beginning, except the genericReader(Box<dyn Read + 'static>)
. If this reader also implementedSeek
, we would be able to get its position before starting the body-write, and reset it to that position on a 307 / 308 to read from it again. However, this would be a breaking API change toRequest::send(&mut self, reader: impl Read + 'static) -> Response
as the argument now also needs to implementSeek
. (Additionally,io::Empty
currently doesn't implementSeek
, for which I opened rust-lang/rust#78029.)Another option would be to require the reader to be
Clone
, however I'd see that as a strictly worse version ofSeek
.The text was updated successfully, but these errors were encountered: