mirror of
https://github.com/actix/actix-web.git
synced 2024-12-20 23:26:44 +00:00
use trait instead of pipeline
This commit is contained in:
parent
4a40b026a4
commit
b98ab2eebe
15 changed files with 189 additions and 145 deletions
|
@ -5,7 +5,7 @@ use handler::{Reply, RouteHandler};
|
||||||
use router::{Router, Pattern};
|
use router::{Router, Pattern};
|
||||||
use resource::Resource;
|
use resource::Resource;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use channel::{HttpHandler, IntoHttpHandler};
|
use channel::{HttpHandler, IntoHttpHandler, HttpHandlerTask};
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use middlewares::Middleware;
|
use middlewares::Middleware;
|
||||||
use server::ServerSettings;
|
use server::ServerSettings;
|
||||||
|
@ -16,14 +16,12 @@ pub struct HttpApplication<S> {
|
||||||
prefix: String,
|
prefix: String,
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
router: Router<S>,
|
router: Router<S>,
|
||||||
middlewares: Rc<Vec<Box<Middleware>>>,
|
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> HttpApplication<S> {
|
impl<S: 'static> HttpApplication<S> {
|
||||||
|
|
||||||
fn run(&self, req: HttpRequest) -> Reply {
|
fn run(&self, mut req: HttpRequest<S>) -> Reply {
|
||||||
let mut req = req.with_state(Rc::clone(&self.state), self.router.clone());
|
|
||||||
|
|
||||||
if let Some(h) = self.router.recognize(&mut req) {
|
if let Some(h) = self.router.recognize(&mut req) {
|
||||||
h.handle(req)
|
h.handle(req)
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,10 +32,12 @@ impl<S: 'static> HttpApplication<S> {
|
||||||
|
|
||||||
impl<S: 'static> HttpHandler for HttpApplication<S> {
|
impl<S: 'static> HttpHandler for HttpApplication<S> {
|
||||||
|
|
||||||
fn handle(&self, req: HttpRequest) -> Result<Pipeline, HttpRequest> {
|
fn handle(&self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest> {
|
||||||
if req.path().starts_with(&self.prefix) {
|
if req.path().starts_with(&self.prefix) {
|
||||||
Ok(Pipeline::new(req, Rc::clone(&self.middlewares),
|
let req = req.with_state(Rc::clone(&self.state), self.router.clone());
|
||||||
&|req: HttpRequest| self.run(req)))
|
|
||||||
|
Ok(Box::new(Pipeline::new(req, Rc::clone(&self.middlewares),
|
||||||
|
&|req: HttpRequest<S>| self.run(req))))
|
||||||
} else {
|
} else {
|
||||||
Err(req)
|
Err(req)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ struct ApplicationParts<S> {
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
resources: HashMap<Pattern, Option<Resource<S>>>,
|
resources: HashMap<Pattern, Option<Resource<S>>>,
|
||||||
external: HashMap<String, Pattern>,
|
external: HashMap<String, Pattern>,
|
||||||
middlewares: Vec<Box<Middleware>>,
|
middlewares: Vec<Box<Middleware<S>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Structure that follows the builder pattern for building `Application` structs.
|
/// Structure that follows the builder pattern for building `Application` structs.
|
||||||
|
@ -204,7 +204,7 @@ impl<S> Application<S> where S: 'static {
|
||||||
|
|
||||||
/// Register a middleware
|
/// Register a middleware
|
||||||
pub fn middleware<T>(&mut self, mw: T) -> &mut Self
|
pub fn middleware<T>(&mut self, mw: T) -> &mut Self
|
||||||
where T: Middleware + 'static
|
where T: Middleware<S> + 'static
|
||||||
{
|
{
|
||||||
self.parts.as_mut().expect("Use after finish")
|
self.parts.as_mut().expect("Use after finish")
|
||||||
.middlewares.push(Box::new(mw));
|
.middlewares.push(Box::new(mw));
|
||||||
|
@ -322,7 +322,8 @@ mod tests {
|
||||||
let app = Application::with_state("/", 10)
|
let app = Application::with_state("/", 10)
|
||||||
.resource("/", |r| r.h(httpcodes::HTTPOk))
|
.resource("/", |r| r.h(httpcodes::HTTPOk))
|
||||||
.finish();
|
.finish();
|
||||||
|
let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.run(HttpRequest::default()).msg().unwrap().status(), StatusCode::OK);
|
app.run(req).msg().unwrap().status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,31 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use h1;
|
use h1;
|
||||||
use h2;
|
use h2;
|
||||||
use pipeline::Pipeline;
|
use error::Error;
|
||||||
|
use h1writer::Writer;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use server::ServerSettings;
|
use server::ServerSettings;
|
||||||
|
|
||||||
/// Low level http request handler
|
/// Low level http request handler
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait HttpHandler: 'static {
|
pub trait HttpHandler: 'static {
|
||||||
|
|
||||||
/// Handle request
|
/// Handle request
|
||||||
fn handle(&self, req: HttpRequest) -> Result<Pipeline, HttpRequest>;
|
fn handle(&self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>;
|
||||||
|
|
||||||
/// Set server settings
|
/// Set server settings
|
||||||
fn server_settings(&mut self, settings: ServerSettings) {}
|
fn server_settings(&mut self, settings: ServerSettings) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HttpHandlerTask {
|
||||||
|
|
||||||
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<(), Error>;
|
||||||
|
|
||||||
|
fn disconnected(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
/// Conversion helper trait
|
/// Conversion helper trait
|
||||||
pub trait IntoHttpHandler {
|
pub trait IntoHttpHandler {
|
||||||
/// The associated type which is result of conversion.
|
/// The associated type which is result of conversion.
|
||||||
|
@ -40,7 +51,7 @@ impl<T: HttpHandler> IntoHttpHandler for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HttpProtocol<T, H>
|
enum HttpProtocol<T, H>
|
||||||
where T: AsyncRead + AsyncWrite + 'static, H: 'static
|
where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static
|
||||||
{
|
{
|
||||||
H1(h1::Http1<T, H>),
|
H1(h1::Http1<T, H>),
|
||||||
H2(h2::Http2<T, H>),
|
H2(h2::Http2<T, H>),
|
||||||
|
@ -48,7 +59,7 @@ enum HttpProtocol<T, H>
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct HttpChannel<T, H>
|
pub struct HttpChannel<T, H>
|
||||||
where T: AsyncRead + AsyncWrite + 'static, H: 'static
|
where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static
|
||||||
{
|
{
|
||||||
proto: Option<HttpProtocol<T, H>>,
|
proto: Option<HttpProtocol<T, H>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use bytes::{Bytes, BytesMut, BufMut, Writer};
|
||||||
|
|
||||||
use body::{Body, Binary};
|
use body::{Body, Binary};
|
||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use payload::{PayloadSender, PayloadWriter};
|
use payload::{PayloadSender, PayloadWriter};
|
||||||
|
|
||||||
|
@ -336,8 +336,8 @@ impl Default for PayloadEncoder {
|
||||||
|
|
||||||
impl PayloadEncoder {
|
impl PayloadEncoder {
|
||||||
|
|
||||||
pub fn new(req: &HttpRequest, resp: &mut HttpResponse) -> PayloadEncoder {
|
pub fn new(req: &HttpMessage, resp: &mut HttpResponse) -> PayloadEncoder {
|
||||||
let version = resp.version().unwrap_or_else(|| req.version());
|
let version = resp.version().unwrap_or_else(|| req.version);
|
||||||
let mut body = resp.replace_body(Body::Empty);
|
let mut body = resp.replace_body(Body::Empty);
|
||||||
let has_body = match body {
|
let has_body = match body {
|
||||||
Body::Empty => false,
|
Body::Empty => false,
|
||||||
|
@ -350,7 +350,7 @@ impl PayloadEncoder {
|
||||||
let encoding = match *resp.content_encoding() {
|
let encoding = match *resp.content_encoding() {
|
||||||
ContentEncoding::Auto => {
|
ContentEncoding::Auto => {
|
||||||
// negotiate content-encoding
|
// negotiate content-encoding
|
||||||
if let Some(val) = req.headers().get(ACCEPT_ENCODING) {
|
if let Some(val) = req.headers.get(ACCEPT_ENCODING) {
|
||||||
if let Ok(enc) = val.to_str() {
|
if let Ok(enc) = val.to_str() {
|
||||||
AcceptEncoding::parse(enc)
|
AcceptEncoding::parse(enc)
|
||||||
} else {
|
} else {
|
||||||
|
|
10
src/error.rs
10
src/error.rs
|
@ -491,12 +491,12 @@ pub struct ErrorNotFound<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorNotFound<T>, StatusCode::NOT_FOUND);
|
ERROR_WRAP!(ErrorNotFound<T>, StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Helper type that can wrap any error and generate *METHOD_NOT_ALLOWED* response.
|
/// Helper type that can wrap any error and generate *METHOD NOT ALLOWED* response.
|
||||||
pub struct ErrorMethodNotAllowed<T>(pub T);
|
pub struct ErrorMethodNotAllowed<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorMethodNotAllowed<T>, StatusCode::METHOD_NOT_ALLOWED);
|
ERROR_WRAP!(ErrorMethodNotAllowed<T>, StatusCode::METHOD_NOT_ALLOWED);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Helper type that can wrap any error and generate *REQUEST_TIMEOUT* response.
|
/// Helper type that can wrap any error and generate *REQUEST TIMEOUT* response.
|
||||||
pub struct ErrorRequestTimeout<T>(pub T);
|
pub struct ErrorRequestTimeout<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorRequestTimeout<T>, StatusCode::REQUEST_TIMEOUT);
|
ERROR_WRAP!(ErrorRequestTimeout<T>, StatusCode::REQUEST_TIMEOUT);
|
||||||
|
|
||||||
|
@ -511,17 +511,17 @@ pub struct ErrorGone<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorGone<T>, StatusCode::GONE);
|
ERROR_WRAP!(ErrorGone<T>, StatusCode::GONE);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Helper type that can wrap any error and generate *PRECONDITION_FAILED* response.
|
/// Helper type that can wrap any error and generate *PRECONDITION FAILED* response.
|
||||||
pub struct ErrorPreconditionFailed<T>(pub T);
|
pub struct ErrorPreconditionFailed<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorPreconditionFailed<T>, StatusCode::PRECONDITION_FAILED);
|
ERROR_WRAP!(ErrorPreconditionFailed<T>, StatusCode::PRECONDITION_FAILED);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Helper type that can wrap any error and generate *EXPECTATION_FAILED* response.
|
/// Helper type that can wrap any error and generate *EXPECTATION FAILED* response.
|
||||||
pub struct ErrorExpectationFailed<T>(pub T);
|
pub struct ErrorExpectationFailed<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorExpectationFailed<T>, StatusCode::EXPECTATION_FAILED);
|
ERROR_WRAP!(ErrorExpectationFailed<T>, StatusCode::EXPECTATION_FAILED);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Helper type that can wrap any error and generate *INTERNAL_SERVER_ERROR* response.
|
/// Helper type that can wrap any error and generate *INTERNAL SERVER ERROR* response.
|
||||||
pub struct ErrorInternalServerError<T>(pub T);
|
pub struct ErrorInternalServerError<T>(pub T);
|
||||||
ERROR_WRAP!(ErrorInternalServerError<T>, StatusCode::INTERNAL_SERVER_ERROR);
|
ERROR_WRAP!(ErrorInternalServerError<T>, StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use tokio_core::reactor::Timeout;
|
||||||
|
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use encoding::PayloadType;
|
use encoding::PayloadType;
|
||||||
use channel::HttpHandler;
|
use channel::{HttpHandler, HttpHandlerTask};
|
||||||
use h1writer::H1Writer;
|
use h1writer::H1Writer;
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
@ -69,7 +69,7 @@ pub(crate) struct Http1<T: AsyncWrite + 'static, H: 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
pipe: Pipeline,
|
pipe: Box<HttpHandlerTask>,
|
||||||
flags: EntryFlags,
|
flags: EntryFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use http::header::{HeaderValue, CONNECTION, CONTENT_TYPE, DATE};
|
||||||
use date;
|
use date;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
use encoding::PayloadEncoder;
|
use encoding::PayloadEncoder;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
|
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
|
@ -16,16 +16,16 @@ const MAX_WRITE_BUFFER_SIZE: usize = 65_536; // max buffer size 64k
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum WriterState {
|
pub enum WriterState {
|
||||||
Done,
|
Done,
|
||||||
Pause,
|
Pause,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send stream
|
/// Send stream
|
||||||
pub(crate) trait Writer {
|
pub trait Writer {
|
||||||
fn written(&self) -> u64;
|
fn written(&self) -> u64;
|
||||||
|
|
||||||
fn start(&mut self, req: &mut HttpRequest, resp: &mut HttpResponse)
|
fn start(&mut self, req: &mut HttpMessage, resp: &mut HttpResponse)
|
||||||
-> Result<WriterState, io::Error>;
|
-> Result<WriterState, io::Error>;
|
||||||
|
|
||||||
fn write(&mut self, payload: &[u8]) -> Result<WriterState, io::Error>;
|
fn write(&mut self, payload: &[u8]) -> Result<WriterState, io::Error>;
|
||||||
|
@ -116,7 +116,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&mut self, req: &mut HttpRequest, msg: &mut HttpResponse)
|
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse)
|
||||||
-> Result<WriterState, io::Error>
|
-> Result<WriterState, io::Error>
|
||||||
{
|
{
|
||||||
trace!("Prepare response with status: {:?}", msg.status());
|
trace!("Prepare response with status: {:?}", msg.status());
|
||||||
|
@ -129,7 +129,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connection upgrade
|
// Connection upgrade
|
||||||
let version = msg.version().unwrap_or_else(|| req.version());
|
let version = msg.version().unwrap_or_else(|| req.version);
|
||||||
if msg.upgrade() {
|
if msg.upgrade() {
|
||||||
msg.headers_mut().insert(CONNECTION, HeaderValue::from_static("upgrade"));
|
msg.headers_mut().insert(CONNECTION, HeaderValue::from_static("upgrade"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use tokio_core::reactor::Timeout;
|
||||||
|
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use h2writer::H2Writer;
|
use h2writer::H2Writer;
|
||||||
use channel::HttpHandler;
|
use channel::{HttpHandler, HttpHandlerTask};
|
||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use encoding::PayloadType;
|
use encoding::PayloadType;
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
|
@ -217,7 +217,7 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
task: Pipeline,
|
task: Box<HttpHandlerTask>,
|
||||||
payload: PayloadType,
|
payload: PayloadType,
|
||||||
recv: RecvStream,
|
recv: RecvStream,
|
||||||
stream: H2Writer,
|
stream: H2Writer,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use http::header::{HeaderValue, CONNECTION, CONTENT_TYPE, TRANSFER_ENCODING, DAT
|
||||||
use date;
|
use date;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
use encoding::PayloadEncoder;
|
use encoding::PayloadEncoder;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use h1writer::{Writer, WriterState};
|
use h1writer::{Writer, WriterState};
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ impl Writer for H2Writer {
|
||||||
self.written
|
self.written
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&mut self, req: &mut HttpRequest, msg: &mut HttpResponse)
|
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse)
|
||||||
-> Result<WriterState, io::Error>
|
-> Result<WriterState, io::Error>
|
||||||
{
|
{
|
||||||
trace!("Prepare response with status: {:?}", msg.status());
|
trace!("Prepare response with status: {:?}", msg.status());
|
||||||
|
|
|
@ -19,18 +19,17 @@ use error::{ParseError, PayloadError, UrlGenerationError,
|
||||||
MultipartError, CookieParseError, HttpRangeError, UrlencodedError};
|
MultipartError, CookieParseError, HttpRangeError, UrlencodedError};
|
||||||
|
|
||||||
|
|
||||||
struct HttpMessage {
|
pub struct HttpMessage {
|
||||||
version: Version,
|
pub version: Version,
|
||||||
method: Method,
|
pub method: Method,
|
||||||
uri: Uri,
|
pub uri: Uri,
|
||||||
headers: HeaderMap,
|
pub headers: HeaderMap,
|
||||||
extensions: Extensions,
|
pub extensions: Extensions,
|
||||||
params: Params<'static>,
|
pub params: Params<'static>,
|
||||||
cookies: Option<Vec<Cookie<'static>>>,
|
pub cookies: Option<Vec<Cookie<'static>>>,
|
||||||
addr: Option<SocketAddr>,
|
pub addr: Option<SocketAddr>,
|
||||||
payload: Payload,
|
pub payload: Payload,
|
||||||
info: Option<ConnectionInfo<'static>>,
|
pub info: Option<ConnectionInfo<'static>>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HttpMessage {
|
impl Default for HttpMessage {
|
||||||
|
@ -51,6 +50,27 @@ impl Default for HttpMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HttpMessage {
|
||||||
|
|
||||||
|
/// Checks if a connection should be kept alive.
|
||||||
|
pub fn keep_alive(&self) -> bool {
|
||||||
|
if let Some(conn) = self.headers.get(header::CONNECTION) {
|
||||||
|
if let Ok(conn) = conn.to_str() {
|
||||||
|
if self.version == Version::HTTP_10 && conn.contains("keep-alive") {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.version == Version::HTTP_11 &&
|
||||||
|
!(conn.contains("close") || conn.contains("upgrade"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.version != Version::HTTP_10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An HTTP Request
|
/// An HTTP Request
|
||||||
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Rc<S>, Option<Router<S>>);
|
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Rc<S>, Option<Router<S>>);
|
||||||
|
|
||||||
|
@ -101,6 +121,10 @@ impl<S> HttpRequest<S> {
|
||||||
unsafe{mem::transmute(r)}
|
unsafe{mem::transmute(r)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_inner(&mut self) -> &mut HttpMessage {
|
||||||
|
self.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
/// Shared application state
|
/// Shared application state
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn state(&self) -> &S {
|
pub fn state(&self) -> &S {
|
||||||
|
|
|
@ -35,9 +35,9 @@ impl DefaultHeaders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Middleware for DefaultHeaders {
|
impl<S> Middleware<S> for DefaultHeaders {
|
||||||
|
|
||||||
fn response(&self, _: &mut HttpRequest, mut resp: HttpResponse) -> Response {
|
fn response(&self, _: &mut HttpRequest<S>, mut resp: HttpResponse) -> Response {
|
||||||
for (key, value) in self.0.iter() {
|
for (key, value) in self.0.iter() {
|
||||||
if !resp.headers().contains_key(key) {
|
if !resp.headers().contains_key(key) {
|
||||||
resp.headers_mut().insert(key, value.clone());
|
resp.headers_mut().insert(key, value.clone());
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct StartTime(time::Tm);
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
|
|
||||||
fn log(&self, req: &mut HttpRequest, resp: &HttpResponse) {
|
fn log<S>(&self, req: &mut HttpRequest<S>, resp: &HttpResponse) {
|
||||||
let entry_time = req.extensions().get::<StartTime>().unwrap().0;
|
let entry_time = req.extensions().get::<StartTime>().unwrap().0;
|
||||||
|
|
||||||
let render = |fmt: &mut Formatter| {
|
let render = |fmt: &mut Formatter| {
|
||||||
|
@ -99,14 +99,14 @@ impl Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Middleware for Logger {
|
impl<S> Middleware<S> for Logger {
|
||||||
|
|
||||||
fn start(&self, req: &mut HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest<S>) -> Started {
|
||||||
req.extensions().insert(StartTime(time::now()));
|
req.extensions().insert(StartTime(time::now()));
|
||||||
Started::Done
|
Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self, req: &mut HttpRequest, resp: &HttpResponse) -> Finished {
|
fn finish(&self, req: &mut HttpRequest<S>, resp: &HttpResponse) -> Finished {
|
||||||
self.log(req, resp);
|
self.log(req, resp);
|
||||||
Finished::Done
|
Finished::Done
|
||||||
}
|
}
|
||||||
|
@ -199,8 +199,8 @@ pub enum FormatText {
|
||||||
|
|
||||||
impl FormatText {
|
impl FormatText {
|
||||||
|
|
||||||
fn render(&self, fmt: &mut Formatter,
|
fn render<S>(&self, fmt: &mut Formatter,
|
||||||
req: &HttpRequest,
|
req: &HttpRequest<S>,
|
||||||
resp: &HttpResponse,
|
resp: &HttpResponse,
|
||||||
entry_time: time::Tm) -> Result<(), fmt::Error>
|
entry_time: time::Tm) -> Result<(), fmt::Error>
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,22 +46,22 @@ pub enum Finished {
|
||||||
|
|
||||||
/// Middleware definition
|
/// Middleware definition
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait Middleware {
|
pub trait Middleware<S> {
|
||||||
|
|
||||||
/// Method is called when request is ready. It may return
|
/// Method is called when request is ready. It may return
|
||||||
/// future, which should resolve before next middleware get called.
|
/// future, which should resolve before next middleware get called.
|
||||||
fn start(&self, req: &mut HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest<S>) -> Started {
|
||||||
Started::Done
|
Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method is called when handler returns response,
|
/// Method is called when handler returns response,
|
||||||
/// but before sending http message to peer.
|
/// but before sending http message to peer.
|
||||||
fn response(&self, req: &mut HttpRequest, resp: HttpResponse) -> Response {
|
fn response(&self, req: &mut HttpRequest<S>, resp: HttpResponse) -> Response {
|
||||||
Response::Done(resp)
|
Response::Done(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method is called after body stream get sent to peer.
|
/// Method is called after body stream get sent to peer.
|
||||||
fn finish(&self, req: &mut HttpRequest, resp: &HttpResponse) -> Finished {
|
fn finish(&self, req: &mut HttpRequest<S>, resp: &HttpResponse) -> Finished {
|
||||||
Finished::Done
|
Finished::Done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
@ -79,18 +80,18 @@ unsafe impl Send for SessionImplBox {}
|
||||||
unsafe impl Sync for SessionImplBox {}
|
unsafe impl Sync for SessionImplBox {}
|
||||||
|
|
||||||
/// Session storage middleware
|
/// Session storage middleware
|
||||||
pub struct SessionStorage<T>(T);
|
pub struct SessionStorage<T, S>(T, PhantomData<S>);
|
||||||
|
|
||||||
impl<T: SessionBackend> SessionStorage<T> {
|
impl<S, T: SessionBackend<S>> SessionStorage<T, S> {
|
||||||
/// Create session storage
|
/// Create session storage
|
||||||
pub fn new(backend: T) -> SessionStorage<T> {
|
pub fn new(backend: T) -> SessionStorage<T, S> {
|
||||||
SessionStorage(backend)
|
SessionStorage(backend, PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SessionBackend> Middleware for SessionStorage<T> {
|
impl<S: 'static, T: SessionBackend<S>> Middleware<S> for SessionStorage<T, S> {
|
||||||
|
|
||||||
fn start(&self, req: &mut HttpRequest) -> Started {
|
fn start(&self, req: &mut HttpRequest<S>) -> Started {
|
||||||
let mut req = req.clone();
|
let mut req = req.clone();
|
||||||
|
|
||||||
let fut = self.0.from_request(&mut req)
|
let fut = self.0.from_request(&mut req)
|
||||||
|
@ -106,7 +107,7 @@ impl<T: SessionBackend> Middleware for SessionStorage<T> {
|
||||||
Started::Future(Box::new(fut))
|
Started::Future(Box::new(fut))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(&self, req: &mut HttpRequest, resp: HttpResponse) -> Response {
|
fn response(&self, req: &mut HttpRequest<S>, resp: HttpResponse) -> Response {
|
||||||
if let Some(s_box) = req.extensions().remove::<Arc<SessionImplBox>>() {
|
if let Some(s_box) = req.extensions().remove::<Arc<SessionImplBox>>() {
|
||||||
s_box.0.write(resp)
|
s_box.0.write(resp)
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,12 +134,12 @@ pub trait SessionImpl: 'static {
|
||||||
|
|
||||||
/// Session's storage backend trait definition.
|
/// Session's storage backend trait definition.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait SessionBackend: Sized + 'static {
|
pub trait SessionBackend<S>: Sized + 'static {
|
||||||
type Session: SessionImpl;
|
type Session: SessionImpl;
|
||||||
type ReadFuture: Future<Item=Self::Session, Error=Error>;
|
type ReadFuture: Future<Item=Self::Session, Error=Error>;
|
||||||
|
|
||||||
/// Parse the session from request and load data from a storage backend.
|
/// Parse the session from request and load data from a storage backend.
|
||||||
fn from_request(&self, request: &mut HttpRequest) -> Self::ReadFuture;
|
fn from_request(&self, request: &mut HttpRequest<S>) -> Self::ReadFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dummy session impl, does not do anything
|
/// Dummy session impl, does not do anything
|
||||||
|
@ -258,7 +259,7 @@ impl CookieSessionInner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, req: &mut HttpRequest) -> HashMap<String, String> {
|
fn load<S>(&self, req: &mut HttpRequest<S>) -> HashMap<String, String> {
|
||||||
if let Ok(cookies) = req.cookies() {
|
if let Ok(cookies) = req.cookies() {
|
||||||
for cookie in cookies {
|
for cookie in cookies {
|
||||||
if cookie.name() == self.name {
|
if cookie.name() == self.name {
|
||||||
|
@ -316,12 +317,12 @@ impl CookieSessionBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionBackend for CookieSessionBackend {
|
impl<S> SessionBackend<S> for CookieSessionBackend {
|
||||||
|
|
||||||
type Session = CookieSession;
|
type Session = CookieSession;
|
||||||
type ReadFuture = FutureResult<CookieSession, Error>;
|
type ReadFuture = FutureResult<CookieSession, Error>;
|
||||||
|
|
||||||
fn from_request(&self, req: &mut HttpRequest) -> Self::ReadFuture {
|
fn from_request(&self, req: &mut HttpRequest<S>) -> Self::ReadFuture {
|
||||||
let state = self.0.load(req);
|
let state = self.0.load(req);
|
||||||
FutOk(
|
FutOk(
|
||||||
CookieSession {
|
CookieSession {
|
||||||
|
|
141
src/pipeline.rs
141
src/pipeline.rs
|
@ -5,6 +5,7 @@ use std::cell::RefCell;
|
||||||
use futures::{Async, Poll, Future, Stream};
|
use futures::{Async, Poll, Future, Stream};
|
||||||
use futures::task::{Task as FutureTask, current as current_task};
|
use futures::task::{Task as FutureTask, current as current_task};
|
||||||
|
|
||||||
|
use channel::HttpHandlerTask;
|
||||||
use body::{Body, BodyStream};
|
use body::{Body, BodyStream};
|
||||||
use context::{Frame, IoContext};
|
use context::{Frame, IoContext};
|
||||||
use error::{Error, UnexpectedTaskFrame};
|
use error::{Error, UnexpectedTaskFrame};
|
||||||
|
@ -14,23 +15,23 @@ use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use middlewares::{Middleware, Finished, Started, Response};
|
use middlewares::{Middleware, Finished, Started, Response};
|
||||||
|
|
||||||
type Handler = Fn(HttpRequest) -> Reply;
|
type Handler<S> = Fn(HttpRequest<S>) -> Reply;
|
||||||
pub(crate) type PipelineHandler<'a> = &'a Fn(HttpRequest) -> Reply;
|
pub(crate) type PipelineHandler<'a, S> = &'a Fn(HttpRequest<S>) -> Reply;
|
||||||
|
|
||||||
pub struct Pipeline(PipelineState);
|
pub struct Pipeline<S>(PipelineState<S>);
|
||||||
|
|
||||||
enum PipelineState {
|
enum PipelineState<S> {
|
||||||
None,
|
None,
|
||||||
Error,
|
Error,
|
||||||
Starting(StartMiddlewares),
|
Starting(StartMiddlewares<S>),
|
||||||
Handler(WaitingResponse),
|
Handler(WaitingResponse<S>),
|
||||||
RunMiddlewares(RunMiddlewares),
|
RunMiddlewares(RunMiddlewares<S>),
|
||||||
Response(ProcessResponse),
|
Response(ProcessResponse<S>),
|
||||||
Finishing(FinishingMiddlewares),
|
Finishing(FinishingMiddlewares<S>),
|
||||||
Completed(Completed),
|
Completed(Completed<S>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineState {
|
impl<S> PipelineState<S> {
|
||||||
|
|
||||||
fn is_done(&self) -> bool {
|
fn is_done(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -71,16 +72,16 @@ impl PipelineState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PipelineInfo {
|
struct PipelineInfo<S> {
|
||||||
req: HttpRequest,
|
req: HttpRequest<S>,
|
||||||
count: usize,
|
count: usize,
|
||||||
mws: Rc<Vec<Box<Middleware>>>,
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
context: Option<Box<IoContext>>,
|
context: Option<Box<IoContext>>,
|
||||||
error: Option<Error>,
|
error: Option<Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipelineInfo {
|
impl<S> PipelineInfo<S> {
|
||||||
fn new(req: HttpRequest) -> PipelineInfo {
|
fn new(req: HttpRequest<S>) -> PipelineInfo<S> {
|
||||||
PipelineInfo {
|
PipelineInfo {
|
||||||
req: req,
|
req: req,
|
||||||
count: 0,
|
count: 0,
|
||||||
|
@ -91,7 +92,7 @@ impl PipelineInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
||||||
fn req_mut(&self) -> &mut HttpRequest {
|
fn req_mut(&self) -> &mut HttpRequest<S> {
|
||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
unsafe{mem::transmute(&self.req)}
|
unsafe{mem::transmute(&self.req)}
|
||||||
}
|
}
|
||||||
|
@ -158,25 +159,30 @@ impl Future for DrainFut {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Pipeline {
|
impl<S> Pipeline<S> {
|
||||||
|
|
||||||
pub fn new(req: HttpRequest,
|
pub fn new(req: HttpRequest<S>,
|
||||||
mw: Rc<Vec<Box<Middleware>>>,
|
mw: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
handler: PipelineHandler) -> Pipeline
|
handler: PipelineHandler<S>) -> Pipeline<S>
|
||||||
{
|
{
|
||||||
Pipeline(StartMiddlewares::init(mw, req, handler))
|
Pipeline(StartMiddlewares::init(mw, req, handler))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn error<R: Into<HttpResponse>>(err: R) -> Self {
|
impl Pipeline<()> {
|
||||||
Pipeline(ProcessResponse::init(
|
pub fn error<R: Into<HttpResponse>>(err: R) -> Box<HttpHandlerTask> {
|
||||||
Box::new(PipelineInfo::new(HttpRequest::default())), err.into()))
|
Box::new(Pipeline(ProcessResponse::init(
|
||||||
|
PipelineInfo::new(HttpRequest::default()), err.into())))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn disconnected(&mut self) {
|
impl<S> HttpHandlerTask for Pipeline<S> {
|
||||||
|
|
||||||
|
fn disconnected(&mut self) {
|
||||||
self.0.disconnect()
|
self.0.disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_io<T: Writer>(&mut self, io: &mut T) -> Poll<bool, Error> {
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = mem::replace(&mut self.0, PipelineState::None);
|
let state = mem::replace(&mut self.0, PipelineState::None);
|
||||||
match state {
|
match state {
|
||||||
|
@ -256,7 +262,7 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll(&mut self) -> Poll<(), Error> {
|
fn poll(&mut self) -> Poll<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = mem::replace(&mut self.0, PipelineState::None);
|
let state = mem::replace(&mut self.0, PipelineState::None);
|
||||||
match state {
|
match state {
|
||||||
|
@ -327,16 +333,16 @@ impl Pipeline {
|
||||||
type Fut = Box<Future<Item=Option<HttpResponse>, Error=Error>>;
|
type Fut = Box<Future<Item=Option<HttpResponse>, Error=Error>>;
|
||||||
|
|
||||||
/// Middlewares start executor
|
/// Middlewares start executor
|
||||||
struct StartMiddlewares {
|
struct StartMiddlewares<S> {
|
||||||
hnd: *mut Handler,
|
hnd: *mut Handler<S>,
|
||||||
fut: Option<Fut>,
|
fut: Option<Fut>,
|
||||||
info: Box<PipelineInfo>,
|
info: PipelineInfo<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StartMiddlewares {
|
impl<S> StartMiddlewares<S> {
|
||||||
|
|
||||||
fn init(mws: Rc<Vec<Box<Middleware>>>,
|
fn init(mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
req: HttpRequest, handler: PipelineHandler) -> PipelineState {
|
req: HttpRequest<S>, handler: PipelineHandler<S>) -> PipelineState<S> {
|
||||||
let mut info = PipelineInfo {
|
let mut info = PipelineInfo {
|
||||||
req: req,
|
req: req,
|
||||||
count: 0,
|
count: 0,
|
||||||
|
@ -351,37 +357,37 @@ impl StartMiddlewares {
|
||||||
loop {
|
loop {
|
||||||
if info.count == len {
|
if info.count == len {
|
||||||
let reply = (&*handler)(info.req.clone());
|
let reply = (&*handler)(info.req.clone());
|
||||||
return WaitingResponse::init(Box::new(info), reply)
|
return WaitingResponse::init(info, reply)
|
||||||
} else {
|
} else {
|
||||||
match info.mws[info.count].start(&mut info.req) {
|
match info.mws[info.count].start(&mut info.req) {
|
||||||
Started::Done =>
|
Started::Done =>
|
||||||
info.count += 1,
|
info.count += 1,
|
||||||
Started::Response(resp) =>
|
Started::Response(resp) =>
|
||||||
return RunMiddlewares::init(Box::new(info), resp),
|
return RunMiddlewares::init(info, resp),
|
||||||
Started::Future(mut fut) =>
|
Started::Future(mut fut) =>
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::NotReady) =>
|
Ok(Async::NotReady) =>
|
||||||
return PipelineState::Starting(StartMiddlewares {
|
return PipelineState::Starting(StartMiddlewares {
|
||||||
hnd: handler as *const _ as *mut _,
|
hnd: handler as *const _ as *mut _,
|
||||||
fut: Some(fut),
|
fut: Some(fut),
|
||||||
info: Box::new(info)}),
|
info: info}),
|
||||||
Ok(Async::Ready(resp)) => {
|
Ok(Async::Ready(resp)) => {
|
||||||
if let Some(resp) = resp {
|
if let Some(resp) = resp {
|
||||||
return RunMiddlewares::init(Box::new(info), resp);
|
return RunMiddlewares::init(info, resp);
|
||||||
}
|
}
|
||||||
info.count += 1;
|
info.count += 1;
|
||||||
}
|
}
|
||||||
Err(err) =>
|
Err(err) =>
|
||||||
return ProcessResponse::init(Box::new(info), err.into()),
|
return ProcessResponse::init(info, err.into()),
|
||||||
},
|
},
|
||||||
Started::Err(err) =>
|
Started::Err(err) =>
|
||||||
return ProcessResponse::init(Box::new(info), err.into()),
|
return ProcessResponse::init(info, err.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(mut self) -> Result<PipelineState, PipelineState> {
|
fn poll(mut self) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
let len = self.info.mws.len();
|
let len = self.info.mws.len();
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
match self.fut.as_mut().unwrap().poll() {
|
match self.fut.as_mut().unwrap().poll() {
|
||||||
|
@ -421,14 +427,14 @@ impl StartMiddlewares {
|
||||||
}
|
}
|
||||||
|
|
||||||
// waiting for response
|
// waiting for response
|
||||||
struct WaitingResponse {
|
struct WaitingResponse<S> {
|
||||||
info: Box<PipelineInfo>,
|
info: PipelineInfo<S>,
|
||||||
stream: PipelineResponse,
|
stream: PipelineResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaitingResponse {
|
impl<S> WaitingResponse<S> {
|
||||||
|
|
||||||
fn init(info: Box<PipelineInfo>, reply: Reply) -> PipelineState
|
fn init(info: PipelineInfo<S>, reply: Reply) -> PipelineState<S>
|
||||||
{
|
{
|
||||||
let stream = match reply.into() {
|
let stream = match reply.into() {
|
||||||
ReplyItem::Message(resp) =>
|
ReplyItem::Message(resp) =>
|
||||||
|
@ -443,7 +449,7 @@ impl WaitingResponse {
|
||||||
WaitingResponse { info: info, stream: stream })
|
WaitingResponse { info: info, stream: stream })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(mut self) -> Result<PipelineState, PipelineState> {
|
fn poll(mut self) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
let stream = mem::replace(&mut self.stream, PipelineResponse::None);
|
let stream = mem::replace(&mut self.stream, PipelineResponse::None);
|
||||||
|
|
||||||
match stream {
|
match stream {
|
||||||
|
@ -494,15 +500,15 @@ impl WaitingResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Middlewares response executor
|
/// Middlewares response executor
|
||||||
pub(crate) struct RunMiddlewares {
|
struct RunMiddlewares<S> {
|
||||||
info: Box<PipelineInfo>,
|
info: PipelineInfo<S>,
|
||||||
curr: usize,
|
curr: usize,
|
||||||
fut: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
|
fut: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunMiddlewares {
|
impl<S> RunMiddlewares<S> {
|
||||||
|
|
||||||
fn init(mut info: Box<PipelineInfo>, mut resp: HttpResponse) -> PipelineState
|
fn init(mut info: PipelineInfo<S>, mut resp: HttpResponse) -> PipelineState<S>
|
||||||
{
|
{
|
||||||
if info.count == 0 {
|
if info.count == 0 {
|
||||||
return ProcessResponse::init(info, resp);
|
return ProcessResponse::init(info, resp);
|
||||||
|
@ -532,7 +538,7 @@ impl RunMiddlewares {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(mut self) -> Result<PipelineState, PipelineState> {
|
fn poll(mut self) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
let len = self.info.mws.len();
|
let len = self.info.mws.len();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -570,12 +576,12 @@ impl RunMiddlewares {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProcessResponse {
|
struct ProcessResponse<S> {
|
||||||
resp: HttpResponse,
|
resp: HttpResponse,
|
||||||
iostate: IOState,
|
iostate: IOState,
|
||||||
running: RunningState,
|
running: RunningState,
|
||||||
drain: DrainVec,
|
drain: DrainVec,
|
||||||
info: Box<PipelineInfo>,
|
info: PipelineInfo<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
@ -625,9 +631,9 @@ impl Drop for DrainVec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessResponse {
|
impl<S> ProcessResponse<S> {
|
||||||
|
|
||||||
fn init(info: Box<PipelineInfo>, resp: HttpResponse) -> PipelineState
|
fn init(info: PipelineInfo<S>, resp: HttpResponse) -> PipelineState<S>
|
||||||
{
|
{
|
||||||
PipelineState::Response(
|
PipelineState::Response(
|
||||||
ProcessResponse{ resp: resp,
|
ProcessResponse{ resp: resp,
|
||||||
|
@ -637,14 +643,15 @@ impl ProcessResponse {
|
||||||
info: info})
|
info: info})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_io<T: Writer>(mut self, io: &mut T) -> Result<PipelineState, PipelineState> {
|
fn poll_io(mut self, io: &mut Writer) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
if self.drain.0.is_empty() && self.running != RunningState::Paused {
|
if self.drain.0.is_empty() && self.running != RunningState::Paused {
|
||||||
// if task is paused, write buffer is probably full
|
// if task is paused, write buffer is probably full
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let result = match mem::replace(&mut self.iostate, IOState::Done) {
|
let result = match mem::replace(&mut self.iostate, IOState::Done) {
|
||||||
IOState::Response => {
|
IOState::Response => {
|
||||||
let result = match io.start(self.info.req_mut(), &mut self.resp) {
|
let result = match io.start(self.info.req_mut().get_inner(),
|
||||||
|
&mut self.resp) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.info.error = Some(err.into());
|
self.info.error = Some(err.into());
|
||||||
|
@ -804,15 +811,15 @@ impl ProcessResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Middlewares start executor
|
/// Middlewares start executor
|
||||||
struct FinishingMiddlewares {
|
struct FinishingMiddlewares<S> {
|
||||||
info: Box<PipelineInfo>,
|
info: PipelineInfo<S>,
|
||||||
resp: HttpResponse,
|
resp: HttpResponse,
|
||||||
fut: Option<Box<Future<Item=(), Error=Error>>>,
|
fut: Option<Box<Future<Item=(), Error=Error>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinishingMiddlewares {
|
impl<S> FinishingMiddlewares<S> {
|
||||||
|
|
||||||
fn init(info: Box<PipelineInfo>, resp: HttpResponse) -> PipelineState {
|
fn init(info: PipelineInfo<S>, resp: HttpResponse) -> PipelineState<S> {
|
||||||
if info.count == 0 {
|
if info.count == 0 {
|
||||||
Completed::init(info)
|
Completed::init(info)
|
||||||
} else {
|
} else {
|
||||||
|
@ -822,7 +829,7 @@ impl FinishingMiddlewares {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(mut self) -> Result<PipelineState, PipelineState> {
|
fn poll(mut self) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
loop {
|
loop {
|
||||||
// poll latest fut
|
// poll latest fut
|
||||||
let not_ready = if let Some(ref mut fut) = self.fut {
|
let not_ready = if let Some(ref mut fut) = self.fut {
|
||||||
|
@ -861,11 +868,11 @@ impl FinishingMiddlewares {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Completed(Box<PipelineInfo>);
|
struct Completed<S>(PipelineInfo<S>);
|
||||||
|
|
||||||
impl Completed {
|
impl<S> Completed<S> {
|
||||||
|
|
||||||
fn init(info: Box<PipelineInfo>) -> PipelineState {
|
fn init(info: PipelineInfo<S>) -> PipelineState<S> {
|
||||||
if info.context.is_none() {
|
if info.context.is_none() {
|
||||||
PipelineState::None
|
PipelineState::None
|
||||||
} else {
|
} else {
|
||||||
|
@ -873,7 +880,7 @@ impl Completed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(mut self) -> Result<PipelineState, PipelineState> {
|
fn poll(mut self) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||||
match self.0.poll_context() {
|
match self.0.poll_context() {
|
||||||
Ok(Async::NotReady) => Ok(PipelineState::Completed(self)),
|
Ok(Async::NotReady) => Ok(PipelineState::Completed(self)),
|
||||||
Ok(Async::Ready(())) => Ok(PipelineState::None),
|
Ok(Async::Ready(())) => Ok(PipelineState::None),
|
||||||
|
@ -890,11 +897,11 @@ mod tests {
|
||||||
use tokio_core::reactor::Core;
|
use tokio_core::reactor::Core;
|
||||||
use futures::future::{lazy, result};
|
use futures::future::{lazy, result};
|
||||||
|
|
||||||
impl PipelineState {
|
impl<S> PipelineState<S> {
|
||||||
fn is_none(&self) -> Option<bool> {
|
fn is_none(&self) -> Option<bool> {
|
||||||
if let PipelineState::None = *self { Some(true) } else { None }
|
if let PipelineState::None = *self { Some(true) } else { None }
|
||||||
}
|
}
|
||||||
fn completed(self) -> Option<Completed> {
|
fn completed(self) -> Option<Completed<S>> {
|
||||||
if let PipelineState::Completed(c) = self { Some(c) } else { None }
|
if let PipelineState::Completed(c) = self { Some(c) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,18 +53,18 @@ struct MiddlewareTest {
|
||||||
finish: Arc<AtomicUsize>,
|
finish: Arc<AtomicUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl middlewares::Middleware for MiddlewareTest {
|
impl<S> middlewares::Middleware<S> for MiddlewareTest {
|
||||||
fn start(&self, _: &mut HttpRequest) -> middlewares::Started {
|
fn start(&self, _: &mut HttpRequest<S>) -> middlewares::Started {
|
||||||
self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
middlewares::Started::Done
|
middlewares::Started::Done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> middlewares::Response {
|
fn response(&self, _: &mut HttpRequest<S>, resp: HttpResponse) -> middlewares::Response {
|
||||||
self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
middlewares::Response::Done(resp)
|
middlewares::Response::Done(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) -> middlewares::Finished {
|
fn finish(&self, _: &mut HttpRequest<S>, _: &HttpResponse) -> middlewares::Finished {
|
||||||
self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
middlewares::Finished::Done
|
middlewares::Finished::Done
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue