Skip to content

Commit e1aeab3

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

File tree

3 files changed

+81
-7
lines changed

3 files changed

+81
-7
lines changed

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

Lines changed: 30 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,14 @@ 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+
if output.written_len() > 0 {
60+
return ControlFlow::Break(Ok(()));
61+
} else {
62+
continue;
63+
}
64+
}
5865
// poll for more data for the next decode
5966
_ => break,
6067
}
@@ -66,7 +73,12 @@ impl Decoder {
6673
Ok(true) => {
6774
if self.multiple_members {
6875
if let Err(err) = decoder.reinit() {
69-
return ControlFlow::Break(Err(err));
76+
self.state = State::Error(err);
77+
if output.written_len() > 0 {
78+
return ControlFlow::Break(Ok(()));
79+
} else {
80+
continue;
81+
}
7082
}
7183

7284
// The decode stage might consume all the input,
@@ -78,7 +90,14 @@ impl Decoder {
7890
}
7991
}
8092
Ok(false) => State::Flushing,
81-
Err(err) => return ControlFlow::Break(Err(err)),
93+
Err(err) => {
94+
self.state = State::Error(err);
95+
if output.written_len() > 0 {
96+
return ControlFlow::Break(Ok(()));
97+
} else {
98+
continue;
99+
}
100+
}
82101
}
83102
}
84103

@@ -95,6 +114,13 @@ impl Decoder {
95114
State::Decoding
96115
}
97116
}
117+
118+
State::Error(_) => {
119+
let State::Error(err) = std::mem::replace(&mut self.state, State::Done) else {
120+
unreachable!()
121+
};
122+
return ControlFlow::Break(Err(err));
123+
}
98124
};
99125

100126
if output.has_no_spare_space() {

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ enum State {
1010
Flushing,
1111
Finishing,
1212
Done,
13+
Error(std::io::Error),
1314
}
1415

1516
#[derive(Debug)]
@@ -53,7 +54,12 @@ impl Encoder {
5354
State::Finishing
5455
} else {
5556
if let Err(err) = encoder.encode(input, output) {
56-
return ControlFlow::Break(Err(err));
57+
self.state = State::Error(err);
58+
if output.written_len() > 0 {
59+
return ControlFlow::Break(Ok(()));
60+
} else {
61+
continue;
62+
}
5763
}
5864

5965
read += input.written().len();
@@ -72,16 +78,37 @@ impl Encoder {
7278
break;
7379
}
7480
Ok(false) => State::Flushing,
75-
Err(err) => return ControlFlow::Break(Err(err)),
81+
Err(err) => {
82+
self.state = State::Error(err);
83+
if output.written_len() > 0 {
84+
return ControlFlow::Break(Ok(()));
85+
} else {
86+
continue;
87+
}
88+
}
7689
},
7790

7891
State::Finishing => match encoder.finish(output) {
7992
Ok(true) => State::Done,
8093
Ok(false) => State::Finishing,
81-
Err(err) => return ControlFlow::Break(Err(err)),
94+
Err(err) => {
95+
self.state = State::Error(err);
96+
if output.written_len() > 0 {
97+
return ControlFlow::Break(Ok(()));
98+
} else {
99+
continue;
100+
}
101+
}
82102
},
83103

84104
State::Done => return ControlFlow::Break(Ok(())),
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+
}
85112
};
86113

87114
if output.has_no_spare_space() {

crates/async-compression/tests/gzip.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,24 @@ 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+
use flate2::bufread::GzDecoder;
60+
use std::io::Read;
61+
62+
let mut bytes = compress_with_header(&[1, 2, 3, 4, 5, 6]);
63+
64+
// Remove the footer.
65+
bytes.truncate(bytes.len() - 8);
66+
67+
let mut decoder = GzDecoder::new(bytes.as_slice());
68+
69+
let mut output = vec![];
70+
let result = decoder.read_to_end(&mut output);
71+
72+
assert!(result.is_err());
73+
assert_eq!(output, &[1, 2, 3, 4, 5, 6][..]);
74+
}

0 commit comments

Comments
 (0)