Skip to content

Commit 31a4e72

Browse files
committed
On error the decoder now emits everything it was able to decode.
Before this we would return the error and whatever we had in our decoded buffer would be swallowed. Fixes #453.
1 parent 0370b47 commit 31a4e72

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

crates/async-compression/src/generic/bufread/decoder.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::{
22
codecs::DecodeV2,
33
core::util::{PartialBuffer, WriteBuffer},
44
};
5-
65
use std::{io::Result, ops::ControlFlow};
76

87
#[derive(Debug)]
@@ -11,6 +10,7 @@ enum State {
1110
Flushing,
1211
Done,
1312
Next,
13+
Error(std::io::Error),
1414
}
1515

1616
#[derive(Debug)]
@@ -54,7 +54,10 @@ impl Decoder {
5454
Ok(true) => State::Flushing,
5555
// ignore the first error, occurs when input is empty
5656
// but we need to run decode to flush
57-
Err(err) if !first => return ControlFlow::Break(Err(err)),
57+
Err(err) if !first => {
58+
self.state = State::Error(err);
59+
return ControlFlow::Break(Ok(()));
60+
}
5861
// poll for more data for the next decode
5962
_ => break,
6063
}
@@ -66,7 +69,8 @@ impl Decoder {
6669
Ok(true) => {
6770
if self.multiple_members {
6871
if let Err(err) = decoder.reinit() {
69-
return ControlFlow::Break(Err(err));
72+
self.state = State::Error(err);
73+
return ControlFlow::Break(Ok(()));
7074
}
7175

7276
// The decode stage might consume all the input,
@@ -78,7 +82,10 @@ impl Decoder {
7882
}
7983
}
8084
Ok(false) => State::Flushing,
81-
Err(err) => return ControlFlow::Break(Err(err)),
85+
Err(err) => {
86+
self.state = State::Error(err);
87+
return ControlFlow::Break(Ok(()));
88+
}
8289
}
8390
}
8491

@@ -95,6 +102,13 @@ impl Decoder {
95102
State::Decoding
96103
}
97104
}
105+
106+
State::Error(_) => {
107+
let State::Error(err) = std::mem::replace(&mut self.state, State::Done) else {
108+
unreachable!()
109+
};
110+
return ControlFlow::Break(Err(err));
111+
}
98112
};
99113

100114
if output.has_no_spare_space() {

crates/async-compression/tests/gzip.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,18 @@ fn gzip_bufread_chunks_decompress_with_extra_header() {
5151

5252
assert_eq!(output, &[1, 2, 3, 4, 5, 6][..]);
5353
}
54+
55+
#[test]
56+
#[ntest::timeout(1000)]
57+
#[cfg(feature = "futures-io")]
58+
fn gzip_bufread_chunks_decompress_without_footer_emits_all_payload() {
59+
let mut bytes = compress_with_header(&[1, 2, 3, 4, 5, 6]);
60+
61+
// Remove the footer.
62+
bytes.truncate(bytes.len() - 8);
63+
64+
let input = InputStream::from(bytes.chunks(2));
65+
let output = bufread::decompress(bufread::from(&input));
66+
67+
assert_eq!(output, &[1, 2, 3, 4, 5, 6][..]);
68+
}

0 commit comments

Comments
 (0)