tower_web/routing/
service.rs1use 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
15pub struct RoutedService<T, U>
17where
18 T: Resource,
19{
20 resource: T,
22
23 catch: U,
25
26 config: Config,
28
29 routes: Arc<RouteSet<T::Destination>>,
32}
33
34#[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
80impl<T, U> RoutedService<T, U>
83where T: Resource,
84{
85 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 Ok(().into())
110 }
111
112 fn call(&mut self, request: Self::Request) -> Self::Future {
113 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 let route_match = RouteMatch::new(&request, captures, &self.config);
121
122 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
146impl<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}