1 mod and;
2 mod and_then;
3 mod boxed;
4 mod map;
5 mod map_err;
6 mod or;
7 mod or_else;
8 mod recover;
9 mod service;
10 mod unify;
11 mod untuple_one;
12 mod wrap;
13
14 use futures::{future, Future, IntoFuture};
15
16 pub(crate) use generic::{one, Combine, Either, Func, HList, One, Tuple};
17 use reject::{CombineRejection, Reject, Rejection};
18 use route::{self, Route};
19
20 pub(crate) use self::and::And;
21 use self::and_then::AndThen;
22 pub use self::boxed::BoxedFilter;
23 pub(crate) use self::map::Map;
24 pub(crate) use self::map_err::MapErr;
25 pub(crate) use self::or::Or;
26 use self::or_else::OrElse;
27 use self::recover::Recover;
28 use self::unify::Unify;
29 use self::untuple_one::UntupleOne;
30 pub(crate) use self::wrap::{Wrap, WrapSealed};
31
32 // A crate-private base trait, allowing the actual `filter` method to change
33 // signatures without it being a breaking change.
34 pub trait FilterBase {
35 type Extract: Tuple; // + Send;
36 type Error: Reject;
37 type Future: Future<Item = Self::Extract, Error = Self::Error> + Send;
38
filter(&self) -> Self::Future39 fn filter(&self) -> Self::Future;
40
41 // crate-private for now
42
map_err<F, E>(self, fun: F) -> MapErr<Self, F> where Self: Sized, F: Fn(Self::Error) -> E + Clone, E: ::std::fmt::Debug + Send,43 fn map_err<F, E>(self, fun: F) -> MapErr<Self, F>
44 where
45 Self: Sized,
46 F: Fn(Self::Error) -> E + Clone,
47 E: ::std::fmt::Debug + Send,
48 {
49 MapErr {
50 filter: self,
51 callback: fun,
52 }
53 }
54 }
55
56 /// This just makes use of rustdoc's ability to make compile_fail tests.
57 /// This is specifically testing to make sure `Filter::filter` isn't
58 /// able to be called from outside the crate (since rustdoc tests are
59 /// compiled as new crates).
60 ///
61 /// ```compile_fail
62 /// use warp::Filter;
63 ///
64 /// let _ = warp::any().filter();
65 /// ```
__warp_filter_compilefail_doctest()66 pub fn __warp_filter_compilefail_doctest() {
67 // Duplicate code to make sure the code is otherwise valid.
68 let _ = ::any().filter();
69 }
70
71 /// Composable request filters.
72 ///
73 /// A `Filter` can optionally extract some data from a request, combine
74 /// it with others, mutate it, and return back some value as a reply. The
75 /// power of `Filter`s come from being able to isolate small subsets, and then
76 /// chain and reuse them in various parts of your app.
77 ///
78 /// # Extracting Tuples
79 ///
80 /// You may notice that several of these filters extract some tuple, often
81 /// times a tuple of just 1 item! Why?
82 ///
83 /// If a filter extracts a `(String,)`, that simply means that it
84 /// extracts a `String`. If you were to `map` the filter, the argument type
85 /// would be exactly that, just a `String`.
86 ///
87 /// What is it? It's just some type magic that allows for automatic combining
88 /// and flattening of tuples. Without it, combining two filters together with
89 /// `and`, where one extracted `()`, and another `String`, would mean the
90 /// `map` would be given a single argument of `((), String,)`, which is just
91 /// no fun.
92 pub trait Filter: FilterBase {
93 /// Composes a new `Filter` that requires both this and the other to filter a request.
94 ///
95 /// Additionally, this will join together the extracted values of both
96 /// filters, so that `map` and `and_then` receive them as separate arguments.
97 ///
98 /// If a `Filter` extracts nothing (so, `()`), combining with any other
99 /// filter will simply discard the `()`. If a `Filter` extracts one or
100 /// more items, combining will mean it extracts the values of itself
101 /// combined with the other.
102 ///
103 /// # Example
104 ///
105 /// ```
106 /// use warp::Filter;
107 ///
108 /// // Match `/hello/:name`...
109 /// warp::path("hello")
110 /// .and(warp::path::param::<String>());
111 /// ```
and<F>(self, other: F) -> And<Self, F> where Self: Sized, <Self::Extract as Tuple>::HList: Combine<<F::Extract as Tuple>::HList>, F: Filter + Clone, F::Error: CombineRejection<Self::Error>,112 fn and<F>(self, other: F) -> And<Self, F>
113 where
114 Self: Sized,
115 //Self::Extract: HList + Combine<F::Extract>,
116 <Self::Extract as Tuple>::HList: Combine<<F::Extract as Tuple>::HList>,
117 F: Filter + Clone,
118 F::Error: CombineRejection<Self::Error>,
119 {
120 And {
121 first: self,
122 second: other,
123 }
124 }
125
126 /// Composes a new `Filter` of either this or the other filter.
127 ///
128 /// # Example
129 ///
130 /// ```
131 /// use std::net::SocketAddr;
132 /// use warp::Filter;
133 ///
134 /// // Match either `/:u32` or `/:socketaddr`
135 /// warp::path::param::<u32>()
136 /// .or(warp::path::param::<SocketAddr>());
137 /// ```
or<F>(self, other: F) -> Or<Self, F> where Self: Sized, F: Filter, F::Error: CombineRejection<Self::Error>,138 fn or<F>(self, other: F) -> Or<Self, F>
139 where
140 Self: Sized,
141 F: Filter,
142 F::Error: CombineRejection<Self::Error>,
143 {
144 Or {
145 first: self,
146 second: other,
147 }
148 }
149
150 /// Composes this `Filter` with a function receiving the extracted value.
151 ///
152 ///
153 /// # Example
154 ///
155 /// ```
156 /// use warp::Filter;
157 ///
158 /// // Map `/:id`
159 /// warp::path::param().map(|id: u64| {
160 /// format!("Hello #{}", id)
161 /// });
162 /// ```
163 ///
164 /// # `Func`
165 ///
166 /// The generic `Func` trait is implemented for any function that receives
167 /// the same arguments as this `Filter` extracts. In practice, this
168 /// shouldn't ever bother you, and simply makes things feel more natural.
169 ///
170 /// For example, if three `Filter`s were combined together, suppose one
171 /// extracts nothing (so `()`), and the other two extract two integers,
172 /// a function that accepts exactly two integer arguments is allowed.
173 /// Specifically, any `Fn(u32, u32)`.
174 ///
175 /// Without `Product` and `Func`, this would be a lot messier. First of
176 /// all, the `()`s couldn't be discarded, and the tuples would be nested.
177 /// So, instead, you'd need to pass an `Fn(((), (u32, u32)))`. That's just
178 /// a single argument. Bleck!
179 ///
180 /// Even worse, the tuples would shuffle the types around depending on
181 /// the exact invocation of `and`s. So, `unit.and(int).and(int)` would
182 /// result in a different extracted type from `unit.and(int.and(int)`,
183 /// or from `int.and(unit).and(int)`. If you changed around the order
184 /// of filters, while still having them be semantically equivalent, you'd
185 /// need to update all your `map`s as well.
186 ///
187 /// `Product`, `HList`, and `Func` do all the heavy work so that none of
188 /// this is a bother to you. What's more, the types are enforced at
189 /// compile-time, and tuple flattening is optimized away to nothing by
190 /// LLVM.
map<F>(self, fun: F) -> Map<Self, F> where Self: Sized, F: Func<Self::Extract> + Clone,191 fn map<F>(self, fun: F) -> Map<Self, F>
192 where
193 Self: Sized,
194 F: Func<Self::Extract> + Clone,
195 {
196 Map {
197 filter: self,
198 callback: fun,
199 }
200 }
201
202 /// Composes this `Filter` with a function receiving the extracted value.
203 ///
204 /// The function should return some `IntoFuture` type.
205 ///
206 /// The `Error` type of the return `Future` needs be a `Rejection`, which
207 /// means most futures will need to have their error mapped into one.
208 ///
209 /// # Example
210 ///
211 /// ```
212 /// use warp::Filter;
213 ///
214 /// // Validate after `/:id`
215 /// warp::path::param().and_then(|id: u64| {
216 /// if id != 0 {
217 /// Ok(format!("Hello #{}", id))
218 /// } else {
219 /// Err(warp::reject::not_found())
220 /// }
221 /// });
222 /// ```
and_then<F>(self, fun: F) -> AndThen<Self, F> where Self: Sized, F: Func<Self::Extract> + Clone, F::Output: IntoFuture + Send, <F::Output as IntoFuture>::Error: CombineRejection<Self::Error>, <F::Output as IntoFuture>::Future: Send,223 fn and_then<F>(self, fun: F) -> AndThen<Self, F>
224 where
225 Self: Sized,
226 F: Func<Self::Extract> + Clone,
227 F::Output: IntoFuture + Send,
228 <F::Output as IntoFuture>::Error: CombineRejection<Self::Error>,
229 <F::Output as IntoFuture>::Future: Send,
230 {
231 AndThen {
232 filter: self,
233 callback: fun,
234 }
235 }
236
237 /// Compose this `Filter` with a function receiving an error.
238 ///
239 /// The function should return some `IntoFuture` type yielding the
240 /// same item and error types.
or_else<F>(self, fun: F) -> OrElse<Self, F> where Self: Sized, F: Func<Self::Error>, F::Output: IntoFuture<Item = Self::Extract, Error = Self::Error> + Send, <F::Output as IntoFuture>::Future: Send,241 fn or_else<F>(self, fun: F) -> OrElse<Self, F>
242 where
243 Self: Sized,
244 F: Func<Self::Error>,
245 F::Output: IntoFuture<Item = Self::Extract, Error = Self::Error> + Send,
246 <F::Output as IntoFuture>::Future: Send,
247 {
248 OrElse {
249 filter: self,
250 callback: fun,
251 }
252 }
253
254 /// Compose this `Filter` with a function receiving an error and
255 /// returning a *new* type, instead of the *same* type.
256 ///
257 /// This is useful for "customizing" rejections into new response types.
258 /// See also the [errors example][ex].
259 ///
260 /// [ex]: https://github.com/seanmonstar/warp/blob/master/examples/errors.rs
recover<F>(self, fun: F) -> Recover<Self, F> where Self: Sized, F: Func<Self::Error>, F::Output: IntoFuture<Error = Self::Error> + Send, <F::Output as IntoFuture>::Future: Send,261 fn recover<F>(self, fun: F) -> Recover<Self, F>
262 where
263 Self: Sized,
264 F: Func<Self::Error>,
265 F::Output: IntoFuture<Error = Self::Error> + Send,
266 <F::Output as IntoFuture>::Future: Send,
267 {
268 Recover {
269 filter: self,
270 callback: fun,
271 }
272 }
273
274 /// Unifies the extracted value of `Filter`s composed with `or`.
275 ///
276 /// When a `Filter` extracts some `Either<T, T>`, where both sides
277 /// are the same type, this combinator can be used to grab the
278 /// inner value, regardless of which side of `Either` it was. This
279 /// is useful for values that could be extracted from multiple parts
280 /// of a request, and the exact place isn't important.
281 ///
282 /// # Example
283 ///
284 /// ```rust
285 /// use std::net::SocketAddr;
286 /// use warp::Filter;
287 ///
288 /// let client_ip = warp::header("x-real-ip")
289 /// .or(warp::header("x-forwarded-for"))
290 /// .unify()
291 /// .map(|ip: SocketAddr| {
292 /// // Get the IP from either header,
293 /// // and unify into the inner type.
294 /// });
295 /// ```
unify<T>(self) -> Unify<Self> where Self: Filter<Extract = (Either<T, T>,)> + Sized, T: Tuple,296 fn unify<T>(self) -> Unify<Self>
297 where
298 Self: Filter<Extract = (Either<T, T>,)> + Sized,
299 T: Tuple,
300 {
301 Unify { filter: self }
302 }
303
304 /// Convenience method to remove one layer of tupling.
305 ///
306 /// This is useful for when things like `map` don't return a new value,
307 /// but just `()`, since warp will wrap it up into a `((),)`.
308 ///
309 /// # Example
310 ///
311 /// ```
312 /// use warp::Filter;
313 ///
314 /// let route = warp::path::param()
315 /// .map(|num: u64| {
316 /// println!("just logging: {}", num);
317 /// // returning "nothing"
318 /// })
319 /// .untuple_one()
320 /// .map(|| {
321 /// println!("the ((),) was removed");
322 /// warp::reply()
323 /// });
324 /// ```
325 ///
326 /// ```
327 /// use warp::Filter;
328 ///
329 /// let route = warp::any()
330 /// .map(|| {
331 /// // wanting to return a tuple
332 /// (true, 33)
333 /// })
334 /// .untuple_one()
335 /// .map(|is_enabled: bool, count: i32| {
336 /// println!("untupled: ({}, {})", is_enabled, count);
337 /// });
338 /// ```
untuple_one<T>(self) -> UntupleOne<Self> where Self: Filter<Extract = (T,)> + Sized, T: Tuple,339 fn untuple_one<T>(self) -> UntupleOne<Self>
340 where
341 Self: Filter<Extract = (T,)> + Sized,
342 T: Tuple,
343 {
344 UntupleOne { filter: self }
345 }
346
347 /// Wraps the current filter with some wrapper.
348 ///
349 /// The wrapper may do some preparation work before starting this filter,
350 /// and may do post-processing after the filter completes.
351 ///
352 /// # Example
353 ///
354 /// ```
355 /// use warp::Filter;
356 ///
357 /// let route = warp::any()
358 /// .map(warp::reply);
359 ///
360 /// // Wrap the route with a log wrapper.
361 /// let route = route.with(warp::log("example"));
362 /// ```
with<W>(self, wrapper: W) -> W::Wrapped where Self: Sized, W: Wrap<Self>,363 fn with<W>(self, wrapper: W) -> W::Wrapped
364 where
365 Self: Sized,
366 W: Wrap<Self>,
367 {
368 wrapper.wrap(self)
369 }
370
371 /// Boxes this filter into a trait object, making it easier to name the type.
372 ///
373 /// # Example
374 ///
375 /// ```
376 /// use warp::Filter;
377 ///
378 /// fn impl_reply() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
379 /// warp::any()
380 /// .map(warp::reply)
381 /// .boxed()
382 /// }
383 ///
384 /// fn named_i32() -> warp::filters::BoxedFilter<(i32,)> {
385 /// warp::path::param::<i32>()
386 /// .boxed()
387 /// }
388 ///
389 /// fn named_and() -> warp::filters::BoxedFilter<(i32, String)> {
390 /// warp::path::param::<i32>()
391 /// .and(warp::header::<String>("host"))
392 /// .boxed()
393 /// }
394 /// ```
boxed(self) -> BoxedFilter<Self::Extract> where Self: Sized + Send + Sync + 'static, Self::Extract: Send, Self::Error: Into<Rejection>,395 fn boxed(self) -> BoxedFilter<Self::Extract>
396 where
397 Self: Sized + Send + Sync + 'static,
398 Self::Extract: Send,
399 Self::Error: Into<Rejection>,
400 {
401 BoxedFilter::new(self)
402 }
403 }
404
405 impl<T: FilterBase> Filter for T {}
406
407 pub trait FilterClone: Filter + Clone {}
408
409 impl<T: Filter + Clone> FilterClone for T {}
410
_assert_object_safe()411 fn _assert_object_safe() {
412 fn _assert(_f: &dyn Filter<Extract = (), Error = (), Future = future::FutureResult<(), ()>>) {}
413 }
414
415 // ===== FilterFn =====
416
filter_fn<F, U>(func: F) -> FilterFn<F> where F: Fn(&mut Route) -> U, U: IntoFuture, U::Item: Tuple, U::Error: Reject,417 pub(crate) fn filter_fn<F, U>(func: F) -> FilterFn<F>
418 where
419 F: Fn(&mut Route) -> U,
420 U: IntoFuture,
421 U::Item: Tuple,
422 U::Error: Reject,
423 {
424 FilterFn { func }
425 }
426
filter_fn_one<F, U>( func: F, ) -> FilterFn<impl Fn(&mut Route) -> future::Map<U::Future, fn(U::Item) -> (U::Item,)> + Copy> where F: Fn(&mut Route) -> U + Copy, U: IntoFuture, U::Error: Reject,427 pub(crate) fn filter_fn_one<F, U>(
428 func: F,
429 ) -> FilterFn<impl Fn(&mut Route) -> future::Map<U::Future, fn(U::Item) -> (U::Item,)> + Copy>
430 where
431 F: Fn(&mut Route) -> U + Copy,
432 U: IntoFuture,
433 U::Error: Reject,
434 {
435 filter_fn(move |route| func(route).into_future().map(tup_one as _))
436 }
437
tup_one<T>(item: T) -> (T,)438 fn tup_one<T>(item: T) -> (T,) {
439 (item,)
440 }
441
442 #[derive(Copy, Clone)]
443 #[allow(missing_debug_implementations)]
444 pub(crate) struct FilterFn<F> {
445 // TODO: could include a `debug_str: &'static str` to be used in Debug impl
446 func: F,
447 }
448
449 impl<F, U> FilterBase for FilterFn<F>
450 where
451 F: Fn(&mut Route) -> U,
452 U: IntoFuture,
453 U::Future: Send,
454 U::Item: Tuple,
455 U::Error: Reject,
456 {
457 type Extract = U::Item;
458 type Error = U::Error;
459 type Future = U::Future;
460
461 #[inline]
filter(&self) -> Self::Future462 fn filter(&self) -> Self::Future {
463 route::with(|route| (self.func)(route).into_future())
464 }
465 }
466