1#![doc(html_root_url = "https://tsharp.github.io/hyper-routing/doc/hyper_routing")]
2
3extern crate futures;
34extern crate hyper;
35
36use std::task::{Context, Poll};
37use futures::future;
38use hyper::header::CONTENT_LENGTH;
39use hyper::service::Service;
40use hyper::{Body, Request, Response};
41
42use hyper::Method;
43use hyper::StatusCode;
44
45mod builder;
46pub mod handlers;
47mod path;
48pub mod route;
49
50pub use self::builder::RouterBuilder;
51pub use self::path::Path;
52pub use self::route::Route;
53pub use self::route::RouteBuilder;
54
55pub type Handler = fn(Request<Body>) -> Response<Body>;
56pub type HttpResult<T> = Result<T, StatusCode>;
57
58#[derive(Debug)]
60pub struct Router {
61 routes: Vec<Route>,
62}
63
64impl Router {
65 pub fn find_handler_with_defaults(&self, request: &Request<Body>) -> Handler {
72 let matching_routes = self.find_matching_routes(request.uri().path());
73 match matching_routes.len() {
74 x if x == 0 => handlers::default_404_handler,
75 _ => self
76 .find_for_method(&matching_routes, request.method())
77 .unwrap_or(handlers::method_not_supported_handler),
78 }
79 }
80
81 pub fn find_handler(&self, request: &Request<Body>) -> HttpResult<Handler> {
87 let matching_routes = self.find_matching_routes(request.uri().path());
88 match matching_routes.len() {
89 x if x == 0 => Err(StatusCode::NOT_FOUND),
90 _ => self
91 .find_for_method(&matching_routes, request.method())
92 .map(Ok)
93 .unwrap_or(Err(StatusCode::METHOD_NOT_ALLOWED)),
94 }
95 }
96
97 pub fn find_matching_routes(&self, request_path: &str) -> Vec<&Route> {
99 self.routes
100 .iter()
101 .filter(|route| route.path.matcher.is_match(&request_path))
102 .collect()
103 }
104
105 fn find_for_method(&self, routes: &[&Route], method: &Method) -> Option<Handler> {
106 let method = method.clone();
107 routes
108 .iter()
109 .find(|route| route.method == method)
110 .map(|route| route.handler)
111 }
112}
113
114#[derive(Debug)]
116pub struct RouterService {
117 pub router: Router,
118 pub error_handler: fn(StatusCode) -> Response<Body>,
119}
120
121impl RouterService {
122 pub fn new(router: Router) -> RouterService {
123 RouterService {
124 router,
125 error_handler: Self::default_error_handler,
126 }
127 }
128
129 fn default_error_handler(status_code: StatusCode) -> Response<Body> {
130 let error = "Routing error: page not found";
131 Response::builder()
132 .header(CONTENT_LENGTH, error.len() as u64)
133 .status(match status_code {
134 StatusCode::NOT_FOUND => StatusCode::NOT_FOUND,
135 _ => StatusCode::INTERNAL_SERVER_ERROR,
136 })
137 .body(Body::from(error))
138 .expect("Failed to construct a response")
139 }
140}
141
142impl Service<Request<Body>> for RouterService {
143 type Response = Response<Body>;
144 type Error = hyper::Error;
145 type Future = future::Ready<Result<Self::Response, Self::Error>>;
146
147 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
148 Ok(()).into()
149 }
150
151 fn call(&mut self, request: Request<Body>) -> Self::Future {
152 futures::future::ok(match self.router.find_handler(&request) {
153 Ok(handler) => handler(request),
154 Err(status_code) => (self.error_handler)(status_code),
155 })
156 }
157}