1use std::convert::Infallible;
2use std::future::Future;
3use std::net::SocketAddr;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7use futures_util::future::TryFuture;
8use hyper::service::Service;
9use pin_project::pin_project;
10
11use crate::reject::IsReject;
12use crate::reply::{Reply, Response};
13use crate::route::{self, Route};
14use crate::{Filter, Request};
15
16pub fn service<F>(filter: F) -> FilteredService<F>
53where
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)]
62pub struct FilteredService<F> {
63 filter: F,
64}
65
66impl<F> FilteredService<F>
67where
68 F: Filter,
69 <F::Future as TryFuture>::Ok: Reply,
70 <F::Future as TryFuture>::Error: IsReject,
71{
72 #[inline]
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
86impl<F> Service<Request> for FilteredService<F>
87where
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
96 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
97 Poll::Ready(Ok(()))
98 }
99
100 #[inline]
101 fn call(&mut self, req: Request) -> Self::Future {
102 self.call_with_addr(req, None)
103 }
104}
105
106#[pin_project]
107#[derive(Debug)]
108pub struct FilteredFuture<F> {
109 #[pin]
110 future: F,
111 route: ::std::cell::RefCell<Route>,
112}
113
114impl<F> Future for FilteredFuture<F>
115where
116 F: TryFuture,
117 F::Ok: Reply,
118 F::Error: IsReject,
119{
120 type Output = Result<Response, Infallible>;
121
122 #[inline]
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 tracing::debug!("rejected: {:?}", err);
133 Poll::Ready(Ok(err.into_response()))
134 }
135 }
136 }
137}