Skip to content

Commit 1fe4c09

Browse files
authored
fix(decompression): disable multiple_members option for gzip decoder (#621)
This was mistakenly enabled previously, but it does not make sense in an HTTP context.
1 parent 3bf1ba7 commit 1fe4c09

File tree

3 files changed

+50
-44
lines changed

3 files changed

+50
-44
lines changed

tower-http/src/compression_utils.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,23 @@ where
237237

238238
// poll any remaining frames, such as trailers
239239
let body = M::get_pin_mut(this.read).get_pin_mut().get_pin_mut();
240-
body.poll_frame(cx).map(|option| {
241-
option.map(|result| {
242-
result
243-
.map(|frame| frame.map_data(|mut data| data.copy_to_bytes(data.remaining())))
244-
.map_err(|err| err.into())
245-
})
246-
})
240+
match ready!(body.poll_frame(cx)) {
241+
Some(Ok(frame)) if frame.is_trailers() => Poll::Ready(Some(Ok(
242+
frame.map_data(|mut data| data.copy_to_bytes(data.remaining()))
243+
))),
244+
Some(Ok(frame)) => {
245+
if let Ok(bytes) = frame.into_data() {
246+
if bytes.has_remaining() {
247+
return Poll::Ready(Some(Err(
248+
"there are extra bytes after body has been decompressed".into(),
249+
)));
250+
}
251+
}
252+
Poll::Ready(None)
253+
}
254+
Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
255+
None => Poll::Ready(None),
256+
}
247257
}
248258
}
249259

tower-http/src/decompression/body.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,7 @@ where
344344
type Output = GzipDecoder<Self::Input>;
345345

346346
fn apply(input: Self::Input, _quality: CompressionLevel) -> Self::Output {
347-
let mut decoder = GzipDecoder::new(input);
348-
decoder.multiple_members(true);
349-
decoder
347+
GzipDecoder::new(input)
350348
}
351349

352350
fn get_pin_mut(pinned: Pin<&mut Self::Output>) -> Pin<&mut Self::Input> {

tower-http/src/decompression/mod.rs

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -150,24 +150,6 @@ mod tests {
150150
Ok(Response::builder().body(body).unwrap())
151151
}
152152

153-
#[tokio::test]
154-
async fn decompress_multi_gz() {
155-
let mut client = Decompression::new(service_fn(handle_multi_gz));
156-
157-
let req = Request::builder()
158-
.header("accept-encoding", "gzip")
159-
.body(Body::empty())
160-
.unwrap();
161-
let res = client.ready().await.unwrap().call(req).await.unwrap();
162-
163-
// read the body, it will be decompressed automatically
164-
let body = res.into_body();
165-
let decompressed_data =
166-
String::from_utf8(body.collect().await.unwrap().to_bytes().to_vec()).unwrap();
167-
168-
assert_eq!(decompressed_data, "Hello, World!");
169-
}
170-
171153
#[tokio::test]
172154
async fn decompress_multi_zstd() {
173155
let mut client = Decompression::new(service_fn(handle_multi_zstd));
@@ -186,22 +168,6 @@ mod tests {
186168
assert_eq!(decompressed_data, "Hello, World!");
187169
}
188170

189-
async fn handle_multi_gz(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
190-
let mut buf = Vec::new();
191-
let mut enc1 = GzEncoder::new(&mut buf, Default::default());
192-
enc1.write_all(b"Hello, ").unwrap();
193-
enc1.finish().unwrap();
194-
195-
let mut enc2 = GzEncoder::new(&mut buf, Default::default());
196-
enc2.write_all(b"World!").unwrap();
197-
enc2.finish().unwrap();
198-
199-
let mut res = Response::new(Body::from(buf));
200-
res.headers_mut()
201-
.insert("content-encoding", "gzip".parse().unwrap());
202-
Ok(res)
203-
}
204-
205171
async fn handle_multi_zstd(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
206172
let mut buf = Vec::new();
207173
let mut enc1 = zstd::Encoder::new(&mut buf, Default::default()).unwrap();
@@ -254,4 +220,36 @@ mod tests {
254220
.insert("content-encoding", "gzip".parse().unwrap());
255221
Ok(res)
256222
}
223+
224+
#[tokio::test]
225+
async fn decompress_empty_with_trailers() {
226+
let mut client =
227+
Decompression::new(Compression::new(service_fn(handle_empty_with_trailers)));
228+
229+
let req = Request::builder()
230+
.header("accept-encoding", "gzip")
231+
.body(Body::empty())
232+
.unwrap();
233+
let res = client.ready().await.unwrap().call(req).await.unwrap();
234+
235+
let body = res.into_body();
236+
let collected = body.collect().await.unwrap();
237+
let trailers = collected.trailers().cloned().unwrap();
238+
let decompressed_data = String::from_utf8(collected.to_bytes().to_vec()).unwrap();
239+
240+
assert_eq!(decompressed_data, "");
241+
assert_eq!(trailers["foo"], "bar");
242+
}
243+
244+
async fn handle_empty_with_trailers(
245+
_req: Request<Body>,
246+
) -> Result<Response<WithTrailers<Body>>, Infallible> {
247+
let mut trailers = HeaderMap::new();
248+
trailers.insert(HeaderName::from_static("foo"), "bar".parse().unwrap());
249+
let body = Body::empty().with_trailers(trailers);
250+
Ok(Response::builder()
251+
.header("content-encoding", "gzip")
252+
.body(body)
253+
.unwrap())
254+
}
257255
}

0 commit comments

Comments
 (0)