mirror of https://github.com/rwf2/Rocket.git
This commit is a squash of the following commits:
* Add content-type responsers for JSON, HTML, and plain text. * Use content-type responders in content_type example. * Conditionally create Request `from` HypRequest. * Clean-up dispatching and handling in main rocket. * Change Level enum to Logging Level and reexport. * Allow users to set logging level before launch. * Fix content_type example error handling. * Percent decode params when user requests `String`.
This commit is contained in:
parent
90d8621adf
commit
a1ad05e879
|
@ -4,7 +4,8 @@
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use rocket::{Rocket, Request, ContentType, Error};
|
use rocket::{Rocket, Request, Error};
|
||||||
|
use rocket::response::JSON;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct Person {
|
struct Person {
|
||||||
|
@ -13,24 +14,24 @@ struct Person {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[GET(path = "/<name>/<age>", content = "application/json")]
|
#[GET(path = "/<name>/<age>", content = "application/json")]
|
||||||
fn hello(name: String, age: i8) -> String {
|
fn hello(name: String, age: i8) -> JSON<String> {
|
||||||
let person = Person {
|
let person = Person {
|
||||||
name: name,
|
name: name,
|
||||||
age: age,
|
age: age,
|
||||||
};
|
};
|
||||||
|
|
||||||
serde_json::to_string(&person).unwrap()
|
JSON(serde_json::to_string(&person).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[error(code = "404")]
|
#[error(code = "404")]
|
||||||
fn not_found<'r>(error: Error, request: &'r Request<'r>) -> String {
|
fn not_found<'r>(error: Error, request: &'r Request<'r>) -> String {
|
||||||
match error {
|
match error {
|
||||||
Error::NoRoute if !request.content_type().is_json() => {
|
Error::BadMethod if !request.content_type().is_json() => {
|
||||||
format!("<p>This server only supports JSON requests, not '{}'.</p>",
|
format!("<p>This server only supports JSON requests, not '{}'.</p>",
|
||||||
request.content_type())
|
request.content_type())
|
||||||
}
|
}
|
||||||
Error::NoRoute => {
|
Error::NoRoute => {
|
||||||
format!("<p>Sorry, this server but '{}' is not a valid path!</p>
|
format!("<p>Sorry, '{}' is not a valid path!</p>
|
||||||
<p>Try visiting /hello/<name>/<age> instead.</p>",
|
<p>Try visiting /hello/<name>/<age> instead.</p>",
|
||||||
request.uri())
|
request.uri())
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,6 @@ fn not_found<'r>(error: Error, request: &'r Request<'r>) -> String {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rocket = Rocket::new("0.0.0.0", 8000);
|
let mut rocket = Rocket::new("0.0.0.0", 8000);
|
||||||
rocket.mount("/hello", routes![hello]);
|
rocket.mount("/hello", routes![hello]).catch(errors![not_found]);
|
||||||
rocket.catch(errors![not_found]);
|
|
||||||
rocket.launch();
|
rocket.launch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
pub use hyper::mime::{Mime, TopLevel, SubLevel};
|
pub use response::mime::{Mime, TopLevel, SubLevel};
|
||||||
|
use response::mime::{Param};
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use hyper::mime::{Param};
|
|
||||||
use self::TopLevel::{Text, Application};
|
use self::TopLevel::{Text, Application};
|
||||||
use self::SubLevel::{Json, Html};
|
use self::SubLevel::{Json, Html};
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,6 @@ pub enum Error {
|
||||||
BadMethod,
|
BadMethod,
|
||||||
BadParse,
|
BadParse,
|
||||||
NoRoute, // FIXME: Add a chain of routes attempted.
|
NoRoute, // FIXME: Add a chain of routes attempted.
|
||||||
|
Internal,
|
||||||
NoKey
|
NoKey
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
||||||
use url::{self};
|
use url;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub mod handler {
|
||||||
pub type ErrorHandler = for<'r> fn(error: Error, &'r Request<'r>) -> Response<'r>;
|
pub type ErrorHandler = for<'r> fn(error: Error, &'r Request<'r>) -> Response<'r>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use logger::RocketLogger;
|
pub use logger::{RocketLogger, LoggingLevel};
|
||||||
pub use content_type::ContentType;
|
pub use content_type::ContentType;
|
||||||
pub use codegen::{StaticRouteInfo, StaticCatchInfo};
|
pub use codegen::{StaticRouteInfo, StaticCatchInfo};
|
||||||
pub use request::Request;
|
pub use request::Request;
|
||||||
|
|
|
@ -2,9 +2,10 @@ use log::{self, Log, LogLevel, LogRecord, LogMetadata};
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
pub struct RocketLogger(Level);
|
pub struct RocketLogger(LoggingLevel);
|
||||||
|
|
||||||
pub enum Level {
|
#[derive(PartialEq)]
|
||||||
|
pub enum LoggingLevel {
|
||||||
/// Only shows errors and warning.
|
/// Only shows errors and warning.
|
||||||
Critical,
|
Critical,
|
||||||
/// Shows everything except debug and trace information.
|
/// Shows everything except debug and trace information.
|
||||||
|
@ -13,13 +14,13 @@ pub enum Level {
|
||||||
Debug,
|
Debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Level {
|
impl LoggingLevel {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn max_log_level(&self) -> LogLevel {
|
fn max_log_level(&self) -> LogLevel {
|
||||||
match *self {
|
match *self {
|
||||||
Level::Critical => LogLevel::Warn,
|
LoggingLevel::Critical => LogLevel::Warn,
|
||||||
Level::Normal => LogLevel::Info,
|
LoggingLevel::Normal => LogLevel::Info,
|
||||||
Level::Debug => LogLevel::Trace
|
LoggingLevel::Debug => LogLevel::Trace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +56,7 @@ impl Log for RocketLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Rocket, we abuse target with value "_" to indicate indentation.
|
// In Rocket, we abuse target with value "_" to indicate indentation.
|
||||||
if record.target() == "_" {
|
if record.target() == "_" && self.0 != LoggingLevel::Critical {
|
||||||
print!(" {} ", White.paint("=>"));
|
print!(" {} ", White.paint("=>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ impl Log for RocketLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(level: Level) {
|
pub fn init(level: LoggingLevel) {
|
||||||
let result = log::set_logger(|max_log_level| {
|
let result = log::set_logger(|max_log_level| {
|
||||||
max_log_level.set(level.max_log_level().to_log_level_filter());
|
max_log_level.set(level.max_log_level().to_log_level_filter());
|
||||||
Box::new(RocketLogger(level))
|
Box::new(RocketLogger(level))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
||||||
|
use url;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
|
@ -13,6 +14,13 @@ impl<'a> FromParam<'a> for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FromParam<'a> for String {
|
||||||
|
fn from_param(p: &'a str) -> Result<String, Error> {
|
||||||
|
let decoder = url::percent_encoding::percent_decode(p.as_bytes());
|
||||||
|
decoder.decode_utf8().map_err(|_| Error::BadParse).map(|s| s.into_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_with_fromstr {
|
macro_rules! impl_with_fromstr {
|
||||||
($($T:ident),+) => ($(
|
($($T:ident),+) => ($(
|
||||||
impl<'a> FromParam<'a> for $T {
|
impl<'a> FromParam<'a> for $T {
|
||||||
|
@ -24,5 +32,5 @@ macro_rules! impl_with_fromstr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
|
impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
|
||||||
bool, String, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
|
bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
|
||||||
SocketAddr);
|
SocketAddr);
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use std::io::{Read};
|
use std::io::{Read};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use term_painter::Color::*;
|
||||||
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use param::FromParam;
|
use param::FromParam;
|
||||||
|
@ -16,10 +20,10 @@ use router::Route;
|
||||||
use request::{HyperHeaders, HyperRequest};
|
use request::{HyperHeaders, HyperRequest};
|
||||||
|
|
||||||
pub struct Request<'a> {
|
pub struct Request<'a> {
|
||||||
pub params: RefCell<Option<Vec<&'a str>>>, // This also sucks.
|
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub uri: URIBuf, // FIXME: Should be URI (without Hyper).
|
pub uri: URIBuf, // FIXME: Should be URI (without Hyper).
|
||||||
pub data: Vec<u8>, // FIXME: Don't read this! (bad Hyper.)
|
pub data: Vec<u8>, // FIXME: Don't read this! (bad Hyper.)
|
||||||
|
params: RefCell<Option<Vec<&'a str>>>, // This also sucks.
|
||||||
headers: HyperHeaders, // This sucks.
|
headers: HyperHeaders, // This sucks.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +37,6 @@ impl<'a> Request<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn mock(method: Method, uri: &str) -> Request {
|
pub fn mock(method: Method, uri: &str) -> Request {
|
||||||
Request {
|
Request {
|
||||||
params: RefCell::new(None),
|
params: RefCell::new(None),
|
||||||
|
@ -44,7 +47,6 @@ impl<'a> Request<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME: Get rid of Hyper.
|
// FIXME: Get rid of Hyper.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn headers(&self) -> &HyperHeaders {
|
pub fn headers(&self) -> &HyperHeaders {
|
||||||
|
@ -70,27 +72,38 @@ impl<'a> Request<'a> {
|
||||||
self.headers.set::<header::ContentType>(hyper_ct)
|
self.headers.set::<header::ContentType>(hyper_ct)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
pub fn from_hyp<'h, 'k>(hyper_req: HyperRequest<'h, 'k>)
|
||||||
|
-> Result<Request<'a>, String> {
|
||||||
impl<'a, 'h, 'k> From<HyperRequest<'h, 'k>> for Request<'a> {
|
|
||||||
fn from(hyper_req: HyperRequest<'h, 'k>) -> Request<'a> {
|
|
||||||
let (_, h_method, h_headers, h_uri, _, mut h_body) = hyper_req.deconstruct();
|
let (_, h_method, h_headers, h_uri, _, mut h_body) = hyper_req.deconstruct();
|
||||||
|
|
||||||
let uri = match h_uri {
|
let uri = match h_uri {
|
||||||
HyperRequestUri::AbsolutePath(s) => URIBuf::from(s),
|
HyperRequestUri::AbsolutePath(s) => URIBuf::from(s),
|
||||||
_ => panic!("Can only accept absolute paths!")
|
_ => return Err(format!("Bad URI: {}", h_uri))
|
||||||
|
};
|
||||||
|
|
||||||
|
let method = match Method::from_hyp(&h_method) {
|
||||||
|
Some(m) => m,
|
||||||
|
_ => return Err(format!("Bad method: {}", h_method))
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: GRRR.
|
// FIXME: GRRR.
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
h_body.read_to_end(&mut data).unwrap();
|
h_body.read_to_end(&mut data).unwrap();
|
||||||
|
|
||||||
Request {
|
let request = Request {
|
||||||
params: RefCell::new(None),
|
params: RefCell::new(None),
|
||||||
method: Method::from_hyp(&h_method).unwrap(),
|
method: method,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
data: data,
|
data: data,
|
||||||
headers: h_headers,
|
headers: h_headers,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> fmt::Display for Request<'r> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.uri))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
use response::{header, Responder, FreshHyperResponse, Outcome};
|
||||||
|
use response::mime::{Mime, TopLevel, SubLevel};
|
||||||
|
|
||||||
|
macro_rules! impl_data_type_responder {
|
||||||
|
($name:ident: $top:ident/$sub:ident) => (
|
||||||
|
pub struct $name<T: Responder>(pub T);
|
||||||
|
|
||||||
|
impl<T: Responder> Responder for $name<T> {
|
||||||
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
||||||
|
let mime = Mime(TopLevel::$top, SubLevel::$sub, vec![]);
|
||||||
|
res.headers_mut().set(header::ContentType(mime));
|
||||||
|
self.0.respond(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_data_type_responder!(JSON: Application/Json);
|
||||||
|
impl_data_type_responder!(HTML: Text/Html);
|
||||||
|
impl_data_type_responder!(Plain: Text/Plain);
|
|
@ -4,6 +4,7 @@ mod redirect;
|
||||||
mod with_status;
|
mod with_status;
|
||||||
mod outcome;
|
mod outcome;
|
||||||
mod cookied;
|
mod cookied;
|
||||||
|
mod data_type;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -11,6 +12,7 @@ pub use hyper::status::StatusCode;
|
||||||
pub use hyper::header;
|
pub use hyper::header;
|
||||||
pub use hyper::mime;
|
pub use hyper::mime;
|
||||||
|
|
||||||
|
pub use self::data_type::*;
|
||||||
pub use self::responder::Responder;
|
pub use self::responder::Responder;
|
||||||
pub use self::empty::{Empty, Forward};
|
pub use self::empty::{Empty, Forward};
|
||||||
pub use self::redirect::Redirect;
|
pub use self::redirect::Redirect;
|
||||||
|
|
|
@ -14,8 +14,11 @@ pub trait Responder {
|
||||||
|
|
||||||
impl<'a> Responder for &'a str {
|
impl<'a> Responder for &'a str {
|
||||||
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
||||||
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
|
if res.headers().get::<header::ContentType>().is_none() {
|
||||||
res.headers_mut().set(header::ContentType(mime));
|
let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
|
||||||
|
res.headers_mut().set(header::ContentType(mime));
|
||||||
|
}
|
||||||
|
|
||||||
res.send(self.as_bytes()).unwrap();
|
res.send(self.as_bytes()).unwrap();
|
||||||
Outcome::Complete
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
|
@ -23,8 +26,10 @@ impl<'a> Responder for &'a str {
|
||||||
|
|
||||||
impl Responder for String {
|
impl Responder for String {
|
||||||
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
|
if res.headers().get::<header::ContentType>().is_none() {
|
||||||
res.headers_mut().set(header::ContentType(mime));
|
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
|
||||||
|
res.headers_mut().set(header::ContentType(mime));
|
||||||
|
}
|
||||||
res.send(self.as_bytes()).unwrap();
|
res.send(self.as_bytes()).unwrap();
|
||||||
Outcome::Complete
|
Outcome::Complete
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,11 @@ use response::FreshHyperResponse;
|
||||||
use request::HyperRequest;
|
use request::HyperRequest;
|
||||||
use catcher;
|
use catcher;
|
||||||
|
|
||||||
use std::io::Read;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
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,91 +16,80 @@ pub struct Rocket {
|
||||||
port: isize,
|
port: isize,
|
||||||
router: Router,
|
router: Router,
|
||||||
catchers: HashMap<u16, Catcher>,
|
catchers: HashMap<u16, Catcher>,
|
||||||
}
|
log_set: bool,
|
||||||
|
|
||||||
fn uri_is_absolute(uri: &HyperRequestUri) -> bool {
|
|
||||||
match *uri {
|
|
||||||
HyperRequestUri::AbsolutePath(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn method_is_valid(method: &HyperMethod) -> bool {
|
|
||||||
Method::from_hyp(method).is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HyperHandler for Rocket {
|
impl HyperHandler for Rocket {
|
||||||
fn handle<'h, 'k>(&self, req: HyperRequest<'h, 'k>,
|
fn handle<'h, 'k>(&self, req: HyperRequest<'h, 'k>,
|
||||||
mut res: FreshHyperResponse<'h>) {
|
mut res: FreshHyperResponse<'h>) {
|
||||||
info!("{:?} '{}':", Green.paint(&req.method), Blue.paint(&req.uri));
|
|
||||||
|
|
||||||
let finalize = |mut req: HyperRequest, _res: FreshHyperResponse| {
|
|
||||||
let mut buf = vec![];
|
|
||||||
// FIXME: Simple DOS attack here. Working around Hyper bug.
|
|
||||||
let _ = req.read_to_end(&mut buf);
|
|
||||||
};
|
|
||||||
|
|
||||||
if !uri_is_absolute(&req.uri) {
|
|
||||||
error_!("Internal failure. Bad URI.");
|
|
||||||
debug_!("Debug: {}", req.uri);
|
|
||||||
return finalize(req, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !method_is_valid(&req.method) {
|
|
||||||
error_!("Internal failure. Bad method.");
|
|
||||||
debug_!("Method: {}", req.method);
|
|
||||||
return finalize(req, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.headers_mut().set(response::header::Server("rocket".to_string()));
|
res.headers_mut().set(response::header::Server("rocket".to_string()));
|
||||||
self.dispatch(req, res)
|
self.dispatch(req, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rocket {
|
impl Rocket {
|
||||||
fn dispatch<'h, 'k>(&self, hyper_req: HyperRequest<'h, 'k>,
|
fn dispatch<'h, 'k>(&self, hyp_req: HyperRequest<'h, 'k>,
|
||||||
res: FreshHyperResponse<'h>) {
|
res: FreshHyperResponse<'h>) {
|
||||||
let req = Request::from(hyper_req);
|
// Get a copy of the URI for later use.
|
||||||
let route = self.router.route(&req);
|
let uri = hyp_req.uri.to_string();
|
||||||
if let Some(route) = route {
|
|
||||||
|
// 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);
|
||||||
|
let route = self.router.route(&request);
|
||||||
|
if let Some(ref route) = route {
|
||||||
// Retrieve and set the requests parameters.
|
// Retrieve and set the requests parameters.
|
||||||
req.set_params(&route);
|
request.set_params(route);
|
||||||
|
|
||||||
// Here's the magic: dispatch the request to the handler.
|
// Here's the magic: dispatch the request to the handler.
|
||||||
let outcome = (route.handler)(&req).respond(res);
|
let outcome = (route.handler)(&request).respond(res);
|
||||||
info_!("{} {}", White.paint("Outcome:"), outcome);
|
info_!("{} {}", White.paint("Outcome:"), outcome);
|
||||||
|
|
||||||
// // TODO: keep trying lower ranked routes before dispatching a not
|
// TODO: keep trying lower ranked routes before dispatching a not
|
||||||
// // found error.
|
// found error.
|
||||||
// outcome.map_forward(|res| {
|
outcome.map_forward(|res| {
|
||||||
// error_!("No further matching routes.");
|
error_!("No further matching routes.");
|
||||||
// // TODO: Have some way to know why this was failed forward. Use that
|
// TODO: Have some way to know why this was failed forward. Use that
|
||||||
// // instead of always using an unchained error.
|
// instead of always using an unchained error.
|
||||||
// self.handle_not_found(req, res);
|
self.handle_not_found(&request, res);
|
||||||
// });
|
});
|
||||||
} else {
|
} else {
|
||||||
error_!("No matching routes.");
|
error_!("No matching routes.");
|
||||||
return self.handle_not_found(&req, res);
|
self.handle_not_found(&request, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A closure which we call when we know there is no route.
|
// 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.
|
||||||
fn handle_not_found<'r>(&self, request: &'r Request<'r>,
|
fn handle_not_found<'r>(&self, request: &'r Request<'r>,
|
||||||
response: FreshHyperResponse) {
|
response: FreshHyperResponse) {
|
||||||
error_!("Dispatch failed. Returning 404.");
|
error_!("{} dispatch failed: 404.", request);
|
||||||
let catcher = self.catchers.get(&404).unwrap();
|
let catcher = self.catchers.get(&404).unwrap();
|
||||||
catcher.handle(Error::NoRoute, request).respond(response);
|
catcher.handle(Error::NoRoute, request).respond(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(address: &'static str, port: isize) -> Rocket {
|
pub fn new(address: &'static str, port: isize) -> Rocket {
|
||||||
// FIXME: Allow user to override level/disable logging.
|
|
||||||
logger::init(logger::Level::Normal);
|
|
||||||
|
|
||||||
Rocket {
|
Rocket {
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
router: Router::new(),
|
router: Router::new(),
|
||||||
catchers: catcher::defaults::get(),
|
catchers: catcher::defaults::get(),
|
||||||
|
log_set: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,11 +124,24 @@ impl Rocket {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch(self) {
|
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) {
|
||||||
if self.router.has_collisions() {
|
if self.router.has_collisions() {
|
||||||
warn!("Route collisions detected!");
|
warn!("Route collisions detected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.log_set {
|
||||||
|
self.log(LoggingLevel::Normal)
|
||||||
|
}
|
||||||
|
|
||||||
let full_addr = format!("{}:{}", self.address, self.port);
|
let full_addr = format!("{}:{}", self.address, self.port);
|
||||||
info!("🚀 {} {}...", White.paint("Rocket has launched from"),
|
info!("🚀 {} {}...", White.paint("Rocket has launched from"),
|
||||||
White.bold().paint(&full_addr));
|
White.bold().paint(&full_addr));
|
||||||
|
|
|
@ -181,7 +181,7 @@ fn content_type_to_expr(ecx: &ExtCtxt, content_type: &ContentType) -> P<Expr> {
|
||||||
pub fn route_decorator(known_method: Option<Spanned<Method>>, ecx: &mut ExtCtxt,
|
pub fn route_decorator(known_method: Option<Spanned<Method>>, ecx: &mut ExtCtxt,
|
||||||
sp: Span, meta_item: &MetaItem, annotated: &Annotatable,
|
sp: Span, meta_item: &MetaItem, annotated: &Annotatable,
|
||||||
push: &mut FnMut(Annotatable)) {
|
push: &mut FnMut(Annotatable)) {
|
||||||
::rocket::logger::init(::rocket::logger::Level::Debug);
|
::rocket::logger::init(::rocket::LoggingLevel::Debug);
|
||||||
|
|
||||||
// Get the encompassing item and function declaration for the annotated func.
|
// Get the encompassing item and function declaration for the annotated func.
|
||||||
let parser = MetaItemParser::new(ecx, meta_item, annotated, &sp);
|
let parser = MetaItemParser::new(ecx, meta_item, annotated, &sp);
|
||||||
|
|
Loading…
Reference in New Issue