1 //! Header Filters
2 //!
3 //! These filters are used to interact with the Request HTTP headers. Some
4 //! of them, like `exact` and `exact_ignore_case`, are just predicates,
5 //! they don't extract any values. The `header` filter allows parsing
6 //! a type from any header.
7 use std::str::FromStr;
8
9 use headers::{Header, HeaderMapExt};
10 use http::HeaderMap;
11
12 use filter::{filter_fn, filter_fn_one, Filter, One};
13 use never::Never;
14 use reject::{self, Rejection};
15
16 /// Create a `Filter` that tries to parse the specified header.
17 ///
18 /// This `Filter` will look for a header with supplied name, and try to
19 /// parse to a `T`, otherwise rejects the request.
20 ///
21 /// # Example
22 ///
23 /// ```
24 /// use std::net::SocketAddr;
25 ///
26 /// // Parse `content-length: 100` as a `u64`
27 /// let content_length = warp::header::<u64>("content-length");
28 ///
29 /// // Parse `host: 127.0.0.1:8080` as a `SocketAddr
30 /// let local_host = warp::header::<SocketAddr>("host");
31 ///
32 /// // Parse `foo: bar` into a `String`
33 /// let foo = warp::header::<String>("foo");
34 /// ```
header<T: FromStr + Send>( name: &'static str, ) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy35 pub fn header<T: FromStr + Send>(
36 name: &'static str,
37 ) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {
38 filter_fn_one(move |route| {
39 trace!("header({:?})", name);
40 route
41 .headers()
42 .get(name)
43 .ok_or_else(|| reject::missing_header(name))
44 .and_then(|value| {
45 value
46 .to_str()
47 .map_err(|_| reject::invalid_header(name))
48 })
49 .and_then(|s| T::from_str(s).map_err(|_| reject::invalid_header(name)))
50 })
51 }
52
header2<T: Header + Send>() -> impl Filter<Extract = One<T>, Error = Rejection> + Copy53 pub(crate) fn header2<T: Header + Send>() -> impl Filter<Extract = One<T>, Error = Rejection> + Copy
54 {
55 filter_fn_one(move |route| {
56 trace!("header2({:?})", T::name());
57 route
58 .headers()
59 .typed_get()
60 .ok_or_else(|| reject::invalid_header(T::name().as_str()))
61 })
62 }
63
64 /// Create a `Filter` that tries to parse the specified header, if it exists.
65 ///
66 /// If the header does not exist, it yields `None`. Otherwise, it will try to
67 /// parse as a `T`, and if it fails, a invalid header rejection is return. If
68 /// successful, the filter yields `Some(T)`.
69 ///
70 /// # Example
71 ///
72 /// ```
73 /// // Grab the `authorization` header if it exists.
74 /// let opt_auth = warp::header::optional::<String>("authorization");
75 /// ```
optional<T>( name: &'static str, ) -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy where T: FromStr + Send,76 pub fn optional<T>(
77 name: &'static str,
78 ) -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy
79 where
80 T: FromStr + Send,
81 {
82 filter_fn_one(move |route| {
83 trace!("optional({:?})", name);
84 let result = route.headers().get(name).map(|value| {
85 value
86 .to_str()
87 .map_err(|_| reject::invalid_header(name))?
88 .parse::<T>()
89 .map_err(|_| reject::invalid_header(name))
90 });
91
92 match result {
93 Some(Ok(t)) => Ok(Some(t)),
94 Some(Err(e)) => Err(e),
95 None => Ok(None),
96 }
97 })
98 }
99
optional2<T>() -> impl Filter<Extract = One<Option<T>>, Error = Never> + Copy where T: Header + Send,100 pub(crate) fn optional2<T>() -> impl Filter<Extract = One<Option<T>>, Error = Never> + Copy
101 where
102 T: Header + Send,
103 {
104 filter_fn_one(move |route| Ok(route.headers().typed_get()))
105 }
106
107 /* TODO
108 pub fn exact2<T>(header: T) -> impl FilterClone<Extract=(), Error=Rejection>
109 where
110 T: Header + PartialEq + Clone + Send,
111 {
112 filter_fn(move |route| {
113 trace!("exact2({:?})", T::NAME);
114 route.headers()
115 .typed_get::<T>()
116 .and_then(|val| if val == header {
117 Some(())
118 } else {
119 None
120 })
121 .ok_or_else(|| reject::bad_request())
122 })
123 }
124 */
125
126 /// Create a `Filter` that requires a header to match the value exactly.
127 ///
128 /// This `Filter` will look for a header with supplied name and the exact
129 /// value, otherwise rejects the request.
130 ///
131 /// # Example
132 ///
133 /// ```
134 /// // Require `dnt: 1` header to be set.
135 /// let must_dnt = warp::header::exact("dnt", "1");
136 /// ```
exact( name: &'static str, value: &'static str, ) -> impl Filter<Extract = (), Error = Rejection> + Copy137 pub fn exact(
138 name: &'static str,
139 value: &'static str,
140 ) -> impl Filter<Extract = (), Error = Rejection> + Copy {
141 filter_fn(move |route| {
142 trace!("exact?({:?}, {:?})", name, value);
143 route
144 .headers()
145 .get(name)
146 .ok_or_else(|| reject::missing_header(name))
147 .and_then(|val| {
148 if val == value {
149 Ok(())
150 } else {
151 Err(reject::invalid_header(name))
152 }
153 })
154 })
155 }
156
157 /// Create a `Filter` that requires a header to match the value exactly.
158 ///
159 /// This `Filter` will look for a header with supplied name and the exact
160 /// value, ignoring ASCII case, otherwise rejects the request.
161 ///
162 /// # Example
163 ///
164 /// ```
165 /// // Require `connection: keep-alive` header to be set.
166 /// let keep_alive = warp::header::exact("connection", "keep-alive");
167 /// ```
exact_ignore_case( name: &'static str, value: &'static str, ) -> impl Filter<Extract = (), Error = Rejection> + Copy168 pub fn exact_ignore_case(
169 name: &'static str,
170 value: &'static str,
171 ) -> impl Filter<Extract = (), Error = Rejection> + Copy {
172 filter_fn(move |route| {
173 trace!("exact_ignore_case({:?}, {:?})", name, value);
174 route
175 .headers()
176 .get(name)
177 .ok_or_else(|| reject::missing_header(name))
178 .and_then(|val| {
179 if val.as_bytes().eq_ignore_ascii_case(value.as_bytes()) {
180 Ok(())
181 } else {
182 Err(reject::invalid_header(name))
183 }
184 })
185 })
186 }
187
188 /// Create a `Filter` that returns a clone of the request's `HeaderMap`.
189 ///
190 /// # Example
191 ///
192 /// ```
193 /// use warp::{Filter, http::HeaderMap};
194 ///
195 /// let headers = warp::header::headers_cloned()
196 /// .map(|headers: HeaderMap| {
197 /// format!("header count: {}", headers.len())
198 /// });
199 /// ```
headers_cloned() -> impl Filter<Extract = One<HeaderMap>, Error = Never> + Copy200 pub fn headers_cloned() -> impl Filter<Extract = One<HeaderMap>, Error = Never> + Copy {
201 filter_fn_one(|route| Ok(route.headers().clone()))
202 }
203