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::{HeaderValue, Request, Response, header::HeaderName, headers::Header};
84use rama_core::{Context, Layer, Service};
85use rama_utils::macros::define_inner_service_accessors;
86use std::fmt;
87
88mod header;
89use header::InsertHeaderMode;
90
91pub use header::{BoxMakeHeaderValueFn, MakeHeaderValue};
92
93/// Layer that applies [`SetRequestHeader`] which adds a request header.
94///
95/// See [`SetRequestHeader`] for more details.
96pub struct SetRequestHeaderLayer<M> {
97    header_name: HeaderName,
98    make: M,
99    mode: InsertHeaderMode,
100}
101
102impl<M> fmt::Debug for SetRequestHeaderLayer<M> {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        f.debug_struct("SetRequestHeaderLayer")
105            .field("header_name", &self.header_name)
106            .field("mode", &self.mode)
107            .field("make", &std::any::type_name::<M>())
108            .finish()
109    }
110}
111
112impl<M> SetRequestHeaderLayer<M> {
113    /// Create a new [`SetRequestHeaderLayer`].
114    ///
115    /// If a previous value exists for the same header, it is removed and replaced with the new
116    /// header value.
117    pub fn overriding(header_name: HeaderName, make: M) -> Self {
118        Self::new(header_name, make, InsertHeaderMode::Override)
119    }
120
121    /// Create a new [`SetRequestHeaderLayer`].
122    ///
123    /// The new header is always added, preserving any existing values. If previous values exist,
124    /// the header will have multiple values.
125    pub fn appending(header_name: HeaderName, make: M) -> Self {
126        Self::new(header_name, make, InsertHeaderMode::Append)
127    }
128
129    /// Create a new [`SetRequestHeaderLayer`].
130    ///
131    /// If a previous value exists for the header, the new value is not inserted.
132    pub fn if_not_present(header_name: HeaderName, make: M) -> Self {
133        Self::new(header_name, make, InsertHeaderMode::IfNotPresent)
134    }
135
136    fn new(header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
137        Self {
138            make,
139            header_name,
140            mode,
141        }
142    }
143}
144
145impl SetRequestHeaderLayer<HeaderValue> {
146    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
147    ///
148    /// See [`SetRequestHeaderLayer::overriding`] for more details.
149    pub fn overriding_typed<H: Header>(header: H) -> Self {
150        Self::overriding(H::name().clone(), header.encode_to_value())
151    }
152
153    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
154    ///
155    /// See [`SetRequestHeaderLayer::appending`] for more details.
156    pub fn appending_typed<H: Header>(header: H) -> Self {
157        Self::appending(H::name().clone(), header.encode_to_value())
158    }
159
160    /// Create a new [`SetRequestHeaderLayer`] from a typed [`Header`].
161    ///
162    /// See [`SetRequestHeaderLayer::if_not_present`] for more details.
163    pub fn if_not_present_typed<H: Header>(header: H) -> Self {
164        Self::if_not_present(H::name().clone(), header.encode_to_value())
165    }
166}
167
168impl<F, A> SetRequestHeaderLayer<BoxMakeHeaderValueFn<F, A>> {
169    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
170    ///
171    /// See [`SetRequestHeaderLayer::overriding`] for more details.
172    pub fn overriding_fn(header_name: HeaderName, make_fn: F) -> Self {
173        Self::new(
174            header_name,
175            BoxMakeHeaderValueFn::new(make_fn),
176            InsertHeaderMode::Override,
177        )
178    }
179
180    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
181    ///
182    /// See [`SetRequestHeaderLayer::appending`] for more details.
183    pub fn appending_fn(header_name: HeaderName, make_fn: F) -> Self {
184        Self::new(
185            header_name,
186            BoxMakeHeaderValueFn::new(make_fn),
187            InsertHeaderMode::Append,
188        )
189    }
190
191    /// Create a new [`SetRequestHeaderLayer`] from a [`super::MakeHeaderValueFn`].
192    ///
193    /// See [`SetRequestHeaderLayer::if_not_present`] for more details.
194    pub fn if_not_present_fn(header_name: HeaderName, make_fn: F) -> Self {
195        Self::new(
196            header_name,
197            BoxMakeHeaderValueFn::new(make_fn),
198            InsertHeaderMode::IfNotPresent,
199        )
200    }
201}
202
203impl<S, M> Layer<S> for SetRequestHeaderLayer<M>
204where
205    M: Clone,
206{
207    type Service = SetRequestHeader<S, M>;
208
209    fn layer(&self, inner: S) -> Self::Service {
210        SetRequestHeader {
211            inner,
212            header_name: self.header_name.clone(),
213            make: self.make.clone(),
214            mode: self.mode,
215        }
216    }
217
218    fn into_layer(self, inner: S) -> Self::Service {
219        SetRequestHeader {
220            inner,
221            header_name: self.header_name,
222            make: self.make,
223            mode: self.mode,
224        }
225    }
226}
227
228impl<M> Clone for SetRequestHeaderLayer<M>
229where
230    M: Clone,
231{
232    fn clone(&self) -> Self {
233        Self {
234            make: self.make.clone(),
235            header_name: self.header_name.clone(),
236            mode: self.mode,
237        }
238    }
239}
240
241/// Middleware that sets a header on the request.
242#[derive(Clone)]
243pub struct SetRequestHeader<S, M> {
244    inner: S,
245    header_name: HeaderName,
246    make: M,
247    mode: InsertHeaderMode,
248}
249
250impl<S, M> SetRequestHeader<S, M> {
251    /// Create a new [`SetRequestHeader`].
252    ///
253    /// If a previous value exists for the same header, it is removed and replaced with the new
254    /// header value.
255    pub fn overriding(inner: S, header_name: HeaderName, make: M) -> Self {
256        Self::new(inner, header_name, make, InsertHeaderMode::Override)
257    }
258
259    /// Create a new [`SetRequestHeader`].
260    ///
261    /// The new header is always added, preserving any existing values. If previous values exist,
262    /// the header will have multiple values.
263    pub fn appending(inner: S, header_name: HeaderName, make: M) -> Self {
264        Self::new(inner, header_name, make, InsertHeaderMode::Append)
265    }
266
267    /// Create a new [`SetRequestHeader`].
268    ///
269    /// If a previous value exists for the header, the new value is not inserted.
270    pub fn if_not_present(inner: S, header_name: HeaderName, make: M) -> Self {
271        Self::new(inner, header_name, make, InsertHeaderMode::IfNotPresent)
272    }
273
274    fn new(inner: S, header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
275        Self {
276            inner,
277            header_name,
278            make,
279            mode,
280        }
281    }
282
283    define_inner_service_accessors!();
284}
285
286impl<S, F, A> SetRequestHeader<S, BoxMakeHeaderValueFn<F, A>> {
287    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
288    ///
289    /// See [`SetRequestHeader::overriding`] for more details.
290    pub fn overriding_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
291        Self::new(
292            inner,
293            header_name,
294            BoxMakeHeaderValueFn::new(make_fn),
295            InsertHeaderMode::Override,
296        )
297    }
298
299    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
300    ///
301    /// See [`SetRequestHeader::appending`] for more details.
302    pub fn appending_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
303        Self::new(
304            inner,
305            header_name,
306            BoxMakeHeaderValueFn::new(make_fn),
307            InsertHeaderMode::Append,
308        )
309    }
310
311    /// Create a new [`SetRequestHeader`] from a [`super::MakeHeaderValueFn`].
312    ///
313    /// See [`SetRequestHeader::if_not_present`] for more details.
314    pub fn if_not_present_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
315        Self::new(
316            inner,
317            header_name,
318            BoxMakeHeaderValueFn::new(make_fn),
319            InsertHeaderMode::IfNotPresent,
320        )
321    }
322}
323
324impl<S, M> fmt::Debug for SetRequestHeader<S, M>
325where
326    S: fmt::Debug,
327{
328    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329        f.debug_struct("SetRequestHeader")
330            .field("inner", &self.inner)
331            .field("header_name", &self.header_name)
332            .field("mode", &self.mode)
333            .field("make", &std::any::type_name::<M>())
334            .finish()
335    }
336}
337
338impl<ReqBody, ResBody, State, S, M> Service<State, Request<ReqBody>> for SetRequestHeader<S, M>
339where
340    ReqBody: Send + 'static,
341    ResBody: Send + 'static,
342    State: Clone + Send + Sync + 'static,
343    S: Service<State, Request<ReqBody>, Response = Response<ResBody>>,
344    M: MakeHeaderValue<State, ReqBody>,
345{
346    type Response = S::Response;
347    type Error = S::Error;
348
349    async fn serve(
350        &self,
351        ctx: Context<State>,
352        req: Request<ReqBody>,
353    ) -> Result<Self::Response, Self::Error> {
354        let (ctx, req) = self
355            .mode
356            .apply(&self.header_name, ctx, req, &self.make)
357            .await;
358        self.inner.serve(ctx, req).await
359    }
360}