1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-23 23:51:06 +01:00

better middleware error handling

This commit is contained in:
Nikolay Kim 2017-11-25 09:40:57 -08:00
parent 1fc64bc83d
commit f4972150cc
2 changed files with 36 additions and 41 deletions

View File

@ -16,7 +16,7 @@ pub enum Started {
/// handler execution halts. /// handler execution halts.
Response(HttpRequest, HttpResponse), Response(HttpRequest, HttpResponse),
/// Execution completed, runs future to completion. /// Execution completed, runs future to completion.
Future(Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=(HttpRequest, HttpResponse)>>), Future(Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=Error>>),
} }
/// Middleware execution result /// Middleware execution result
@ -24,7 +24,7 @@ pub enum Response {
/// New http response got generated /// New http response got generated
Response(HttpResponse), Response(HttpResponse),
/// Result is a future that resolves to a new http response /// Result is a future that resolves to a new http response
Future(Box<Future<Item=HttpResponse, Error=HttpResponse>>), Future(Box<Future<Item=HttpResponse, Error=Error>>),
} }
/// Middleware finish result /// Middleware finish result

View File

@ -34,12 +34,13 @@ impl Pipeline {
Pipeline(PipelineState::Task(Box::new((task, req)))) Pipeline(PipelineState::Task(Box::new((task, req))))
} else { } else {
match Start::init(mw, req, handler, payload) { match Start::init(mw, req, handler, payload) {
StartResult::Ready(res) => { Ok(StartResult::Ready(res)) =>
Pipeline(PipelineState::Handle(res)) Pipeline(PipelineState::Handle(res)),
}, Ok(StartResult::NotReady(res)) =>
StartResult::NotReady(res) => { Pipeline(PipelineState::Starting(res)),
Pipeline(PipelineState::Starting(res)) Err(err) =>
}, Pipeline(PipelineState::Error(
Box::new((Task::reply(err), HttpRequest::for_error()))))
} }
} }
} }
@ -70,12 +71,15 @@ impl Pipeline {
} }
PipelineState::Starting(mut st) => { PipelineState::Starting(mut st) => {
match st.poll() { match st.poll() {
Async::NotReady => { Ok(Async::NotReady) => {
self.0 = PipelineState::Starting(st); self.0 = PipelineState::Starting(st);
return Ok(Async::NotReady) return Ok(Async::NotReady)
} }
Async::Ready(h) => Ok(Async::Ready(h)) =>
self.0 = PipelineState::Handle(h), self.0 = PipelineState::Handle(h),
Err(err) =>
self.0 = PipelineState::Error(
Box::new((Task::reply(err), HttpRequest::for_error())))
} }
} }
PipelineState::Handle(mut st) => { PipelineState::Handle(mut st) => {
@ -222,7 +226,7 @@ impl Finish {
} }
} }
type Fut = Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=(HttpRequest, HttpResponse)>>; type Fut = Box<Future<Item=(HttpRequest, Option<HttpResponse>), Error=Error>>;
/// Middlewares start executor /// Middlewares start executor
struct Start { struct Start {
@ -242,8 +246,9 @@ enum StartResult {
impl Start { impl Start {
fn init(mw: Rc<Vec<Box<Middleware>>>, fn init(mw: Rc<Vec<Box<Middleware>>>,
req: HttpRequest, handler: PipelineHandler, payload: Payload) -> StartResult req: HttpRequest,
{ handler: PipelineHandler,
payload: Payload) -> Result<StartResult, Error> {
Start { Start {
idx: 0, idx: 0,
fut: None, fut: None,
@ -266,13 +271,13 @@ impl Start {
task task
} }
fn start(mut self, mut req: HttpRequest) -> StartResult { fn start(mut self, mut req: HttpRequest) -> Result<StartResult, Error> {
loop { loop {
if self.idx >= self.middlewares.len() { if self.idx >= self.middlewares.len() {
let task = (unsafe{&*self.hnd})( let task = (unsafe{&*self.hnd})(
&mut req, self.payload.take().expect("Something is completlywrong")); &mut req, self.payload.take().expect("Something is completlywrong"));
return StartResult::Ready( return Ok(StartResult::Ready(
Box::new(Handle::new(self.idx-1, req, self.prepare(task), self.middlewares))) Box::new(Handle::new(self.idx-1, req, self.prepare(task), self.middlewares))))
} else { } else {
req = match self.middlewares[self.idx].start(req) { req = match self.middlewares[self.idx].start(req) {
Started::Done(req) => { Started::Done(req) => {
@ -280,31 +285,27 @@ impl Start {
req req
} }
Started::Response(req, resp) => { Started::Response(req, resp) => {
return StartResult::Ready( return Ok(StartResult::Ready(
Box::new(Handle::new( Box::new(Handle::new(
self.idx, req, self.prepare(Task::reply(resp)), self.middlewares))) self.idx, req, self.prepare(Task::reply(resp)), self.middlewares))))
}, },
Started::Future(mut fut) => { Started::Future(mut fut) => {
match fut.poll() { match fut.poll() {
Ok(Async::NotReady) => { Ok(Async::NotReady) => {
self.fut = Some(fut); self.fut = Some(fut);
return StartResult::NotReady(self) return Ok(StartResult::NotReady(self))
} }
Ok(Async::Ready((req, resp))) => { Ok(Async::Ready((req, resp))) => {
self.idx += 1; self.idx += 1;
if let Some(resp) = resp { if let Some(resp) = resp {
return StartResult::Ready( return Ok(StartResult::Ready(
Box::new(Handle::new( Box::new(Handle::new(
self.idx, req, self.idx, req,
self.prepare(Task::reply(resp)), self.middlewares))) self.prepare(Task::reply(resp)), self.middlewares))))
} }
req req
} }
Err((req, resp)) => { Err(err) => return Err(err)
return StartResult::Ready(Box::new(Handle::new(
self.idx, req,
self.prepare(Task::reply(resp)), self.middlewares)))
}
} }
}, },
} }
@ -312,23 +313,23 @@ impl Start {
} }
} }
fn poll(&mut self) -> Async<Box<Handle>> { fn poll(&mut self) -> Poll<Box<Handle>, Error> {
'outer: loop { 'outer: loop {
match self.fut.as_mut().unwrap().poll() { match self.fut.as_mut().unwrap().poll() {
Ok(Async::NotReady) => return Async::NotReady, Ok(Async::NotReady) => return Ok(Async::NotReady),
Ok(Async::Ready((mut req, resp))) => { Ok(Async::Ready((mut req, resp))) => {
self.idx += 1; self.idx += 1;
if let Some(resp) = resp { if let Some(resp) = resp {
return Async::Ready(Box::new(Handle::new( return Ok(Async::Ready(Box::new(Handle::new(
self.idx, req, self.idx, req,
self.prepare(Task::reply(resp)), Rc::clone(&self.middlewares)))) self.prepare(Task::reply(resp)), Rc::clone(&self.middlewares)))))
} }
if self.idx >= self.middlewares.len() { if self.idx >= self.middlewares.len() {
let task = (unsafe{&*self.hnd})( let task = (unsafe{&*self.hnd})(
&mut req, self.payload.take().expect("Something is completlywrong")); &mut req, self.payload.take().expect("Something is completlywrong"));
return Async::Ready(Box::new(Handle::new( return Ok(Async::Ready(Box::new(Handle::new(
self.idx-1, req, self.idx-1, req,
self.prepare(task), Rc::clone(&self.middlewares)))) self.prepare(task), Rc::clone(&self.middlewares)))))
} else { } else {
loop { loop {
req = match self.middlewares[self.idx].start(req) { req = match self.middlewares[self.idx].start(req) {
@ -337,10 +338,10 @@ impl Start {
req req
} }
Started::Response(req, resp) => { Started::Response(req, resp) => {
return Async::Ready(Box::new(Handle::new( return Ok(Async::Ready(Box::new(Handle::new(
self.idx, req, self.idx, req,
self.prepare(Task::reply(resp)), self.prepare(Task::reply(resp)),
Rc::clone(&self.middlewares)))) Rc::clone(&self.middlewares)))))
}, },
Started::Future(mut fut) => { Started::Future(mut fut) => {
self.fut = Some(fut); self.fut = Some(fut);
@ -350,17 +351,11 @@ impl Start {
} }
} }
} }
Err((req, resp)) => { Err(err) => return Err(err)
return Async::Ready(Box::new(Handle::new(
self.idx, req,
self.prepare(Task::reply(resp)),
Rc::clone(&self.middlewares))))
} }
} }
} }
} }
}
/// Middlewares response executor /// Middlewares response executor
pub(crate) struct MiddlewaresResponse { pub(crate) struct MiddlewaresResponse {