luminal_router/service/
mod.rs1use futures::future;
6use hyper::{self, Method, StatusCode};
7use hyper::server::{Request, Response, Service};
8
9use std::collections::HashMap;
10
11mod builder;
12
13use {LuminalFuture, LuminalService};
14use error::*;
15use tree::RouteTree;
16use route::Route;
17pub use self::builder::{FnRouteBuilder, ServiceRouteBuilder};
18
19#[derive(Default)]
21pub struct Router {
22 routes: HashMap<Method, RouteTree<Route<Box<LuminalService>>>>,
23}
24
25impl Service for Router {
26 type Request = Request;
27 type Response = Response;
28 type Error = hyper::Error;
29 type Future = LuminalFuture;
30
31 fn call(&self, req: Request) -> Self::Future {
32 let route = self.dispatch(req.method(), req.path());
33 if let Some(&Some(ref route)) = route {
34 route.target.call(req)
35 } else {
36 let mut response = Response::new();
37 response.set_status(StatusCode::NotFound);
38 Box::new(future::ok(response))
39 }
40 }
41}
42
43impl Router {
44 pub fn new() -> Self {
45 Router {
46 ..Default::default()
47 }
48 }
49
50 pub fn add<
53 S: Service<
54 Request = Request,
55 Response = Response,
56 Error = hyper::Error,
57 Future = LuminalFuture,
58 >
59 + 'static,
60 >(
61 &mut self,
62 method: Method,
63 route: &str,
64 service: S,
65 ) -> Result<()> {
66 {
67 let routing = self.routes
68 .entry(method)
69 .or_insert_with(RouteTree::empty_root);
70 routing.add(route, Route::new(route, Box::new(service)))?;
71 }
72 Ok(())
73 }
74
75 pub fn dispatch<'a>(
76 &'a self,
77 method: &Method,
78 route_path: &str,
79 ) -> Option<&'a Option<Route<Box<LuminalService>>>> {
80 if let Some(routing) = self.routes.get(method) {
81 if let Some(route) = routing.dispatch(route_path) {
82 Some(route)
83 } else {
84 None
85 }
86 } else {
87 None
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 extern crate tokio_core;
95
96 use hyper::Body;
97 use hyper::header::ContentLength;
98 use futures::Stream;
99 use futures::future::Future;
100
101 use self::tokio_core::reactor::Core;
102
103 use super::*;
104
105 struct StringHandler(String);
106
107 impl Service for StringHandler {
108 type Request = Request;
109 type Response = Response;
110 type Error = hyper::Error;
111 type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
112 fn call(&self, _req: Request) -> Self::Future {
113 Box::new(future::ok(
114 Response::new()
115 .with_header(ContentLength(self.0.len() as u64))
116 .with_body(self.0.clone()),
117 ))
118 }
119 }
120
121 impl StringHandler {
122 fn new(msg: &str) -> Self {
123 StringHandler(msg.to_owned())
124 }
125 }
126
127 fn get_bar_handler(_req: Request) -> LuminalFuture {
128 let msg = String::from("Get bar");
129 Box::new(future::ok(
130 Response::new()
131 .with_header(ContentLength(msg.len() as u64))
132 .with_body(msg),
133 ))
134 }
135
136 #[test]
137 fn test_router() {
138 let router = FnRouteBuilder::new()
139 .get("/foo/bar", get_bar_handler)
140 .expect("Should have been able to add route")
141 .service_builder()
142 .get("/foo/baz", StringHandler::new("Baz"))
143 .expect("Should have been able to add route")
144 .post("/foo/bar", StringHandler::new("Post bar"))
145 .expect("Should have been able to add route")
146 .build();
147
148 assert_call(&router, Method::Get, "/foo/bar", "Get bar");
149 assert_call(&router, Method::Post, "/foo/bar", "Post bar");
150 assert_call(&router, Method::Get, "/foo/baz", "Baz");
151 }
152
153 #[test]
154 fn test_not_found() {
155 let router = Router {
156 ..Default::default()
157 };
158
159 let uri = "/foo"
160 .parse()
161 .expect("Should have been able to convert to uri");
162 let req: Request<Body> = Request::new(Method::Get, uri);
163
164 let work = router.call(req);
165
166 let mut core = Core::new().expect("Should have been able to create core");
167
168 let response = core.run(work)
169 .expect("Should have been able to run router call");
170
171 assert_eq!(
172 StatusCode::NotFound,
173 response.status(),
174 "Should have received not found status."
175 );
176 }
177
178 fn assert_call(router: &Router, method: Method, uri: &str, expected: &str) {
179 let uri = uri.parse()
180 .expect("Should have been able to convert to uri");
181 let req: Request<Body> = Request::new(method, uri);
182
183 let work = router.call(req);
184
185 let mut core = Core::new().expect("Should have been able to create core");
186
187 let response = core.run(work)
188 .expect("Should have been able to run router call");
189
190 assert_eq!(
191 StatusCode::Ok,
192 response.status(),
193 "Should have received Ok status."
194 );
195
196 let body = core.run(response.body().concat2())
197 .expect("Should have been able to resolve body concat");
198 let body: &[u8] = &body.to_vec();
199
200 assert_eq!(
201 expected.as_bytes(),
202 body,
203 "Should have received correct body content"
204 );
205 }
206}