1 use std::convert::Infallible;
2 use std::future::Future;
3 use std::net::SocketAddr;
4 use std::pin::Pin;
5 use std::task::{Context, Poll};
6 
7 use futures::future::TryFuture;
8 use hyper::service::Service;
9 use pin_project::pin_project;
10 
11 use crate::reject::IsReject;
12 use crate::reply::{Reply, Response};
13 use crate::route::{self, Route};
14 use crate::{Filter, Request};
15 
16 /// Convert a `Filter` into a `Service`.
17 ///
18 /// Filters are normally what APIs are built on in warp. However, it can be
19 /// useful to convert a `Filter` into a [`Service`][Service], such as if
20 /// further customizing a `hyper::Service`, or if wanting to make use of
21 /// the greater [Tower][tower] set of middleware.
22 ///
23 /// # Example
24 ///
25 /// Running a `warp::Filter` on a regular `hyper::Server`:
26 ///
27 /// ```
28 /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
29 /// use std::convert::Infallible;
30 /// use warp::Filter;
31 ///
32 /// // Our Filter...
33 /// let route = warp::any().map(|| "Hello From Warp!");
34 ///
35 /// // Convert it into a `Service`...
36 /// let svc = warp::service(route);
37 ///
38 /// // Typical hyper setup...
39 /// let make_svc = hyper::service::make_service_fn(move |_| async move {
40 ///     Ok::<_, Infallible>(svc)
41 /// });
42 ///
43 /// hyper::Server::bind(&([127, 0, 0, 1], 3030).into())
44 ///     .serve(make_svc)
45 ///     .await?;
46 /// # Ok(())
47 /// # }
48 /// ```
49 ///
50 /// [Service]: https://docs.rs/hyper/0.13.*/hyper/service/trait.Service.html
51 /// [tower]: https://docs.rs/tower
service<F>(filter: F) -> FilteredService<F> where F: Filter, <F::Future as TryFuture>::Ok: Reply, <F::Future as TryFuture>::Error: IsReject,52 pub fn service<F>(filter: F) -> FilteredService<F>
53 where
54     F: Filter,
55     <F::Future as TryFuture>::Ok: Reply,
56     <F::Future as TryFuture>::Error: IsReject,
57 {
58     FilteredService { filter }
59 }
60 
61 #[derive(Copy, Clone, Debug)]
62 pub struct FilteredService<F> {
63     filter: F,
64 }
65 
66 impl<F> FilteredService<F>
67 where
68     F: Filter,
69     <F::Future as TryFuture>::Ok: Reply,
70     <F::Future as TryFuture>::Error: IsReject,
71 {
72     #[inline]
call_with_addr( &self, req: Request, remote_addr: Option<SocketAddr>, ) -> FilteredFuture<F::Future>73     pub(crate) fn call_with_addr(
74         &self,
75         req: Request,
76         remote_addr: Option<SocketAddr>,
77     ) -> FilteredFuture<F::Future> {
78         debug_assert!(!route::is_set(), "nested route::set calls");
79 
80         let route = Route::new(req, remote_addr);
81         let fut = route::set(&route, || self.filter.filter(super::Internal));
82         FilteredFuture { future: fut, route }
83     }
84 }
85 
86 impl<F> Service<Request> for FilteredService<F>
87 where
88     F: Filter,
89     <F::Future as TryFuture>::Ok: Reply,
90     <F::Future as TryFuture>::Error: IsReject,
91 {
92     type Response = Response;
93     type Error = Infallible;
94     type Future = FilteredFuture<F::Future>;
95 
poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>>96     fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
97         Poll::Ready(Ok(()))
98     }
99 
100     #[inline]
call(&mut self, req: Request) -> Self::Future101     fn call(&mut self, req: Request) -> Self::Future {
102         self.call_with_addr(req, None)
103     }
104 }
105 
106 #[pin_project]
107 #[derive(Debug)]
108 pub struct FilteredFuture<F> {
109     #[pin]
110     future: F,
111     route: ::std::cell::RefCell<Route>,
112 }
113 
114 impl<F> Future for FilteredFuture<F>
115 where
116     F: TryFuture,
117     F::Ok: Reply,
118     F::Error: IsReject,
119 {
120     type Output = Result<Response, Infallible>;
121 
122     #[inline]
poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>123     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
124         debug_assert!(!route::is_set(), "nested route::set calls");
125 
126         let pin = self.project();
127         let fut = pin.future;
128         match route::set(&pin.route, || fut.try_poll(cx)) {
129             Poll::Ready(Ok(ok)) => Poll::Ready(Ok(ok.into_response())),
130             Poll::Pending => Poll::Pending,
131             Poll::Ready(Err(err)) => {
132                 log::debug!("rejected: {:?}", err);
133                 Poll::Ready(Ok(err.into_response()))
134             }
135         }
136     }
137 }
138