rama_http/layer/set_header/request/
mod.rs

1//! Set a header on the request.
2//!
3//! The header value to be set may be provided as a fixed value when the
4//! middleware is constructed, or determined dynamically based on the request
5//! by a closure. See the [`MakeHeaderValue`] trait for details.
6//!
7//! # Example
8//!
9//! Setting a header from a fixed value provided when the middleware is constructed:
10//!
11//! ```
12//! use rama_http::layer::set_header::SetRequestHeaderLayer;
13//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}};
14//! use rama_core::service::service_fn;
15//! use rama_core::{Context, Service, Layer};
16//! use rama_core::error::BoxError;
17//!
18//! # #[tokio::main]
19//! # async fn main() -> Result<(), BoxError> {
20//! # let http_client = service_fn(async |_: Request| {
21//! #     Ok::<_, std::convert::Infallible>(Response::new(Body::empty()))
22//! # });
23//! #
24//! let mut svc = (
25//!     // Layer that sets `User-Agent: my very cool proxy` on requests.
26//!     //
27//!     // `if_not_present` will only insert the header if it does not already
28//!     // have a value.
29//!     SetRequestHeaderLayer::if_not_present(
30//!         header::USER_AGENT,
31//!         HeaderValue::from_static("my very cool proxy"),
32//!     ),
33//! ).into_layer(http_client);
34//!
35//! let request = Request::new(Body::empty());
36//!
37//! let response = svc.serve(Context::default(), request).await?;
38//! #
39//! # Ok(())
40//! # }
41//! ```
42//!
43//! Setting a header based on a value determined dynamically from the request:
44//!
45//! ```
46//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}};
47//! use rama_http::layer::set_header::SetRequestHeaderLayer;
48//! use rama_core::service::service_fn;
49//! use rama_core::{Context, Service, Layer};
50//! use rama_core::error::BoxError;
51//!
52//! # #[tokio::main]
53//! # async fn main() -> Result<(), BoxError> {
54//! # let http_client = service_fn(async || {
55//! #     Ok::<_, std::convert::Infallible>(Response::new(Body::empty()))
56//! # });
57//! fn date_header_value() -> HeaderValue {
58//!     // ...
59//!     # HeaderValue::from_static("now")
60//! }
61//!
62//! let mut svc = (
63//!     // Layer that sets `Date` to the current date and time.
64//!     //
65//!     // `overriding` will insert the header and override any previous values it
66//!     // may have.
67//!     SetRequestHeaderLayer::overriding_fn(
68//!         header::DATE,
69//!         async || {
70//!             Some(date_header_value())
71//!         }
72//!     ),
73//! ).into_layer(http_client);
74//!
75//! let request = Request::new(Body::default());
76//!
77//! let response = svc.serve(Context::default(), request).await?;
78//! #
79//! # Ok(())
80//! # }
81//! ```
82
83use crate::{
84    HeaderValue, Request, Response,
85    header::HeaderName,
86    headers::{Header, HeaderExt},
87};
88use rama_core::{Context, Layer, Service};
89use rama_utils::macros::define_inner_service_accessors;
90use std::fmt;
91
92mod header;
93use header::InsertHeaderMode;
94
95pub use header::{BoxMakeHeaderValueFn, MakeHeaderValue};
96
97/// Layer that applies [`SetRequestHeader`] which adds a request header.
98///
99/// See [`SetRequestHeader`] for more details.
100pub struct SetRequestHeaderLayer<M> {
101    header_name: HeaderName,
102    make: M,
103    mode: InsertHeaderMode,
104}
105
106impl<M> fmt::Debug for SetRequestHeaderLayer<M> {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        f.debug_struct("SetRequestHeaderLayer")
109            .field("header_name", &self.header_name)
110            .field("mode", &self.mode)
111            .field("make", &std::any::type_name::<M>())
112            .finish()
113    }
114}
115
116impl<M> SetRequestHeaderLayer<M> {
117    /// Create a new [`SetRequestHeaderLayer`].
118    ///
119    /// If a previous value exists for the same header, it is removed and replaced with the new
120    /// header value.
121    pub fn overriding(header_name: HeaderName, make: M) -> Self {
122        Self::new(header_name, make, InsertHeaderMode::Override)
123    }
124
125    /// Create a new [`SetRequestHeaderLayer`].
126    ///
127    /// The new header is always added, preserving any existing values. If previous values exist,
128    /// the header will have multiple values.
129    pub fn appending(header_name: HeaderName, make: M) -> Self {
130        Self::new(header_name, make, InsertHeaderMode::Append)
131    }
132
133    /// Create a new [`SetRequestHeaderLayer`].
134    ///
135    /// If a previous value exists for the header, the new value is not inserted.
136    pub fn if_not_present(header_name: HeaderName, make: M) -> Self {
137        Self::new(header_name, make, InsertHeaderMode::IfNotPresent)
138    }
139
140    fn new(header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
141        Self {
142            make,
143            header_name,
144            mode,
145        }
146    }
147}
148
149impl SetRequestHeaderLayer<HeaderValue> {
150    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
151    ///
152    /// See [`SetRequestHeaderLayer::overriding`] for more details.
153    pub fn overriding_typed<H: Header>(header: H) -> Self {
154        Self::overriding(H::name().clone(), header.encode_to_value())
155    }
156
157    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
158    ///
159    /// See [`SetRequestHeaderLayer::appending`] for more details.
160    pub fn appending_typed<H: Header>(header: H) -> Self {
161        Self::appending(H::name().clone(), header.encode_to_value())
162    }
163
164    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
165    ///
166    /// See [`SetRequestHeaderLayer::if_not_present`] for more details.
167    pub fn if_not_present_typed<H: Header>(header: H) -> Self {
168        Self::if_not_present(H::name().clone(), header.encode_to_value())
169    }
170}
171
172impl<F, A> SetRequestHeaderLayer<BoxMakeHeaderValueFn<F, A>> {
173    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
174    ///
175    /// See [`SetRequestHeaderLayer::overriding`] for more details.
176    pub fn overriding_fn(header_name: HeaderName, make_fn: F) -> Self {
177        Self::new(
178            header_name,
179            BoxMakeHeaderValueFn::new(make_fn),
180            InsertHeaderMode::Override,
181        )
182    }
183
184    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
185    ///
186    /// See [`SetRequestHeaderLayer::appending`] for more details.
187    pub fn appending_fn(header_name: HeaderName, make_fn: F) -> Self {
188        Self::new(
189            header_name,
190            BoxMakeHeaderValueFn::new(make_fn),
191            InsertHeaderMode::Append,
192        )
193    }
194
195    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
196    ///
197    /// See [`SetRequestHeaderLayer::if_not_present`] for more details.
198    pub fn if_not_present_fn(header_name: HeaderName, make_fn: F) -> Self {
199        Self::new(
200            header_name,
201            BoxMakeHeaderValueFn::new(make_fn),
202            InsertHeaderMode::IfNotPresent,
203        )
204    }
205}
206
207impl<S, M> Layer<S> for SetRequestHeaderLayer<M>
208where
209    M: Clone,
210{
211    type Service = SetRequestHeader<S, M>;
212
213    fn layer(&self, inner: S) -> Self::Service {
214        SetRequestHeader {
215            inner,
216            header_name: self.header_name.clone(),
217            make: self.make.clone(),
218            mode: self.mode,
219        }
220    }
221
222    fn into_layer(self, inner: S) -> Self::Service {
223        SetRequestHeader {
224            inner,
225            header_name: self.header_name,
226            make: self.make,
227            mode: self.mode,
228        }
229    }
230}
231
232impl<M> Clone for SetRequestHeaderLayer<M>
233where
234    M: Clone,
235{
236    fn clone(&self) -> Self {
237        Self {
238            make: self.make.clone(),
239            header_name: self.header_name.clone(),
240            mode: self.mode,
241        }
242    }
243}
244
245/// Middleware that sets a header on the request.
246#[derive(Clone)]
247pub struct SetRequestHeader<S, M> {
248    inner: S,
249    header_name: HeaderName,
250    make: M,
251    mode: InsertHeaderMode,
252}
253
254impl<S, M> SetRequestHeader<S, M> {
255    /// Create a new [`SetRequestHeader`].
256    ///
257    /// If a previous value exists for the same header, it is removed and replaced with the new
258    /// header value.
259    pub fn overriding(inner: S, header_name: HeaderName, make: M) -> Self {
260        Self::new(inner, header_name, make, InsertHeaderMode::Override)
261    }
262
263    /// Create a new [`SetRequestHeader`].
264    ///
265    /// The new header is always added, preserving any existing values. If previous values exist,
266    /// the header will have multiple values.
267    pub fn appending(inner: S, header_name: HeaderName, make: M) -> Self {
268        Self::new(inner, header_name, make, InsertHeaderMode::Append)
269    }
270
271    /// Create a new [`SetRequestHeader`].
272    ///
273    /// If a previous value exists for the header, the new value is not inserted.
274    pub fn if_not_present(inner: S, header_name: HeaderName, make: M) -> Self {
275        Self::new(inner, header_name, make, InsertHeaderMode::IfNotPresent)
276    }
277
278    fn new(inner: S, header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
279        Self {
280            inner,
281            header_name,
282            make,
283            mode,
284        }
285    }
286
287    define_inner_service_accessors!();
288}
289
290impl<S, F, A> SetRequestHeader<S, BoxMakeHeaderValueFn<F, A>> {
291    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
292    ///
293    /// See [`SetRequestHeader::overriding`] for more details.
294    pub fn overriding_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
295        Self::new(
296            inner,
297            header_name,
298            BoxMakeHeaderValueFn::new(make_fn),
299            InsertHeaderMode::Override,
300        )
301    }
302
303    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
304    ///
305    /// See [`SetRequestHeader::appending`] for more details.
306    pub fn appending_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
307        Self::new(
308            inner,
309            header_name,
310            BoxMakeHeaderValueFn::new(make_fn),
311            InsertHeaderMode::Append,
312        )
313    }
314
315    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
316    ///
317    /// See [`SetRequestHeader::if_not_present`] for more details.
318    pub fn if_not_present_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
319        Self::new(
320            inner,
321            header_name,
322            BoxMakeHeaderValueFn::new(make_fn),
323            InsertHeaderMode::IfNotPresent,
324        )
325    }
326}
327
328impl<S, M> fmt::Debug for SetRequestHeader<S, M>
329where
330    S: fmt::Debug,
331{
332    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333        f.debug_struct("SetRequestHeader")
334            .field("inner", &self.inner)
335            .field("header_name", &self.header_name)
336            .field("mode", &self.mode)
337            .field("make", &std::any::type_name::<M>())
338            .finish()
339    }
340}
341
342impl<ReqBody, ResBody, State, S, M> Service<State, Request<ReqBody>> for SetRequestHeader<S, M>
343where
344    ReqBody: Send + 'static,
345    ResBody: Send + 'static,
346    State: Clone + Send + Sync + 'static,
347    S: Service<State, Request<ReqBody>, Response = Response<ResBody>>,
348    M: MakeHeaderValue<State, ReqBody>,
349{
350    type Response = S::Response;
351    type Error = S::Error;
352
353    async fn serve(
354        &self,
355        ctx: Context<State>,
356        req: Request<ReqBody>,
357    ) -> Result<Self::Response, Self::Error> {
358        let (ctx, req) = self
359            .mode
360            .apply(&self.header_name, ctx, req, &self.make)
361            .await;
362        self.inner.serve(ctx, req).await
363    }
364}