tower_web/routing/
service.rs

1use config::Config;
2use error::{self, Error, Catch};
3use http::status::StatusCode;
4use routing::{Resource, ResourceFuture, RouteSet, RouteMatch};
5use util::http::HttpFuture;
6use util::tuple::Either2;
7
8use futures::{Future, Poll};
9use http;
10use tower_service::Service;
11
12use std::fmt;
13use std::sync::Arc;
14
15/// Web service
16pub struct RoutedService<T, U>
17where
18    T: Resource,
19{
20    /// Resource that handles the request
21    resource: T,
22
23    /// Error handler
24    catch: U,
25
26    /// Config
27    config: Config,
28
29    /// Route set. Processes request to determine how the resource will process
30    /// it.
31    routes: Arc<RouteSet<T::Destination>>,
32}
33
34/// Response future returned by `RoutedService`
35#[derive(Debug)]
36pub struct RoutedResponse<T, U>
37where U: Catch,
38{
39    request: http::Request<()>,
40    catch: U,
41    state: State<T, U::Future>,
42}
43
44#[derive(Debug)]
45enum State<T, U> {
46    Pending(T),
47    Catching(U),
48}
49
50impl<T, U> Clone for RoutedService<T, U>
51where
52    T: Resource,
53    U: Clone,
54{
55    fn clone(&self) -> RoutedService<T, U> {
56        RoutedService {
57            resource: self.resource.clone(),
58            catch: self.catch.clone(),
59            config: self.config.clone(),
60            routes: self.routes.clone(),
61        }
62    }
63}
64
65impl<T, U> fmt::Debug for RoutedService<T, U>
66where
67    T: Resource + fmt::Debug,
68    T::Destination: fmt::Debug,
69    U: fmt::Debug,
70{
71    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
72        fmt.debug_struct("RoutedService")
73            .field("resource", &self.resource)
74            .field("catch", &self.catch)
75            .field("routes", &self.routes)
76            .finish()
77    }
78}
79
80// ===== impl RoutedService =====
81
82impl<T, U> RoutedService<T, U>
83where T: Resource,
84{
85    /// Create a new `RoutedService`
86    pub(crate) fn new(resource: T, catch: U, config: Config, routes: RouteSet<T::Destination>) -> Self {
87        let routes = Arc::new(routes);
88
89        RoutedService {
90            resource,
91            catch,
92            config,
93            routes,
94        }
95    }
96}
97
98impl<T, U> Service for RoutedService<T, U>
99where T: Resource,
100      U: Catch,
101{
102    type Request = http::Request<T::RequestBody>;
103    type Response = <Self::Future as Future>::Item;
104    type Error = Error;
105    type Future = RoutedResponse<T::Future, U>;
106
107    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
108        // Always ready
109        Ok(().into())
110    }
111
112    fn call(&mut self, request: Self::Request) -> Self::Future {
113        // TODO: Use the body
114        let (head, body) = request.into_parts();
115        let request = http::Request::from_parts(head, ());
116
117        let state = match self.routes.test(&request) {
118            Some((destination, captures)) => {
119                // Create the `RouteMatch` for the routing result
120                let route_match = RouteMatch::new(&request, captures, &self.config);
121
122                // Dispatch the requeest
123                let pending = self.resource
124                    .dispatch(destination, &route_match, body);
125
126                State::Pending(pending)
127            }
128            None => {
129                let error = Error::from(StatusCode::NOT_FOUND);
130                let catching = self.catch.catch(&request, error);
131
132                State::Catching(catching)
133            }
134        };
135
136        let catch = self.catch.clone();
137
138        RoutedResponse {
139            request,
140            catch,
141            state,
142        }
143    }
144}
145
146// ===== impl RoutedResponse =====
147
148impl<T, U> Future for RoutedResponse<T, U>
149where T: ResourceFuture,
150      U: Catch,
151{
152    type Item = http::Response<Either2<T::Body, error::Map<U::Body>>>;
153    type Error = Error;
154
155    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
156        use self::State::*;
157        use util::tuple::Either2::*;
158        use futures::Async::*;
159
160        loop {
161            let catching = match self.state {
162                Pending(ref mut fut) => {
163                    let error = match fut.poll_response(&self.request) {
164                        Ok(Ready(v)) => {
165                            let v = v.map(A);
166                            return Ok(Ready(v))
167                        }
168                        Ok(NotReady) => return Ok(NotReady),
169                        Err(e) => e,
170                    };
171
172                    self.catch.catch(&self.request, error)
173                }
174                Catching(ref mut fut) => {
175                    let resp = try_ready!(HttpFuture::poll_http(fut))
176                        .map(|body| B(error::Map::new(body)));
177
178                    return Ok(Ready(resp));
179                }
180            };
181
182            self.state = Catching(catching);
183        }
184    }
185}