From 833bec4b8da309da3965d49a303d6df4bf7d71a1 Mon Sep 17 00:00:00 2001 From: valkyrie_pilot Date: Fri, 5 Jan 2024 00:47:30 -0700 Subject: [PATCH 01/11] support servefile zstd (#450) * support servefile zstd * Add zstd serve_file test * ZStd precompressed file - RustRover did not show that it needed to be added --- test-files/precompressed.txt.zst | Bin 0 -> 36 bytes tower-http/src/services/fs/serve_file.rs | 35 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test-files/precompressed.txt.zst diff --git a/test-files/precompressed.txt.zst b/test-files/precompressed.txt.zst new file mode 100644 index 0000000000000000000000000000000000000000..813fc9557c066ce0ab9c61d4fdead4f6da8b8121 GIT binary patch literal 36 qcmdPcs{dC-d?y2gQbue!DwL!amnfuV=A Self { + Self(self.0.precompressed_zstd()) + } + /// Set a specific read buffer chunk size. /// /// The default capacity is 64kb. @@ -129,6 +143,7 @@ where mod tests { use crate::services::ServeFile; use crate::test_helpers::Body; + use async_compression::tokio::bufread::ZstdDecoder; use brotli::BrotliDecompress; use flate2::bufread::DeflateDecoder; use flate2::bufread::GzDecoder; @@ -139,6 +154,7 @@ mod tests { use mime::Mime; use std::io::Read; use std::str::FromStr; + use tokio::io::AsyncReadExt; use tower::ServiceExt; #[tokio::test] @@ -342,6 +358,25 @@ mod tests { assert!(decompressed.starts_with("\"This is a test file!\"")); } + #[tokio::test] + async fn precompressed_zstd() { + let svc = ServeFile::new("../test-files/precompressed.txt").precompressed_zstd(); + let request = Request::builder() + .header("Accept-Encoding", "zstd,br") + .body(Body::empty()) + .unwrap(); + let res = svc.oneshot(request).await.unwrap(); + + assert_eq!(res.headers()["content-type"], "text/plain"); + assert_eq!(res.headers()["content-encoding"], "zstd"); + + let body = res.into_body().collect().await.unwrap().to_bytes(); + let mut decoder = ZstdDecoder::new(&body[..]); + let mut decompressed = String::new(); + decoder.read_to_string(&mut decompressed).await.unwrap(); + assert!(decompressed.starts_with("\"This is a test file!\"")); + } + #[tokio::test] async fn multi_precompressed() { let svc = ServeFile::new("../test-files/precompressed.txt") From ed963f189d9d2942b6c7e35cb1a5e905c74e5187 Mon Sep 17 00:00:00 2001 From: Oliver THEBAULT Date: Sat, 13 Jan 2024 21:36:35 +0100 Subject: [PATCH 02/11] examples: Migrate axum-key-value-store to hyper 1 --- examples/axum-key-value-store/Cargo.toml | 9 ++++----- examples/axum-key-value-store/src/main.rs | 19 +++++++------------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/examples/axum-key-value-store/Cargo.toml b/examples/axum-key-value-store/Cargo.toml index 2ac9475e..c8775c9b 100644 --- a/examples/axum-key-value-store/Cargo.toml +++ b/examples/axum-key-value-store/Cargo.toml @@ -7,11 +7,10 @@ publish = false license = "MIT" [dependencies] -hyper = { version = "0.14.15", features = ["full"] } -tokio = { version = "1.2.0", features = ["full"] } +tokio = { version = "1.32.0", features = ["full"] } tower = { version = "0.4.13", features = ["full"] } tower-http = { path = "../../tower-http", features = ["full"] } tracing = "0.1" -tracing-subscriber = { version = "0.3.11", features = ["env-filter"] } -axum = "0.6" -clap = { version = "4.3.16", features = ["derive"] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +axum = "0.7" +clap = { version = "4.4.4", features = ["derive"] } diff --git a/examples/axum-key-value-store/src/main.rs b/examples/axum-key-value-store/src/main.rs index a5e5a327..2f1b42de 100644 --- a/examples/axum-key-value-store/src/main.rs +++ b/examples/axum-key-value-store/src/main.rs @@ -1,8 +1,3 @@ -fn main() { - eprintln!("this example has not yet been updated to hyper 1.0"); -} - -/* use axum::{ body::Bytes, extract::{Path, State}, @@ -18,6 +13,7 @@ use std::{ sync::{Arc, RwLock}, time::Duration, }; +use tokio::net::TcpListener; use tower::ServiceBuilder; use tower_http::{ timeout::TimeoutLayer, @@ -49,10 +45,12 @@ async fn main() { // Run our service let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, config.port)); tracing::info!("Listening on {}", addr); - axum::Server::bind(&addr) - .serve(app().into_make_service()) - .await - .expect("server error"); + axum::serve( + TcpListener::bind(addr).await.expect("bind error"), + app().into_make_service(), + ) + .await + .expect("server error"); } fn app() -> Router { @@ -79,8 +77,6 @@ fn app() -> Router { .sensitive_response_headers(sensitive_headers) // Set a timeout .layer(TimeoutLayer::new(Duration::from_secs(10))) - // Box the response body so it implements `Default` which is required by axum - .map_response_body(axum::body::boxed) // Compress responses .compression() // Set a `Content-Type` if there isn't one already. @@ -113,4 +109,3 @@ async fn set_key(Path(path): Path, state: State, value: Bytes) // See https://github.com/tokio-rs/axum/blob/main/examples/testing/src/main.rs for an example of // how to test axum apps -*/ From 503217c6d688ddeb63c611c6de89e79673fdb8d6 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 17 Aug 2023 13:17:01 +0200 Subject: [PATCH 03/11] cors: Send a single vary header with comma-separated values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … instead of multiple vary headers. --- tower-http/src/cors/mod.rs | 16 +--------------- tower-http/src/cors/vary.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/tower-http/src/cors/mod.rs b/tower-http/src/cors/mod.rs index 0dac8e6b..6883ac31 100644 --- a/tower-http/src/cors/mod.rs +++ b/tower-http/src/cors/mod.rs @@ -618,24 +618,10 @@ where // These headers are applied to both preflight and subsequent regular CORS requests: // https://fetch.spec.whatwg.org/#http-responses - headers.extend(self.layer.allow_origin.to_header(origin, &parts)); headers.extend(self.layer.allow_credentials.to_header(origin, &parts)); headers.extend(self.layer.allow_private_network.to_header(origin, &parts)); - - let mut vary_headers = self.layer.vary.values(); - if let Some(first) = vary_headers.next() { - let mut header = match headers.entry(header::VARY) { - header::Entry::Occupied(_) => { - unreachable!("no vary header inserted up to this point") - } - header::Entry::Vacant(v) => v.insert_entry(first), - }; - - for val in vary_headers { - header.append(val); - } - } + headers.extend(self.layer.vary.to_header()); // Return results immediately upon preflight request if parts.method == Method::OPTIONS { diff --git a/tower-http/src/cors/vary.rs b/tower-http/src/cors/vary.rs index b1dddc36..af7697bd 100644 --- a/tower-http/src/cors/vary.rs +++ b/tower-http/src/cors/vary.rs @@ -1,6 +1,6 @@ use std::array; -use http::{header::HeaderName, HeaderValue}; +use http::header::{self, HeaderName, HeaderValue}; use super::preflight_request_headers; @@ -26,8 +26,17 @@ impl Vary { Self(headers.into_iter().map(Into::into).collect()) } - pub(super) fn values(&self) -> impl Iterator + '_ { - self.0.iter().cloned() + pub(super) fn to_header(&self) -> Option<(HeaderName, HeaderValue)> { + let values = &self.0; + let mut res = values.get(0)?.as_bytes().to_owned(); + for val in &values[1..] { + res.extend_from_slice(b", "); + res.extend_from_slice(val.as_bytes()); + } + + let header_val = HeaderValue::from_bytes(&res) + .expect("comma-separated list of HeaderValues is always a valid HeaderValue"); + Some((header::VARY, header_val)) } } From b07c7313f635613d0600bf8840999732b686a80a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 1 Oct 2023 10:07:45 +0200 Subject: [PATCH 04/11] cors: Don't overwrite vary header set by the inner service --- tower-http/src/cors/mod.rs | 7 +++++++ tower-http/src/cors/tests.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tower-http/src/cors/tests.rs diff --git a/tower-http/src/cors/mod.rs b/tower-http/src/cors/mod.rs index 6883ac31..0524122d 100644 --- a/tower-http/src/cors/mod.rs +++ b/tower-http/src/cors/mod.rs @@ -681,6 +681,13 @@ where match self.project().inner.project() { KindProj::CorsCall { future, headers } => { let mut response: Response = ready!(future.poll(cx))?; + + // vary header can have multiple values, don't overwrite + // previously-set value(s). + if let Some(vary) = headers.remove(header::VARY) { + headers.append(header::VARY, vary); + } + // extend will overwrite previous headers of remaining names response.headers_mut().extend(headers.drain()); Poll::Ready(Ok(response)) diff --git a/tower-http/src/cors/tests.rs b/tower-http/src/cors/tests.rs new file mode 100644 index 00000000..4eccc41c --- /dev/null +++ b/tower-http/src/cors/tests.rs @@ -0,0 +1,33 @@ +use std::convert::Infallible; + +use http::{header, HeaderValue, Request, Response}; +use hyper::Body; +use tower::{service_fn, util::ServiceExt, Layer}; + +use crate::cors::CorsLayer; + +#[tokio::test] +#[allow( + clippy::declare_interior_mutable_const, + clippy::borrow_interior_mutable_const +)] +async fn vary_set_by_inner_service() { + const CUSTOM_VARY_HEADERS: HeaderValue = HeaderValue::from_static("accept, accept-encoding"); + const PERMISSIVE_CORS_VARY_HEADERS: HeaderValue = HeaderValue::from_static( + "origin, access-control-request-method, access-control-request-headers", + ); + + async fn inner_svc(_: Request) -> Result, Infallible> { + Ok(Response::builder() + .header(header::VARY, CUSTOM_VARY_HEADERS) + .body(Body::empty()) + .unwrap()) + } + + let svc = CorsLayer::permissive().layer(service_fn(inner_svc)); + let res = svc.oneshot(Request::new(Body::empty())).await.unwrap(); + let mut vary_headers = res.headers().get_all(header::VARY).into_iter(); + assert_eq!(vary_headers.next(), Some(&CUSTOM_VARY_HEADERS)); + assert_eq!(vary_headers.next(), Some(&PERMISSIVE_CORS_VARY_HEADERS)); + assert_eq!(vary_headers.next(), None); +} From 43b71965a54165d3d34ecbe2af5f68a863fe20eb Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 13 Jan 2024 23:49:56 +0100 Subject: [PATCH 05/11] Update CHANGELOG.md --- tower-http/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tower-http/CHANGELOG.md b/tower-http/CHANGELOG.md index ddb718c9..e05e0f16 100644 --- a/tower-http/CHANGELOG.md +++ b/tower-http/CHANGELOG.md @@ -36,6 +36,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Accepts range headers with ranges where the end of range goes past the end of the document by bumping http-range-header to `0.4` +- cors: Keep Vary headers set by the inner service when setting response headers ([#398]) + +[#398]: https://github.com/tower-rs/tower-http/pull/398 [#418]: https://github.com/tower-rs/tower-http/pull/418 [#433]: https://github.com/tower-rs/tower-http/pull/433 From f47f2f61afb44a94bee2502045998719e569e9ff Mon Sep 17 00:00:00 2001 From: Wolfus20 Date: Tue, 9 Jan 2024 16:23:11 +0800 Subject: [PATCH 06/11] Add default generic parameters for trace::{ResponseBody, ResponseFuture} Fixes: #233 --- tower-http/src/trace/body.rs | 4 ++-- tower-http/src/trace/future.rs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tower-http/src/trace/body.rs b/tower-http/src/trace/body.rs index 7a27cd90..d713f243 100644 --- a/tower-http/src/trace/body.rs +++ b/tower-http/src/trace/body.rs @@ -1,4 +1,4 @@ -use super::{OnBodyChunk, OnEos, OnFailure}; +use super::{DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, OnBodyChunk, OnEos, OnFailure}; use crate::classify::ClassifyEos; use http_body::{Body, Frame}; use pin_project_lite::pin_project; @@ -14,7 +14,7 @@ pin_project! { /// Response body for [`Trace`]. /// /// [`Trace`]: super::Trace - pub struct ResponseBody { + pub struct ResponseBody { #[pin] pub(crate) inner: B, pub(crate) classify_eos: Option, diff --git a/tower-http/src/trace/future.rs b/tower-http/src/trace/future.rs index feac51bf..e205ea32 100644 --- a/tower-http/src/trace/future.rs +++ b/tower-http/src/trace/future.rs @@ -1,4 +1,7 @@ -use super::{OnBodyChunk, OnEos, OnFailure, OnResponse, ResponseBody}; +use super::{ + DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnResponse, OnBodyChunk, OnEos, + OnFailure, OnResponse, ResponseBody, +}; use crate::classify::{ClassifiedResponse, ClassifyResponse}; use http::Response; use http_body::Body; @@ -15,7 +18,7 @@ pin_project! { /// Response future for [`Trace`]. /// /// [`Trace`]: super::Trace - pub struct ResponseFuture { + pub struct ResponseFuture { #[pin] pub(crate) inner: F, pub(crate) span: Span, From 469bdac3193ed22da9ea524a454d8cda93ffa0d5 Mon Sep 17 00:00:00 2001 From: Wolfus20 Date: Tue, 9 Jan 2024 17:34:53 +0800 Subject: [PATCH 07/11] Add and implement HttpMakeClassifier and GrpcMakeClassifier type aliases Fixes: #233 --- tower-http/src/builder.rs | 13 ++++--------- tower-http/src/trace/layer.rs | 6 +++--- tower-http/src/trace/mod.rs | 11 ++++++++++- tower-http/src/trace/service.rs | 8 ++++---- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tower-http/src/builder.rs b/tower-http/src/builder.rs index d8d14aa0..4c27a95c 100644 --- a/tower-http/src/builder.rs +++ b/tower-http/src/builder.rs @@ -1,8 +1,5 @@ use tower::ServiceBuilder; -#[cfg(feature = "trace")] -use crate::classify::{GrpcErrorsAsFailures, ServerErrorsAsFailures, SharedClassifier}; - #[allow(unused_imports)] use http::header::HeaderName; #[allow(unused_imports)] @@ -126,7 +123,7 @@ pub trait ServiceBuilderExt: crate::sealed::Sealed + Sized { #[cfg(feature = "trace")] fn trace_for_http( self, - ) -> ServiceBuilder>, L>>; + ) -> ServiceBuilder, L>>; /// High level tracing that classifies responses using gRPC headers. /// @@ -140,7 +137,7 @@ pub trait ServiceBuilderExt: crate::sealed::Sealed + Sized { #[cfg(feature = "trace")] fn trace_for_grpc( self, - ) -> ServiceBuilder>, L>>; + ) -> ServiceBuilder, L>>; /// Follow redirect resposes using the [`Standard`] policy. /// @@ -427,16 +424,14 @@ impl ServiceBuilderExt for ServiceBuilder { #[cfg(feature = "trace")] fn trace_for_http( self, - ) -> ServiceBuilder>, L>> - { + ) -> ServiceBuilder, L>> { self.layer(crate::trace::TraceLayer::new_for_http()) } #[cfg(feature = "trace")] fn trace_for_grpc( self, - ) -> ServiceBuilder>, L>> - { + ) -> ServiceBuilder, L>> { self.layer(crate::trace::TraceLayer::new_for_grpc()) } diff --git a/tower-http/src/trace/layer.rs b/tower-http/src/trace/layer.rs index 7314f754..21ff321c 100644 --- a/tower-http/src/trace/layer.rs +++ b/tower-http/src/trace/layer.rs @@ -1,6 +1,6 @@ use super::{ DefaultMakeSpan, DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, - DefaultOnResponse, Trace, + DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, Trace, }; use crate::classify::{ GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier, @@ -176,7 +176,7 @@ impl } } -impl TraceLayer> { +impl TraceLayer { /// Create a new [`TraceLayer`] using [`ServerErrorsAsFailures`] which supports classifying /// regular HTTP responses based on the status code. pub fn new_for_http() -> Self { @@ -192,7 +192,7 @@ impl TraceLayer> { } } -impl TraceLayer> { +impl TraceLayer { /// Create a new [`TraceLayer`] using [`GrpcErrorsAsFailures`] which supports classifying /// gRPC responses and streams based on the `grpc-status` header. pub fn new_for_grpc() -> Self { diff --git a/tower-http/src/trace/mod.rs b/tower-http/src/trace/mod.rs index 255bb703..0b57a18d 100644 --- a/tower-http/src/trace/mod.rs +++ b/tower-http/src/trace/mod.rs @@ -400,7 +400,16 @@ pub use self::{ on_response::{DefaultOnResponse, OnResponse}, service::Trace, }; -use crate::LatencyUnit; +use crate::{ + classify::{GrpcErrorsAsFailures, ServerErrorsAsFailures, SharedClassifier}, + LatencyUnit, +}; + +/// MakeClassifier for HTTP requests. +pub type HttpMakeClassifier = SharedClassifier; + +/// MakeClassifier for gRPC requests. +pub type GrpcMakeClassifier = SharedClassifier; macro_rules! event_dynamic_lvl { ( $(target: $target:expr,)? $(parent: $parent:expr,)? $lvl:expr, $($tt:tt)* ) => { diff --git a/tower-http/src/trace/service.rs b/tower-http/src/trace/service.rs index f58172f3..1ab4c1f0 100644 --- a/tower-http/src/trace/service.rs +++ b/tower-http/src/trace/service.rs @@ -1,7 +1,7 @@ use super::{ DefaultMakeSpan, DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest, - DefaultOnResponse, MakeSpan, OnBodyChunk, OnEos, OnFailure, OnRequest, OnResponse, - ResponseBody, ResponseFuture, TraceLayer, + DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, MakeSpan, OnBodyChunk, OnEos, + OnFailure, OnRequest, OnResponse, ResponseBody, ResponseFuture, TraceLayer, }; use crate::classify::{ GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier, @@ -207,7 +207,7 @@ impl impl Trace< S, - SharedClassifier, + HttpMakeClassifier, DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse, @@ -235,7 +235,7 @@ impl impl Trace< S, - SharedClassifier, + GrpcMakeClassifier, DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse, From 7189afe85b6dfa0a74b8df4a4eaefa1fdf77be17 Mon Sep 17 00:00:00 2001 From: Wolfus20 Date: Sun, 14 Jan 2024 20:36:24 +0800 Subject: [PATCH 08/11] Add CHANGELOG entry for PR #455 --- tower-http/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tower-http/CHANGELOG.md b/tower-http/CHANGELOG.md index e05e0f16..7e4e14a2 100644 --- a/tower-http/CHANGELOG.md +++ b/tower-http/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Added -- None. +- **trace:** Add default generic parameters for `ResponseBody` and `ResponseFuture` ([#455]) +- **trace:** Add type aliases `HttpMakeClassifier` and `GrpcMakeClassifier` ([#455]) ## Changed @@ -23,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - None. +[#455]: https://github.com/tower-rs/tower-http/pull/455 + # 0.5.0 (November 21, 2023) ## Changed From c9c72fed08a0f77f75b5aa6ac3de282ae7df7032 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 14 Jan 2024 21:45:42 +0100 Subject: [PATCH 09/11] Release 0.5.1 (#459) --- tower-http/CHANGELOG.md | 20 ++++++++------------ tower-http/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/tower-http/CHANGELOG.md b/tower-http/CHANGELOG.md index 7e4e14a2..4e949efb 100644 --- a/tower-http/CHANGELOG.md +++ b/tower-http/CHANGELOG.md @@ -7,23 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased +# 0.5.1 (January 14, 2024) + ## Added +- **fs:** Support files precompressed with `zstd` in `ServeFile` - **trace:** Add default generic parameters for `ResponseBody` and `ResponseFuture` ([#455]) - **trace:** Add type aliases `HttpMakeClassifier` and `GrpcMakeClassifier` ([#455]) -## Changed - -- None. - -## Removed - -- None. - ## Fixed -- None. +- **cors:** Keep Vary headers set by the inner service when setting response headers ([#398]) +- **fs:** `ServeDir` now no longer redirects from `/directory` to `/directory/` + if `append_index_html_on_directories` is disabled ([#421]) +[#398]: https://github.com/tower-rs/tower-http/pull/398 +[#421]: https://github.com/tower-rs/tower-http/pull/421 [#455]: https://github.com/tower-rs/tower-http/pull/455 # 0.5.0 (November 21, 2023) @@ -39,9 +38,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Accepts range headers with ranges where the end of range goes past the end of the document by bumping http-range-header to `0.4` -- cors: Keep Vary headers set by the inner service when setting response headers ([#398]) - -[#398]: https://github.com/tower-rs/tower-http/pull/398 [#418]: https://github.com/tower-rs/tower-http/pull/418 [#433]: https://github.com/tower-rs/tower-http/pull/433 diff --git a/tower-http/Cargo.toml b/tower-http/Cargo.toml index c5b46c46..45f8a785 100644 --- a/tower-http/Cargo.toml +++ b/tower-http/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tower-http" description = "Tower middleware and utilities for HTTP clients and servers" -version = "0.5.0" +version = "0.5.1" authors = ["Tower Maintainers "] edition = "2018" license = "MIT" From c205deafc113ff2330dc1d347032fe24d0ee965d Mon Sep 17 00:00:00 2001 From: Tanguy Date: Sun, 21 Jan 2024 13:10:58 +0100 Subject: [PATCH 10/11] Append `Accept-Encoding` to Vary header when compressing --- tower-http/src/compression/future.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tower-http/src/compression/future.rs b/tower-http/src/compression/future.rs index 98763006..dec1cdda 100644 --- a/tower-http/src/compression/future.rs +++ b/tower-http/src/compression/future.rs @@ -46,6 +46,12 @@ where let (mut parts, body) = res.into_parts(); + if should_compress { + parts + .headers + .append(header::VARY, header::ACCEPT_ENCODING.into()); + } + let body = match (should_compress, self.encoding) { // if compression is _not_ support or the client doesn't accept it (false, _) | (_, Encoding::Identity) => { From cca6c6864e72bab63e89832d70342e159450c721 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 21 Jan 2024 15:30:21 +0100 Subject: [PATCH 11/11] Update changelog (#462) --- tower-http/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tower-http/CHANGELOG.md b/tower-http/CHANGELOG.md index 4e949efb..822a4d82 100644 --- a/tower-http/CHANGELOG.md +++ b/tower-http/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased +## Added: + +- **compression:** Will now send a `vary: accept-encoding` header on compressed responses ([#399]) + +[#399]: https://github.com/tower-rs/tower-http/pull/399 + # 0.5.1 (January 14, 2024) ## Added