warp/filters/
reply.rs

1//! Reply Filters
2//!
3//! These "filters" behave a little differently than the rest. Instead of
4//! being used directly on requests, these filters "wrap" other filters.
5//!
6//!
7//! ## Wrapping a `Filter` (`with`)
8//!
9//! ```
10//! use warp::Filter;
11//!
12//! let with_server = warp::reply::with::header("server", "warp");
13//!
14//! let route = warp::any()
15//!     .map(warp::reply)
16//!     .with(with_server);
17//! ```
18//!
19//! Wrapping allows adding in conditional logic *before* the request enters
20//! the inner filter (though the `with::header` wrapper does not).
21
22use std::convert::TryFrom;
23use std::sync::Arc;
24
25use http::header::{HeaderMap, HeaderName, HeaderValue};
26
27use self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_};
28use crate::filter::{Filter, Map, WrapSealed};
29use crate::reply::Reply;
30
31/// Wrap a [`Filter`] that adds a header to the reply.
32///
33/// # Note
34///
35/// This **only** adds a header if the underlying filter is successful, and
36/// returns a [`Reply`] If the underlying filter was rejected, the
37/// header is not added.
38///
39/// # Example
40///
41/// ```
42/// use warp::Filter;
43///
44/// // Always set `foo: bar` header.
45/// let route = warp::any()
46///     .map(warp::reply)
47///     .with(warp::reply::with::header("foo", "bar"));
48/// ```
49pub fn header<K, V>(name: K, value: V) -> WithHeader
50where
51    HeaderName: TryFrom<K>,
52    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
53    HeaderValue: TryFrom<V>,
54    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
55{
56    let (name, value) = assert_name_and_value(name, value);
57    WithHeader { name, value }
58}
59
60/// Wrap a [`Filter`] that adds multiple headers to the reply.
61///
62/// # Note
63///
64/// This **only** adds a header if the underlying filter is successful, and
65/// returns a [`Reply`] If the underlying filter was rejected, the
66/// header is not added.
67///
68/// # Example
69///
70/// ```
71/// use warp::http::header::{HeaderMap, HeaderValue};
72/// use warp::Filter;
73///
74/// let mut headers = HeaderMap::new();
75/// headers.insert("server", HeaderValue::from_static("wee/0"));
76/// headers.insert("foo", HeaderValue::from_static("bar"));
77///
78/// // Always set `server: wee/0` and `foo: bar` headers.
79/// let route = warp::any()
80///     .map(warp::reply)
81///     .with(warp::reply::with::headers(headers));
82/// ```
83pub fn headers(headers: HeaderMap) -> WithHeaders {
84    WithHeaders {
85        headers: Arc::new(headers),
86    }
87}
88
89// pub fn headers?
90
91/// Wrap a [`Filter`] that adds a header to the reply, if they
92/// aren't already set.
93///
94/// # Note
95///
96/// This **only** adds a header if the underlying filter is successful, and
97/// returns a [`Reply`] If the underlying filter was rejected, the
98/// header is not added.
99///
100/// # Example
101///
102/// ```
103/// use warp::Filter;
104///
105/// // Set `server: warp` if not already set.
106/// let route = warp::any()
107///     .map(warp::reply)
108///     .with(warp::reply::with::default_header("server", "warp"));
109/// ```
110pub fn default_header<K, V>(name: K, value: V) -> WithDefaultHeader
111where
112    HeaderName: TryFrom<K>,
113    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
114    HeaderValue: TryFrom<V>,
115    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
116{
117    let (name, value) = assert_name_and_value(name, value);
118    WithDefaultHeader { name, value }
119}
120
121/// Wrap a `Filter` to always set a header.
122#[derive(Clone, Debug)]
123pub struct WithHeader {
124    name: HeaderName,
125    value: HeaderValue,
126}
127
128impl<F, R> WrapSealed<F> for WithHeader
129where
130    F: Filter<Extract = (R,)>,
131    R: Reply,
132{
133    type Wrapped = Map<F, WithHeader_>;
134
135    fn wrap(&self, filter: F) -> Self::Wrapped {
136        let with = WithHeader_ { with: self.clone() };
137        filter.map(with)
138    }
139}
140
141/// Wrap a `Filter` to always set multiple headers.
142#[derive(Clone, Debug)]
143pub struct WithHeaders {
144    headers: Arc<HeaderMap>,
145}
146
147impl<F, R> WrapSealed<F> for WithHeaders
148where
149    F: Filter<Extract = (R,)>,
150    R: Reply,
151{
152    type Wrapped = Map<F, WithHeaders_>;
153
154    fn wrap(&self, filter: F) -> Self::Wrapped {
155        let with = WithHeaders_ { with: self.clone() };
156        filter.map(with)
157    }
158}
159
160/// Wrap a `Filter` to set a header if it is not already set.
161#[derive(Clone, Debug)]
162pub struct WithDefaultHeader {
163    name: HeaderName,
164    value: HeaderValue,
165}
166
167impl<F, R> WrapSealed<F> for WithDefaultHeader
168where
169    F: Filter<Extract = (R,)>,
170    R: Reply,
171{
172    type Wrapped = Map<F, WithDefaultHeader_>;
173
174    fn wrap(&self, filter: F) -> Self::Wrapped {
175        let with = WithDefaultHeader_ { with: self.clone() };
176        filter.map(with)
177    }
178}
179
180fn assert_name_and_value<K, V>(name: K, value: V) -> (HeaderName, HeaderValue)
181where
182    HeaderName: TryFrom<K>,
183    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
184    HeaderValue: TryFrom<V>,
185    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
186{
187    let name = <HeaderName as TryFrom<K>>::try_from(name)
188        .map_err(Into::into)
189        .unwrap_or_else(|_| panic!("invalid header name"));
190
191    let value = <HeaderValue as TryFrom<V>>::try_from(value)
192        .map_err(Into::into)
193        .unwrap_or_else(|_| panic!("invalid header value"));
194
195    (name, value)
196}
197
198mod sealed {
199    use super::{WithDefaultHeader, WithHeader, WithHeaders};
200    use crate::generic::{Func, One};
201    use crate::reply::{Reply, Reply_};
202
203    #[derive(Clone)]
204    #[allow(missing_debug_implementations)]
205    pub struct WithHeader_ {
206        pub(super) with: WithHeader,
207    }
208
209    impl<R: Reply> Func<One<R>> for WithHeader_ {
210        type Output = Reply_;
211
212        fn call(&self, args: One<R>) -> Self::Output {
213            let mut resp = args.0.into_response();
214            // Use "insert" to replace any set header...
215            resp.headers_mut()
216                .insert(&self.with.name, self.with.value.clone());
217            Reply_(resp)
218        }
219    }
220
221    #[derive(Clone)]
222    #[allow(missing_debug_implementations)]
223    pub struct WithHeaders_ {
224        pub(super) with: WithHeaders,
225    }
226
227    impl<R: Reply> Func<One<R>> for WithHeaders_ {
228        type Output = Reply_;
229
230        fn call(&self, args: One<R>) -> Self::Output {
231            let mut resp = args.0.into_response();
232            for (name, value) in &*self.with.headers {
233                resp.headers_mut().insert(name, value.clone());
234            }
235            Reply_(resp)
236        }
237    }
238
239    #[derive(Clone)]
240    #[allow(missing_debug_implementations)]
241    pub struct WithDefaultHeader_ {
242        pub(super) with: WithDefaultHeader,
243    }
244
245    impl<R: Reply> Func<One<R>> for WithDefaultHeader_ {
246        type Output = Reply_;
247
248        fn call(&self, args: One<R>) -> Self::Output {
249            let mut resp = args.0.into_response();
250            resp.headers_mut()
251                .entry(&self.with.name)
252                .or_insert_with(|| self.with.value.clone());
253
254            Reply_(resp)
255        }
256    }
257}