Seperate request dispatch into hyper and non-hyper parts.

This commit is contained in:
Sergio Benitez 2016-10-16 00:03:08 -07:00
parent 471239c567
commit 3008820494
1 changed files with 44 additions and 46 deletions

View File

@ -9,6 +9,7 @@ use term_painter::ToStyle;
use config; use config;
use logger; use logger;
use request::{Request, Data, FormItems}; use request::{Request, Data, FormItems};
use response::Responder;
use router::{Router, Route}; use router::{Router, Route};
use catcher::{self, Catcher}; use catcher::{self, Catcher};
use outcome::Outcome; use outcome::Outcome;
@ -29,49 +30,68 @@ pub struct Rocket {
#[doc(hidden)] #[doc(hidden)]
impl HyperHandler for Rocket { impl HyperHandler for Rocket {
fn handle<'h, 'k>(&self, fn handle<'h, 'k>(&self,
req: HyperRequest<'h, 'k>, hyp_req: HyperRequest<'h, 'k>,
mut res: FreshHyperResponse<'h>) { mut res: FreshHyperResponse<'h>) {
res.headers_mut().set(header::Server("rocket".to_string()));
self.dispatch(req, res)
}
}
impl Rocket {
fn dispatch<'h, 'k>(&self,
hyp_req: HyperRequest<'h, 'k>,
mut res: FreshHyperResponse<'h>) {
// Get a copy of the URI for later use.
let uri = hyp_req.uri.to_string();
// Get all of the information from Hyper. // Get all of the information from Hyper.
let (_, h_method, h_headers, h_uri, _, h_body) = hyp_req.deconstruct(); let (_, h_method, h_headers, h_uri, _, h_body) = hyp_req.deconstruct();
// Get a copy of the URI for later use.
let uri = h_uri.to_string();
// Try to create a Rocket request from the hyper request info. // Try to create a Rocket request from the hyper request info.
let mut request = match Request::new(h_method, h_headers, h_uri) { let mut request = match Request::new(h_method, h_headers, h_uri) {
Ok(req) => req, Ok(req) => req,
Err(ref reason) => { Err(ref reason) => {
let mock_request = Request::mock(Method::Get, uri.as_str()); let mock_request = Request::mock(Method::Get, uri.as_str());
debug_!("Bad request: {}", reason); error!("{}: bad request ({}).", mock_request, reason);
return self.handle_error(StatusCode::InternalServerError, return self.handle_error(StatusCode::InternalServerError,
&mock_request, res); &mock_request, res);
} }
}; };
// Retrieve the data from the request. // Retrieve the data from the hyper body.
let mut data = match Data::from_hyp(h_body) { let data = match Data::from_hyp(h_body) {
Ok(data) => data, Ok(data) => data,
Err(reason) => { Err(reason) => {
debug_!("Bad data in request: {}", reason); error_!("Bad data in request: {}", reason);
return self.handle_error(StatusCode::InternalServerError, return self.handle_error(StatusCode::InternalServerError,
&request, res); &request, res);
} }
}; };
// Preprocess the request. // Set the common response headers and preprocess the request.
res.headers_mut().set(header::Server("rocket".to_string()));
self.preprocess_request(&mut request, &data); self.preprocess_request(&mut request, &data);
// Now that we've Rocket-ized everything, actually dispath the request.
info!("{}:", request); info!("{}:", request);
trace_!("Peek size: {} bytes", data.peek().len()); let mut responder = match self.dispatch(&request, data) {
Ok(responder) => responder,
Err(code) => return self.handle_error(code, &request, res)
};
// We have a responder. Update the cookies in the header.
let cookie_delta = request.cookies().delta();
if cookie_delta.len() > 0 {
res.headers_mut().set(HyperSetCookie(cookie_delta));
}
// Actually call the responder.
let outcome = responder.respond(res);
info_!("{} {}", White.paint("Outcome:"), outcome);
// Check if the responder wants to forward to a catcher. If it doesn't,
// it's a success or failure, so we can't do any more processing.
if let Some((code, f_res)) = outcome.forwarded() {
return self.handle_error(code, &request, f_res);
}
}
}
impl Rocket {
fn dispatch<'r>(&self, request: &'r Request, mut data: Data)
-> Result<Box<Responder + 'r>, StatusCode> {
// Go through the list of matching routes until we fail or succeed.
let matches = self.router.route(&request); let matches = self.router.route(&request);
for route in matches { for route in matches {
// Retrieve and set the requests parameters. // Retrieve and set the requests parameters.
@ -84,36 +104,15 @@ impl Rocket {
// Check if the request processing completed or if the request needs // Check if the request processing completed or if the request needs
// to be forwarded. If it does, continue the loop to try again. // to be forwarded. If it does, continue the loop to try again.
info_!("{} {}", White.paint("Response:"), response); info_!("{} {}", White.paint("Response:"), response);
let mut responder = match response { match response {
Outcome::Success(responder) => responder, Outcome::Success(responder) => return Ok(responder),
Outcome::Failure(status_code) => { Outcome::Failure(status_code) => return Err(status_code),
return self.handle_error(status_code, &request, res); Outcome::Forward(unused_data) => data = unused_data,
}
Outcome::Forward(unused_data) => {
data = unused_data;
continue;
}
};
// We have a responder. Update the cookies in the header.
let cookie_delta = request.cookies().delta();
if cookie_delta.len() > 0 {
res.headers_mut().set(HyperSetCookie(cookie_delta));
}
// Actually process the response.
let outcome = responder.respond(res);
info_!("{} {}", White.paint("Outcome:"), outcome);
// Check if the responder wants to forward to a catcher.
match outcome.forwarded() {
Some((c, r)) => return self.handle_error(c, &request, r),
None => return
}; };
} }
error_!("No matching routes."); error_!("No matching routes.");
self.handle_error(StatusCode::NotFound, &request, res); Err(StatusCode::NotFound)
} }
/// Preprocess the request for Rocket-specific things. At this time, we're /// Preprocess the request for Rocket-specific things. At this time, we're
@ -142,7 +141,6 @@ impl Rocket {
code: StatusCode, code: StatusCode,
req: &'r Request, req: &'r Request,
response: FreshHyperResponse) { response: FreshHyperResponse) {
// Find the catcher or use the one for internal server errors. // Find the catcher or use the one for internal server errors.
let catcher = self.catchers.get(&code.to_u16()).unwrap_or_else(|| { let catcher = self.catchers.get(&code.to_u16()).unwrap_or_else(|| {
error_!("No catcher found for {}.", code); error_!("No catcher found for {}.", code);