1extern crate futures;
7extern crate http;
8extern crate hyper;
9
10use futures::future::{self, Future};
11use hyper::Body;
12use hyper::server::{Request, Response, Service};
13
14pub type LuminalFuture = Box<Future<Item = Response, Error = hyper::Error>>;
16
17pub trait Handler {
19 fn handle(&self, req: http::Request<Body>) -> Result<LuminalFuture, Response>;
20}
21
22pub struct HandlerService<H: Handler> {
24 handler: H,
25}
26
27impl<H: Handler> HandlerService<H> {
28 pub fn new(handler: H) -> Self {
29 HandlerService { handler }
30 }
31}
32
33impl<H: Handler> Service for HandlerService<H> {
34 type Request = Request;
35 type Response = Response;
36 type Error = hyper::Error;
37 type Future = LuminalFuture;
38
39 fn call(&self, request: Request) -> Self::Future {
41 match self.handler.handle(request.into()) {
42 Ok(response) => response,
43 Err(error) => Box::new(future::ok(error)),
44 }
45 }
46}
47
48pub fn handler_fn<F>(func: F) -> HandlerFn<F>
50where
51 F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
52{
53 HandlerFn { func }
54}
55
56pub struct HandlerFn<F>
58where
59 F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
60{
61 func: F,
62}
63
64impl<F> Handler for HandlerFn<F>
65where
66 F: Fn(http::Request<Body>) -> Result<LuminalFuture, Response>,
67{
68 fn handle(&self, req: http::Request<Body>) -> Result<LuminalFuture, Response> {
69 (self.func)(req)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 extern crate tokio_core;
76
77 use futures::Stream;
78 use hyper::Method;
79 use hyper::{Body, StatusCode};
80
81 use self::tokio_core::reactor::Core;
82
83 use super::*;
84
85 enum TestHandler {
86 Success(String),
87 Failure(String),
88 }
89
90 impl Handler for TestHandler {
91 fn handle(&self, _request: http::Request<Body>) -> Result<LuminalFuture, Response> {
92 match *self {
93 TestHandler::Success(ref body) => {
94 let body: String = body.clone();
95 Ok(Box::new(futures::future::ok(
96 Response::new().with_status(StatusCode::Ok).with_body(body),
97 )))
98 }
99 TestHandler::Failure(ref error) => {
100 let body: String = error.clone();
101 Err(Response::new()
102 .with_status(StatusCode::InternalServerError)
103 .with_body(body))
104 }
105 }
106 }
107 }
108
109 fn test_fn(_req: http::Request<Body>) -> Result<LuminalFuture, Response> {
110 Ok(Box::new(futures::future::ok(
111 Response::new()
112 .with_status(StatusCode::Ok)
113 .with_body(String::from("test")),
114 )))
115 }
116
117 #[test]
118 fn test_success() {
119 let handler = TestHandler::Success(String::from("Success"));
120 let service = HandlerService::new(handler);
121
122 assert_call(&service, Method::Get, "/foo", (&StatusCode::Ok, "Success"));
123 }
124
125 #[test]
126 fn test_failure() {
127 let handler = TestHandler::Failure(String::from("Error"));
128 let service = HandlerService::new(handler);
129
130 assert_call(
131 &service,
132 Method::Get,
133 "/foo",
134 (&StatusCode::InternalServerError, "Error"),
135 );
136 }
137
138 #[test]
139 fn test_handler_fn() {
140 let handler = handler_fn(test_fn);
141 let service = HandlerService::new(handler);
142
143 assert_call(&service, Method::Get, "/foo", (&StatusCode::Ok, "test"));
144 }
145
146 fn assert_call<H>(
147 service: &HandlerService<H>,
148 method: Method,
149 uri: &str,
150 expected: (&StatusCode, &str),
151 ) where
152 H: Handler,
153 {
154 let uri = uri.parse()
155 .expect("Should have been able to convert to uri");
156 let req: Request<Body> = Request::new(method, uri);
157
158 let work = service.call(req);
159
160 let mut core = Core::new().expect("Should have been able to create core");
161
162 let response = core.run(work)
163 .expect("Should have been able to run router call");
164
165 assert_eq!(
166 *expected.0,
167 response.status(),
168 "Should have received {} status.",
169 expected.0
170 );
171
172 let body = core.run(response.body().concat2())
173 .expect("Should have been able to resolve body concat");
174 let body: &[u8] = &body.to_vec();
175
176 assert_eq!(
177 expected.1.as_bytes(),
178 body,
179 "Should have received correct body content"
180 );
181 }
182}