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