mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
refactor error handling
This commit is contained in:
parent
d555fcabfc
commit
f85925a652
@ -20,12 +20,6 @@ codecov = { repository = "fafhrd91/actix-web", branch = "master", service = "git
|
|||||||
name = "actix_web"
|
name = "actix_web"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
# Enable nightly features
|
|
||||||
nightly = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
|
@ -15,13 +15,11 @@ impl Actor for MyRoute {
|
|||||||
impl Route for MyRoute {
|
impl Route for MyRoute {
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn request(req: HttpRequest, payload: Payload, ctx: &mut HttpContext<Self>) -> Reply<Self> {
|
fn request(req: &mut HttpRequest, payload: Payload,
|
||||||
|
ctx: &mut HttpContext<Self>) -> RouteResult<Self> {
|
||||||
println!("{:?}", req);
|
println!("{:?}", req);
|
||||||
|
|
||||||
let multipart = match req.multipart(payload) {
|
let multipart = req.multipart(payload)?;
|
||||||
Ok(mp) => mp,
|
|
||||||
Err(e) => return e.into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// get Multipart stream
|
// get Multipart stream
|
||||||
WrapStream::<MyRoute>::actstream(multipart)
|
WrapStream::<MyRoute>::actstream(multipart)
|
||||||
|
@ -48,24 +48,19 @@ impl Actor for WsChatSession {
|
|||||||
impl Route for WsChatSession {
|
impl Route for WsChatSession {
|
||||||
type State = WsChatSessionState;
|
type State = WsChatSessionState;
|
||||||
|
|
||||||
fn request(req: HttpRequest, payload: Payload, ctx: &mut HttpContext<Self>) -> Reply<Self>
|
fn request(req: &mut HttpRequest,
|
||||||
|
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
||||||
{
|
{
|
||||||
// websocket handshakre, it may fail if request is not websocket request
|
// websocket handshakre, it may fail if request is not websocket request
|
||||||
match ws::handshake(&req) {
|
let resp = ws::handshake(&req)?;
|
||||||
Ok(resp) => {
|
ctx.start(resp);
|
||||||
ctx.start(resp);
|
ctx.add_stream(ws::WsStream::new(payload));
|
||||||
ctx.add_stream(ws::WsStream::new(payload));
|
Reply::async(
|
||||||
Reply::async(
|
WsChatSession {
|
||||||
WsChatSession {
|
id: 0,
|
||||||
id: 0,
|
hb: Instant::now(),
|
||||||
hb: Instant::now(),
|
room: "Main".to_owned(),
|
||||||
room: "Main".to_owned(),
|
name: None})
|
||||||
name: None})
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
Reply::reply(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,18 +17,12 @@ impl Route for MyWebSocket {
|
|||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn request(req: &mut HttpRequest,
|
fn request(req: &mut HttpRequest,
|
||||||
payload: Payload, ctx: &mut HttpContext<Self>) -> Reply<Self>
|
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
||||||
{
|
{
|
||||||
match ws::handshake(&req) {
|
let resp = ws::handshake(&req)?;
|
||||||
Ok(resp) => {
|
ctx.start(resp);
|
||||||
ctx.start(resp);
|
ctx.add_stream(ws::WsStream::new(payload));
|
||||||
ctx.add_stream(ws::WsStream::new(payload));
|
Reply::async(MyWebSocket)
|
||||||
Reply::async(MyWebSocket)
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
Reply::reply(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ impl<S> ApplicationBuilder<S> where S: 'static {
|
|||||||
///
|
///
|
||||||
/// fn request(req: &mut HttpRequest,
|
/// fn request(req: &mut HttpRequest,
|
||||||
/// payload: Payload,
|
/// payload: Payload,
|
||||||
/// ctx: &mut HttpContext<Self>) -> Reply<Self> {
|
/// ctx: &mut HttpContext<Self>) -> RouteResult<Self> {
|
||||||
/// Reply::reply(httpcodes::HTTPOk)
|
/// Reply::reply(httpcodes::HTTPOk)
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
12
src/error.rs
12
src/error.rs
@ -110,8 +110,7 @@ impl From<httparse::Error> for ParseError {
|
|||||||
/// Return `BadRequest` for `ParseError`
|
/// Return `BadRequest` for `ParseError`
|
||||||
impl From<ParseError> for HttpResponse {
|
impl From<ParseError> for HttpResponse {
|
||||||
fn from(err: ParseError) -> Self {
|
fn from(err: ParseError) -> Self {
|
||||||
HttpResponse::new(StatusCode::BAD_REQUEST,
|
HttpResponse::from_error(StatusCode::BAD_REQUEST, err)
|
||||||
Body::Binary(err.description().into()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,24 +118,21 @@ impl From<ParseError> for HttpResponse {
|
|||||||
/// Response generation can return `HttpError`, so it is internal error
|
/// Response generation can return `HttpError`, so it is internal error
|
||||||
impl From<HttpError> for HttpResponse {
|
impl From<HttpError> for HttpResponse {
|
||||||
fn from(err: HttpError) -> Self {
|
fn from(err: HttpError) -> Self {
|
||||||
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR,
|
HttpResponse::from_error(StatusCode::INTERNAL_SERVER_ERROR, err)
|
||||||
Body::Binary(err.description().into()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `BadRequest` for `cookie::ParseError`
|
/// Return `BadRequest` for `cookie::ParseError`
|
||||||
impl From<cookie::ParseError> for HttpResponse {
|
impl From<cookie::ParseError> for HttpResponse {
|
||||||
fn from(err: cookie::ParseError) -> Self {
|
fn from(err: cookie::ParseError) -> Self {
|
||||||
HttpResponse::new(StatusCode::BAD_REQUEST,
|
HttpResponse::from_error(StatusCode::BAD_REQUEST, err)
|
||||||
Body::Binary(err.description().into()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `BadRequest` for `MultipartError`
|
/// Return `BadRequest` for `MultipartError`
|
||||||
impl From<MultipartError> for HttpResponse {
|
impl From<MultipartError> for HttpResponse {
|
||||||
fn from(err: MultipartError) -> Self {
|
fn from(err: MultipartError) -> Self {
|
||||||
HttpResponse::new(StatusCode::BAD_REQUEST,
|
HttpResponse::from_error(StatusCode::BAD_REQUEST, err)
|
||||||
Body::Binary(err.description().into()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
//! Pieces pertaining to the HTTP message protocol.
|
//! Pieces pertaining to the HTTP message protocol.
|
||||||
use std::{io, mem, str};
|
use std::{io, mem, str};
|
||||||
|
use std::error::Error as Error;
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
|
|
||||||
use cookie::CookieJar;
|
use cookie::CookieJar;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error};
|
use http::{StatusCode, Version, HeaderMap, HttpTryFrom, Error as HttpError};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use Cookie;
|
use Cookie;
|
||||||
@ -57,6 +58,7 @@ pub struct HttpResponse {
|
|||||||
body: Body,
|
body: Body,
|
||||||
chunked: bool,
|
chunked: bool,
|
||||||
connection_type: Option<ConnectionType>,
|
connection_type: Option<ConnectionType>,
|
||||||
|
error: Option<Box<Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpResponse {
|
impl HttpResponse {
|
||||||
@ -81,9 +83,34 @@ impl HttpResponse {
|
|||||||
chunked: false,
|
chunked: false,
|
||||||
// compression: None,
|
// compression: None,
|
||||||
connection_type: None,
|
connection_type: None,
|
||||||
|
error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a response from error
|
||||||
|
#[inline]
|
||||||
|
pub fn from_error<E: Error + 'static>(status: StatusCode, error: E) -> HttpResponse {
|
||||||
|
let body = Body::Binary(error.description().into());
|
||||||
|
|
||||||
|
HttpResponse {
|
||||||
|
version: None,
|
||||||
|
headers: Default::default(),
|
||||||
|
status: status,
|
||||||
|
reason: None,
|
||||||
|
body: body,
|
||||||
|
chunked: false,
|
||||||
|
// compression: None,
|
||||||
|
connection_type: None,
|
||||||
|
error: Some(Box::new(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `error` which is responsible for this response
|
||||||
|
#[inline]
|
||||||
|
pub fn error(&self) -> Option<&Box<Error>> {
|
||||||
|
self.error.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the HTTP version of this response.
|
/// Get the HTTP version of this response.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn version(&self) -> Option<Version> {
|
pub fn version(&self) -> Option<Version> {
|
||||||
@ -226,7 +253,7 @@ impl Parts {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HttpResponseBuilder {
|
pub struct HttpResponseBuilder {
|
||||||
parts: Option<Parts>,
|
parts: Option<Parts>,
|
||||||
err: Option<Error>,
|
err: Option<HttpError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpResponseBuilder {
|
impl HttpResponseBuilder {
|
||||||
@ -348,7 +375,7 @@ impl HttpResponseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body
|
/// Set a body
|
||||||
pub fn body<B: Into<Body>>(&mut self, body: B) -> Result<HttpResponse, Error> {
|
pub fn body<B: Into<Body>>(&mut self, body: B) -> Result<HttpResponse, HttpError> {
|
||||||
let mut parts = self.parts.take().expect("cannot reuse response builder");
|
let mut parts = self.parts.take().expect("cannot reuse response builder");
|
||||||
if let Some(e) = self.err.take() {
|
if let Some(e) = self.err.take() {
|
||||||
return Err(e)
|
return Err(e)
|
||||||
@ -366,11 +393,12 @@ impl HttpResponseBuilder {
|
|||||||
body: body.into(),
|
body: body.into(),
|
||||||
chunked: parts.chunked,
|
chunked: parts.chunked,
|
||||||
connection_type: parts.connection_type,
|
connection_type: parts.connection_type,
|
||||||
|
error: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parts<'a>(parts: &'a mut Option<Parts>, err: &Option<Error>) -> Option<&'a mut Parts>
|
fn parts<'a>(parts: &'a mut Option<Parts>, err: &Option<HttpError>) -> Option<&'a mut Parts>
|
||||||
{
|
{
|
||||||
if err.is_some() {
|
if err.is_some() {
|
||||||
return None
|
return None
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
//! Http framework for [Actix](https://github.com/fafhrd91/actix)
|
//! Http framework for [Actix](https://github.com/fafhrd91/actix)
|
||||||
|
|
||||||
#![cfg_attr(feature="nightly", feature(
|
|
||||||
try_trait, // std::ops::Try #42327
|
|
||||||
))]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
@ -53,7 +49,7 @@ pub use application::{Application, ApplicationBuilder, Middleware};
|
|||||||
pub use httprequest::{HttpRequest, UrlEncoded};
|
pub use httprequest::{HttpRequest, UrlEncoded};
|
||||||
pub use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
|
pub use httpresponse::{Body, HttpResponse, HttpResponseBuilder};
|
||||||
pub use payload::{Payload, PayloadItem, PayloadError};
|
pub use payload::{Payload, PayloadItem, PayloadError};
|
||||||
pub use route::{Route, RouteFactory, RouteHandler};
|
pub use route::{Route, RouteFactory, RouteHandler, RouteResult};
|
||||||
pub use resource::{Reply, Resource};
|
pub use resource::{Reply, Resource};
|
||||||
pub use recognizer::{Params, RouteRecognizer};
|
pub use recognizer::{Params, RouteRecognizer};
|
||||||
pub use logger::Logger;
|
pub use logger::Logger;
|
||||||
|
@ -8,7 +8,7 @@ use http::Method;
|
|||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
|
||||||
use task::Task;
|
use task::Task;
|
||||||
use route::{Route, RouteHandler, Frame, FnHandler, StreamHandler};
|
use route::{Route, RouteHandler, RouteResult, Frame, FnHandler, StreamHandler};
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use context::HttpContext;
|
use context::HttpContext;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
@ -141,13 +141,13 @@ pub struct Reply<A: Actor + Route> (ReplyItem<A>);
|
|||||||
impl<A> Reply<A> where A: Actor + Route
|
impl<A> Reply<A> where A: Actor + Route
|
||||||
{
|
{
|
||||||
/// Create async response
|
/// Create async response
|
||||||
pub fn async(act: A) -> Self {
|
pub fn async(act: A) -> RouteResult<A> {
|
||||||
Reply(ReplyItem::Actor(act))
|
Ok(Reply(ReplyItem::Actor(act)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send response
|
/// Send response
|
||||||
pub fn reply<R: Into<HttpResponse>>(response: R) -> Self {
|
pub fn reply<R: Into<HttpResponse>>(response: R) -> RouteResult<A> {
|
||||||
Reply(ReplyItem::Message(response.into()))
|
Ok(Reply(ReplyItem::Message(response.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into(self, mut ctx: HttpContext<A>) -> Task where A: Actor<Context=HttpContext<A>>
|
pub fn into(self, mut ctx: HttpContext<A>) -> Task where A: Actor<Context=HttpContext<A>>
|
||||||
@ -168,27 +168,6 @@ impl<A, T> From<T> for Reply<A>
|
|||||||
where T: Into<HttpResponse>, A: Actor + Route
|
where T: Into<HttpResponse>, A: Actor + Route
|
||||||
{
|
{
|
||||||
fn from(item: T) -> Self {
|
fn from(item: T) -> Self {
|
||||||
Reply::reply(item)
|
Reply(ReplyItem::Message(item.into()))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="nightly")]
|
|
||||||
use std::ops::Try;
|
|
||||||
|
|
||||||
#[cfg(feature="nightly")]
|
|
||||||
impl<A> Try for Reply<A> where A: Actor + Route {
|
|
||||||
type Ok = HttpResponse;
|
|
||||||
type Error = HttpResponse;
|
|
||||||
|
|
||||||
fn into_result(self) -> Result<Self::Ok, Self::Error> {
|
|
||||||
panic!("Reply -> Result conversion is not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_error(v: Self::Error) -> Self {
|
|
||||||
Reply::reply(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_ok(v: Self::Ok) -> Self {
|
|
||||||
Reply::reply(v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/route.rs
10
src/route.rs
@ -33,6 +33,9 @@ pub trait RouteHandler<S>: 'static {
|
|||||||
fn set_prefix(&mut self, prefix: String) {}
|
fn set_prefix(&mut self, prefix: String) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request handling result.
|
||||||
|
pub type RouteResult<T> = Result<Reply<T>, HttpResponse>;
|
||||||
|
|
||||||
/// Actors with ability to handle http requests.
|
/// Actors with ability to handle http requests.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait Route: Actor {
|
pub trait Route: Actor {
|
||||||
@ -74,7 +77,7 @@ pub trait Route: Actor {
|
|||||||
/// In that case `HttpContext::start` and `HttpContext::write` has to be used
|
/// In that case `HttpContext::start` and `HttpContext::write` has to be used
|
||||||
/// for writing response.
|
/// for writing response.
|
||||||
fn request(req: &mut HttpRequest,
|
fn request(req: &mut HttpRequest,
|
||||||
payload: Payload, ctx: &mut Self::Context) -> Reply<Self>;
|
payload: Payload, ctx: &mut Self::Context) -> RouteResult<Self>;
|
||||||
|
|
||||||
/// This method creates `RouteFactory` for this actor.
|
/// This method creates `RouteFactory` for this actor.
|
||||||
fn factory() -> RouteFactory<Self, Self::State> {
|
fn factory() -> RouteFactory<Self, Self::State> {
|
||||||
@ -99,7 +102,10 @@ impl<A, S> RouteHandler<S> for RouteFactory<A, S>
|
|||||||
return Task::reply(resp)
|
return Task::reply(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
A::request(req, payload, &mut ctx).into(ctx)
|
match A::request(req, payload, &mut ctx) {
|
||||||
|
Ok(reply) => reply.into(ctx),
|
||||||
|
Err(err) => Task::reply(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
//! impl Route for WsRoute {
|
//! impl Route for WsRoute {
|
||||||
//! type State = ();
|
//! type State = ();
|
||||||
//!
|
//!
|
||||||
//! fn request(req: &mut HttpRequest, payload: Payload, ctx: &mut HttpContext<Self>) -> Reply<Self>
|
//! fn request(req: &mut HttpRequest,
|
||||||
|
//! payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
|
||||||
//! {
|
//! {
|
||||||
//! // WebSocket handshake
|
//! // WebSocket handshake
|
||||||
//! match ws::handshake(&req) {
|
//! match ws::handshake(&req) {
|
||||||
|
Loading…
Reference in New Issue
Block a user