-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Gzip decoder returns too early while consuming TCP fragmented chuncked body #2381
Comments
Seems like I've found out a reason. reqwest/src/async_impl/decoder.rs Lines 468 to 472 in 8c7f338
#[cfg(feature = "gzip")]
DecoderType::Gzip => Poll::Ready(Ok(Inner::Gzip(Box::pin(FramedRead::new(
{
let mut d = GzipDecoder::new(StreamReader::new(_body));
d.multiple_members(true);
d
},
BytesCodec::new(),
))))), And now it works as expected! Should all other decoders be created with this option enabled? I think yes. Should this option be enabled only if
But response processing hangs up when neither And I'm not sure how multiple-resource bodies should be processed. https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages#body_2 |
…nstar#2484) When a response body is being decompressed, and the length wasn't known, but was using chunked transfer-encoding, the remaining `0\r\n\r\n` was not consumed. That would leave the connection in a state that could be not be reused, and so the pool had to discard it. This fix makes sure the remaining end chunk is consumed, improving the amount of pooled connections that can be reused. Closes seanmonstar#2381
Hello. I believe a found a bug. It doesn't make HTTP response incorrect but it effectively disables connection reusing.
![reqwest-bug-diagram](https://private-user-images.githubusercontent.com/35865938/357254129-f1a7fd97-7919-4c6e-b7b9-15c98a5c681b.svg?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk4NzcwMzUsIm5iZiI6MTczOTg3NjczNSwicGF0aCI6Ii8zNTg2NTkzOC8zNTcyNTQxMjktZjFhN2ZkOTctNzkxOS00YzZlLWI3YjktMTVjOThhNWM2ODFiLnN2Zz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjE4VDExMDUzNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTUxYTI4M2I1NWM3OWMwMzg5ZDM3NGNjMjlmOGI4YmNkM2JlOTRkZTRkYWM4ZmRkOGE0MTFkMDQzMGJjMTM4MmYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.yEHu-gd-0yRmkrdT4Ssb_M5Ar-ohn19y6PG9ZF1YIlM)
I drew a diagram for such case.
As you can see Client (with activated
gzip
feature) sends request to server. Server responds with chunked gzipped body, but body somehow is fragmented at TCP level (see diagram) and those fragments are divided by some time (milliseconds at least, so you can'tread()
them together with one call). But first fragment contains whole gzipped bytes.Gzip decoder returns (and, as consequence, Response::text() call too) immediately after decoding last encoded byte, i.e. it doesn't wait for full response body arrival. And then Response is dropped (because Response::text() consumes Response). And it prevents connection from being put back in pool and being reused (because connection itself is still waiting for bytes from server).
I created minimal reproduction https://github.com/Andrey36652/reqwest-chunked-bug where client shoud make 3 consecutive requests to the server that responds with fragmented body (there is a 4 seconds delay between the fragments, so it should be ~12 seconds in total). But when I run it, all 3 requests are resolved immediately as you can see from timestamps (and each uses new connection).
If I disable gzip deconding in Client (uncomment line in
src/client.rs
) then behaviour is correct - each request waits until full body will be consumed and returns only after that moment.I don't know if an error is in
reqwest
or inasync-compression
crate, and I'm afraid my knowledge isn't enough to find a solution.The text was updated successfully, but these errors were encountered: