2016-04-01 23:54:53 +00:00
|
|
|
use super::*;
|
2016-08-27 04:34:28 +00:00
|
|
|
use response::{FreshHyperResponse, Outcome};
|
2016-04-01 23:54:53 +00:00
|
|
|
use request::HyperRequest;
|
2016-04-06 20:50:02 +00:00
|
|
|
use catcher;
|
2016-04-01 23:54:53 +00:00
|
|
|
|
2016-04-06 20:50:02 +00:00
|
|
|
use std::collections::HashMap;
|
2016-08-24 08:30:09 +00:00
|
|
|
|
2016-04-01 23:54:53 +00:00
|
|
|
use term_painter::Color::*;
|
|
|
|
use term_painter::ToStyle;
|
|
|
|
|
|
|
|
use hyper::server::Server as HyperServer;
|
|
|
|
use hyper::server::Handler as HyperHandler;
|
|
|
|
|
|
|
|
pub struct Rocket {
|
2016-09-08 07:25:40 +00:00
|
|
|
address: String,
|
2016-04-01 23:54:53 +00:00
|
|
|
port: isize,
|
2016-04-06 10:26:43 +00:00
|
|
|
router: Router,
|
2016-04-06 20:50:02 +00:00
|
|
|
catchers: HashMap<u16, Catcher>,
|
2016-08-27 01:37:28 +00:00
|
|
|
log_set: bool,
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
|
2016-04-01 23:54:53 +00:00
|
|
|
impl HyperHandler for Rocket {
|
2016-08-26 08:55:11 +00:00
|
|
|
fn handle<'h, 'k>(&self, req: HyperRequest<'h, 'k>,
|
|
|
|
mut res: FreshHyperResponse<'h>) {
|
2016-08-02 02:07:36 +00:00
|
|
|
res.headers_mut().set(response::header::Server("rocket".to_string()));
|
2016-04-23 02:48:03 +00:00
|
|
|
self.dispatch(req, res)
|
2016-04-01 23:54:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Rocket {
|
2016-08-27 01:37:28 +00:00
|
|
|
fn dispatch<'h, 'k>(&self, hyp_req: HyperRequest<'h, 'k>,
|
2016-08-27 04:34:28 +00:00
|
|
|
mut res: FreshHyperResponse<'h>) {
|
2016-08-27 01:37:28 +00:00
|
|
|
// Get a copy of the URI for later use.
|
|
|
|
let uri = hyp_req.uri.to_string();
|
|
|
|
|
|
|
|
// Try to create a Rocket request from the hyper request.
|
|
|
|
let request = match Request::from_hyp(hyp_req) {
|
|
|
|
Ok(req) => req,
|
|
|
|
Err(reason) => {
|
|
|
|
let mock_request = Request::mock(Method::Get, uri.as_str());
|
|
|
|
return self.handle_internal_error(reason, &mock_request, res);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
info!("{}:", request);
|
2016-08-27 04:34:28 +00:00
|
|
|
let matches = self.router.route(&request);
|
|
|
|
for route in matches {
|
2016-08-26 08:55:11 +00:00
|
|
|
// Retrieve and set the requests parameters.
|
2016-08-27 04:34:28 +00:00
|
|
|
info_!("Matched: {}", route);
|
2016-08-27 01:37:28 +00:00
|
|
|
request.set_params(route);
|
2016-08-26 08:55:11 +00:00
|
|
|
|
|
|
|
// Here's the magic: dispatch the request to the handler.
|
2016-08-27 01:37:28 +00:00
|
|
|
let outcome = (route.handler)(&request).respond(res);
|
2016-08-26 08:55:11 +00:00
|
|
|
info_!("{} {}", White.paint("Outcome:"), outcome);
|
|
|
|
|
2016-08-27 05:05:33 +00:00
|
|
|
// Get the result if we failed so we can try again.
|
2016-08-27 04:34:28 +00:00
|
|
|
res = match outcome {
|
2016-08-27 05:05:33 +00:00
|
|
|
Outcome::FailForward(r) => r,
|
|
|
|
Outcome::Complete | Outcome::FailStop => return,
|
2016-08-27 04:34:28 +00:00
|
|
|
};
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
2016-08-27 04:34:28 +00:00
|
|
|
|
2016-09-08 07:02:17 +00:00
|
|
|
error_!("No matching routes.");
|
2016-08-27 04:34:28 +00:00
|
|
|
self.handle_not_found(&request, res);
|
2016-08-26 08:55:11 +00:00
|
|
|
}
|
2016-04-11 10:57:23 +00:00
|
|
|
|
2016-08-27 01:37:28 +00:00
|
|
|
// Call on internal server error.
|
|
|
|
fn handle_internal_error<'r>(&self, reason: String, request: &'r Request<'r>,
|
|
|
|
response: FreshHyperResponse) {
|
|
|
|
error!("Internal server error.");
|
|
|
|
debug!("{}", reason);
|
|
|
|
let catcher = self.catchers.get(&500).unwrap();
|
|
|
|
catcher.handle(Error::Internal, request).respond(response);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call when no route was found.
|
2016-08-26 08:55:11 +00:00
|
|
|
fn handle_not_found<'r>(&self, request: &'r Request<'r>,
|
|
|
|
response: FreshHyperResponse) {
|
2016-08-27 01:37:28 +00:00
|
|
|
error_!("{} dispatch failed: 404.", request);
|
2016-08-26 08:55:11 +00:00
|
|
|
let catcher = self.catchers.get(&404).unwrap();
|
|
|
|
catcher.handle(Error::NoRoute, request).respond(response);
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 07:25:40 +00:00
|
|
|
pub fn new<S: ToString>(address: S, port: isize) -> Rocket {
|
2016-04-01 23:54:53 +00:00
|
|
|
Rocket {
|
2016-09-08 07:25:40 +00:00
|
|
|
address: address.to_string(),
|
2016-04-01 23:54:53 +00:00
|
|
|
port: port,
|
2016-04-06 10:26:43 +00:00
|
|
|
router: Router::new(),
|
2016-04-06 20:50:02 +00:00
|
|
|
catchers: catcher::defaults::get(),
|
2016-08-27 01:37:28 +00:00
|
|
|
log_set: false,
|
2016-04-01 23:54:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-11 10:57:23 +00:00
|
|
|
pub fn mount(&mut self, base: &'static str, routes: Vec<Route>)
|
|
|
|
-> &mut Self {
|
2016-08-27 04:34:28 +00:00
|
|
|
self.enable_normal_logging_if_disabled();
|
2016-08-24 08:30:09 +00:00
|
|
|
info!("🛰 {} '{}':", Magenta.paint("Mounting"), base);
|
2016-04-02 07:51:40 +00:00
|
|
|
for mut route in routes {
|
|
|
|
let path = format!("{}/{}", base, route.path.as_str());
|
|
|
|
route.set_path(path);
|
|
|
|
|
2016-08-24 08:30:09 +00:00
|
|
|
info_!("{}", route);
|
2016-04-02 07:51:40 +00:00
|
|
|
self.router.add(route);
|
2016-04-01 23:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-04-06 10:26:43 +00:00
|
|
|
pub fn catch(&mut self, catchers: Vec<Catcher>) -> &mut Self {
|
2016-08-27 04:34:28 +00:00
|
|
|
self.enable_normal_logging_if_disabled();
|
2016-08-24 08:30:09 +00:00
|
|
|
info!("👾 {}:", Magenta.paint("Catchers"));
|
2016-04-06 20:50:02 +00:00
|
|
|
for c in catchers {
|
|
|
|
if self.catchers.contains_key(&c.code) &&
|
|
|
|
!self.catchers.get(&c.code).unwrap().is_default() {
|
|
|
|
let msg = format!("warning: overrides {} catcher!", c.code);
|
2016-08-27 04:34:28 +00:00
|
|
|
warn!("{} ({})", c, Yellow.paint(msg.as_str()));
|
2016-04-06 20:50:02 +00:00
|
|
|
} else {
|
2016-08-24 08:30:09 +00:00
|
|
|
info_!("{}", c);
|
2016-04-06 20:50:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.catchers.insert(c.code, c);
|
2016-04-06 10:26:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-08-27 04:34:28 +00:00
|
|
|
fn enable_normal_logging_if_disabled(&mut self) {
|
|
|
|
if !self.log_set {
|
|
|
|
logger::init(LoggingLevel::Normal);
|
|
|
|
self.log_set = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:37:28 +00:00
|
|
|
pub fn log(&mut self, level: LoggingLevel) {
|
|
|
|
if self.log_set {
|
|
|
|
warn!("Log level already set! Not overriding.");
|
|
|
|
} else {
|
|
|
|
logger::init(level);
|
|
|
|
self.log_set = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn launch(mut self) {
|
2016-08-27 04:34:28 +00:00
|
|
|
self.enable_normal_logging_if_disabled();
|
2016-04-01 23:54:53 +00:00
|
|
|
if self.router.has_collisions() {
|
2016-08-24 08:30:09 +00:00
|
|
|
warn!("Route collisions detected!");
|
2016-04-01 23:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let full_addr = format!("{}:{}", self.address, self.port);
|
2016-08-24 08:30:09 +00:00
|
|
|
info!("🚀 {} {}...", White.paint("Rocket has launched from"),
|
2016-04-03 10:36:30 +00:00
|
|
|
White.bold().paint(&full_addr));
|
2016-04-01 23:54:53 +00:00
|
|
|
let _ = HyperServer::http(full_addr.as_str()).unwrap().handle(self);
|
|
|
|
}
|
2016-04-03 10:36:30 +00:00
|
|
|
|
|
|
|
pub fn mount_and_launch(mut self, base: &'static str, routes: Vec<Route>) {
|
|
|
|
self.mount(base, routes);
|
|
|
|
self.launch();
|
|
|
|
}
|
2016-04-01 23:54:53 +00:00
|
|
|
}
|