From 6e504c3735f398f06391104827546bbff02b71b5 Mon Sep 17 00:00:00 2001 From: Malloc Voidstar <1284317+AlyoshaVasilieva@users.noreply.github.com> Date: Sun, 26 May 2024 15:46:04 -0700 Subject: [PATCH] Add test for zstd window size Also bump the version of the zstd dev dependency. --- tower-http/Cargo.toml | 2 +- tower-http/src/compression/layer.rs | 37 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tower-http/Cargo.toml b/tower-http/Cargo.toml index f9ad55ec..9ee353b7 100644 --- a/tower-http/Cargo.toml +++ b/tower-http/Cargo.toml @@ -55,7 +55,7 @@ tokio = { version = "1", features = ["full"] } tower = { version = "0.4.10", features = ["buffer", "util", "retry", "make", "timeout"] } tracing-subscriber = "0.3" uuid = { version = "1.0", features = ["v4"] } -zstd = "0.12" +zstd = "0.13" [features] default = [] diff --git a/tower-http/src/compression/layer.rs b/tower-http/src/compression/layer.rs index 9d7fa801..5eca0c50 100644 --- a/tower-http/src/compression/layer.rs +++ b/tower-http/src/compression/layer.rs @@ -200,4 +200,41 @@ mod tests { Ok(()) } + + /// Test ensuring that zstd compression will not exceed an 8MiB window size; browsers do not + /// accept responses using 16MiB+ window sizes. + #[tokio::test] + async fn zstd_is_web_safe() -> Result<(), crate::BoxError> { + async fn zeroes(_req: Request) -> Result, Infallible> { + Ok(Response::new(Body::from(vec![0u8; 18_874_368]))) + } + // zstd will (I believe) lower its window size if a larger one isn't beneficial and + // it knows the size of the input; use an 18MiB body to ensure it would want a + // >=16MiB window (though it might not be able to see the input size here). + + let zstd_layer = CompressionLayer::new() + .quality(CompressionLevel::Best) + .no_br() + .no_deflate() + .no_gzip(); + + let mut service = ServiceBuilder::new().layer(zstd_layer).service_fn(zeroes); + + let request = Request::builder() + .header(ACCEPT_ENCODING, "zstd") + .body(Body::empty())?; + + let response = service.ready().await?.call(request).await?; + + assert_eq!(response.headers()["content-encoding"], "zstd"); + + let body = response.into_body(); + let bytes = body.collect().await?.to_bytes(); + let mut dec = zstd::Decoder::new(&*bytes)?; + dec.window_log_max(23)?; // Limit window size accepted by decoder to 2 ^ 23 bytes (8MiB) + + std::io::copy(&mut dec, &mut std::io::sink())?; + + Ok(()) + } }