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