diff --git a/tower-http/src/compression/mod.rs b/tower-http/src/compression/mod.rs index 080d1d51..5107fac3 100644 --- a/tower-http/src/compression/mod.rs +++ b/tower-http/src/compression/mod.rs @@ -98,7 +98,7 @@ mod tests { use http::header::{ ACCEPT_ENCODING, ACCEPT_RANGES, CONTENT_ENCODING, CONTENT_RANGE, CONTENT_TYPE, RANGE, }; - use http::{HeaderMap, HeaderName, Request, Response}; + use http::{HeaderMap, HeaderName, HeaderValue, Request, Response}; use http_body_util::BodyExt; use std::convert::Infallible; use std::io::Read; @@ -150,6 +150,46 @@ mod tests { assert_eq!(trailers["foo"], "bar"); } + #[tokio::test] + async fn x_gzip_works() { + let svc = service_fn(handle); + let mut svc = Compression::new(svc).compress_when(Always); + + // call the service + let req = Request::builder() + .header("accept-encoding", "x-gzip") + .body(Body::empty()) + .unwrap(); + let res = svc.ready().await.unwrap().call(req).await.unwrap(); + + // we treat x-gzip as equivalent to gzip and don't have to return x-gzip + // taking extra caution by checking all headers with this name + assert_eq!( + res.headers() + .get_all("content-encoding") + .iter() + .collect::>(), + vec!(HeaderValue::from_static("gzip")) + ); + + // read the compressed body + let collected = res.into_body().collect().await.unwrap(); + let trailers = collected.trailers().cloned().unwrap(); + let compressed_data = collected.to_bytes(); + + // decompress the body + // doing this with flate2 as that is much easier than async-compression and blocking during + // tests is fine + let mut decoder = GzDecoder::new(&compressed_data[..]); + let mut decompressed = String::new(); + decoder.read_to_string(&mut decompressed).unwrap(); + + assert_eq!(decompressed, "Hello, World!"); + + // trailers are maintained + assert_eq!(trailers["foo"], "bar"); + } + #[tokio::test] async fn zstd_works() { let svc = service_fn(handle); diff --git a/tower-http/src/content_encoding.rs b/tower-http/src/content_encoding.rs index 9273a0f3..11860726 100644 --- a/tower-http/src/content_encoding.rs +++ b/tower-http/src/content_encoding.rs @@ -61,7 +61,9 @@ impl Encoding { ))] fn parse(s: &str, _supported_encoding: impl SupportedEncodings) -> Option { #[cfg(any(feature = "fs", feature = "compression-gzip"))] - if s.eq_ignore_ascii_case("gzip") && _supported_encoding.gzip() { + if (s.eq_ignore_ascii_case("gzip") || s.eq_ignore_ascii_case("x-gzip")) + && _supported_encoding.gzip() + { return Some(Encoding::Gzip); } @@ -297,6 +299,28 @@ mod tests { assert_eq!(Encoding::Brotli, encoding); } + #[test] + fn accept_encoding_header_gzip_x_gzip() { + let mut headers = http::HeaderMap::new(); + headers.append( + http::header::ACCEPT_ENCODING, + http::HeaderValue::from_static("gzip,x-gzip"), + ); + let encoding = Encoding::from_headers(&headers, SupportedEncodingsAll); + assert_eq!(Encoding::Gzip, encoding); + } + + #[test] + fn accept_encoding_header_x_gzip_deflate() { + let mut headers = http::HeaderMap::new(); + headers.append( + http::header::ACCEPT_ENCODING, + http::HeaderValue::from_static("deflate,x-gzip"), + ); + let encoding = Encoding::from_headers(&headers, SupportedEncodingsAll); + assert_eq!(Encoding::Gzip, encoding); + } + #[test] fn accept_encoding_header_three_encodings() { let mut headers = http::HeaderMap::new();