From ed83d67f71385be3379e6829c7187ab8c230eedd Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 8 Oct 2024 21:05:55 +0000 Subject: [PATCH] fix(tokio): attempt to decode from internal state even if nothing was read Unlike zlib, miniz_oxide consumes data into internal state even if there is not enough space in the output buffer. Next time poll_fill_buf() is called we should try to decode from internal state even if no new compressed data was read. This change is a port of fix (commit https://github.com/Nullus157/async-compression/commit/22ed0ac4caf5d60628ff8836dd1dc2d3289cf43f) from `futures` to `tokio`. --- src/tokio/bufread/generic/decoder.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/tokio/bufread/generic/decoder.rs b/src/tokio/bufread/generic/decoder.rs index 2f4d8c7f..aa568f4f 100644 --- a/src/tokio/bufread/generic/decoder.rs +++ b/src/tokio/bufread/generic/decoder.rs @@ -65,18 +65,37 @@ impl Decoder { ) -> Poll> { let mut this = self.project(); + let mut first = true; + loop { *this.state = match this.state { State::Decoding => { - let input = ready!(this.reader.as_mut().poll_fill_buf(cx))?; - if input.is_empty() { + let input = if first { + &[][..] + } else { + ready!(this.reader.as_mut().poll_fill_buf(cx))? + }; + + if input.is_empty() && !first { // Avoid attempting to reinitialise the decoder if the reader // has returned EOF. *this.multiple_members = false; + State::Flushing } else { let mut input = PartialBuffer::new(input); - let done = this.decoder.decode(&mut input, output)?; + let done = this.decoder.decode(&mut input, output).or_else(|err| { + // ignore the first error, occurs when input is empty + // but we need to run decode to flush + if first { + Ok(false) + } else { + Err(err) + } + })?; + + first = false; + let len = input.written().len(); this.reader.as_mut().consume(len); if done {