Skip to content

Commit e80522e

Browse files
committed
Use a real router.
1 parent eb89a36 commit e80522e

File tree

4 files changed

+86
-45
lines changed

4 files changed

+86
-45
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ hyper = { git = "https://github.com/hyperium/hyper.git" }
1919
kernel32-sys = "0.2.2"
2020
lazy_static = "0.2"
2121
libc = "0.2.7"
22+
mime = "0.2.3"
2223
rand = "0.3"
2324
ref_slice = "1.1.1"
2425
reqwest = "0.6"
2526
result = "0.0.1"
27+
route-recognizer = "0.1.12"
2628
scopeguard = "0.3"
2729
semver = "0.6"
2830
serde = "1.0"

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ extern crate result;
4040
extern crate ref_slice;
4141
extern crate crates_index;
4242
extern crate hyper;
43+
#[macro_use]
44+
extern crate mime;
4345
extern crate arc_cell;
46+
extern crate route_recognizer;
4447

4548
#[macro_use]
4649
pub mod log;

src/server/mod.rs

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
11
use arc_cell::ArcCell;
2-
use futures::{self, Future, Stream};
2+
use futures::{self, BoxFuture, Future, Stream};
33
use futures_cpupool::CpuPool;
44
use hyper::{self, Get, Post, StatusCode};
55
use hyper::header::{ContentLength, ContentType};
66
use hyper::server::{Http, Request, Response, Service};
7+
use route_recognizer::{Match, Params, Router};
78

89
use serde::Serialize;
910
use serde::de::DeserializeOwned;
1011
use serde_json;
1112
use std::env;
12-
use std::fs::File;
13-
use std::io::Read;
1413
use std::net::SocketAddr;
15-
use std::path::Path;
1614
use std::str;
1715
use std::sync::Arc;
1816

1917
mod api;
2018

2119
pub struct Data;
2220

21+
type Handler = fn(&Server, Request, Params) -> BoxFuture<Response, hyper::Error>;
2322
struct Server {
23+
router: Router<Handler>,
2424
data: ArcCell<Data>,
2525
pool: CpuPool,
2626
}
2727

2828
impl Server {
29-
fn handle_get<F, S>(&self, req: &Request, handler: F) -> <Server as Service>::Future
29+
fn handle_get<F, S>(&self,
30+
req: Request,
31+
_params: Params,
32+
handler: F)
33+
-> <Server as Service>::Future
3034
where F: FnOnce(&Data) -> S,
3135
S: Serialize
3236
{
33-
assert_eq!(*req.method(), Get);
37+
if *req.method() != Get {
38+
return self.error(StatusCode::BadRequest);
39+
};
3440
let data = self.data.get();
3541
let result = handler(&data);
3642
let response = Response::new()
@@ -39,12 +45,31 @@ impl Server {
3945
futures::future::ok(response).boxed()
4046
}
4147

42-
fn handle_post<F, D, S>(&self, req: Request, handler: F) -> <Server as Service>::Future
48+
fn handle_static(&self,
49+
req: Request,
50+
_params: Params,
51+
content_type: ContentType,
52+
body: &'static str)
53+
-> <Server as Service>::Future {
54+
if *req.method() != Get {
55+
return self.error(StatusCode::BadRequest);
56+
};
57+
let response = Response::new().with_header(content_type).with_body(body);
58+
futures::future::ok(response).boxed()
59+
}
60+
61+
fn handle_post<F, D, S>(&self,
62+
req: Request,
63+
_params: Params,
64+
handler: F)
65+
-> <Server as Service>::Future
4366
where F: FnOnce(D, &Data) -> S + Send + 'static,
4467
D: DeserializeOwned,
4568
S: Serialize
4669
{
47-
assert_eq!(*req.method(), Post);
70+
if *req.method() != Post {
71+
return self.error(StatusCode::BadRequest);
72+
};
4873
let length = req.headers()
4974
.get::<ContentLength>()
5075
.expect("content-length to exist")
@@ -82,59 +107,62 @@ impl Server {
82107
})
83108
.boxed()
84109
}
110+
111+
fn error(&self, status: StatusCode) -> <Server as Service>::Future {
112+
futures::future::ok(Response::new()
113+
.with_header(ContentType::html())
114+
.with_status(status))
115+
.boxed()
116+
}
85117
}
86118

87119
impl Service for Server {
88120
type Request = Request;
89121
type Response = Response;
90122
type Error = hyper::Error;
91-
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
123+
type Future = BoxFuture<Self::Response, Self::Error>;
92124

93125
fn call(&self, req: Request) -> Self::Future {
94-
let fs_path = format!("static{}",
95-
if req.path() == "" || req.path() == "/" {
96-
"/index.html"
97-
} else {
98-
req.path()
99-
});
100-
101-
info!("handling: req.path()={:?}, fs_path={:?}",
102-
req.path(),
103-
fs_path);
104-
105-
if fs_path.contains("./") | fs_path.contains("../") {
106-
return futures::future::ok(Response::new()
107-
.with_header(ContentType::html())
108-
.with_status(StatusCode::NotFound))
109-
.boxed();
110-
}
126+
info!("handling: req.path()={:?}", req.path());
111127

112-
if Path::new(&fs_path).is_file() {
113-
return self.pool
114-
.spawn_fn(move || {
115-
let mut f = File::open(&fs_path).unwrap();
116-
let mut source = Vec::new();
117-
f.read_to_end(&mut source).unwrap();
118-
futures::future::ok(Response::new().with_body(source))
119-
})
120-
.boxed();
128+
match self.router.recognize(req.path()) {
129+
Ok(Match { handler, params }) => handler(self, req, params),
130+
Err(_) => self.error(StatusCode::NotFound),
121131
}
122132

123-
match req.path() {
124-
"/api/get" => self.handle_get(&req, api::get::handler),
125-
"/api/post" => self.handle_post(req, api::post::handler),
126-
_ => {
127-
futures::future::ok(Response::new()
128-
.with_header(ContentType::html())
129-
.with_status(StatusCode::NotFound))
130-
.boxed()
131-
}
132-
}
133+
133134
}
134135
}
135136

137+
macro_rules! route {
138+
($router:ident, $path:expr, $method:ident, $($handler:tt)* ) => (
139+
$router.add($path,
140+
|server: &Server, req, params| server.$method(req, params, $($handler)*));
141+
)
142+
}
143+
136144
pub fn start(data: Data) {
145+
let mut router = Router::<Handler>::new();
146+
route!(router, "/api/get", handle_get, api::get::handler);
147+
route!(router, "/api/post", handle_post, api::post::handler);
148+
route!(router,
149+
"/static/report.html",
150+
handle_static,
151+
ContentType::html(),
152+
include_str!("../../static/report.html"));
153+
route!(router,
154+
"/static/report.js",
155+
handle_static,
156+
ContentType(mime!(Application / Javascript)),
157+
include_str!("../../static/report.js"));
158+
route!(router,
159+
"/static/report.css",
160+
handle_static,
161+
ContentType(mime!(Text / Css)),
162+
include_str!("../../static/report.css"));
163+
137164
let server = Arc::new(Server {
165+
router,
138166
data: ArcCell::new(Arc::new(data)),
139167
pool: CpuPool::new_num_cpus(),
140168
});

0 commit comments

Comments
 (0)