Skip to main content

tower_http/set_header/response/
mod.rs

1//! Middleware for setting headers on HTTP responses.
2//!
3//! This module provides middleware for setting one or more headers on HTTP responses, either with fixed values or values determined dynamically from the response.
4//!
5//! # Single Header
6//!
7//! Use [`SetResponseHeaderLayer`] and [`SetResponseHeader`] to set a single header. The header value can be a fixed value or computed dynamically using a closure. See [`crate::set_header::MakeHeaderValue`] for details.
8//!
9//! ## Example: Fixed Value
10//!
11//! ```
12//! use http::{Request, Response, header::{self, HeaderValue}};
13//! use tower::{Service, ServiceExt, ServiceBuilder};
14//! use tower_http::set_header::SetResponseHeaderLayer;
15//! use http_body_util::Full;
16//! use bytes::Bytes;
17//!
18//! # #[tokio::main]
19//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//! # let render_html = tower::service_fn(|request: Request<Full<Bytes>>| async move {
21//! #     Ok::<_, std::convert::Infallible>(Response::new(request.into_body()))
22//! # });
23//!
24//! let mut svc = ServiceBuilder::new()
25//!     .layer(
26//!         SetResponseHeaderLayer::if_not_present(
27//!             header::CONTENT_TYPE,
28//!             HeaderValue::from_static("text/html"),
29//!         )
30//!     )
31//!     .service(render_html);
32//!
33//! let request = Request::new(Full::default());
34//!
35//! let response = svc.ready().await?.call(request).await?;
36//!
37//! assert_eq!(response.headers()["content-type"], "text/html");
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! ## Example: Dynamic Value
43//!
44//! ```
45//! use http::{Request, Response, header::{self, HeaderValue}};
46//! use tower::{Service, ServiceExt, ServiceBuilder};
47//! use tower_http::set_header::SetResponseHeaderLayer;
48//! use bytes::Bytes;
49//! use http_body_util::Full;
50//! use http_body::Body as _; // for `Body::size_hint`
51//!
52//! # #[tokio::main]
53//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
54//! # let render_html = tower::service_fn(|request: Request<Full<Bytes>>| async move {
55//! #     Ok::<_, std::convert::Infallible>(Response::new(Full::from("1234567890")))
56//! # });
57//!
58//! let mut svc = ServiceBuilder::new()
59//!     .layer(
60//!         SetResponseHeaderLayer::overriding(
61//!             header::CONTENT_LENGTH,
62//!             |response: &Response<Full<Bytes>>| {
63//!                 if let Some(size) = response.body().size_hint().exact() {
64//!                     Some(HeaderValue::from_str(&size.to_string()).unwrap())
65//!                 } else {
66//!                     None
67//!                 }
68//!             }
69//!         )
70//!     )
71//!     .service(render_html);
72//!
73//! let request = Request::new(Full::default());
74//!
75//! let response = svc.ready().await?.call(request).await?;
76//!
77//! assert_eq!(response.headers()["content-length"], "10");
78//! # Ok(())
79//! # }
80//! ```
81//!
82//! # Multiple Headers
83//!
84//! Use [`SetMultipleResponseHeadersLayer`] and [`SetMultipleResponseHeader`] to set multiple headers at once. Each header can have a fixed value or be computed dynamically.
85//!
86//! Note: this layer uses boxing (allocation + dynamic dispatch) to support mixed producer
87//! types in a single vec. Stacking multiple [`SetResponseHeaderLayer`] avoids this at the
88//! cost of a more complex composed service type.
89//!
90//! ## Example: Multiple Fixed Values
91//!
92//! ```
93//! use http::{Request, Response, header::{self, HeaderValue}};
94//! use tower::{Service, ServiceExt, ServiceBuilder};
95//! use tower_http::set_header::{HeaderMetadata, response::{SetMultipleResponseHeadersLayer}};
96//! use http_body_util::Full;
97//! use bytes::Bytes;
98//!
99//! # #[tokio::main]
100//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
101//! # let render_html = tower::service_fn(|request: Request<Full<Bytes>>| async move {
102//! #     Ok::<_, std::convert::Infallible>(Response::new(request.into_body()))
103//! # });
104//!
105//! let mut svc = ServiceBuilder::new()
106//!     .layer(
107//!         SetMultipleResponseHeadersLayer::overriding(vec![
108//!             (header::CONTENT_TYPE, HeaderValue::from_static("text/html")).into(),
109//!             (header::CACHE_CONTROL, HeaderValue::from_static("no-cache")).into(),
110//!         ])
111//!     )
112//!     .service(render_html);
113//!
114//! let request = Request::new(Full::default());
115//!
116//! let response = svc.ready().await?.call(request).await?;
117//!
118//! assert_eq!(response.headers()["content-type"], "text/html");
119//! assert_eq!(response.headers()["cache-control"], "no-cache");
120//! # Ok(())
121//! # }
122//! ```
123//!
124//! ## Example: Multiple Dynamic Values
125//!
126//! ```
127//! use http::{Request, Response, header::{self, HeaderValue}};
128//! use tower::{Service, ServiceExt, ServiceBuilder};
129//! use tower_http::set_header::{HeaderMetadata, response::{SetMultipleResponseHeadersLayer}};
130//! use bytes::Bytes;
131//! use http_body_util::Full;
132//! use http_body::Body as _; // for `Body::size_hint`
133//!
134//! # #[tokio::main]
135//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
136//! # let render_html = tower::service_fn(|request: Request<Full<Bytes>>| async move {
137//! #     Ok::<_, std::convert::Infallible>(Response::new(Full::from("1234567890")))
138//! # });
139//!
140//! let mut svc = ServiceBuilder::new()
141//!     .layer(
142//!         SetMultipleResponseHeadersLayer::overriding(vec![
143//!             (header::CONTENT_LENGTH, |response: &Response<Full<Bytes>>| {
144//!                 if let Some(size) = response.body().size_hint().exact() {
145//!                     Some(HeaderValue::from_str(&size.to_string()).unwrap())
146//!                 } else {
147//!                     None
148//!                 }
149//!             }).into(),
150//!         ])
151//!     )
152//!     .service(render_html);
153//!
154//! let request = Request::new(Full::default());
155//!
156//! let response = svc.ready().await?.call(request).await?;
157//!
158//! assert_eq!(response.headers()["content-length"], "10");
159//! # Ok(())
160//! # }
161//! ```
162//!
163//! # Modes
164//!
165//! - `overriding`: If a previous value exists for the same header, it is removed and replaced with the new value.
166//! - `appending`: The new header is always added, preserving any existing values. If previous values exist, the header will have multiple values.
167//! - `if_not_present`: If a previous value exists for the header, the new value is not inserted.
168//!
169//! See [`SetResponseHeaderLayer`], [`SetResponseHeader`], [`SetMultipleResponseHeadersLayer`], and [`SetMultipleResponseHeader`] for more details.
170
171mod multiple_headers;
172mod single_header;
173
174pub use multiple_headers::{SetMultipleResponseHeader, SetMultipleResponseHeadersLayer};
175pub use single_header::{SetResponseHeader, SetResponseHeaderLayer};