mirror of https://github.com/rwf2/Rocket.git
Can now assign outcome to response. Route mismatches now forward.
This means we have almost all of the infrastructure in place to properly use ranked requests. At the moment, we only use this to allow user error handlers when a responder fails. But, soon enough, we'll try the next highest ranked route until there are no more matching routes. Yipee!
This commit is contained in:
parent
3f2954ab5c
commit
b8b44a0594
|
@ -19,17 +19,17 @@ pub enum Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Method {
|
impl Method {
|
||||||
pub fn from_hyp(method: HyperMethod) -> Option<Method> {
|
pub fn from_hyp(method: &HyperMethod) -> Option<Method> {
|
||||||
match method {
|
match method {
|
||||||
HyperMethod::Get => Some(Get),
|
&HyperMethod::Get => Some(Get),
|
||||||
HyperMethod::Put => Some(Put),
|
&HyperMethod::Put => Some(Put),
|
||||||
HyperMethod::Post => Some(Post),
|
&HyperMethod::Post => Some(Post),
|
||||||
HyperMethod::Delete => Some(Delete),
|
&HyperMethod::Delete => Some(Delete),
|
||||||
HyperMethod::Options => Some(Options),
|
&HyperMethod::Options => Some(Options),
|
||||||
HyperMethod::Head => Some(Head),
|
&HyperMethod::Head => Some(Head),
|
||||||
HyperMethod::Trace => Some(Trace),
|
&HyperMethod::Trace => Some(Trace),
|
||||||
HyperMethod::Connect => Some(Connect),
|
&HyperMethod::Connect => Some(Connect),
|
||||||
HyperMethod::Patch => Some(Patch),
|
&HyperMethod::Patch => Some(Patch),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use param::FromParam;
|
||||||
|
|
||||||
pub use hyper::server::Request as HyperRequest;
|
pub use hyper::server::Request as HyperRequest;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Request<'a> {
|
pub struct Request<'a> {
|
||||||
params: Vec<&'a str>,
|
params: Vec<&'a str>,
|
||||||
pub uri: &'a str,
|
pub uri: &'a str,
|
||||||
|
|
|
@ -10,11 +10,20 @@ impl Empty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for Empty {
|
impl Responder for Empty {
|
||||||
fn respond<'a>(&mut self, mut res: HyperResponse<'a, HyperFresh>) {
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
res.headers_mut().set(header::ContentLength(0));
|
res.headers_mut().set(header::ContentLength(0));
|
||||||
*(res.status_mut()) = self.0;
|
*(res.status_mut()) = self.0;
|
||||||
|
|
||||||
let mut stream = res.start().unwrap();
|
let mut stream = res.start().unwrap();
|
||||||
stream.write_all(b"").unwrap();
|
stream.write_all(b"").unwrap();
|
||||||
|
Outcome::Complete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Forward;
|
||||||
|
|
||||||
|
impl Responder for Forward {
|
||||||
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
|
Outcome::FailForward(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ mod empty;
|
||||||
mod responder;
|
mod responder;
|
||||||
mod redirect;
|
mod redirect;
|
||||||
mod with_status;
|
mod with_status;
|
||||||
|
mod outcome;
|
||||||
|
|
||||||
pub use hyper::server::Response as HyperResponse;
|
pub use hyper::server::Response as HyperResponse;
|
||||||
pub use hyper::net::Fresh as HyperFresh;
|
pub use hyper::net::Fresh as HyperFresh;
|
||||||
|
@ -9,12 +10,15 @@ pub use hyper::status::StatusCode;
|
||||||
pub use hyper::header;
|
pub use hyper::header;
|
||||||
|
|
||||||
pub use self::responder::Responder;
|
pub use self::responder::Responder;
|
||||||
pub use self::empty::Empty;
|
pub use self::empty::{Empty, Forward};
|
||||||
pub use self::redirect::Redirect;
|
pub use self::redirect::Redirect;
|
||||||
pub use self::with_status::StatusResponse;
|
pub use self::with_status::StatusResponse;
|
||||||
|
pub use self::outcome::Outcome;
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
pub type FreshHyperResponse<'a> = HyperResponse<'a, HyperFresh>;
|
||||||
|
|
||||||
pub struct Response<'a>(Box<Responder + 'a>);
|
pub struct Response<'a>(Box<Responder + 'a>);
|
||||||
|
|
||||||
impl<'a> Response<'a> {
|
impl<'a> Response<'a> {
|
||||||
|
@ -27,6 +31,10 @@ impl<'a> Response<'a> {
|
||||||
Response(Box::new(StatusResponse::new(status, body)))
|
Response(Box::new(StatusResponse::new(status, body)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn forward() -> Response<'a> {
|
||||||
|
Response(Box::new(Forward))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_raw_status<T: Responder + 'a>(status: u16, body: T)
|
pub fn with_raw_status<T: Responder + 'a>(status: u16, body: T)
|
||||||
-> Response<'a> {
|
-> Response<'a> {
|
||||||
let status_code = StatusCode::from_u16(status);
|
let status_code = StatusCode::from_u16(status);
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
use response::*;
|
||||||
|
|
||||||
|
use term_painter::Color::*;
|
||||||
|
use term_painter::ToStyle;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub enum Outcome<'h> {
|
||||||
|
Complete,
|
||||||
|
FailStop,
|
||||||
|
FailForward(HyperResponse<'h, HyperFresh>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'h> Outcome<'h> {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
&Outcome::Complete => "Complete",
|
||||||
|
&Outcome::FailStop => "FailStop",
|
||||||
|
&Outcome::FailForward(..) => "FailForward",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_forward(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Outcome::FailForward(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_forward<F>(self, f: F)
|
||||||
|
where F: FnOnce(FreshHyperResponse<'h>) {
|
||||||
|
match self {
|
||||||
|
Outcome::FailForward(res) => f(res),
|
||||||
|
_ => { /* nothing */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_forward_or<F, R>(self, default: R, f: F) -> R
|
||||||
|
where F: FnOnce(FreshHyperResponse<'h>) -> R {
|
||||||
|
match self {
|
||||||
|
Outcome::FailForward(res) => f(res),
|
||||||
|
_ => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_failure(&self) -> bool {
|
||||||
|
self == &Outcome::FailStop
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_complete(&self) -> bool {
|
||||||
|
self == &Outcome::Complete
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_int(&self) -> isize {
|
||||||
|
match self {
|
||||||
|
&Outcome::Complete => 0,
|
||||||
|
&Outcome::FailStop => 1,
|
||||||
|
&Outcome::FailForward(..) => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'h> PartialEq for Outcome<'h> {
|
||||||
|
fn eq(&self, other: &Outcome<'h>) -> bool {
|
||||||
|
self.as_int() == other.as_int()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'h> fmt::Debug for Outcome<'h> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Outcome::{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'h> fmt::Display for Outcome<'h> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&Outcome::Complete => {
|
||||||
|
write!(f, "{}", Green.paint("Complete"))
|
||||||
|
},
|
||||||
|
&Outcome::FailStop => {
|
||||||
|
write!(f, "{}", Red.paint("Failed"))
|
||||||
|
},
|
||||||
|
&Outcome::FailForward(..) => {
|
||||||
|
write!(f, "{}", Yellow.paint("Forwarding"))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,11 +22,12 @@ impl Redirect {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Responder for Redirect {
|
impl<'a> Responder for Redirect {
|
||||||
fn respond<'b>(&mut self, mut res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
||||||
res.headers_mut().set(header::ContentLength(0));
|
res.headers_mut().set(header::ContentLength(0));
|
||||||
res.headers_mut().set(header::Location(self.1.clone()));
|
res.headers_mut().set(header::Location(self.1.clone()));
|
||||||
*(res.status_mut()) = self.0;
|
*(res.status_mut()) = self.0;
|
||||||
res.send(b"").unwrap();
|
res.send(b"").unwrap();
|
||||||
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,24 +8,26 @@ use std::fmt;
|
||||||
// In particular, we want to try the next ranked route when when parsing
|
// In particular, we want to try the next ranked route when when parsing
|
||||||
// parameters doesn't work out.
|
// parameters doesn't work out.
|
||||||
pub trait Responder {
|
pub trait Responder {
|
||||||
fn respond<'a>(&mut self, mut res: HyperResponse<'a, HyperFresh>);
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Responder for &'a str {
|
impl<'a> Responder for &'a str {
|
||||||
fn respond<'b>(&mut self, res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'b>(&mut self, res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
||||||
res.send(self.as_bytes()).unwrap();
|
res.send(self.as_bytes()).unwrap();
|
||||||
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for String {
|
impl Responder for String {
|
||||||
fn respond<'b>(&mut self, res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
res.send(self.as_bytes()).unwrap();
|
res.send(self.as_bytes()).unwrap();
|
||||||
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Should we set a content-type here? Safari needs text/html to render.
|
// FIXME: Should we set a content-type here? Safari needs text/html to render.
|
||||||
impl Responder for File {
|
impl Responder for File {
|
||||||
fn respond<'b>(&mut self, mut res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
let size = self.metadata().unwrap().len();
|
let size = self.metadata().unwrap().len();
|
||||||
|
|
||||||
res.headers_mut().set(header::ContentLength(size));
|
res.headers_mut().set(header::ContentLength(size));
|
||||||
|
@ -36,36 +38,38 @@ impl Responder for File {
|
||||||
|
|
||||||
let mut stream = res.start().unwrap();
|
let mut stream = res.start().unwrap();
|
||||||
stream.write_all(&v).unwrap();
|
stream.write_all(&v).unwrap();
|
||||||
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder> Responder for Option<T> {
|
impl<T: Responder> Responder for Option<T> {
|
||||||
fn respond<'b>(&mut self, res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
if self.is_none() {
|
if self.is_none() {
|
||||||
println!("Option is none.");
|
println!("Option is none.");
|
||||||
// TODO: Should this be a 404 or 500?
|
// TODO: Should this be a 404 or 500?
|
||||||
return Empty::new(StatusCode::NotFound).respond(res)
|
return Empty::new(StatusCode::NotFound).respond(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.as_mut().unwrap().respond(res);
|
self.as_mut().unwrap().respond(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
||||||
// prepend with `default` when using impl specialization
|
// prepend with `default` when using impl specialization
|
||||||
default fn respond<'b>(&mut self, res: HyperResponse<'b, HyperFresh>) {
|
default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>)
|
||||||
|
-> Outcome<'a> {
|
||||||
if self.is_err() {
|
if self.is_err() {
|
||||||
println!("Error: {:?}", self.as_ref().err().unwrap());
|
println!("Error: {:?}", self.as_ref().err().unwrap());
|
||||||
// TODO: Should this be a 404 or 500?
|
// TODO: Should this be a 404 or 500?
|
||||||
return Empty::new(StatusCode::NotFound).respond(res)
|
return Empty::new(StatusCode::NotFound).respond(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.as_mut().unwrap().respond(res);
|
self.as_mut().unwrap().respond(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
|
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
|
||||||
fn respond<'b>(&mut self, res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
match self {
|
match self {
|
||||||
&mut Ok(ref mut responder) => responder.respond(res),
|
&mut Ok(ref mut responder) => responder.respond(res),
|
||||||
&mut Err(ref mut responder) => responder.respond(res)
|
&mut Err(ref mut responder) => responder.respond(res)
|
||||||
|
|
|
@ -15,9 +15,9 @@ impl<R: Responder> StatusResponse<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Responder> Responder for StatusResponse<R> {
|
impl<R: Responder> Responder for StatusResponse<R> {
|
||||||
fn respond<'b>(&mut self, mut res: HyperResponse<'b, HyperFresh>) {
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
||||||
*(res.status_mut()) = self.status;
|
*(res.status_mut()) = self.status;
|
||||||
self.responder.respond(res);
|
self.responder.respond(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use response::{HyperResponse, HyperFresh};
|
use response::FreshHyperResponse;
|
||||||
use request::HyperRequest;
|
use request::HyperRequest;
|
||||||
use catcher;
|
use catcher;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ use term_painter::Color::*;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
use hyper::uri::RequestUri as HyperRequestUri;
|
use hyper::uri::RequestUri as HyperRequestUri;
|
||||||
|
use hyper::method::Method as HyperMethod;
|
||||||
use hyper::server::Server as HyperServer;
|
use hyper::server::Server as HyperServer;
|
||||||
use hyper::server::Handler as HyperHandler;
|
use hyper::server::Handler as HyperHandler;
|
||||||
|
|
||||||
|
@ -19,46 +20,94 @@ pub struct Rocket {
|
||||||
catchers: HashMap<u16, Catcher>,
|
catchers: HashMap<u16, Catcher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uri_is_absolute(uri: &HyperRequestUri) -> bool {
|
||||||
|
match uri {
|
||||||
|
&HyperRequestUri::AbsolutePath(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_absolute_path<'a>(uri: &'a HyperRequestUri) -> &'a str {
|
||||||
|
match uri {
|
||||||
|
&HyperRequestUri::AbsolutePath(ref s) => s.as_str(),
|
||||||
|
_ => panic!("Can only accept absolute paths!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn method_is_valid(method: &HyperMethod) -> bool {
|
||||||
|
Method::from_hyp(method).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
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, req: HyperRequest<'a, 'k>,
|
||||||
res: HyperResponse<'a, HyperFresh>) {
|
res: FreshHyperResponse<'a>) {
|
||||||
println!("{:?} {:?}", Green.paint(&req.method), Blue.paint(&req.uri));
|
println!("{:?} '{}'", Green.paint(&req.method), Blue.paint(&req.uri));
|
||||||
|
|
||||||
let mut buf = vec![];
|
let finalize = |mut req: HyperRequest, _res: FreshHyperResponse| {
|
||||||
req.read_to_end(&mut buf); // FIXME: Simple DOS attack here.
|
let mut buf = vec![];
|
||||||
if let HyperRequestUri::AbsolutePath(uri_string) = req.uri {
|
// FIXME: Simple DOS attack here. Working around Hyper bug.
|
||||||
if let Some(method) = Method::from_hyp(req.method) {
|
let _ = req.read_to_end(&mut buf);
|
||||||
let uri_str = uri_string.as_str();
|
};
|
||||||
let route = self.router.route(method, uri_str);
|
|
||||||
|
|
||||||
if route.is_some() {
|
if !uri_is_absolute(&req.uri) {
|
||||||
let route = route.unwrap();
|
println!("{}", Red.paint("\t=> Internal failure. Bad URI."));
|
||||||
let params = route.get_params(uri_str);
|
println!("{} {:?}", Yellow.paint("\t=> Debug:"), req.uri);
|
||||||
let request = Request::new(params, uri_str, &buf);
|
return finalize(req, res);
|
||||||
|
|
||||||
println!("{}", Green.paint("\t=> Dispatching request."));
|
|
||||||
// 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!("{}", Red.paint("\t=> Internal failure. Bad method or path."));
|
if !method_is_valid(&req.method) {
|
||||||
Response::server_error().respond(res);
|
println!("{}", Yellow.paint("\t=> Internal failure. Bad method."));
|
||||||
|
println!("{} {:?}", Yellow.paint("\t=> Debug:"), req.method);
|
||||||
|
return finalize(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.dispatch(req, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rocket {
|
impl Rocket {
|
||||||
|
fn dispatch<'h, 'k>(&self, mut req: HyperRequest<'h, 'k>,
|
||||||
|
mut res: FreshHyperResponse<'h>) {
|
||||||
|
// We read all of the contents now because we have to do it at some
|
||||||
|
// point thanks to Hyper. FIXME: Simple DOS attack here.
|
||||||
|
let mut buf = vec![];
|
||||||
|
let _ = req.read_to_end(&mut buf);
|
||||||
|
|
||||||
|
// Extract the method, uri, and try to find a route.
|
||||||
|
let method = Method::from_hyp(&req.method).unwrap();
|
||||||
|
let uri = unwrap_absolute_path(&req.uri);
|
||||||
|
let route = self.router.route(method, uri);
|
||||||
|
|
||||||
|
// A closure which we call when we know there is no route.
|
||||||
|
let handle_not_found = |response: FreshHyperResponse| {
|
||||||
|
let request = Request::new(vec![], uri, &buf);
|
||||||
|
let handler_404 = self.catchers.get(&404).unwrap().handler;
|
||||||
|
println!("{}", Red.paint("\t<= Dispatch failed. Returning 404."));
|
||||||
|
handler_404(request).respond(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
// No route found. Handle the not_found error and return.
|
||||||
|
if route.is_none() {
|
||||||
|
println!("{}", Red.paint("\t=> No matching routes."));
|
||||||
|
return handle_not_found(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, we've got a route. Unwrap it, generate a request, and try to
|
||||||
|
// dispatch. TODO: keep trying lower ranked routes before dispatching a
|
||||||
|
// not found error.
|
||||||
|
println!("\t=> {}", Magenta.paint("Dispatching request."));
|
||||||
|
let route = route.unwrap();
|
||||||
|
let params = route.get_params(uri);
|
||||||
|
let request = Request::new(params, uri, &buf);
|
||||||
|
let outcome = (route.handler)(request).respond(res);
|
||||||
|
|
||||||
|
println!("\t=> {} {}", White.paint("Outcome:"), outcome);
|
||||||
|
outcome.map_forward(|res| {
|
||||||
|
println!("{}", Red.paint("\t=> No further matching routes."));
|
||||||
|
handle_not_found(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(address: &'static str, port: isize) -> Rocket {
|
pub fn new(address: &'static str, port: isize) -> Rocket {
|
||||||
Rocket {
|
Rocket {
|
||||||
address: address,
|
address: address,
|
||||||
|
@ -68,7 +117,8 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount(&mut self, base: &'static str, routes: Vec<Route>) -> &mut Self {
|
pub fn mount(&mut self, base: &'static str, routes: Vec<Route>)
|
||||||
|
-> &mut Self {
|
||||||
println!("🛰 {} '{}':", Magenta.paint("Mounting"), Blue.paint(base));
|
println!("🛰 {} '{}':", Magenta.paint("Mounting"), Blue.paint(base));
|
||||||
for mut route in routes {
|
for mut route in routes {
|
||||||
let path = format!("{}/{}", base, route.path.as_str());
|
let path = format!("{}/{}", base, route.path.as_str());
|
||||||
|
|
|
@ -30,6 +30,8 @@ impl Router {
|
||||||
// TODO: Make a `Router` trait with this function. Rename this `Router`
|
// TODO: Make a `Router` trait with this function. Rename this `Router`
|
||||||
// struct to something like `RocketRouter`. If that happens, returning a
|
// struct to something like `RocketRouter`. If that happens, returning a
|
||||||
// `Route` structure is inflexible. Have it be an associated type.
|
// `Route` structure is inflexible. Have it be an associated type.
|
||||||
|
// FIXME: Figure out a way to get more than one route, i.e., to correctly
|
||||||
|
// handle ranking.
|
||||||
pub fn route<'b>(&'b self, method: Method, uri: &str) -> Option<&'b Route> {
|
pub fn route<'b>(&'b self, method: Method, uri: &str) -> Option<&'b Route> {
|
||||||
let mut matched_route: Option<&Route> = None;
|
let mut matched_route: Option<&Route> = None;
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ impl Router {
|
||||||
let num_segments = path.segment_count();
|
let num_segments = path.segment_count();
|
||||||
if let Some(routes) = self.routes.get(&(method, num_segments)) {
|
if let Some(routes) = self.routes.get(&(method, num_segments)) {
|
||||||
for route in routes.iter().filter(|r| r.collides_with(uri)) {
|
for route in routes.iter().filter(|r| r.collides_with(uri)) {
|
||||||
println!("\t=> Matched {} to: {}", uri, route);
|
println!("\t=> {} {}", Magenta.paint("Matched:"), route);
|
||||||
if let Some(existing_route) = matched_route {
|
if let Some(existing_route) = matched_route {
|
||||||
if route.rank > existing_route.rank {
|
if route.rank > existing_route.rank {
|
||||||
matched_route = Some(route);
|
matched_route = Some(route);
|
||||||
|
|
|
@ -359,7 +359,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
||||||
let param_fn_item = quote_stmt!(ecx,
|
let param_fn_item = quote_stmt!(ecx,
|
||||||
let $param_ident: $param_ty = match _req.get_param($i) {
|
let $param_ident: $param_ty = match _req.get_param($i) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => return rocket::Response::not_found()
|
Err(_) => return rocket::Response::forward()
|
||||||
};
|
};
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue