mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-18 05:41:50 +01:00
Log request processing errors
This commit is contained in:
parent
98931a8623
commit
7cf221f767
@ -4,10 +4,13 @@
|
|||||||
|
|
||||||
* Fix HEAD requests handling
|
* Fix HEAD requests handling
|
||||||
|
|
||||||
* Can't have multiple Applications on a single server with different state #49
|
* Log request processing errors
|
||||||
|
|
||||||
|
* Allow multiple Applications on a single server with different state #49
|
||||||
|
|
||||||
* CORS middleware: allowed_headers is defaulting to None #50
|
* CORS middleware: allowed_headers is defaulting to None #50
|
||||||
|
|
||||||
|
|
||||||
## 0.3.1 (2018-01-13)
|
## 0.3.1 (2018-01-13)
|
||||||
|
|
||||||
* Fix directory entry path #47
|
* Fix directory entry path #47
|
||||||
|
@ -81,7 +81,7 @@ version = "0.9"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.4"
|
env_logger = "0.5"
|
||||||
reqwest = "0.8"
|
reqwest = "0.8"
|
||||||
skeptic = "0.13"
|
skeptic = "0.13"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -6,6 +6,6 @@ workspace = "../.."
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "*"
|
futures = "*"
|
||||||
env_logger = "0.4"
|
env_logger = "0.5"
|
||||||
actix = "0.4"
|
actix = "0.4"
|
||||||
actix-web = { path="../.." }
|
actix-web = { path="../.." }
|
||||||
|
@ -7,6 +7,7 @@ extern crate env_logger;
|
|||||||
extern crate futures;
|
extern crate futures;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
|
||||||
|
use std::{io, env};
|
||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
use actix_web::middleware::RequestSession;
|
use actix_web::middleware::RequestSession;
|
||||||
use futures::future::{FutureResult, result};
|
use futures::future::{FutureResult, result};
|
||||||
@ -56,17 +57,17 @@ fn index(mut req: HttpRequest) -> Result<HttpResponse> {
|
|||||||
fn p404(req: HttpRequest) -> Result<HttpResponse> {
|
fn p404(req: HttpRequest) -> Result<HttpResponse> {
|
||||||
|
|
||||||
// html
|
// html
|
||||||
let html = format!(r#"<!DOCTYPE html><html><head><title>actix - basics</title><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /></head>
|
let html = r#"<!DOCTYPE html><html><head><title>actix - basics</title><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /></head>
|
||||||
<body>
|
<body>
|
||||||
<a href="index.html">back to home</a>
|
<a href="index.html">back to home</a>
|
||||||
<h1>404</h1>
|
<h1>404</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>"#);
|
</html>"#;
|
||||||
|
|
||||||
// response
|
// response
|
||||||
Ok(HttpResponse::build(StatusCode::NOT_FOUND)
|
Ok(HttpResponse::build(StatusCode::NOT_FOUND)
|
||||||
.content_type("text/html; charset=utf-8")
|
.content_type("text/html; charset=utf-8")
|
||||||
.body(&html).unwrap())
|
.body(html).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,8 +93,9 @@ fn with_param(req: HttpRequest) -> Result<HttpResponse>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::std::env::set_var("RUST_LOG", "actix_web=info");
|
env::set_var("RUST_LOG", "actix_web=debug");
|
||||||
let _ = env_logger::init();
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
|
env_logger::init();
|
||||||
let sys = actix::System::new("basic-example");
|
let sys = actix::System::new("basic-example");
|
||||||
|
|
||||||
let addr = HttpServer::new(
|
let addr = HttpServer::new(
|
||||||
@ -121,6 +123,9 @@ fn main() {
|
|||||||
_ => httpcodes::HTTPNotFound,
|
_ => httpcodes::HTTPNotFound,
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
.resource("/error.html", |r| r.f(|req| {
|
||||||
|
error::ErrorBadRequest(io::Error::new(io::ErrorKind::Other, "test"))
|
||||||
|
}))
|
||||||
// static files
|
// static files
|
||||||
.handler("/static/", fs::StaticFiles::new("../static/", true))
|
.handler("/static/", fs::StaticFiles::new("../static/", true))
|
||||||
// redirect
|
// redirect
|
||||||
|
47
src/error.rs
47
src/error.rs
@ -9,8 +9,8 @@ use std::error::Error as StdError;
|
|||||||
|
|
||||||
use cookie;
|
use cookie;
|
||||||
use httparse;
|
use httparse;
|
||||||
use failure::Fail;
|
|
||||||
use futures::Canceled;
|
use futures::Canceled;
|
||||||
|
use failure::{Fail, Backtrace};
|
||||||
use http2::Error as Http2Error;
|
use http2::Error as Http2Error;
|
||||||
use http::{header, StatusCode, Error as HttpError};
|
use http::{header, StatusCode, Error as HttpError};
|
||||||
use http::uri::InvalidUriBytes;
|
use http::uri::InvalidUriBytes;
|
||||||
@ -22,6 +22,8 @@ use url::ParseError as UrlParseError;
|
|||||||
pub use cookie::{ParseError as CookieParseError};
|
pub use cookie::{ParseError as CookieParseError};
|
||||||
|
|
||||||
use body::Body;
|
use body::Body;
|
||||||
|
use handler::Responder;
|
||||||
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed, HTTPExpectationFailed};
|
use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed, HTTPExpectationFailed};
|
||||||
|
|
||||||
@ -33,9 +35,9 @@ use httpcodes::{HTTPBadRequest, HTTPMethodNotAllowed, HTTPExpectationFailed};
|
|||||||
pub type Result<T, E=Error> = result::Result<T, E>;
|
pub type Result<T, E=Error> = result::Result<T, E>;
|
||||||
|
|
||||||
/// General purpose actix web error
|
/// General purpose actix web error
|
||||||
#[derive(Fail, Debug)]
|
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
cause: Box<ResponseError>,
|
cause: Box<ResponseError>,
|
||||||
|
backtrace: Option<Backtrace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
@ -64,6 +66,16 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.backtrace.is_none() {
|
||||||
|
fmt::Debug::fmt(&self.cause, f)
|
||||||
|
} else {
|
||||||
|
write!(f, "{:?}\n\n{:?}", &self.cause, self.backtrace.as_ref().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `HttpResponse` for `Error`
|
/// `HttpResponse` for `Error`
|
||||||
impl From<Error> for HttpResponse {
|
impl From<Error> for HttpResponse {
|
||||||
fn from(err: Error) -> Self {
|
fn from(err: Error) -> Self {
|
||||||
@ -74,7 +86,12 @@ impl From<Error> for HttpResponse {
|
|||||||
/// `Error` for any error that implements `ResponseError`
|
/// `Error` for any error that implements `ResponseError`
|
||||||
impl<T: ResponseError> From<T> for Error {
|
impl<T: ResponseError> From<T> for Error {
|
||||||
fn from(err: T) -> Error {
|
fn from(err: T) -> Error {
|
||||||
Error { cause: Box::new(err) }
|
let backtrace = if err.backtrace().is_none() {
|
||||||
|
Some(Backtrace::new())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Error { cause: Box::new(err), backtrace: backtrace }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,21 +506,37 @@ macro_rules! ERROR_WRAP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug + 'static> Fail for $type {}
|
impl<T: fmt::Display + fmt::Debug + 'static> Fail for $type {}
|
||||||
impl<T: fmt::Debug + 'static> fmt::Display for $type {
|
impl<T: Fail> Fail for $type {
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.cause().backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Display + 'static> fmt::Display for $type {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?}", self.0)
|
fmt::Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ResponseError for $type
|
impl<T> ResponseError for $type
|
||||||
where T: Send + Sync + fmt::Debug + 'static,
|
where T: Send + Sync + fmt::Debug + fmt::Display + 'static
|
||||||
{
|
{
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
HttpResponse::new($status, Body::Empty)
|
HttpResponse::new($status, Body::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Responder for $type
|
||||||
|
where T: Send + Sync + fmt::Debug + fmt::Display + 'static
|
||||||
|
{
|
||||||
|
type Item = HttpResponse;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn respond_to(self, _: HttpRequest) -> Result<HttpResponse, Error> {
|
||||||
|
Err(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use std::rc::Rc;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use log::Level::Debug;
|
||||||
use futures::{Async, Poll, Future, Stream};
|
use futures::{Async, Poll, Future, Stream};
|
||||||
use futures::unsync::oneshot;
|
use futures::unsync::oneshot;
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ impl<S: 'static, H: PipelineHandler<S>> PipelineState<S, H> {
|
|||||||
|
|
||||||
struct PipelineInfo<S> {
|
struct PipelineInfo<S> {
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
count: usize,
|
count: u16,
|
||||||
mws: Rc<Vec<Box<Middleware<S>>>>,
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
context: Option<Box<ActorHttpContext>>,
|
context: Option<Box<ActorHttpContext>>,
|
||||||
error: Option<Error>,
|
error: Option<Error>,
|
||||||
@ -211,13 +212,13 @@ impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
|||||||
fn init(info: &mut PipelineInfo<S>, handler: Rc<RefCell<H>>) -> PipelineState<S, H> {
|
fn init(info: &mut PipelineInfo<S>, handler: Rc<RefCell<H>>) -> PipelineState<S, H> {
|
||||||
// execute middlewares, we need this stage because middlewares could be non-async
|
// execute middlewares, we need this stage because middlewares could be non-async
|
||||||
// and we can move to next state immediately
|
// and we can move to next state immediately
|
||||||
let len = info.mws.len();
|
let len = info.mws.len() as u16;
|
||||||
loop {
|
loop {
|
||||||
if info.count == len {
|
if info.count == len {
|
||||||
let reply = handler.borrow_mut().handle(info.req.clone());
|
let reply = handler.borrow_mut().handle(info.req.clone());
|
||||||
return WaitingResponse::init(info, reply)
|
return WaitingResponse::init(info, reply)
|
||||||
} else {
|
} else {
|
||||||
match info.mws[info.count].start(&mut info.req) {
|
match info.mws[info.count as usize].start(&mut info.req) {
|
||||||
Ok(Started::Done) =>
|
Ok(Started::Done) =>
|
||||||
info.count += 1,
|
info.count += 1,
|
||||||
Ok(Started::Response(resp)) =>
|
Ok(Started::Response(resp)) =>
|
||||||
@ -246,7 +247,7 @@ impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> {
|
fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> {
|
||||||
let len = info.mws.len();
|
let len = info.mws.len() as u16;
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
match self.fut.as_mut().unwrap().poll() {
|
match self.fut.as_mut().unwrap().poll() {
|
||||||
Ok(Async::NotReady) => return None,
|
Ok(Async::NotReady) => return None,
|
||||||
@ -260,7 +261,7 @@ impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
|||||||
return Some(WaitingResponse::init(info, reply));
|
return Some(WaitingResponse::init(info, reply));
|
||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
match info.mws[info.count].start(info.req_mut()) {
|
match info.mws[info.count as usize].start(info.req_mut()) {
|
||||||
Ok(Started::Done) =>
|
Ok(Started::Done) =>
|
||||||
info.count += 1,
|
info.count += 1,
|
||||||
Ok(Started::Response(resp)) => {
|
Ok(Started::Response(resp)) => {
|
||||||
@ -334,7 +335,7 @@ impl<S: 'static, H> RunMiddlewares<S, H> {
|
|||||||
loop {
|
loop {
|
||||||
resp = match info.mws[curr].response(info.req_mut(), resp) {
|
resp = match info.mws[curr].response(info.req_mut(), resp) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
info.count = curr + 1;
|
info.count = (curr + 1) as u16;
|
||||||
return ProcessResponse::init(err.into())
|
return ProcessResponse::init(err.into())
|
||||||
}
|
}
|
||||||
Ok(Response::Done(r)) => {
|
Ok(Response::Done(r)) => {
|
||||||
@ -458,6 +459,13 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(err) = self.resp.error() {
|
||||||
|
warn!("Error occured during request handling: {}", err);
|
||||||
|
if log_enabled!(Debug) {
|
||||||
|
debug!("{:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.resp.replace_body(Body::Empty) {
|
match self.resp.replace_body(Body::Empty) {
|
||||||
Body::Streaming(stream) =>
|
Body::Streaming(stream) =>
|
||||||
self.iostate = IOState::Payload(stream),
|
self.iostate = IOState::Payload(stream),
|
||||||
@ -586,7 +594,6 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
},
|
},
|
||||||
Ok(Async::NotReady) => return Err(PipelineState::Response(self)),
|
Ok(Async::NotReady) => return Err(PipelineState::Response(self)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("Error sending data: {}", err);
|
|
||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(FinishingMiddlewares::init(info, self.resp))
|
return Ok(FinishingMiddlewares::init(info, self.resp))
|
||||||
}
|
}
|
||||||
@ -599,7 +606,6 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
match io.write_eof() {
|
match io.write_eof() {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("Error sending data: {}", err);
|
|
||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(FinishingMiddlewares::init(info, self.resp))
|
return Ok(FinishingMiddlewares::init(info, self.resp))
|
||||||
}
|
}
|
||||||
@ -661,7 +667,7 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
|
|||||||
self.fut = None;
|
self.fut = None;
|
||||||
info.count -= 1;
|
info.count -= 1;
|
||||||
|
|
||||||
match info.mws[info.count].finish(info.req_mut(), &self.resp) {
|
match info.mws[info.count as usize].finish(info.req_mut(), &self.resp) {
|
||||||
Finished::Done => {
|
Finished::Done => {
|
||||||
if info.count == 0 {
|
if info.count == 0 {
|
||||||
return Some(Completed::init(info))
|
return Some(Completed::init(info))
|
||||||
@ -682,6 +688,10 @@ impl<S, H> Completed<S, H> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn init(info: &mut PipelineInfo<S>) -> PipelineState<S, H> {
|
fn init(info: &mut PipelineInfo<S>) -> PipelineState<S, H> {
|
||||||
|
if let Some(ref err) = info.error {
|
||||||
|
error!("Error occured during request handling: {}", err);
|
||||||
|
}
|
||||||
|
|
||||||
if info.context.is_none() {
|
if info.context.is_none() {
|
||||||
PipelineState::None
|
PipelineState::None
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user