mirror of https://github.com/rwf2/Rocket.git
Use Outcome as the result of all fallible conversions.
This commit is contained in:
parent
aa2f2061ac
commit
722f613686
|
@ -105,12 +105,11 @@ impl RouteGenerateExt for RouteParams {
|
||||||
Some(quote_stmt!(ecx,
|
Some(quote_stmt!(ecx,
|
||||||
let $name: $ty =
|
let $name: $ty =
|
||||||
match ::rocket::request::FromData::from_data(&_req, _data) {
|
match ::rocket::request::FromData::from_data(&_req, _data) {
|
||||||
::rocket::request::DataOutcome::Success(d) => d,
|
::rocket::outcome::Outcome::Success(d) => d,
|
||||||
::rocket::request::DataOutcome::Forward(d) =>
|
::rocket::outcome::Outcome::Forward(d) =>
|
||||||
return ::rocket::Response::forward(d),
|
return ::rocket::Response::forward(d),
|
||||||
::rocket::request::DataOutcome::Failure(_) => {
|
::rocket::outcome::Outcome::Failure((code, _)) => {
|
||||||
let code = ::rocket::http::StatusCode::BadRequest;
|
return ::rocket::Response::failure(code);
|
||||||
return ::rocket::Response::failed(code);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
).expect("data statement"))
|
).expect("data statement"))
|
||||||
|
@ -181,9 +180,13 @@ impl RouteGenerateExt for RouteParams {
|
||||||
let ty = strip_ty_lifetimes(arg.ty.clone());
|
let ty = strip_ty_lifetimes(arg.ty.clone());
|
||||||
fn_param_statements.push(quote_stmt!(ecx,
|
fn_param_statements.push(quote_stmt!(ecx,
|
||||||
let $ident: $ty = match
|
let $ident: $ty = match
|
||||||
<$ty as ::rocket::request::FromRequest>::from_request(&_req) {
|
::rocket::request::FromRequest::from_request(&_req) {
|
||||||
Ok(v) => v,
|
::rocket::outcome::Outcome::Success(v) => v,
|
||||||
Err(_e) => return ::rocket::Response::forward(_data)
|
::rocket::outcome::Outcome::Forward(_) =>
|
||||||
|
return ::rocket::Response::forward(_data),
|
||||||
|
::rocket::outcome::Outcome::Failure((code, _)) => {
|
||||||
|
return ::rocket::Response::failure(code)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
).expect("undeclared param parsing statement"));
|
).expect("undeclared param parsing statement"));
|
||||||
}
|
}
|
||||||
|
@ -240,7 +243,7 @@ fn generic_route_decorator(known_method: Option<Spanned<Method>>,
|
||||||
$query_statement
|
$query_statement
|
||||||
$data_statement
|
$data_statement
|
||||||
let result = $user_fn_name($fn_arguments);
|
let result = $user_fn_name($fn_arguments);
|
||||||
::rocket::Response::complete(result)
|
::rocket::Response::success(result)
|
||||||
}
|
}
|
||||||
).unwrap());
|
).unwrap());
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use rocket::request::{Request, Data, FromData, DataOutcome};
|
use rocket::request::{Request, Data, FromData, DataOutcome};
|
||||||
use rocket::response::{Responder, Outcome, ResponseOutcome, data};
|
use rocket::response::{Responder, ResponseOutcome, data};
|
||||||
use rocket::http::StatusCode;
|
use rocket::http::StatusCode;
|
||||||
use rocket::http::hyper::FreshHyperResponse;
|
use rocket::http::hyper::FreshHyperResponse;
|
||||||
|
|
||||||
|
@ -73,11 +73,11 @@ impl<T: Deserialize> FromData for JSON<T> {
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, SerdeError> {
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, SerdeError> {
|
||||||
if !request.content_type().is_json() {
|
if !request.content_type().is_json() {
|
||||||
error_!("Content-Type is not JSON.");
|
error_!("Content-Type is not JSON.");
|
||||||
return DataOutcome::Forward(data);
|
return DataOutcome::forward(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let reader = data.open().take(MAX_SIZE);
|
let reader = data.open().take(MAX_SIZE);
|
||||||
DataOutcome::from(serde_json::from_reader(reader).map(|val| JSON(val)))
|
DataOutcome::of(serde_json::from_reader(reader).map(|val| JSON(val)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ impl<T: Serialize> Responder for JSON<T> {
|
||||||
Ok(json_string) => data::JSON(json_string).respond(res),
|
Ok(json_string) => data::JSON(json_string).respond(res),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_!("JSON failed to serialize: {:?}", e);
|
error_!("JSON failed to serialize: {:?}", e);
|
||||||
Outcome::Forward((StatusCode::BadRequest, res))
|
ResponseOutcome::forward(StatusCode::BadRequest, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rocket::Rocket;
|
use rocket::Rocket;
|
||||||
use rocket::response::{Content, Outcome, ResponseOutcome, Responder};
|
use rocket::response::{Content, ResponseOutcome, Responder};
|
||||||
use rocket::http::hyper::FreshHyperResponse;
|
use rocket::http::hyper::FreshHyperResponse;
|
||||||
use rocket::http::{ContentType, StatusCode};
|
use rocket::http::{ContentType, StatusCode};
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ impl Responder for Template {
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Some(ref render) => Content(content_type, render.as_str()).respond(res),
|
Some(ref render) => Content(content_type, render.as_str()).respond(res),
|
||||||
None => Outcome::Forward((StatusCode::InternalServerError, res)),
|
None => ResponseOutcome::forward(StatusCode::InternalServerError, res),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use rocket::request::{Request, FromRequest};
|
use rocket::request::{Request, FromRequest, RequestOutcome};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct HeaderCount(usize);
|
struct HeaderCount(usize);
|
||||||
|
@ -17,8 +17,8 @@ impl fmt::Display for HeaderCount {
|
||||||
|
|
||||||
impl<'r> FromRequest<'r> for HeaderCount {
|
impl<'r> FromRequest<'r> for HeaderCount {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
Ok(HeaderCount(request.headers().len()))
|
RequestOutcome::success(HeaderCount(request.headers().len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,35 +13,35 @@ fn forward(_req: &Request, data: Data) -> Response<'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hi(_req: &Request, _: Data) -> Response<'static> {
|
fn hi(_req: &Request, _: Data) -> Response<'static> {
|
||||||
Response::complete("Hello!")
|
Response::success("Hello!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name<'a>(req: &'a Request, _: Data) -> Response<'a> {
|
fn name<'a>(req: &'a Request, _: Data) -> Response<'a> {
|
||||||
Response::complete(req.get_param(0).unwrap_or("unnamed"))
|
Response::success(req.get_param(0).unwrap_or("unnamed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo_url<'a>(req: &'a Request, _: Data) -> Response<'a> {
|
fn echo_url<'a>(req: &'a Request, _: Data) -> Response<'a> {
|
||||||
let param = req.uri().as_str().split_at(6).1;
|
let param = req.uri().as_str().split_at(6).1;
|
||||||
Response::complete(String::from_param(param))
|
Response::success(String::from_param(param))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload(req: &Request, data: Data) -> Response {
|
fn upload(req: &Request, data: Data) -> Response {
|
||||||
if !req.content_type().is_text() {
|
if !req.content_type().is_text() {
|
||||||
println!(" => Content-Type of upload must be data. Ignoring.");
|
println!(" => Content-Type of upload must be data. Ignoring.");
|
||||||
return Response::failed(StatusCode::BadRequest);
|
return Response::failure(StatusCode::BadRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = File::create("/tmp/upload.txt");
|
let file = File::create("/tmp/upload.txt");
|
||||||
if let Ok(mut file) = file {
|
if let Ok(mut file) = file {
|
||||||
if let Ok(n) = io::copy(&mut data.open(), &mut file) {
|
if let Ok(n) = io::copy(&mut data.open(), &mut file) {
|
||||||
return Response::complete(format!("OK: {} bytes uploaded.", n));
|
return Response::success(format!("OK: {} bytes uploaded.", n));
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(" => Failed copying.");
|
println!(" => Failed copying.");
|
||||||
Response::failed(StatusCode::InternalServerError)
|
Response::failure(StatusCode::InternalServerError)
|
||||||
} else {
|
} else {
|
||||||
println!(" => Couldn't open file: {:?}", file.unwrap_err());
|
println!(" => Couldn't open file: {:?}", file.unwrap_err());
|
||||||
Response::failed(StatusCode::InternalServerError)
|
Response::failure(StatusCode::InternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ authors = ["Sergio Benitez <sb@sergio.bz>"]
|
||||||
term-painter = "^0.2"
|
term-painter = "^0.2"
|
||||||
log = "^0.3"
|
log = "^0.3"
|
||||||
url = "^1"
|
url = "^1"
|
||||||
# mime = "^0.2"
|
|
||||||
toml = "^0.2"
|
toml = "^0.2"
|
||||||
|
|
||||||
[dependencies.hyper]
|
[dependencies.hyper]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![feature(question_mark)]
|
#![feature(question_mark)]
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
#![feature(conservative_impl_trait)]
|
#![feature(conservative_impl_trait)]
|
||||||
#![feature(associated_type_defaults)]
|
|
||||||
|
|
||||||
//! # Rocket - Core API Documentation
|
//! # Rocket - Core API Documentation
|
||||||
//!
|
//!
|
||||||
|
@ -31,9 +30,9 @@
|
||||||
//! ## Usage
|
//! ## Usage
|
||||||
//!
|
//!
|
||||||
//! The sanctioned way to use Rocket is via the code generation plugin. This
|
//! The sanctioned way to use Rocket is via the code generation plugin. This
|
||||||
//! makes Rocket easier to use and allows a somewhat stable API as Rust matures.
|
//! makes Rocket easier to use and allows a somewhat stable API as Rocket
|
||||||
//! To use Rocket in your Cargo-based project, add the following to
|
//! matures. To use Rocket with the code generation plugin in your Cargo-based
|
||||||
//! `Cargo.toml`:
|
//! project, add the following to `Cargo.toml`:
|
||||||
//!
|
//!
|
||||||
//! ```rust,ignore
|
//! ```rust,ignore
|
||||||
//! [dependencies]
|
//! [dependencies]
|
||||||
|
@ -54,7 +53,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! See the [guide](https://guide.rocket.rs) for more information on how to
|
//! See the [guide](https://guide.rocket.rs) for more information on how to
|
||||||
//! write Rocket application.
|
//! write Rocket applications.
|
||||||
//!
|
//!
|
||||||
//! ## Configuration
|
//! ## Configuration
|
||||||
//!
|
//!
|
||||||
|
@ -65,7 +64,6 @@
|
||||||
extern crate term_painter;
|
extern crate term_painter;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
// extern crate mime;
|
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
|
||||||
#[cfg(test)] #[macro_use] extern crate lazy_static;
|
#[cfg(test)] #[macro_use] extern crate lazy_static;
|
||||||
|
|
|
@ -1,71 +1,115 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
|
use term_painter::Color;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub enum Outcome<T> {
|
pub enum Outcome<S, E, F> {
|
||||||
/// Signifies that all processing completed successfully.
|
/// Contains the success value.
|
||||||
Success,
|
Success(S),
|
||||||
/// Signifies that some processing occurred that ultimately resulted in
|
/// Contains the failure error value.
|
||||||
/// failure. As a result, no further processing can occur.
|
Failure(E),
|
||||||
Failure,
|
/// Contains the value to forward on.
|
||||||
/// Signifies that no processing occured and as such, processing can be
|
Forward(F),
|
||||||
/// forwarded to the next available target.
|
|
||||||
Forward(T),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Outcome<T> {
|
impl<S, E, F> Outcome<S, E, F> {
|
||||||
pub fn of<A, B: fmt::Debug>(result: Result<A, B>) -> Outcome<T> {
|
/// Unwraps the Outcome, yielding the contents of a Success.
|
||||||
if let Err(e) = result {
|
///
|
||||||
error_!("{:?}", e);
|
/// # Panics
|
||||||
return Outcome::Failure;
|
///
|
||||||
|
/// Panics if the value is not Success.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn unwrap(self) -> S {
|
||||||
|
match self {
|
||||||
|
Outcome::Success(val) => val,
|
||||||
|
_ => panic!("Expected a successful outcome!")
|
||||||
}
|
}
|
||||||
|
|
||||||
Outcome::Success
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str(&self) -> &'static str {
|
/// Return true if this `Outcome` is a `Success`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_success(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Outcome::Success => "Success",
|
Outcome::Success(_) => true,
|
||||||
Outcome::Failure => "FailStop",
|
_ => false
|
||||||
Outcome::Forward(..) => "Forward",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_int(&self) -> isize {
|
/// Return true if this `Outcome` is a `Failure`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_failure(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Outcome::Success => 0,
|
Outcome::Failure(_) => true,
|
||||||
Outcome::Failure => 1,
|
_ => false
|
||||||
Outcome::Forward(..) => 2,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_success(&self) {
|
/// Return true if this `Outcome` is a `Forward`.
|
||||||
if *self != Outcome::Success {
|
#[inline(always)]
|
||||||
panic!("expected a successful outcome");
|
pub fn is_forward(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Outcome::Forward(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts from `Outcome<S, E, F>` to `Option<S>`.
|
||||||
|
///
|
||||||
|
/// Returns the `Some` of the `Success` if this is a `Success`, otherwise
|
||||||
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn succeeded(self) -> Option<S> {
|
||||||
|
match self {
|
||||||
|
Outcome::Success(val) => Some(val),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts from `Outcome<S, E, F>` to `Option<E>`.
|
||||||
|
///
|
||||||
|
/// Returns the `Some` of the `Failure` if this is a `Failure`, otherwise
|
||||||
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn failed(self) -> Option<E> {
|
||||||
|
match self {
|
||||||
|
Outcome::Failure(val) => Some(val),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts from `Outcome<S, E, F>` to `Option<F>`.
|
||||||
|
///
|
||||||
|
/// Returns the `Some` of the `Forward` if this is a `Forward`, otherwise
|
||||||
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn forwarded(self) -> Option<F> {
|
||||||
|
match self {
|
||||||
|
Outcome::Forward(val) => Some(val),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn formatting(&self) -> (Color, &'static str) {
|
||||||
|
match *self {
|
||||||
|
Outcome::Success(..) => (Green, "Succcess"),
|
||||||
|
Outcome::Failure(..) => (Red, "Failure"),
|
||||||
|
Outcome::Forward(..) => (Yellow, "Forward"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> PartialEq for Outcome<T> {
|
impl<S, E, F> fmt::Debug for Outcome<S, E, F> {
|
||||||
fn eq(&self, other: &Outcome<T>) -> bool {
|
|
||||||
self.as_int() == other.as_int()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> fmt::Debug for Outcome<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "Outcome::{}", self.as_str())
|
write!(f, "Outcome::{}", self.formatting().1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Display for Outcome<T> {
|
impl<S, E, F> fmt::Display for Outcome<S, E, F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
let (color, string) = self.formatting();
|
||||||
Outcome::Success => write!(f, "{}", Green.paint("Success")),
|
write!(f, "{}", color.paint(string))
|
||||||
Outcome::Failure => write!(f, "{}", Red.paint("Failure")),
|
|
||||||
Outcome::Forward(..) => write!(f, "{}", Cyan.paint("Forwarding")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,61 @@
|
||||||
use std::fmt::Debug;
|
use outcome::Outcome;
|
||||||
|
use http::StatusCode;
|
||||||
use request::{Request, Data};
|
use request::{Request, Data};
|
||||||
|
|
||||||
|
pub type DataOutcome<S, E> = Outcome<S, (StatusCode, E), Data>;
|
||||||
|
|
||||||
|
impl<S, E> DataOutcome<S, E> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn of(result: Result<S, E>) -> Self {
|
||||||
|
match result {
|
||||||
|
Ok(val) => DataOutcome::success(val),
|
||||||
|
Err(err) => DataOutcome::failure(StatusCode::InternalServerError, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn success(s: S) -> Self {
|
||||||
|
Outcome::Success(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn failure(status: StatusCode, e: E) -> Self {
|
||||||
|
Outcome::Failure((status, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn forward(data: Data) -> Self {
|
||||||
|
Outcome::Forward(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait used to derive an object from incoming request data.
|
/// Trait used to derive an object from incoming request data.
|
||||||
pub trait FromData: Sized {
|
pub trait FromData: Sized {
|
||||||
type Error = ();
|
type Error;
|
||||||
|
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error>;
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromData> FromData for Result<T, T::Error> {
|
impl<T: FromData> FromData for Result<T, T::Error> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
||||||
match T::from_data(request, data) {
|
match T::from_data(request, data) {
|
||||||
DataOutcome::Success(val) => DataOutcome::Success(Ok(val)),
|
Outcome::Success(val) => DataOutcome::success(Ok(val)),
|
||||||
DataOutcome::Failure(val) => DataOutcome::Success(Err(val)),
|
Outcome::Failure((_, val)) => DataOutcome::success(Err(val)),
|
||||||
DataOutcome::Forward(data) => DataOutcome::Forward(data)
|
Outcome::Forward(data) => DataOutcome::forward(data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromData> FromData for Option<T> {
|
impl<T: FromData> FromData for Option<T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
||||||
match T::from_data(request, data) {
|
match T::from_data(request, data) {
|
||||||
DataOutcome::Success(val) => DataOutcome::Success(Some(val)),
|
Outcome::Success(val) => DataOutcome::success(Some(val)),
|
||||||
DataOutcome::Failure(_) => DataOutcome::Success(None),
|
Outcome::Failure(_) => DataOutcome::success(None),
|
||||||
DataOutcome::Forward(data) => DataOutcome::Forward(data)
|
Outcome::Forward(_) => DataOutcome::success(None)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub enum DataOutcome<T, E> {
|
|
||||||
/// Signifies that all processing completed successfully.
|
|
||||||
Success(T),
|
|
||||||
/// Signifies that some processing occurred that ultimately resulted in
|
|
||||||
/// failure. As a result, no further processing can occur.
|
|
||||||
Failure(E),
|
|
||||||
/// Signifies that no processing occured and as such, processing can be
|
|
||||||
/// forwarded to the next available target.
|
|
||||||
Forward(Data),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: Debug> From<Result<T, E>> for DataOutcome<T, E> {
|
|
||||||
fn from(result: Result<T, E>) -> Self {
|
|
||||||
match result {
|
|
||||||
Ok(val) => DataOutcome::Success(val),
|
|
||||||
Err(e) => {
|
|
||||||
error_!("{:?}", e);
|
|
||||||
DataOutcome::Failure(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<Option<T>> for DataOutcome<T, ()> {
|
|
||||||
fn from(result: Option<T>) -> Self {
|
|
||||||
match result {
|
|
||||||
Some(val) => DataOutcome::Success(val),
|
|
||||||
None => DataOutcome::Failure(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,9 @@ impl Drop for Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromData for Data {
|
impl FromData for Data {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
fn from_data(_: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
fn from_data(_: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
||||||
DataOutcome::Success(data)
|
DataOutcome::success(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Form parameter types must implement the [FromForm](trait.FromForm.html)
|
//! Form parameter types must implement the [FromForm](trait.FromForm.html)
|
||||||
//! trait, which is automatically derivable. Automatically deriving `FromForm`
|
//! trait, which is automaForwarp derivable. Automatically deriving `FromForm`
|
||||||
//! for a structure requires that all of its fields implement
|
//! for a structure requires that all of its fields implement
|
||||||
//! [FromFormValue](trait.FormFormValue.html). See the
|
//! [FromFormValue](trait.FormFormValue.html). See the
|
||||||
//! [codegen](/rocket_codegen/) documentation or the [forms guide](/guide/forms)
|
//! [codegen](/rocket_codegen/) documentation or the [forms guide](/guide/forms)
|
||||||
|
@ -27,6 +27,7 @@ use std::marker::PhantomData;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
use http::StatusCode;
|
||||||
use request::{Request, FromData, Data, DataOutcome};
|
use request::{Request, FromData, Data, DataOutcome};
|
||||||
|
|
||||||
// This works, and it's safe, but it sucks to have the lifetime appear twice.
|
// This works, and it's safe, but it sucks to have the lifetime appear twice.
|
||||||
|
@ -103,20 +104,20 @@ impl<'f, T: FromForm<'f>> FromData for Form<'f, T> where T::Error: Debug {
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
||||||
if !request.content_type().is_form() {
|
if !request.content_type().is_form() {
|
||||||
warn_!("Form data does not have form content type.");
|
warn_!("Form data does not have form content type.");
|
||||||
return DataOutcome::Forward(data);
|
return DataOutcome::forward(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut form_string = String::with_capacity(4096);
|
let mut form_string = String::with_capacity(4096);
|
||||||
let mut stream = data.open().take(32768);
|
let mut stream = data.open().take(32768);
|
||||||
if let Err(e) = stream.read_to_string(&mut form_string) {
|
if let Err(e) = stream.read_to_string(&mut form_string) {
|
||||||
error_!("IO Error: {:?}", e);
|
error_!("IO Error: {:?}", e);
|
||||||
DataOutcome::Failure(None)
|
DataOutcome::failure(StatusCode::InternalServerError, None)
|
||||||
} else {
|
} else {
|
||||||
match Form::new(form_string) {
|
match Form::new(form_string) {
|
||||||
Ok(form) => DataOutcome::Success(form),
|
Ok(form) => DataOutcome::success(form),
|
||||||
Err((form_string, e)) => {
|
Err((form_string, e)) => {
|
||||||
error_!("Failed to parse value from form: {:?}", e);
|
error_!("Failed to parse value from form: {:?}", e);
|
||||||
DataOutcome::Failure(Some(form_string))
|
DataOutcome::failure(StatusCode::BadRequest, Some(form_string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +1,95 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use request::Request;
|
use request::Request;
|
||||||
use http::{ContentType, Method, Cookies};
|
use outcome::Outcome;
|
||||||
|
use http::{StatusCode, ContentType, Method, Cookies};
|
||||||
|
|
||||||
|
pub type RequestOutcome<T, E> = Outcome<T, (StatusCode, E), ()>;
|
||||||
|
|
||||||
|
impl<T, E> RequestOutcome<T, E> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn of(result: Result<T, E>) -> Self {
|
||||||
|
match result {
|
||||||
|
Ok(val) => Outcome::Success(val),
|
||||||
|
Err(_) => Outcome::Forward(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn success(t: T) -> Self {
|
||||||
|
Outcome::Success(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn failure(code: StatusCode, error: E) -> Self {
|
||||||
|
Outcome::Failure((code, error))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn forward() -> Self {
|
||||||
|
Outcome::Forward(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait FromRequest<'r>: Sized {
|
pub trait FromRequest<'r>: Sized {
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error>;
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> FromRequest<'r> for &'r Request {
|
impl<'r> FromRequest<'r> for &'r Request {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
Ok(request)
|
RequestOutcome::success(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> FromRequest<'r> for Method {
|
impl<'r> FromRequest<'r> for Method {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
Ok(request.method)
|
RequestOutcome::success(request.method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> FromRequest<'r> for &'r Cookies {
|
impl<'r> FromRequest<'r> for &'r Cookies {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
|
||||||
Ok(request.cookies())
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
|
RequestOutcome::success(request.cookies())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> FromRequest<'r> for ContentType {
|
impl<'r> FromRequest<'r> for ContentType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
Ok(request.content_type())
|
RequestOutcome::success(request.content_type())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
|
||||||
let opt = match T::from_request(request) {
|
|
||||||
Ok(v) => Some(v),
|
|
||||||
Err(_) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(opt)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Result<T, T::Error> {
|
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Result<T, T::Error> {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
Ok(T::from_request(request))
|
match T::from_request(request) {
|
||||||
|
Outcome::Success(val) => RequestOutcome::success(Ok(val)),
|
||||||
|
Outcome::Failure((_, e)) => RequestOutcome::success(Err(e)),
|
||||||
|
Outcome::Forward(_) => RequestOutcome::forward(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
|
match T::from_request(request) {
|
||||||
|
Outcome::Success(val) => RequestOutcome::success(Some(val)),
|
||||||
|
Outcome::Failure(_) => RequestOutcome::success(None),
|
||||||
|
Outcome::Forward(_) => RequestOutcome::success(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod data;
|
||||||
mod from_request;
|
mod from_request;
|
||||||
|
|
||||||
pub use self::request::Request;
|
pub use self::request::Request;
|
||||||
pub use self::from_request::FromRequest;
|
pub use self::from_request::{FromRequest, RequestOutcome};
|
||||||
pub use self::param::{FromParam, FromSegments};
|
pub use self::param::{FromParam, FromSegments};
|
||||||
pub use self::form::{Form, FromForm, FromFormValue, FormItems};
|
pub use self::form::{Form, FromForm, FromFormValue, FormItems};
|
||||||
pub use self::data::{Data, FromData, DataOutcome};
|
pub use self::data::{Data, FromData, DataOutcome};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use response::{ResponseOutcome, Outcome, Responder};
|
use response::{ResponseOutcome, Responder};
|
||||||
use http::hyper::{FreshHyperResponse, StatusCode};
|
use http::hyper::{FreshHyperResponse, StatusCode};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -6,6 +6,6 @@ pub struct Failure(pub StatusCode);
|
||||||
|
|
||||||
impl Responder for Failure {
|
impl Responder for Failure {
|
||||||
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
|
||||||
Outcome::Forward((self.0, res))
|
ResponseOutcome::forward(self.0, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::convert::AsRef;
|
use std::convert::AsRef;
|
||||||
|
|
||||||
use response::{ResponseOutcome, Responder};
|
use response::{ResponseOutcome, Responder};
|
||||||
use request::{Request, FromRequest};
|
use request::{Request, FromRequest, RequestOutcome};
|
||||||
use http::hyper::{HyperSetCookie, HyperCookiePair, FreshHyperResponse};
|
use http::hyper::{HyperSetCookie, HyperCookiePair, FreshHyperResponse};
|
||||||
|
|
||||||
const FLASH_COOKIE_NAME: &'static str = "_flash";
|
const FLASH_COOKIE_NAME: &'static str = "_flash";
|
||||||
|
@ -70,18 +70,12 @@ impl Flash<()> {
|
||||||
|
|
||||||
// TODO: Using Flash<()> is ugly. Either create a type FlashMessage = Flash<()>
|
// TODO: Using Flash<()> is ugly. Either create a type FlashMessage = Flash<()>
|
||||||
// or create a Flash under request that does this.
|
// or create a Flash under request that does this.
|
||||||
// TODO: Consider not removing the 'flash' cookie until after this thing is
|
|
||||||
// dropped. This is because, at the moment, if Flash is including as a
|
|
||||||
// from_request param, and some other param fails, then the flash message will
|
|
||||||
// be dropped needlessly. This may or may not be the intended behavior.
|
|
||||||
// Alternatively, provide a guarantee about the order that from_request params
|
|
||||||
// will be evaluated and recommend that Flash is last.
|
|
||||||
impl<'r> FromRequest<'r> for Flash<()> {
|
impl<'r> FromRequest<'r> for Flash<()> {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_request(request: &'r Request) -> Result<Self, Self::Error> {
|
fn from_request(request: &'r Request) -> RequestOutcome<Self, Self::Error> {
|
||||||
trace_!("Flash: attemping to retrieve message.");
|
trace_!("Flash: attemping to retrieve message.");
|
||||||
request.cookies().find(FLASH_COOKIE_NAME).ok_or(()).and_then(|cookie| {
|
let r = request.cookies().find(FLASH_COOKIE_NAME).ok_or(()).and_then(|cookie| {
|
||||||
// Clear the flash message.
|
// Clear the flash message.
|
||||||
trace_!("Flash: retrieving message: {:?}", cookie);
|
trace_!("Flash: retrieving message: {:?}", cookie);
|
||||||
request.cookies().remove(FLASH_COOKIE_NAME);
|
request.cookies().remove(FLASH_COOKIE_NAME);
|
||||||
|
@ -96,6 +90,8 @@ impl<'r> FromRequest<'r> for Flash<()> {
|
||||||
let name_len: usize = len_str.parse().map_err(|_| ())?;
|
let name_len: usize = len_str.parse().map_err(|_| ())?;
|
||||||
let (name, msg) = (&rest[..name_len], &rest[name_len..]);
|
let (name, msg) = (&rest[..name_len], &rest[name_len..]);
|
||||||
Ok(Flash::named(name, msg))
|
Ok(Flash::named(name, msg))
|
||||||
})
|
});
|
||||||
|
|
||||||
|
RequestOutcome::of(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,56 +18,63 @@ pub use self::data::Content;
|
||||||
pub use self::failure::Failure;
|
pub use self::failure::Failure;
|
||||||
pub use outcome::Outcome;
|
pub use outcome::Outcome;
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use request::Data;
|
use request::Data;
|
||||||
use http::hyper::{StatusCode, FreshHyperResponse};
|
use http::hyper::{StatusCode, FreshHyperResponse};
|
||||||
use term_painter::Color::*;
|
|
||||||
use term_painter::ToStyle;
|
|
||||||
|
|
||||||
pub type ResponseOutcome<'a> = Outcome<(StatusCode, FreshHyperResponse<'a>)>;
|
pub type ResponseOutcome<'a> = Outcome<(), (), (StatusCode, FreshHyperResponse<'a>)>;
|
||||||
|
|
||||||
pub enum Response<'a> {
|
impl<'a> ResponseOutcome<'a> {
|
||||||
Forward(Data),
|
#[inline(always)]
|
||||||
Complete(Box<Responder + 'a>)
|
pub fn of<A, B>(result: Result<A, B>) -> Self {
|
||||||
|
match result {
|
||||||
|
Ok(_) => Outcome::Success(()),
|
||||||
|
Err(_) => Outcome::Failure(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn success() -> ResponseOutcome<'a> {
|
||||||
|
Outcome::Success(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn failure() -> ResponseOutcome<'a> {
|
||||||
|
Outcome::Failure(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn forward(s: StatusCode, r: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
|
||||||
|
Outcome::Forward((s, r))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Response<'a> = Outcome<Box<Responder + 'a>, StatusCode, Data>;
|
||||||
|
|
||||||
impl<'a> Response<'a> {
|
impl<'a> Response<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn complete<T: Responder + 'a>(body: T) -> Response<'a> {
|
pub fn success<T: Responder + 'a>(responder: T) -> Response<'a> {
|
||||||
Response::Complete(Box::new(body))
|
Outcome::Success(Box::new(responder))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn failure(code: StatusCode) -> Response<'static> {
|
||||||
|
Outcome::Failure(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn forward(data: Data) -> Response<'static> {
|
pub fn forward(data: Data) -> Response<'static> {
|
||||||
Response::Forward(data)
|
Outcome::Forward(data)
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn failed(code: StatusCode) -> Response<'static> {
|
|
||||||
Response::complete(Failure(code))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_raw_status<T: Responder + 'a>(status: u16, body: T) -> Response<'a> {
|
pub fn with_raw_status<T: Responder + 'a>(status: u16, body: T) -> Response<'a> {
|
||||||
let status_code = StatusCode::from_u16(status);
|
let status_code = StatusCode::from_u16(status);
|
||||||
Response::complete(StatusResponse::new(status_code, body))
|
Response::success(StatusResponse::new(status_code, body))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn responder(self) -> Option<Box<Responder + 'a>> {
|
pub fn responder(self) -> Option<Box<Responder + 'a>> {
|
||||||
match self {
|
self.succeeded()
|
||||||
Response::Complete(responder) => Some(responder),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::Display for Response<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Response::Complete(..) => write!(f, "{}", Green.paint("Complete")),
|
|
||||||
Response::Forward(..) => write!(f, "{}", Yellow.paint("Forwarding")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use response::{ResponseOutcome, Outcome, Responder};
|
use response::{ResponseOutcome, Responder};
|
||||||
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -31,6 +31,6 @@ impl<'a> Responder for Redirect {
|
||||||
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;
|
||||||
Outcome::of(res.send(b""))
|
ResponseOutcome::of(res.send(b""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::io::{Read, Write};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use response::{Outcome, ResponseOutcome};
|
use response::ResponseOutcome;
|
||||||
use http::mime::{Mime, TopLevel, SubLevel};
|
use http::mime::{Mime, TopLevel, SubLevel};
|
||||||
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ impl<'a> Responder for &'a str {
|
||||||
res.headers_mut().set(header::ContentType(mime));
|
res.headers_mut().set(header::ContentType(mime));
|
||||||
}
|
}
|
||||||
|
|
||||||
Outcome::of(res.send(self.as_bytes()))
|
ResponseOutcome::of(res.send(self.as_bytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ impl Responder for String {
|
||||||
res.headers_mut().set(header::ContentType(mime));
|
res.headers_mut().set(header::ContentType(mime));
|
||||||
}
|
}
|
||||||
|
|
||||||
Outcome::of(res.send(self.as_bytes()))
|
ResponseOutcome::of(res.send(self.as_bytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,18 +42,18 @@ impl Responder for File {
|
||||||
Ok(md) => md.len(),
|
Ok(md) => md.len(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_!("Failed to read file metadata: {:?}", e);
|
error_!("Failed to read file metadata: {:?}", e);
|
||||||
return Outcome::Forward((StatusCode::InternalServerError, res));
|
return ResponseOutcome::forward(StatusCode::InternalServerError, res);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
if let Err(e) = self.read_to_end(&mut v) {
|
if let Err(e) = self.read_to_end(&mut v) {
|
||||||
error_!("Failed to read file: {:?}", e);
|
error_!("Failed to read file: {:?}", e);
|
||||||
return Outcome::Forward((StatusCode::InternalServerError, res));
|
return ResponseOutcome::forward(StatusCode::InternalServerError, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.headers_mut().set(header::ContentLength(size));
|
res.headers_mut().set(header::ContentLength(size));
|
||||||
Outcome::of(res.start().and_then(|mut stream| stream.write_all(&v)))
|
ResponseOutcome::of(res.start().and_then(|mut stream| stream.write_all(&v)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ impl<T: Responder> Responder for Option<T> {
|
||||||
val.respond(res)
|
val.respond(res)
|
||||||
} else {
|
} else {
|
||||||
warn_!("Response was `None`.");
|
warn_!("Response was `None`.");
|
||||||
Outcome::Forward((StatusCode::NotFound, res))
|
ResponseOutcome::forward(StatusCode::NotFound, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
||||||
Ok(ref mut val) => val.respond(res),
|
Ok(ref mut val) => val.respond(res),
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
error_!("{:?}", e);
|
error_!("{:?}", e);
|
||||||
Outcome::Forward((StatusCode::InternalServerError, res))
|
ResponseOutcome::forward(StatusCode::InternalServerError, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io::{Read, Write, ErrorKind};
|
use std::io::{Read, Write, ErrorKind};
|
||||||
|
|
||||||
use response::{Responder, Outcome, ResponseOutcome};
|
use response::{Responder, ResponseOutcome};
|
||||||
use http::hyper::FreshHyperResponse;
|
use http::hyper::FreshHyperResponse;
|
||||||
|
|
||||||
// TODO: Support custom chunk sizes.
|
// TODO: Support custom chunk sizes.
|
||||||
|
@ -31,7 +31,7 @@ impl<T: Read> Responder for Stream<T> {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_!("Failed opening response stream: {:?}", e);
|
error_!("Failed opening response stream: {:?}", e);
|
||||||
return Outcome::Failure;
|
return ResponseOutcome::failure();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,22 +46,22 @@ impl<T: Read> Responder for Stream<T> {
|
||||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
error_!("Error streaming response: {:?}", e);
|
error_!("Error streaming response: {:?}", e);
|
||||||
return Outcome::Failure;
|
return ResponseOutcome::failure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = stream.write_all(&buffer[..read]) {
|
if let Err(e) = stream.write_all(&buffer[..read]) {
|
||||||
error_!("Stream write_all() failed: {:?}", e);
|
error_!("Stream write_all() failed: {:?}", e);
|
||||||
return Outcome::Failure;
|
return ResponseOutcome::failure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = stream.end() {
|
if let Err(e) = stream.end() {
|
||||||
error_!("Stream end() failed: {:?}", e);
|
error_!("Stream end() failed: {:?}", e);
|
||||||
return Outcome::Failure;
|
return ResponseOutcome::failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
Outcome::Success
|
ResponseOutcome::success()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use term_painter::ToStyle;
|
||||||
use config;
|
use config;
|
||||||
use logger;
|
use logger;
|
||||||
use request::{Request, Data, FormItems};
|
use request::{Request, Data, FormItems};
|
||||||
use response::Response;
|
|
||||||
use router::{Router, Route};
|
use router::{Router, Route};
|
||||||
use catcher::{self, Catcher};
|
use catcher::{self, Catcher};
|
||||||
use outcome::Outcome;
|
use outcome::Outcome;
|
||||||
|
@ -86,8 +85,11 @@ impl Rocket {
|
||||||
// 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 {
|
let mut responder = match response {
|
||||||
Response::Complete(responder) => responder,
|
Outcome::Success(responder) => responder,
|
||||||
Response::Forward(unused_data) => {
|
Outcome::Failure(status_code) => {
|
||||||
|
return self.handle_error(status_code, &request, res);
|
||||||
|
}
|
||||||
|
Outcome::Forward(unused_data) => {
|
||||||
data = unused_data;
|
data = unused_data;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -104,9 +106,9 @@ impl Rocket {
|
||||||
info_!("{} {}", White.paint("Outcome:"), outcome);
|
info_!("{} {}", White.paint("Outcome:"), outcome);
|
||||||
|
|
||||||
// Check if the responder wants to forward to a catcher.
|
// Check if the responder wants to forward to a catcher.
|
||||||
match outcome {
|
match outcome.forwarded() {
|
||||||
Outcome::Forward((c, r)) => return self.handle_error(c, &request, r),
|
Some((c, r)) => return self.handle_error(c, &request, r),
|
||||||
Outcome::Success | Outcome::Failure => return,
|
None => return
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +151,7 @@ impl Rocket {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(mut responder) = catcher.handle(Error::NoRoute, req).responder() {
|
if let Some(mut responder) = catcher.handle(Error::NoRoute, req).responder() {
|
||||||
if responder.respond(response) != Outcome::Success {
|
if !responder.respond(response).is_success() {
|
||||||
error_!("Catcher outcome was unsuccessul; aborting response.");
|
error_!("Catcher outcome was unsuccessul; aborting response.");
|
||||||
} else {
|
} else {
|
||||||
info_!("Responded with catcher.");
|
info_!("Responded with catcher.");
|
||||||
|
@ -160,7 +162,7 @@ impl Rocket {
|
||||||
let catcher = self.default_catchers.get(&code.to_u16())
|
let catcher = self.default_catchers.get(&code.to_u16())
|
||||||
.unwrap_or(self.default_catchers.get(&500).expect("500 default"));
|
.unwrap_or(self.default_catchers.get(&500).expect("500 default"));
|
||||||
let responder = catcher.handle(Error::Internal, req).responder();
|
let responder = catcher.handle(Error::Internal, req).responder();
|
||||||
responder.unwrap().respond(response).expect_success()
|
responder.unwrap().respond(response).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ mod tests {
|
||||||
type SimpleRoute = (Method, &'static str);
|
type SimpleRoute = (Method, &'static str);
|
||||||
|
|
||||||
fn dummy_handler(_req: &Request, _: Data) -> Response<'static> {
|
fn dummy_handler(_req: &Request, _: Data) -> Response<'static> {
|
||||||
Response::complete("hi")
|
Response::success("hi")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool {
|
fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool {
|
||||||
|
|
|
@ -75,7 +75,7 @@ mod test {
|
||||||
use {Response, Request, Data};
|
use {Response, Request, Data};
|
||||||
|
|
||||||
fn dummy_handler(_req: &Request, _: Data) -> Response<'static> {
|
fn dummy_handler(_req: &Request, _: Data) -> Response<'static> {
|
||||||
Response::complete("hi")
|
Response::success("hi")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn router_with_routes(routes: &[&'static str]) -> Router {
|
fn router_with_routes(routes: &[&'static str]) -> Router {
|
||||||
|
|
Loading…
Reference in New Issue