warp/filter/
mod.rs

1mod and;
2mod and_then;
3mod boxed;
4mod map;
5mod map_err;
6mod or;
7mod or_else;
8mod recover;
9pub(crate) mod service;
10mod then;
11mod unify;
12mod untuple_one;
13mod wrap;
14
15use std::future::Future;
16
17use futures_util::{future, TryFuture, TryFutureExt};
18
19pub(crate) use crate::generic::{one, Combine, Either, Func, One, Tuple};
20use crate::reject::{CombineRejection, IsReject, Rejection};
21use crate::route::{self, Route};
22
23pub(crate) use self::and::And;
24use self::and_then::AndThen;
25pub use self::boxed::BoxedFilter;
26pub(crate) use self::map::Map;
27pub(crate) use self::map_err::MapErr;
28pub(crate) use self::or::Or;
29use self::or_else::OrElse;
30use self::recover::Recover;
31use self::then::Then;
32use self::unify::Unify;
33use self::untuple_one::UntupleOne;
34pub use self::wrap::wrap_fn;
35pub(crate) use self::wrap::{Wrap, WrapSealed};
36
37// A crate-private base trait, allowing the actual `filter` method to change
38// signatures without it being a breaking change.
39pub trait FilterBase {
40    type Extract: Tuple; // + Send;
41    type Error: IsReject;
42    type Future: Future<Output = Result<Self::Extract, Self::Error>> + Send;
43
44    fn filter(&self, internal: Internal) -> Self::Future;
45
46    fn map_err<F, E>(self, _internal: Internal, fun: F) -> MapErr<Self, F>
47    where
48        Self: Sized,
49        F: Fn(Self::Error) -> E + Clone,
50        E: ::std::fmt::Debug + Send,
51    {
52        MapErr {
53            filter: self,
54            callback: fun,
55        }
56    }
57}
58
59// A crate-private argument to prevent users from calling methods on
60// the `FilterBase` trait.
61//
62// For instance, this innocent user code could otherwise call `filter`:
63//
64// ```
65// async fn with_filter<F: Filter>(f: F) -> Result<F::Extract, F::Error> {
66//     f.filter().await
67// }
68// ```
69#[allow(missing_debug_implementations)]
70pub struct Internal;
71
72/// Composable request filters.
73///
74/// A `Filter` can optionally extract some data from a request, combine
75/// it with others, mutate it, and return back some value as a reply. The
76/// power of `Filter`s come from being able to isolate small subsets, and then
77/// chain and reuse them in various parts of your app.
78///
79/// # Extracting Tuples
80///
81/// You may notice that several of these filters extract some tuple, often
82/// times a tuple of just 1 item! Why?
83///
84/// If a filter extracts a `(String,)`, that simply means that it
85/// extracts a `String`. If you were to `map` the filter, the argument type
86/// would be exactly that, just a `String`.
87///
88/// What is it? It's just some type magic that allows for automatic combining
89/// and flattening of tuples. Without it, combining two filters together with
90/// `and`, where one extracted `()`, and another `String`, would mean the
91/// `map` would be given a single argument of `((), String,)`, which is just
92/// no fun.
93pub trait Filter: FilterBase {
94    /// Composes a new `Filter` that requires both this and the other to filter a request.
95    ///
96    /// Additionally, this will join together the extracted values of both
97    /// filters, so that `map` and `and_then` receive them as separate arguments.
98    ///
99    /// If a `Filter` extracts nothing (so, `()`), combining with any other
100    /// filter will simply discard the `()`. If a `Filter` extracts one or
101    /// more items, combining will mean it extracts the values of itself
102    /// combined with the other.
103    ///
104    /// # Example
105    ///
106    /// ```
107    /// use warp::Filter;
108    ///
109    /// // Match `/hello/:name`...
110    /// warp::path("hello")
111    ///     .and(warp::path::param::<String>());
112    /// ```
113    fn and<F>(self, other: F) -> And<Self, F>
114    where
115        Self: Sized,
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    /// ```
138    fn or<F>(self, other: F) -> Or<Self, F>
139    where
140        Self: Filter<Error = Rejection> + 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.
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 an async function receiving
203    /// the extracted value.
204    ///
205    /// The function should return some `Future` type.
206    ///
207    /// # Example
208    ///
209    /// ```
210    /// use warp::Filter;
211    ///
212    /// // Map `/:id`
213    /// warp::path::param().then(|id: u64| async move {
214    ///   format!("Hello #{}", id)
215    /// });
216    /// ```
217    fn then<F>(self, fun: F) -> Then<Self, F>
218    where
219        Self: Sized,
220        F: Func<Self::Extract> + Clone,
221        F::Output: Future + Send,
222    {
223        Then {
224            filter: self,
225            callback: fun,
226        }
227    }
228
229    /// Composes this `Filter` with a fallible async function receiving
230    /// the extracted value.
231    ///
232    /// The function should return some `TryFuture` type.
233    ///
234    /// The `Error` type of the return `Future` needs be a `Rejection`, which
235    /// means most futures will need to have their error mapped into one.
236    ///
237    /// Rejections are meant to say "this filter didn't accept the request,
238    /// maybe another can". So for application-level errors, consider using
239    /// [`Filter::then`] instead.
240    ///
241    /// # Example
242    ///
243    /// ```
244    /// use warp::Filter;
245    ///
246    /// // Validate after `/:id`
247    /// warp::path::param().and_then(|id: u64| async move {
248    ///     if id != 0 {
249    ///         Ok(format!("Hello #{}", id))
250    ///     } else {
251    ///         Err(warp::reject::not_found())
252    ///     }
253    /// });
254    /// ```
255    fn and_then<F>(self, fun: F) -> AndThen<Self, F>
256    where
257        Self: Sized,
258        F: Func<Self::Extract> + Clone,
259        F::Output: TryFuture + Send,
260        <F::Output as TryFuture>::Error: CombineRejection<Self::Error>,
261    {
262        AndThen {
263            filter: self,
264            callback: fun,
265        }
266    }
267
268    /// Compose this `Filter` with a function receiving an error.
269    ///
270    /// The function should return some `TryFuture` type yielding the
271    /// same item and error types.
272    fn or_else<F>(self, fun: F) -> OrElse<Self, F>
273    where
274        Self: Filter<Error = Rejection> + Sized,
275        F: Func<Rejection>,
276        F::Output: TryFuture<Ok = Self::Extract> + Send,
277        <F::Output as TryFuture>::Error: IsReject,
278    {
279        OrElse {
280            filter: self,
281            callback: fun,
282        }
283    }
284
285    /// Compose this `Filter` with a function receiving an error and
286    /// returning a *new* type, instead of the *same* type.
287    ///
288    /// This is useful for "customizing" rejections into new response types.
289    /// See also the [rejections example][ex].
290    ///
291    /// [ex]: https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs
292    fn recover<F>(self, fun: F) -> Recover<Self, F>
293    where
294        Self: Filter<Error = Rejection> + Sized,
295        F: Func<Rejection>,
296        F::Output: TryFuture + Send,
297        <F::Output as TryFuture>::Error: IsReject,
298    {
299        Recover {
300            filter: self,
301            callback: fun,
302        }
303    }
304
305    /// Unifies the extracted value of `Filter`s composed with `or`.
306    ///
307    /// When a `Filter` extracts some `Either<T, T>`, where both sides
308    /// are the same type, this combinator can be used to grab the
309    /// inner value, regardless of which side of `Either` it was. This
310    /// is useful for values that could be extracted from multiple parts
311    /// of a request, and the exact place isn't important.
312    ///
313    /// # Example
314    ///
315    /// ```rust
316    /// use std::net::SocketAddr;
317    /// use warp::Filter;
318    ///
319    /// let client_ip = warp::header("x-real-ip")
320    ///     .or(warp::header("x-forwarded-for"))
321    ///     .unify()
322    ///     .map(|ip: SocketAddr| {
323    ///         // Get the IP from either header,
324    ///         // and unify into the inner type.
325    ///     });
326    /// ```
327    fn unify<T>(self) -> Unify<Self>
328    where
329        Self: Filter<Extract = (Either<T, T>,)> + Sized,
330        T: Tuple,
331    {
332        Unify { filter: self }
333    }
334
335    /// Convenience method to remove one layer of tupling.
336    ///
337    /// This is useful for when things like `map` don't return a new value,
338    /// but just `()`, since warp will wrap it up into a `((),)`.
339    ///
340    /// # Example
341    ///
342    /// ```
343    /// use warp::Filter;
344    ///
345    /// let route = warp::path::param()
346    ///     .map(|num: u64| {
347    ///         println!("just logging: {}", num);
348    ///         // returning "nothing"
349    ///     })
350    ///     .untuple_one()
351    ///     .map(|| {
352    ///         println!("the ((),) was removed");
353    ///         warp::reply()
354    ///     });
355    /// ```
356    ///
357    /// ```
358    /// use warp::Filter;
359    ///
360    /// let route = warp::any()
361    ///     .map(|| {
362    ///         // wanting to return a tuple
363    ///         (true, 33)
364    ///     })
365    ///     .untuple_one()
366    ///     .map(|is_enabled: bool, count: i32| {
367    ///         println!("untupled: ({}, {})", is_enabled, count);
368    ///     });
369    /// ```
370    fn untuple_one<T>(self) -> UntupleOne<Self>
371    where
372        Self: Filter<Extract = (T,)> + Sized,
373        T: Tuple,
374    {
375        UntupleOne { filter: self }
376    }
377
378    /// Wraps the current filter with some wrapper.
379    ///
380    /// The wrapper may do some preparation work before starting this filter,
381    /// and may do post-processing after the filter completes.
382    ///
383    /// # Example
384    ///
385    /// ```
386    /// use warp::Filter;
387    ///
388    /// let route = warp::any()
389    ///     .map(warp::reply);
390    ///
391    /// // Wrap the route with a log wrapper.
392    /// let route = route.with(warp::log("example"));
393    /// ```
394    fn with<W>(self, wrapper: W) -> W::Wrapped
395    where
396        Self: Sized,
397        W: Wrap<Self>,
398    {
399        wrapper.wrap(self)
400    }
401
402    /// Boxes this filter into a trait object, making it easier to name the type.
403    ///
404    /// # Example
405    ///
406    /// ```
407    /// use warp::Filter;
408    ///
409    /// fn impl_reply() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
410    ///     warp::any()
411    ///         .map(warp::reply)
412    ///         .boxed()
413    /// }
414    ///
415    /// fn named_i32() -> warp::filters::BoxedFilter<(i32,)> {
416    ///     warp::path::param::<i32>()
417    ///         .boxed()
418    /// }
419    ///
420    /// fn named_and() -> warp::filters::BoxedFilter<(i32, String)> {
421    ///     warp::path::param::<i32>()
422    ///         .and(warp::header::<String>("host"))
423    ///         .boxed()
424    /// }
425    /// ```
426    fn boxed(self) -> BoxedFilter<Self::Extract>
427    where
428        Self: Sized + Send + Sync + 'static,
429        Self::Extract: Send,
430        Self::Error: Into<Rejection>,
431    {
432        BoxedFilter::new(self)
433    }
434}
435
436impl<T: FilterBase> Filter for T {}
437
438pub trait FilterClone: Filter + Clone {}
439
440impl<T: Filter + Clone> FilterClone for T {}
441
442fn _assert_object_safe() {
443    fn _assert(_f: &dyn Filter<Extract = (), Error = (), Future = future::Ready<()>>) {}
444}
445
446// ===== FilterFn =====
447
448pub(crate) fn filter_fn<F, U>(func: F) -> FilterFn<F>
449where
450    F: Fn(&mut Route) -> U,
451    U: TryFuture,
452    U::Ok: Tuple,
453    U::Error: IsReject,
454{
455    FilterFn { func }
456}
457
458pub(crate) fn filter_fn_one<F, U>(
459    func: F,
460) -> impl Filter<Extract = (U::Ok,), Error = U::Error> + Copy
461where
462    F: Fn(&mut Route) -> U + Copy,
463    U: TryFuture + Send + 'static,
464    U::Ok: Send,
465    U::Error: IsReject,
466{
467    filter_fn(move |route| func(route).map_ok(|item| (item,)))
468}
469
470#[derive(Copy, Clone)]
471#[allow(missing_debug_implementations)]
472pub(crate) struct FilterFn<F> {
473    // TODO: could include a `debug_str: &'static str` to be used in Debug impl
474    func: F,
475}
476
477impl<F, U> FilterBase for FilterFn<F>
478where
479    F: Fn(&mut Route) -> U,
480    U: TryFuture + Send + 'static,
481    U::Ok: Tuple + Send,
482    U::Error: IsReject,
483{
484    type Extract = U::Ok;
485    type Error = U::Error;
486    type Future = future::IntoFuture<U>;
487
488    #[inline]
489    fn filter(&self, _: Internal) -> Self::Future {
490        route::with(|route| (self.func)(route)).into_future()
491    }
492}