Skip to main content

tower_http/set_header/
mod.rs

1//! Middleware for setting headers on requests and responses.
2//!
3//! See [request] and [response] for more details.
4
5use std::fmt;
6
7use http::{header::HeaderName, HeaderMap, HeaderValue, Request, Response};
8
9pub mod request;
10pub mod response;
11
12#[doc(inline)]
13pub use self::{
14    request::{SetRequestHeader, SetRequestHeaderLayer},
15    response::{SetResponseHeader, SetResponseHeaderLayer},
16};
17
18/// Trait for producing header values.
19///
20/// Used by [`SetRequestHeader`] and [`SetResponseHeader`].
21///
22/// This trait is implemented for closures with the correct type signature. Typically users will
23/// not have to implement this trait for their own types.
24///
25/// It is also implemented directly for [`HeaderValue`]. When a fixed header value should be added
26/// to all responses, it can be supplied directly to the middleware.
27pub trait MakeHeaderValue<T> {
28    /// Try to create a header value from the request or response.
29    fn make_header_value(&mut self, message: &T) -> Option<HeaderValue>;
30}
31
32impl<F, T> MakeHeaderValue<T> for F
33where
34    F: FnMut(&T) -> Option<HeaderValue>,
35{
36    fn make_header_value(&mut self, message: &T) -> Option<HeaderValue> {
37        self(message)
38    }
39}
40
41impl<T> MakeHeaderValue<T> for HeaderValue {
42    fn make_header_value(&mut self, _message: &T) -> Option<HeaderValue> {
43        Some(self.clone())
44    }
45}
46
47impl<T> MakeHeaderValue<T> for Option<HeaderValue> {
48    fn make_header_value(&mut self, _message: &T) -> Option<HeaderValue> {
49        self.clone()
50    }
51}
52
53#[derive(Debug, Clone, Copy)]
54enum InsertHeaderMode {
55    Override,
56    Append,
57    IfNotPresent,
58}
59
60impl InsertHeaderMode {
61    fn apply<T, M>(self, header_name: &HeaderName, target: &mut T, make: &mut M)
62    where
63        T: Headers,
64        M: MakeHeaderValue<T>,
65    {
66        match self {
67            InsertHeaderMode::Override => {
68                if let Some(value) = make.make_header_value(target) {
69                    target.headers_mut().insert(header_name.clone(), value);
70                }
71            }
72            InsertHeaderMode::IfNotPresent => {
73                if !target.headers().contains_key(header_name) {
74                    if let Some(value) = make.make_header_value(target) {
75                        target.headers_mut().insert(header_name.clone(), value);
76                    }
77                }
78            }
79            InsertHeaderMode::Append => {
80                if let Some(value) = make.make_header_value(target) {
81                    target.headers_mut().append(header_name.clone(), value);
82                }
83            }
84        }
85    }
86}
87
88trait Headers {
89    fn headers(&self) -> &HeaderMap;
90
91    fn headers_mut(&mut self) -> &mut HeaderMap;
92}
93
94impl<B> Headers for Request<B> {
95    fn headers(&self) -> &HeaderMap {
96        Request::headers(self)
97    }
98
99    fn headers_mut(&mut self) -> &mut HeaderMap {
100        Request::headers_mut(self)
101    }
102}
103
104impl<B> Headers for Response<B> {
105    fn headers(&self) -> &HeaderMap {
106        Response::headers(self)
107    }
108
109    fn headers_mut(&mut self) -> &mut HeaderMap {
110        Response::headers_mut(self)
111    }
112}
113
114/// A trait that combines MakeHeaderValue and Clone capability for trait objects.
115trait CloneableMakeHeaderValue<T>: MakeHeaderValue<T> + Send + Sync {
116    fn clone_box(&self) -> Box<dyn CloneableMakeHeaderValue<T>>;
117}
118
119impl<T, M> CloneableMakeHeaderValue<T> for M
120where
121    M: MakeHeaderValue<T> + Clone + Send + Sync + 'static,
122{
123    fn clone_box(&self) -> Box<dyn CloneableMakeHeaderValue<T>> {
124        Box::new(self.clone())
125    }
126}
127
128/// A "Bridge" struct that allows for trait object-based header value generation.
129struct BoxedMakeHeaderValue<T>(Box<dyn CloneableMakeHeaderValue<T>>);
130
131impl<T> BoxedMakeHeaderValue<T> {
132    /// Create a new BoxedMakeHeaderValue from any maker that implements MakeHeaderValue and Clone.
133    fn new<M>(maker: M) -> Self
134    where
135        M: MakeHeaderValue<T> + Clone + Send + Sync + 'static,
136    {
137        Self(Box::new(maker))
138    }
139}
140
141impl<T> Clone for BoxedMakeHeaderValue<T> {
142    fn clone(&self) -> Self {
143        Self(self.0.clone_box())
144    }
145}
146
147impl<T> MakeHeaderValue<T> for BoxedMakeHeaderValue<T> {
148    fn make_header_value(&mut self, message: &T) -> Option<HeaderValue> {
149        self.0.make_header_value(message)
150    }
151}
152
153impl<T> fmt::Debug for BoxedMakeHeaderValue<T> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        f.debug_struct("BoxedMakeHeaderValue").finish()
156    }
157}
158
159/// Metadata describing a request or response header to be set.
160#[derive(Debug)]
161pub struct HeaderMetadata<T> {
162    /// The name of the header to set.
163    header_name: HeaderName,
164    /// The value or value factory for the header.
165    make: BoxedMakeHeaderValue<T>,
166}
167
168impl<T> Clone for HeaderMetadata<T> {
169    fn clone(&self) -> Self {
170        Self {
171            header_name: self.header_name.clone(),
172            make: self.make.clone(),
173        }
174    }
175}
176
177impl<T> HeaderMetadata<T> {
178    /// Create a new HeaderMetadata with the given header name and value factory.
179    fn new<M: MakeHeaderValue<T> + Clone + 'static + Send + Sync>(
180        header_name: HeaderName,
181        make: M,
182    ) -> Self {
183        Self {
184            header_name,
185            make: BoxedMakeHeaderValue::new(make),
186        }
187    }
188
189    /// Convert this metadata into a [`HeaderInsertionConfig`] with the given insertion mode.
190    fn build_config(self, mode: InsertHeaderMode) -> HeaderInsertionConfig<T> {
191        HeaderInsertionConfig {
192            header_name: self.header_name,
193            make: self.make,
194            mode,
195        }
196    }
197}
198
199impl<T, M> From<(HeaderName, M)> for HeaderMetadata<T>
200where
201    M: MakeHeaderValue<T> + Clone + 'static + Send + Sync,
202{
203    fn from((header_name, make): (HeaderName, M)) -> Self {
204        HeaderMetadata::new(header_name, make)
205    }
206}
207
208/// Configuration for inserting a header into a response or request.
209struct HeaderInsertionConfig<T> {
210    header_name: HeaderName,
211    make: BoxedMakeHeaderValue<T>,
212    mode: InsertHeaderMode,
213}
214
215impl<T> Clone for HeaderInsertionConfig<T>
216where
217    BoxedMakeHeaderValue<T>: Clone,
218{
219    fn clone(&self) -> Self {
220        Self {
221            header_name: self.header_name.clone(),
222            make: self.make.clone(),
223            mode: self.mode,
224        }
225    }
226}
227
228impl<T> fmt::Debug for HeaderInsertionConfig<T> {
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        f.debug_struct("HeaderInsertionConfig")
231            .field("header_name", &self.header_name)
232            .field("mode", &self.mode)
233            .field("make", &"BoxedMakeHeaderValue")
234            .finish()
235    }
236}