warp/filters/
method.rs

1//! HTTP Method filters.
2//!
3//! The filters deal with the HTTP Method part of a request. Several here will
4//! match the request `Method`, and if not matched, will reject the request
5//! with a `405 Method Not Allowed`.
6//!
7//! There is also [`warp::method()`](method), which never rejects
8//! a request, and just extracts the method to be used in your filter chains.
9use futures_util::future;
10use http::Method;
11
12use crate::filter::{filter_fn, filter_fn_one, Filter, One};
13use crate::reject::Rejection;
14use std::convert::Infallible;
15
16/// Create a `Filter` that requires the request method to be `GET`.
17///
18/// # Example
19///
20/// ```
21/// use warp::Filter;
22///
23/// let get_only = warp::get().map(warp::reply);
24/// ```
25pub fn get() -> impl Filter<Extract = (), Error = Rejection> + Copy {
26    method_is(|| &Method::GET)
27}
28
29/// Create a `Filter` that requires the request method to be `POST`.
30///
31/// # Example
32///
33/// ```
34/// use warp::Filter;
35///
36/// let post_only = warp::post().map(warp::reply);
37/// ```
38pub fn post() -> impl Filter<Extract = (), Error = Rejection> + Copy {
39    method_is(|| &Method::POST)
40}
41
42/// Create a `Filter` that requires the request method to be `PUT`.
43///
44/// # Example
45///
46/// ```
47/// use warp::Filter;
48///
49/// let put_only = warp::put().map(warp::reply);
50/// ```
51pub fn put() -> impl Filter<Extract = (), Error = Rejection> + Copy {
52    method_is(|| &Method::PUT)
53}
54
55/// Create a `Filter` that requires the request method to be `DELETE`.
56///
57/// # Example
58///
59/// ```
60/// use warp::Filter;
61///
62/// let delete_only = warp::delete().map(warp::reply);
63/// ```
64pub fn delete() -> impl Filter<Extract = (), Error = Rejection> + Copy {
65    method_is(|| &Method::DELETE)
66}
67
68/// Create a `Filter` that requires the request method to be `HEAD`.
69///
70/// # Example
71///
72/// ```
73/// use warp::Filter;
74///
75/// let head_only = warp::head().map(warp::reply);
76/// ```
77pub fn head() -> impl Filter<Extract = (), Error = Rejection> + Copy {
78    method_is(|| &Method::HEAD)
79}
80
81/// Create a `Filter` that requires the request method to be `OPTIONS`.
82///
83/// # Example
84///
85/// ```
86/// use warp::Filter;
87///
88/// let options_only = warp::options().map(warp::reply);
89/// ```
90pub fn options() -> impl Filter<Extract = (), Error = Rejection> + Copy {
91    method_is(|| &Method::OPTIONS)
92}
93
94/// Create a `Filter` that requires the request method to be `PATCH`.
95///
96/// # Example
97///
98/// ```
99/// use warp::Filter;
100///
101/// let patch_only = warp::patch().map(warp::reply);
102/// ```
103pub fn patch() -> impl Filter<Extract = (), Error = Rejection> + Copy {
104    method_is(|| &Method::PATCH)
105}
106
107/// Extract the `Method` from the request.
108///
109/// This never rejects a request.
110///
111/// # Example
112///
113/// ```
114/// use warp::Filter;
115///
116/// let route = warp::method()
117///     .map(|method| {
118///         format!("You sent a {} request!", method)
119///     });
120/// ```
121pub fn method() -> impl Filter<Extract = One<Method>, Error = Infallible> + Copy {
122    filter_fn_one(|route| future::ok::<_, Infallible>(route.method().clone()))
123}
124
125// NOTE: This takes a static function instead of `&'static Method` directly
126// so that the `impl Filter` can be zero-sized. Moving it around should be
127// cheaper than holding a single static pointer (which would make it 1 word).
128fn method_is<F>(func: F) -> impl Filter<Extract = (), Error = Rejection> + Copy
129where
130    F: Fn() -> &'static Method + Copy,
131{
132    filter_fn(move |route| {
133        let method = func();
134        tracing::trace!("method::{:?}?: {:?}", method, route.method());
135        if route.method() == method {
136            future::ok(())
137        } else {
138            future::err(crate::reject::method_not_allowed())
139        }
140    })
141}
142
143#[cfg(test)]
144mod tests {
145    #[test]
146    fn method_size_of() {
147        // See comment on `method_is` function.
148        assert_eq!(std::mem::size_of_val(&super::get()), 0,);
149    }
150}