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}