Skip to main content

tower_http/set_header/request/
mod.rs

1//! Middleware for setting headers on HTTP requests.
2//!
3//! This module provides middleware for setting one or more headers on HTTP requests, either with fixed values or values determined dynamically from the request.
4//!
5//! # Single Header
6//!
7//! Use [`SetRequestHeaderLayer`] and [`SetRequestHeader`] 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::SetRequestHeaderLayer;
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 http_client = tower::service_fn(|_: Request<Full<Bytes>>| async move {
21//! #     Ok::<_, std::convert::Infallible>(Response::new(Full::<Bytes>::default()))
22//! # });
23//! #
24//! let mut svc = ServiceBuilder::new()
25//!     .layer(
26//!         // Layer that sets `User-Agent: my very cool app` on requests.
27//!         //
28//!         // `if_not_present` will only insert the header if it does not already
29//!         // have a value.
30//!         SetRequestHeaderLayer::if_not_present(
31//!             header::USER_AGENT,
32//!             HeaderValue::from_static("my very cool app"),
33//!         )
34//!     )
35//!     .service(http_client);
36//!
37//! let request = Request::new(Full::default());
38//!
39//! let response = svc.ready().await?.call(request).await?;
40//! #
41//! # Ok(())
42//! # }
43//! ```
44//!
45//! Setting a header based on a value determined dynamically from the request:
46//!
47//! ```
48//! use http::{Request, Response, header::{self, HeaderValue}};
49//! use tower::{Service, ServiceExt, ServiceBuilder};
50//! use tower_http::set_header::SetRequestHeaderLayer;
51//! use bytes::Bytes;
52//! use http_body_util::Full;
53//!
54//! # #[tokio::main]
55//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
56//! # let http_client = tower::service_fn(|_: Request<Full<Bytes>>| async move {
57//! #     Ok::<_, std::convert::Infallible>(Response::new(Full::<Bytes>::default()))
58//! # });
59//! fn date_header_value() -> HeaderValue {
60//!     // ...
61//!     # HeaderValue::from_static("now")
62//! }
63//!
64//! let mut svc = ServiceBuilder::new()
65//!     .layer(
66//!         // Layer that sets `Date` to the current date and time.
67//!         //
68//!         // `overriding` will insert the header and override any previous values it
69//!         // may have.
70//!         SetRequestHeaderLayer::overriding(
71//!             header::DATE,
72//!             |request: &Request<Full<Bytes>>| {
73//!                 Some(date_header_value())
74//!             }
75//!         )
76//!     )
77//!     .service(http_client);
78//!
79//! let request = Request::new(Full::default());
80//!
81//! let response = svc.ready().await?.call(request).await?;
82//! #
83//! # Ok(())
84//! # }
85//! ```
86//!
87//! # Multiple Headers
88//!
89//! Use [`SetMultipleRequestHeadersLayer`] and [`SetMultipleRequestHeader`] to set multiple headers at once. Each header can have a fixed value or be computed dynamically.
90//!
91//! Note: this layer uses boxing (allocation + dynamic dispatch) to support mixed producer
92//! types in a single `vec`. Stacking multiple [`SetRequestHeaderLayer`] instances avoids this at the
93//! cost of a more complex composed service type.
94//!
95//! ## Example: Multiple Dynamic Values
96//!
97//! ```
98//! use http::{Request, Response, header::{self, HeaderValue}};
99//! use tower::{Service, ServiceExt, ServiceBuilder};
100//! use tower_http::set_header::{HeaderMetadata, request::{SetMultipleRequestHeadersLayer}};
101//! use bytes::Bytes;
102//! use http_body_util::Full;
103//!
104//! # #[tokio::main]
105//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
106//! # let http_client = tower::service_fn(|_: Request<Full<Bytes>>| async move {
107//! #     Ok::<_, std::convert::Infallible>(Response::new(Full::<Bytes>::default()))
108//! # });
109//!
110//! let mut svc = ServiceBuilder::new()
111//!     .layer(
112//!         SetMultipleRequestHeadersLayer::overriding(vec![
113//!             (header::DATE, |_: &Request<Full<Bytes>>| {
114//!                 Some(HeaderValue::from_static("now"))
115//!             }).into(),
116//!         ])
117//!     )
118//!     .service(tower::service_fn(|req: Request<Full<Bytes>>| async move {
119//!         assert_eq!(req.headers()["date"], "now");
120//!         Ok::<_, std::convert::Infallible>(Response::new(Full::<Bytes>::default()))
121//!     }));
122//!
123//! let request = Request::new(Full::default());
124//!
125//! let _response = svc.ready().await?.call(request).await?;
126//! # Ok(())
127//! # }
128//! ```
129//!
130//! # Modes
131//!
132//! - `overriding`: If a previous value exists for the same header, it is removed and replaced with the new value.
133//! - `appending`: The new header is always added, preserving any existing values. If previous values exist, the header will have multiple values.
134//! - `if_not_present`: If a previous value exists for the header, the new value is not inserted.
135//!
136//! See [`SetRequestHeaderLayer`], [`SetRequestHeader`], [`SetMultipleRequestHeadersLayer`], and [`SetMultipleRequestHeader`] for more details.
137
138mod multiple_headers;
139mod single_header;
140
141pub use multiple_headers::{SetMultipleRequestHeader, SetMultipleRequestHeadersLayer};
142pub use single_header::{SetRequestHeader, SetRequestHeaderLayer};