1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-10-11 04:32:28 +00:00
actix-web/src/pipeline.rs

917 lines
31 KiB
Rust
Raw Normal View History

2017-12-01 23:45:15 +00:00
use std::{io, mem};
2017-11-25 06:15:52 +00:00
use std::rc::Rc;
2017-12-01 23:45:15 +00:00
use std::cell::RefCell;
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
use futures::{Async, Poll, Future, Stream};
use futures::task::{Task as FutureTask, current as current_task};
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
use body::{Body, BodyStream};
use context::{Frame, IoContext};
use error::{Error, UnexpectedTaskFrame};
use route::{Reply, ReplyItem};
use h1writer::{Writer, WriterState};
2017-11-25 06:15:52 +00:00
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
2017-11-30 23:13:56 +00:00
use middlewares::{Middleware, Finished, Started, Response};
2017-11-25 06:15:52 +00:00
2017-11-30 23:13:56 +00:00
type Handler = Fn(HttpRequest) -> Reply;
pub(crate) type PipelineHandler<'a> = &'a Fn(HttpRequest) -> Reply;
2017-11-25 06:15:52 +00:00
pub struct Pipeline(PipelineState);
enum PipelineState {
None,
2017-12-01 23:45:15 +00:00
Error,
Starting(StartMiddlewares),
Handler(WaitingResponse),
RunMiddlewares(RunMiddlewares),
Response(ProcessResponse),
Finishing(FinishingMiddlewares),
Completed(Completed),
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
impl PipelineState {
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
fn is_done(&self) -> bool {
match *self {
PipelineState::None | PipelineState::Error
| PipelineState::Starting(_) | PipelineState::Handler(_)
| PipelineState::RunMiddlewares(_) | PipelineState::Response(_) => true,
PipelineState::Finishing(ref st) => st.info.context.is_none(),
PipelineState::Completed(_) => false,
}
}
fn disconnect(&mut self) {
let info = match *self {
PipelineState::None | PipelineState::Error => return,
PipelineState::Starting(ref mut st) => &mut st.info,
PipelineState::Handler(ref mut st) => &mut st.info,
PipelineState::RunMiddlewares(ref mut st) => &mut st.info,
PipelineState::Response(ref mut st) => &mut st.info,
PipelineState::Finishing(ref mut st) => &mut st.info,
PipelineState::Completed(ref mut st) => &mut st.0,
};
if let Some(ref mut context) = info.context {
context.disconnected();
}
}
fn error(&mut self) -> Option<Error> {
let info = match *self {
PipelineState::None | PipelineState::Error => return None,
PipelineState::Starting(ref mut st) => &mut st.info,
PipelineState::Handler(ref mut st) => &mut st.info,
PipelineState::RunMiddlewares(ref mut st) => &mut st.info,
PipelineState::Response(ref mut st) => &mut st.info,
PipelineState::Finishing(ref mut st) => &mut st.info,
PipelineState::Completed(ref mut st) => &mut st.0,
};
info.error.take()
}
}
struct PipelineInfo {
req: HttpRequest,
count: usize,
mws: Rc<Vec<Box<Middleware>>>,
context: Option<Box<IoContext>>,
error: Option<Error>,
}
impl PipelineInfo {
fn new(req: HttpRequest) -> PipelineInfo {
PipelineInfo {
req: req,
count: 0,
mws: Rc::new(Vec::new()),
error: None,
context: None,
}
}
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
fn req_mut(&self) -> &mut HttpRequest {
#[allow(mutable_transmutes)]
unsafe{mem::transmute(&self.req)}
}
fn poll_context(&mut self) -> Poll<(), Error> {
if let Some(ref mut context) = self.context {
match context.poll() {
Err(err) => Err(err),
Ok(Async::NotReady) => Ok(Async::NotReady),
Ok(Async::Ready(_)) => Ok(Async::Ready(())),
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
} else {
Ok(Async::Ready(()))
2017-11-25 06:15:52 +00:00
}
}
2017-12-01 23:45:15 +00:00
}
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
enum PipelineResponse {
None,
Context(Box<IoContext>),
Response(Box<Future<Item=HttpResponse, Error=Error>>),
}
/// Future that resolves when all buffered data get sent
#[doc(hidden)]
#[derive(Debug)]
pub struct DrainFut {
drained: bool,
task: Option<FutureTask>,
}
impl Default for DrainFut {
fn default() -> DrainFut {
DrainFut {
drained: false,
task: None,
}
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
}
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
impl DrainFut {
fn set(&mut self) {
self.drained = true;
if let Some(task) = self.task.take() {
task.notify()
2017-11-25 06:15:52 +00:00
}
}
2017-12-01 23:45:15 +00:00
}
impl Future for DrainFut {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
if self.drained {
Ok(Async::Ready(()))
} else {
self.task = Some(current_task());
Ok(Async::NotReady)
}
}
}
impl Pipeline {
pub fn new(req: HttpRequest,
mw: Rc<Vec<Box<Middleware>>>,
handler: PipelineHandler) -> Pipeline
{
Pipeline(StartMiddlewares::init(mw, req, handler))
}
pub fn error<R: Into<HttpResponse>>(err: R) -> Self {
Pipeline(ProcessResponse::init(
Box::new(PipelineInfo::new(HttpRequest::default())), err.into()))
}
pub(crate) fn disconnected(&mut self) {
self.0.disconnect()
}
2017-11-25 06:15:52 +00:00
2017-11-25 17:28:25 +00:00
pub(crate) fn poll_io<T: Writer>(&mut self, io: &mut T) -> Poll<bool, Error> {
2017-11-25 06:15:52 +00:00
loop {
2017-12-01 23:45:15 +00:00
let state = mem::replace(&mut self.0, PipelineState::None);
match state {
PipelineState::None =>
return Ok(Async::Ready(true)),
PipelineState::Error =>
return Err(io::Error::new(io::ErrorKind::Other, "Internal error").into()),
PipelineState::Starting(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
PipelineState::Handler(st) => {
2017-11-25 06:15:52 +00:00
match st.poll() {
2017-12-01 23:45:15 +00:00
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
}
PipelineState::RunMiddlewares(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
2017-11-25 06:15:52 +00:00
return Ok(Async::NotReady)
}
}
}
2017-12-01 23:45:15 +00:00
PipelineState::Response(st) => {
match st.poll_io(io) {
Ok(state) => {
self.0 = state;
if let Some(error) = self.0.error() {
return Err(error)
} else {
return Ok(Async::Ready(self.0.is_done()))
}
}
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
2017-11-25 06:15:52 +00:00
}
}
}
2017-12-01 23:45:15 +00:00
PipelineState::Finishing(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
}
PipelineState::Completed(st) => {
match st.poll() {
Ok(state) => {
self.0 = state;
return Ok(Async::Ready(true));
}
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
2017-11-25 06:15:52 +00:00
}
}
}
}
pub(crate) fn poll(&mut self) -> Poll<(), Error> {
loop {
2017-12-01 23:45:15 +00:00
let state = mem::replace(&mut self.0, PipelineState::None);
match state {
PipelineState::None | PipelineState::Error => {
return Ok(Async::Ready(()))
}
PipelineState::Starting(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
2017-11-25 06:15:52 +00:00
return Ok(Async::NotReady)
}
2017-12-01 23:45:15 +00:00
}
}
PipelineState::Handler(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
2017-11-25 06:15:52 +00:00
}
}
}
2017-12-01 23:45:15 +00:00
PipelineState::RunMiddlewares(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
PipelineState::Response(_) => {
self.0 = state;
return Ok(Async::NotReady);
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
PipelineState::Finishing(st) => {
match st.poll() {
Ok(state) =>
self.0 = state,
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
PipelineState::Completed(st) => {
match st.poll() {
Ok(state) => {
self.0 = state;
return Ok(Async::Ready(()));
}
Err(state) => {
self.0 = state;
return Ok(Async::NotReady)
}
}
2017-11-25 06:15:52 +00:00
}
}
}
}
}
2017-11-27 05:47:33 +00:00
type Fut = Box<Future<Item=Option<HttpResponse>, Error=Error>>;
2017-11-25 06:15:52 +00:00
/// Middlewares start executor
2017-12-01 23:45:15 +00:00
struct StartMiddlewares {
2017-11-25 06:15:52 +00:00
hnd: *mut Handler,
fut: Option<Fut>,
2017-12-01 23:45:15 +00:00
info: Box<PipelineInfo>,
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
impl StartMiddlewares {
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
fn init(mws: Rc<Vec<Box<Middleware>>>,
req: HttpRequest, handler: PipelineHandler) -> PipelineState {
let mut info = PipelineInfo {
2017-11-27 05:47:33 +00:00
req: req,
2017-12-01 23:45:15 +00:00
count: 0,
mws: mws,
error: None,
context: None,
};
// execute middlewares, we need this stage because middlewares could be non-async
// and we can move to next state immidietly
let len = info.mws.len();
2017-11-25 06:15:52 +00:00
loop {
2017-12-01 23:45:15 +00:00
if info.count == len {
let reply = (&*handler)(info.req.clone());
return WaitingResponse::init(Box::new(info), reply)
2017-11-25 06:15:52 +00:00
} else {
2017-12-01 23:45:15 +00:00
match info.mws[info.count].start(&mut info.req) {
2017-11-27 05:47:33 +00:00
Started::Done =>
2017-12-01 23:45:15 +00:00
info.count += 1,
2017-11-27 05:47:33 +00:00
Started::Response(resp) =>
2017-12-01 23:45:15 +00:00
return RunMiddlewares::init(Box::new(info), resp),
2017-11-27 05:47:33 +00:00
Started::Future(mut fut) =>
2017-11-25 06:15:52 +00:00
match fut.poll() {
2017-12-01 23:45:15 +00:00
Ok(Async::NotReady) =>
return PipelineState::Starting(StartMiddlewares {
hnd: handler as *const _ as *mut _,
fut: Some(fut),
info: Box::new(info)}),
2017-11-27 05:47:33 +00:00
Ok(Async::Ready(resp)) => {
2017-11-25 06:15:52 +00:00
if let Some(resp) = resp {
2017-12-01 23:45:15 +00:00
return RunMiddlewares::init(Box::new(info), resp);
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
info.count += 1;
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
Err(err) =>
return ProcessResponse::init(Box::new(info), err.into()),
2017-11-27 05:47:33 +00:00
},
2017-12-01 23:45:15 +00:00
Started::Err(err) =>
return ProcessResponse::init(Box::new(info), err.into()),
2017-11-25 06:15:52 +00:00
}
}
}
}
2017-12-01 23:45:15 +00:00
fn poll(mut self) -> Result<PipelineState, PipelineState> {
let len = self.info.mws.len();
2017-11-25 06:15:52 +00:00
'outer: loop {
match self.fut.as_mut().unwrap().poll() {
2017-12-01 23:45:15 +00:00
Ok(Async::NotReady) =>
return Err(PipelineState::Starting(self)),
2017-11-27 05:47:33 +00:00
Ok(Async::Ready(resp)) => {
2017-12-01 23:45:15 +00:00
self.info.count += 1;
2017-11-25 06:15:52 +00:00
if let Some(resp) = resp {
2017-12-01 23:45:15 +00:00
return Ok(RunMiddlewares::init(self.info, resp));
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
if self.info.count == len {
let reply = (unsafe{&*self.hnd})(self.info.req.clone());
return Ok(WaitingResponse::init(self.info, reply));
2017-11-25 06:15:52 +00:00
} else {
loop {
2017-12-01 23:45:15 +00:00
match self.info.mws[self.info.count].start(self.info.req_mut()) {
2017-11-27 05:47:33 +00:00
Started::Done =>
2017-12-01 23:45:15 +00:00
self.info.count += 1,
2017-11-27 05:47:33 +00:00
Started::Response(resp) => {
2017-12-01 23:45:15 +00:00
return Ok(RunMiddlewares::init(self.info, resp));
2017-11-25 06:15:52 +00:00
},
2017-11-25 18:52:43 +00:00
Started::Future(fut) => {
2017-11-25 06:15:52 +00:00
self.fut = Some(fut);
continue 'outer
},
2017-12-01 23:45:15 +00:00
Started::Err(err) =>
return Ok(ProcessResponse::init(self.info, err.into()))
2017-11-25 06:15:52 +00:00
}
}
}
}
2017-12-01 23:45:15 +00:00
Err(err) =>
return Ok(ProcessResponse::init(self.info, err.into()))
2017-11-25 06:15:52 +00:00
}
}
}
}
2017-12-01 23:45:15 +00:00
// waiting for response
struct WaitingResponse {
info: Box<PipelineInfo>,
stream: PipelineResponse,
2017-11-25 20:05:27 +00:00
}
2017-12-01 23:45:15 +00:00
impl WaitingResponse {
2017-11-25 20:05:27 +00:00
2017-12-01 23:45:15 +00:00
fn init(info: Box<PipelineInfo>, reply: Reply) -> PipelineState
{
let stream = match reply.into() {
ReplyItem::Message(resp) =>
return RunMiddlewares::init(info, resp),
ReplyItem::Actor(ctx) =>
PipelineResponse::Context(ctx),
ReplyItem::Future(fut) =>
PipelineResponse::Response(fut),
};
PipelineState::Handler(
WaitingResponse { info: info, stream: stream })
2017-11-25 20:05:27 +00:00
}
2017-12-01 23:45:15 +00:00
fn poll(mut self) -> Result<PipelineState, PipelineState> {
let stream = mem::replace(&mut self.stream, PipelineResponse::None);
match stream {
PipelineResponse::Context(mut context) => {
loop {
match context.poll() {
Ok(Async::Ready(Some(frame))) => {
match frame {
Frame::Message(resp) => {
self.info.context = Some(context);
return Ok(RunMiddlewares::init(self.info, resp))
}
Frame::Payload(_) | Frame::Drain(_) => (),
}
},
Ok(Async::Ready(None)) => {
error!("Unexpected eof");
let err: Error = UnexpectedTaskFrame.into();
return Ok(ProcessResponse::init(self.info, err.into()))
},
Ok(Async::NotReady) => {
self.stream = PipelineResponse::Context(context);
return Err(PipelineState::Handler(self))
},
Err(err) =>
return Ok(ProcessResponse::init(self.info, err.into()))
2017-11-25 20:05:27 +00:00
}
}
2017-12-01 23:45:15 +00:00
},
PipelineResponse::Response(mut fut) => {
match fut.poll() {
Ok(Async::NotReady) => {
self.stream = PipelineResponse::Response(fut);
Err(PipelineState::Handler(self))
2017-11-25 20:05:27 +00:00
}
2017-12-01 23:45:15 +00:00
Ok(Async::Ready(response)) =>
Ok(RunMiddlewares::init(self.info, response)),
Err(err) =>
Ok(ProcessResponse::init(self.info, err.into())),
2017-11-25 20:05:27 +00:00
}
2017-12-01 23:45:15 +00:00
}
PipelineResponse::None => {
unreachable!("Broken internal state")
2017-11-25 20:05:27 +00:00
}
}
2017-12-01 23:45:15 +00:00
2017-11-25 20:05:27 +00:00
}
}
2017-11-25 06:15:52 +00:00
/// Middlewares response executor
2017-12-01 23:45:15 +00:00
pub(crate) struct RunMiddlewares {
info: Box<PipelineInfo>,
curr: usize,
2017-11-25 17:28:25 +00:00
fut: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
2017-11-25 06:15:52 +00:00
}
2017-12-01 23:45:15 +00:00
impl RunMiddlewares {
2017-11-25 06:15:52 +00:00
2017-12-01 23:45:15 +00:00
fn init(mut info: Box<PipelineInfo>, mut resp: HttpResponse) -> PipelineState
2017-11-25 06:15:52 +00:00
{
2017-12-01 23:45:15 +00:00
if info.count == 0 {
return ProcessResponse::init(info, resp);
}
let mut curr = 0;
let len = info.mws.len();
2017-11-25 06:15:52 +00:00
loop {
2017-12-01 23:45:15 +00:00
resp = match info.mws[curr].response(info.req_mut(), resp) {
Response::Err(err) => {
info.count = curr + 1;
return ProcessResponse::init(info, err.into())
}
2017-11-25 18:24:45 +00:00
Response::Done(r) => {
2017-12-01 23:45:15 +00:00
curr += 1;
if curr == len {
return ProcessResponse::init(info, r)
2017-11-25 06:15:52 +00:00
} else {
r
}
},
Response::Future(fut) => {
2017-12-01 23:45:15 +00:00
return PipelineState::RunMiddlewares(
RunMiddlewares { info: info, curr: curr, fut: Some(fut) })
2017-11-25 06:15:52 +00:00
},
};
}
}
2017-12-01 23:45:15 +00:00
fn poll(mut self) -> Result<PipelineState, PipelineState> {
let len = self.info.mws.len();
2017-11-25 06:15:52 +00:00
loop {
// poll latest fut
let mut resp = match self.fut.as_mut().unwrap().poll() {
2017-11-25 17:28:25 +00:00
Ok(Async::NotReady) =>
2017-12-01 23:45:15 +00:00
return Ok(PipelineState::RunMiddlewares(self)),
2017-11-25 17:28:25 +00:00
Ok(Async::Ready(resp)) => {
2017-12-01 23:45:15 +00:00
self.curr += 1;
2017-11-25 06:15:52 +00:00
resp
}
2017-12-01 23:45:15 +00:00
Err(err) =>
return Ok(ProcessResponse::init(self.info, err.into())),
2017-11-25 06:15:52 +00:00
};
loop {
2017-12-01 23:45:15 +00:00
if self.curr == len {
return Ok(ProcessResponse::init(self.info, resp));
2017-11-25 06:15:52 +00:00
} else {
2017-12-01 23:45:15 +00:00
match self.info.mws[self.curr].response(self.info.req_mut(), resp) {
2017-11-25 18:24:45 +00:00
Response::Err(err) =>
2017-12-01 23:45:15 +00:00
return Ok(ProcessResponse::init(self.info, err.into())),
2017-11-25 18:24:45 +00:00
Response::Done(r) => {
2017-12-01 23:45:15 +00:00
self.curr += 1;
2017-11-25 06:15:52 +00:00
resp = r
},
Response::Future(fut) => {
self.fut = Some(fut);
break
},
}
}
}
}
}
}
2017-12-01 23:45:15 +00:00
struct ProcessResponse {
resp: HttpResponse,
iostate: IOState,
running: RunningState,
drain: DrainVec,
info: Box<PipelineInfo>,
}
#[derive(PartialEq)]
enum RunningState {
Running,
Paused,
Done,
}
impl RunningState {
#[inline]
fn pause(&mut self) {
if *self != RunningState::Done {
*self = RunningState::Paused
}
}
#[inline]
fn resume(&mut self) {
if *self != RunningState::Done {
*self = RunningState::Running
}
}
}
enum IOState {
Response,
Payload(BodyStream),
Context,
Done,
}
impl IOState {
fn is_done(&self) -> bool {
match *self {
IOState::Done => true,
_ => false
}
}
}
struct DrainVec(Vec<Rc<RefCell<DrainFut>>>);
impl Drop for DrainVec {
fn drop(&mut self) {
for drain in &mut self.0 {
drain.borrow_mut().set()
}
}
}
impl ProcessResponse {
fn init(info: Box<PipelineInfo>, resp: HttpResponse) -> PipelineState
{
PipelineState::Response(
ProcessResponse{ resp: resp,
iostate: IOState::Response,
running: RunningState::Running,
drain: DrainVec(Vec::new()),
info: info})
}
fn poll_io<T: Writer>(mut self, io: &mut T) -> Result<PipelineState, PipelineState> {
if self.drain.0.is_empty() && self.running != RunningState::Paused {
// if task is paused, write buffer is probably full
loop {
let result = match mem::replace(&mut self.iostate, IOState::Done) {
IOState::Response => {
let result = match io.start(self.info.req_mut(), &mut self.resp) {
Ok(res) => res,
Err(err) => {
self.info.error = Some(err.into());
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
};
match self.resp.replace_body(Body::Empty) {
Body::Streaming(stream) | Body::Upgrade(stream) =>
self.iostate = IOState::Payload(stream),
Body::StreamingContext | Body::UpgradeContext =>
self.iostate = IOState::Context,
_ => (),
}
result
},
IOState::Payload(mut body) => {
// always poll context
if self.running == RunningState::Running {
match self.info.poll_context() {
Ok(Async::NotReady) => (),
Ok(Async::Ready(_)) =>
self.running = RunningState::Done,
Err(err) => {
self.info.error = Some(err);
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
}
}
match body.poll() {
Ok(Async::Ready(None)) => {
self.iostate = IOState::Done;
if let Err(err) = io.write_eof() {
self.info.error = Some(err.into());
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
break
},
Ok(Async::Ready(Some(chunk))) => {
self.iostate = IOState::Payload(body);
match io.write(chunk.as_ref()) {
Err(err) => {
self.info.error = Some(err.into());
return Ok(FinishingMiddlewares::init(
self.info, self.resp))
},
Ok(result) => result
}
}
Ok(Async::NotReady) => {
self.iostate = IOState::Payload(body);
break
},
Err(err) => {
self.info.error = Some(err);
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
}
},
IOState::Context => {
match self.info.context.as_mut().unwrap().poll() {
Ok(Async::Ready(Some(frame))) => {
match frame {
Frame::Message(msg) => {
error!("Unexpected message frame {:?}", msg);
self.info.error = Some(UnexpectedTaskFrame.into());
return Ok(
FinishingMiddlewares::init(self.info, self.resp))
},
Frame::Payload(None) => {
self.iostate = IOState::Done;
if let Err(err) = io.write_eof() {
self.info.error = Some(err.into());
return Ok(
FinishingMiddlewares::init(self.info, self.resp))
}
break
},
Frame::Payload(Some(chunk)) => {
self.iostate = IOState::Context;
match io.write(chunk.as_ref()) {
Err(err) => {
self.info.error = Some(err.into());
return Ok(FinishingMiddlewares::init(
self.info, self.resp))
},
Ok(result) => result
}
},
Frame::Drain(fut) => {
self.drain.0.push(fut);
break
}
}
},
Ok(Async::Ready(None)) => {
self.iostate = IOState::Done;
self.info.context.take();
break
}
Ok(Async::NotReady) => {
self.iostate = IOState::Context;
break
}
Err(err) => {
self.info.error = Some(err);
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
}
}
IOState::Done => break,
};
match result {
WriterState::Pause => {
self.running.pause();
break
}
WriterState::Done => {
self.running.resume()
},
}
}
}
// flush io
match io.poll_complete() {
Ok(Async::Ready(_)) =>
self.running.resume(),
Ok(Async::NotReady) =>
return Err(PipelineState::Response(self)),
Err(err) => {
debug!("Error sending data: {}", err);
self.info.error = Some(err.into());
return Ok(FinishingMiddlewares::init(self.info, self.resp))
}
}
// drain futures
if !self.drain.0.is_empty() {
for fut in &mut self.drain.0 {
fut.borrow_mut().set()
}
self.drain.0.clear();
}
// response is completed
if self.iostate.is_done() {
self.resp.set_response_size(io.written());
Ok(FinishingMiddlewares::init(self.info, self.resp))
} else {
Err(PipelineState::Response(self))
}
}
}
/// Middlewares start executor
struct FinishingMiddlewares {
info: Box<PipelineInfo>,
resp: HttpResponse,
fut: Option<Box<Future<Item=(), Error=Error>>>,
}
impl FinishingMiddlewares {
fn init(info: Box<PipelineInfo>, resp: HttpResponse) -> PipelineState {
if info.count == 0 {
Completed::init(info)
} else {
match (FinishingMiddlewares{info: info, resp: resp, fut: None}).poll() {
Ok(st) | Err(st) => st,
}
}
}
fn poll(mut self) -> Result<PipelineState, PipelineState> {
loop {
// poll latest fut
let not_ready = if let Some(ref mut fut) = self.fut {
match fut.poll() {
Ok(Async::NotReady) => {
true
},
Ok(Async::Ready(())) => {
false
},
Err(err) => {
error!("Middleware finish error: {}", err);
false
}
}
} else {
false
};
if not_ready {
return Ok(PipelineState::Finishing(self))
}
self.fut = None;
self.info.count -= 1;
match self.info.mws[self.info.count].finish(self.info.req_mut(), &self.resp) {
Finished::Done => {
if self.info.count == 0 {
return Ok(Completed::init(self.info))
}
}
Finished::Future(fut) => {
self.fut = Some(fut);
},
}
}
}
}
struct Completed(Box<PipelineInfo>);
impl Completed {
fn init(info: Box<PipelineInfo>) -> PipelineState {
if info.context.is_none() {
PipelineState::None
} else {
PipelineState::Completed(Completed(info))
}
}
fn poll(mut self) -> Result<PipelineState, PipelineState> {
match self.0.poll_context() {
Ok(Async::NotReady) => Ok(PipelineState::Completed(self)),
Ok(Async::Ready(())) => Ok(PipelineState::None),
Err(_) => Ok(PipelineState::Error),
}
}
}
2017-12-02 00:10:01 +00:00
#[cfg(test)]
mod tests {
use super::*;
use actix::*;
use context::HttpContext;
impl PipelineState {
fn is_none(&self) -> Option<bool> {
if let PipelineState::None = *self { Some(true) } else { None }
}
fn is_completed(&self) -> Option<bool> {
if let PipelineState::Completed(_) = *self { Some(true) } else { None }
}
}
struct MyActor;
impl Actor for MyActor {
type Context = HttpContext<MyActor>;
}
#[test]
fn test_completed() {
let info = Box::new(PipelineInfo::new(HttpRequest::default()));
Completed::init(info).is_none().unwrap();
let req = HttpRequest::default();
let ctx = HttpContext::new(req.clone(), MyActor);
let mut info = Box::new(PipelineInfo::new(req));
info.context = Some(Box::new(ctx));
Completed::init(info).is_completed().unwrap();
}
}