extern crate futures;
extern crate hyper;
extern crate typemap;
use futures::future::{self, Future};
use hyper::{Body, StatusCode};
use hyper::server::{Request, Response, Service};
use typemap::TypeMap;
use std::marker::PhantomData;
type ServiceFuture = Box<Future<Item = Response, Error = hyper::Error>>;
pub enum HttpRequest {
Raw(Request),
Context { request: Request, context: TypeMap },
}
pub trait IntoResponse {
fn status(&self) -> StatusCode {
StatusCode::InternalServerError
}
fn body(&self) -> Body;
}
pub trait Handler<E: IntoResponse> {
fn handle(&self, req: HttpRequest) -> Result<Response, E>;
}
pub struct HandlerService<H, E>
where
E: IntoResponse,
H: Handler<E>,
{
handler: H,
_phantom: PhantomData<E>,
}
impl<H, E> Service for HandlerService<H, E>
where
E: IntoResponse,
H: Handler<E>,
{
type Request = Request;
type Response = Response;
type Error = hyper::Error;
type Future = ServiceFuture;
fn call(&self, request: Request) -> Self::Future {
let http_request = HttpRequest::Raw(request);
match self.handler.handle(http_request) {
Ok(response) => Box::new(future::ok(response)),
Err(error) => Box::new(future::ok(
Response::new()
.with_status(error.status())
.with_body(error.body()),
)),
}
}
}
pub fn handler_fn<F, E>(func: F) -> HandlerService<HandlerFn<F, E>, E>
where
F: Fn(HttpRequest) -> Result<Response, E>,
E: IntoResponse,
{
HandlerService::new(HandlerFn { func })
}
pub struct HandlerFn<F, E>
where
F: Fn(HttpRequest) -> Result<Response, E>,
E: IntoResponse,
{
func: F,
}
impl<F, E> Handler<E> for HandlerFn<F, E>
where
F: Fn(HttpRequest) -> Result<Response, E>,
E: IntoResponse,
{
fn handle(&self, req: HttpRequest) -> Result<Response, E> {
(self.func)(req)
}
}
impl<H, E> HandlerService<H, E>
where
E: IntoResponse,
H: Handler<E>,
{
pub fn new(handler: H) -> Self {
HandlerService {
handler,
_phantom: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
extern crate luminal_router;
extern crate tokio_core;
use self::luminal_router::Router;
use futures::Stream;
use hyper::Method;
use self::tokio_core::reactor::Core;
use super::*;
#[derive(Clone)]
struct TestError {
status: StatusCode,
body: String,
}
impl IntoResponse for TestError {
fn status(&self) -> StatusCode {
self.status
}
fn body(&self) -> Body {
self.body.clone().into()
}
}
enum TestHandler {
Success(String),
Failure(TestError),
}
impl Handler<TestError> for TestHandler {
fn handle(&self, _request: HttpRequest) -> Result<Response, TestError> {
match *self {
TestHandler::Success(ref body) => {
let body: String = body.clone();
Ok(Response::new().with_status(StatusCode::Ok).with_body(body))
}
TestHandler::Failure(ref error) => Err(error.clone()),
}
}
}
#[test]
fn test_success() {
let handler = TestHandler::Success(String::from("Success"));
let service = HandlerService::new(handler);
assert_call(&service, Method::Get, "/foo", (&StatusCode::Ok, "Success"));
}
#[test]
fn test_failure() {
let handler = TestHandler::Failure(TestError {
status: StatusCode::InternalServerError,
body: String::from("Error"),
});
let service = HandlerService::new(handler);
assert_call(
&service,
Method::Get,
"/foo",
(&StatusCode::InternalServerError, "Error"),
);
}
fn test_fn(_req: HttpRequest) -> Result<Response, TestError> {
Ok(Response::new()
.with_status(StatusCode::Ok)
.with_body(String::from("test")))
}
#[test]
fn test_fn_route() {
let handler = TestHandler::Success(String::from("Success"));
let service = HandlerService::new(handler);
let router = Router::new();
let router = router
.get("/foo", service)
.expect("Should have been able to add handler")
.get("/bar", handler_fn(test_fn))
.expect("Should have been able to add handler fn");
assert_route(&router, Method::Get, "/foo", (&StatusCode::Ok, "Success"));
assert_route(&router, Method::Get, "/bar", (&StatusCode::Ok, "test"));
}
fn assert_route(service: &Router, method: Method, uri: &str, expected: (&StatusCode, &str)) {
let uri = uri.parse()
.expect("Should have been able to convert to uri");
let req: Request<Body> = Request::new(method, uri);
let work = service.call(req);
let mut core = Core::new().expect("Should have been able to create core");
let response = core.run(work)
.expect("Should have been able to run router call");
assert_eq!(
*expected.0,
response.status(),
"Should have received {} status.",
expected.0
);
let body = core.run(response.body().concat2())
.expect("Should have been able to resolve body concat");
let body: &[u8] = &body.to_vec();
assert_eq!(
expected.1.as_bytes(),
body,
"Should have received correct body content"
);
}
fn assert_call<H, E>(
service: &HandlerService<H, E>,
method: Method,
uri: &str,
expected: (&StatusCode, &str),
) where
E: IntoResponse,
H: Handler<E>,
{
let uri = uri.parse()
.expect("Should have been able to convert to uri");
let req: Request<Body> = Request::new(method, uri);
let work = service.call(req);
let mut core = Core::new().expect("Should have been able to create core");
let response = core.run(work)
.expect("Should have been able to run router call");
assert_eq!(
*expected.0,
response.status(),
"Should have received {} status.",
expected.0
);
let body = core.run(response.body().concat2())
.expect("Should have been able to resolve body concat");
let body: &[u8] = &body.to_vec();
assert_eq!(
expected.1.as_bytes(),
body,
"Should have received correct body content"
);
}
}