mirror of https://github.com/rwf2/Rocket.git
Working error handling! Not quite there yet though.
A few important things needs to get this to be 'right': 1a. Have a way to return a response with a status code. 1b. Use that mechanism in the default catchers. 2. Automatically fill in that code from the #[error] handler. 3. Have a way for a responder to say if responding succeeded. 4. Try next highest ranking route if responding with one handler fails.
This commit is contained in:
parent
33c4d89614
commit
1ef7a15bab
|
@ -19,8 +19,7 @@ fn hello(name: &str, age: u8) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rocket = Rocket::new("localhost", 8000);
|
Rocket::new("localhost", 8000).mount_and_launch("/hello", routes![hello]);
|
||||||
rocket.mount_and_launch("/hello", routes![hello]);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,12 @@ fn hello(name: &str, age: i8) -> String {
|
||||||
|
|
||||||
#[error(code = "404")]
|
#[error(code = "404")]
|
||||||
fn not_found() -> &'static str {
|
fn not_found() -> &'static str {
|
||||||
"Sorry, I couldn't find what you're looking for."
|
"<h1>Sorry pal.</h1><p>Go to '/hello/<name>/<age>' instead.</p>"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rocket = Rocket::new("localhost", 8000);
|
let mut rocket = Rocket::new("localhost", 8000);
|
||||||
rocket.mount("/", routes![hello]);
|
rocket.mount("/", routes![hello]);
|
||||||
rocket.catch(errors![not_found]);
|
rocket.catch(errors![not_found]);
|
||||||
// rocket.catch_and_launch(errors![not_found]);
|
|
||||||
rocket.launch();
|
rocket.launch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,25 @@ use term_painter::Color::*;
|
||||||
pub struct Catcher {
|
pub struct Catcher {
|
||||||
pub code: u16,
|
pub code: u16,
|
||||||
pub handler: Handler,
|
pub handler: Handler,
|
||||||
|
is_default: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Catcher {
|
impl Catcher {
|
||||||
pub fn new(code: u16, handler: Handler) -> Catcher {
|
pub fn new(code: u16, handler: Handler) -> Catcher {
|
||||||
|
Catcher::new_with_default(code, handler, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default(code: u16, handler: Handler, default: bool) -> Catcher {
|
||||||
Catcher {
|
Catcher {
|
||||||
code: code,
|
code: code,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
|
is_default: default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_default(&self) -> bool {
|
||||||
|
self.is_default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a StaticCatchInfo> for Catcher {
|
impl<'a> From<&'a StaticCatchInfo> for Catcher {
|
||||||
|
@ -27,6 +37,52 @@ impl<'a> From<&'a StaticCatchInfo> for Catcher {
|
||||||
|
|
||||||
impl fmt::Display for Catcher {
|
impl fmt::Display for Catcher {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {}", Blue.paint(&self.code), Blue.paint("catcher."))
|
write!(f, "{}", Blue.paint(&self.code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod defaults {
|
||||||
|
use request::Request;
|
||||||
|
use response::Response;
|
||||||
|
use super::Catcher;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn get() -> HashMap<u16, Catcher> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(404, Catcher::new_with_default(404, not_found, true));
|
||||||
|
map.insert(500, Catcher::new_with_default(500, internal_error, true));
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not_found(_request: Request) -> Response {
|
||||||
|
// FIXME: Need a way to pass in the status code.
|
||||||
|
Response::new("\
|
||||||
|
<head>\
|
||||||
|
<meta charset=\"utf-8\">\
|
||||||
|
<title>404: Not Found</title>\
|
||||||
|
</head>\
|
||||||
|
<body align=\"center\">\
|
||||||
|
<h1>404: Not Found</h1>\
|
||||||
|
<p>The page you were looking for could not be found.<p>\
|
||||||
|
<hr />\
|
||||||
|
<small>Rocket</small>\
|
||||||
|
</body>\
|
||||||
|
")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn internal_error(_request: Request) -> Response {
|
||||||
|
// FIXME: Need a way to pass in the status code.
|
||||||
|
Response::new("\
|
||||||
|
<head>\
|
||||||
|
<meta charset=\"utf-8\">\
|
||||||
|
<title>404: Not Found</title>\
|
||||||
|
</head>\
|
||||||
|
<body align=\"center\">\
|
||||||
|
<h1>500: Internal Server Error</h1>\
|
||||||
|
<p>The server encountered a problem processing your request.<p>\
|
||||||
|
<hr />\
|
||||||
|
<small>Rocket</small>\
|
||||||
|
")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use response::{HyperResponse, HyperFresh};
|
use response::{HyperResponse, HyperFresh};
|
||||||
use request::HyperRequest;
|
use request::HyperRequest;
|
||||||
|
use catcher;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::collections::HashMap;
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
|
@ -14,37 +16,45 @@ pub struct Rocket {
|
||||||
address: &'static str,
|
address: &'static str,
|
||||||
port: isize,
|
port: isize,
|
||||||
router: Router,
|
router: Router,
|
||||||
catchers: Vec<Catcher>,
|
catchers: HashMap<u16, Catcher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HyperHandler for Rocket {
|
impl HyperHandler for Rocket {
|
||||||
fn handle<'a, 'k>(&'a self, mut req: HyperRequest<'a, 'k>,
|
fn handle<'a, 'k>(&'a self, mut req: HyperRequest<'a, 'k>,
|
||||||
res: HyperResponse<'a, HyperFresh>) {
|
res: HyperResponse<'a, HyperFresh>) {
|
||||||
println!("{} {:?} {:?}", White.paint("Incoming:"),
|
println!("{:?} {:?}", Green.paint(&req.method), Blue.paint(&req.uri));
|
||||||
Green.paint(&req.method), Blue.paint(&req.uri));
|
|
||||||
|
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
req.read_to_end(&mut buf); // FIXME: Simple DOS attack here.
|
req.read_to_end(&mut buf); // FIXME: Simple DOS attack here.
|
||||||
if let HyperRequestUri::AbsolutePath(uri_string) = req.uri {
|
if let HyperRequestUri::AbsolutePath(uri_string) = req.uri {
|
||||||
if let Some(method) = Method::from_hyp(req.method) {
|
if let Some(method) = Method::from_hyp(req.method) {
|
||||||
|
|
||||||
let uri_str = uri_string.as_str();
|
let uri_str = uri_string.as_str();
|
||||||
let route = self.router.route(method, uri_str);
|
let route = self.router.route(method, uri_str);
|
||||||
let mut response = route.map_or(Response::not_found(), |route| {
|
|
||||||
|
if route.is_some() {
|
||||||
|
let route = route.unwrap();
|
||||||
let params = route.get_params(uri_str);
|
let params = route.get_params(uri_str);
|
||||||
let request = Request::new(params, uri_str, &buf);
|
let request = Request::new(params, uri_str, &buf);
|
||||||
(route.handler)(request)
|
|
||||||
});
|
|
||||||
|
|
||||||
println!("{}", Green.paint("\t=> Dispatched request."));
|
println!("{}", Green.paint("\t=> Dispatching request."));
|
||||||
return response.respond(res);
|
// FIXME: Responder should be able to say it didn't work.
|
||||||
|
return (route.handler)(request).respond(res);
|
||||||
|
} else {
|
||||||
|
// FIXME: Try next highest ranking route, not just 404.
|
||||||
|
let request = Request::new(vec![], uri_str, &buf);
|
||||||
|
let handler_404 = self.catchers.get(&404).unwrap().handler;
|
||||||
|
|
||||||
|
let msg = "\t=> Dispatch failed. Returning 404.";
|
||||||
|
println!("{}", Red.paint(msg));
|
||||||
|
return handler_404(request).respond(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", Yellow.paint("\t=> Debug: Method::from_hyp failed!"));
|
println!("{}", Yellow.paint("\t=> Debug: Method::from_hyp failed!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", Red.paint("\t=> Dispatch failed. Returning 404."));
|
println!("{}", Red.paint("\t=> Internal failure. Bad method or path."));
|
||||||
Response::not_found().respond(res);
|
Response::server_error().respond(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +64,7 @@ impl Rocket {
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
router: Router::new(),
|
router: Router::new(),
|
||||||
catchers: Vec::new(),
|
catchers: catcher::defaults::get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +83,16 @@ impl Rocket {
|
||||||
|
|
||||||
pub fn catch(&mut self, catchers: Vec<Catcher>) -> &mut Self {
|
pub fn catch(&mut self, catchers: Vec<Catcher>) -> &mut Self {
|
||||||
println!("👾 {}:", Magenta.paint("Catchers"));
|
println!("👾 {}:", Magenta.paint("Catchers"));
|
||||||
for catcher in catchers {
|
for c in catchers {
|
||||||
println!("\t* {}", catcher);
|
if self.catchers.contains_key(&c.code) &&
|
||||||
self.catchers.push(catcher);
|
!self.catchers.get(&c.code).unwrap().is_default() {
|
||||||
|
let msg = format!("warning: overrides {} catcher!", c.code);
|
||||||
|
println!("\t* {} ({})", c, Yellow.paint(msg.as_str()));
|
||||||
|
} else {
|
||||||
|
println!("\t* {}", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.catchers.insert(c.code, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
|
Loading…
Reference in New Issue