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};