2018-04-29 16:09:08 +00:00
|
|
|
use std::cell::UnsafeCell;
|
2018-04-13 23:02:01 +00:00
|
|
|
use std::marker::PhantomData;
|
2018-01-10 04:00:18 +00:00
|
|
|
use std::rc::Rc;
|
2017-12-05 00:09:22 +00:00
|
|
|
|
2018-04-30 02:35:50 +00:00
|
|
|
use futures::{Async, Future, Poll};
|
|
|
|
|
2017-12-05 00:09:22 +00:00
|
|
|
use error::Error;
|
2018-05-16 18:00:29 +00:00
|
|
|
use handler::{
|
|
|
|
AsyncHandler, AsyncResult, AsyncResultItem, FromRequest, Handler, Responder,
|
|
|
|
RouteHandler, WrapHandler,
|
|
|
|
};
|
2018-03-31 06:07:33 +00:00
|
|
|
use http::StatusCode;
|
2017-12-05 00:09:22 +00:00
|
|
|
use httprequest::HttpRequest;
|
2018-01-10 04:00:18 +00:00
|
|
|
use httpresponse::HttpResponse;
|
2018-05-16 18:00:29 +00:00
|
|
|
use middleware::{
|
|
|
|
Finished as MiddlewareFinished, Middleware, Response as MiddlewareResponse,
|
|
|
|
Started as MiddlewareStarted,
|
|
|
|
};
|
2018-04-13 23:02:01 +00:00
|
|
|
use pred::Predicate;
|
2018-05-09 23:27:31 +00:00
|
|
|
use with::{ExtractorConfig, With, With2, With3, WithAsync};
|
2017-12-05 00:09:22 +00:00
|
|
|
|
|
|
|
/// Resource route definition
|
|
|
|
///
|
|
|
|
/// Route uses builder-like pattern for configuration.
|
|
|
|
/// If handler is not explicitly set, default *404 Not Found* handler is used.
|
|
|
|
pub struct Route<S> {
|
|
|
|
preds: Vec<Box<Predicate<S>>>,
|
2018-01-10 04:00:18 +00:00
|
|
|
handler: InnerHandler<S>,
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> Default for Route<S> {
|
|
|
|
fn default() -> Route<S> {
|
|
|
|
Route {
|
|
|
|
preds: Vec::new(),
|
2018-03-31 06:07:33 +00:00
|
|
|
handler: InnerHandler::new(|_| HttpResponse::new(StatusCode::NOT_FOUND)),
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> Route<S> {
|
2018-01-10 04:00:18 +00:00
|
|
|
#[inline]
|
2017-12-05 00:09:22 +00:00
|
|
|
pub(crate) fn check(&self, req: &mut HttpRequest<S>) -> bool {
|
|
|
|
for pred in &self.preds {
|
|
|
|
if !pred.check(req) {
|
2018-04-13 23:02:01 +00:00
|
|
|
return false;
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2018-01-10 04:00:18 +00:00
|
|
|
#[inline]
|
2018-05-03 23:22:08 +00:00
|
|
|
pub(crate) fn handle(&mut self, req: HttpRequest<S>) -> AsyncResult<HttpResponse> {
|
2017-12-05 00:09:22 +00:00
|
|
|
self.handler.handle(req)
|
|
|
|
}
|
|
|
|
|
2018-01-10 04:00:18 +00:00
|
|
|
#[inline]
|
2018-04-13 23:02:01 +00:00
|
|
|
pub(crate) fn compose(
|
2018-05-16 18:00:29 +00:00
|
|
|
&mut self,
|
|
|
|
req: HttpRequest<S>,
|
|
|
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
2018-05-03 23:22:08 +00:00
|
|
|
) -> AsyncResult<HttpResponse> {
|
|
|
|
AsyncResult::async(Box::new(Compose::new(req, mws, self.handler.clone())))
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
|
2017-12-05 00:32:31 +00:00
|
|
|
/// Add match predicate to route.
|
2017-12-20 06:36:06 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate actix_web;
|
|
|
|
/// # use actix_web::*;
|
|
|
|
/// # fn main() {
|
2018-03-31 07:16:55 +00:00
|
|
|
/// App::new()
|
2017-12-20 06:36:06 +00:00
|
|
|
/// .resource("/path", |r|
|
|
|
|
/// r.route()
|
2018-03-02 02:32:31 +00:00
|
|
|
/// .filter(pred::Get())
|
|
|
|
/// .filter(pred::Header("content-type", "text/plain"))
|
2018-03-31 06:07:33 +00:00
|
|
|
/// .f(|req| HttpResponse::Ok())
|
2017-12-20 06:36:06 +00:00
|
|
|
/// )
|
|
|
|
/// # .finish();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2018-03-02 02:32:31 +00:00
|
|
|
pub fn filter<T: Predicate<S> + 'static>(&mut self, p: T) -> &mut Self {
|
2017-12-20 21:23:50 +00:00
|
|
|
self.preds.push(Box::new(p));
|
2017-12-05 00:09:22 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set handler object. Usually call to this method is last call
|
2018-03-07 22:56:53 +00:00
|
|
|
/// during route configuration, so it does not return reference to self.
|
2017-12-05 00:09:22 +00:00
|
|
|
pub fn h<H: Handler<S>>(&mut self, handler: H) {
|
2018-01-10 04:00:18 +00:00
|
|
|
self.handler = InnerHandler::new(handler);
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set handler function. Usually call to this method is last call
|
2018-03-07 22:56:53 +00:00
|
|
|
/// during route configuration, so it does not return reference to self.
|
2017-12-05 00:09:22 +00:00
|
|
|
pub fn f<F, R>(&mut self, handler: F)
|
2018-04-13 23:02:01 +00:00
|
|
|
where
|
|
|
|
F: Fn(HttpRequest<S>) -> R + 'static,
|
|
|
|
R: Responder + 'static,
|
2017-12-05 00:09:22 +00:00
|
|
|
{
|
2018-01-10 04:00:18 +00:00
|
|
|
self.handler = InnerHandler::new(handler);
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set async handler function.
|
2017-12-20 20:51:39 +00:00
|
|
|
pub fn a<H, R, F, E>(&mut self, handler: H)
|
2018-04-13 23:02:01 +00:00
|
|
|
where
|
|
|
|
H: Fn(HttpRequest<S>) -> F + 'static,
|
|
|
|
F: Future<Item = R, Error = E> + 'static,
|
|
|
|
R: Responder + 'static,
|
|
|
|
E: Into<Error> + 'static,
|
2017-12-05 00:09:22 +00:00
|
|
|
{
|
2018-01-10 04:00:18 +00:00
|
|
|
self.handler = InnerHandler::async(handler);
|
|
|
|
}
|
2018-03-27 06:10:31 +00:00
|
|
|
|
2018-05-06 16:07:30 +00:00
|
|
|
/// Set handler function, use request extractor for parameters.
|
2018-03-27 06:10:31 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate bytes;
|
|
|
|
/// # extern crate actix_web;
|
|
|
|
/// # extern crate futures;
|
|
|
|
/// #[macro_use] extern crate serde_derive;
|
2018-03-31 07:16:55 +00:00
|
|
|
/// use actix_web::{App, Path, Result, http};
|
2018-03-27 06:10:31 +00:00
|
|
|
///
|
|
|
|
/// #[derive(Deserialize)]
|
|
|
|
/// struct Info {
|
|
|
|
/// username: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// /// extract path info using serde
|
2018-03-28 03:33:24 +00:00
|
|
|
/// fn index(info: Path<Info>) -> Result<String> {
|
2018-03-27 06:10:31 +00:00
|
|
|
/// Ok(format!("Welcome {}!", info.username))
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
2018-03-31 07:16:55 +00:00
|
|
|
/// let app = App::new().resource(
|
2018-03-31 00:31:18 +00:00
|
|
|
/// "/{username}/index.html", // <- define path parameters
|
|
|
|
/// |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
|
2018-03-27 06:10:31 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-05-09 23:27:31 +00:00
|
|
|
///
|
|
|
|
/// It is possible to use tuples for specifing multiple extractors for one
|
|
|
|
/// handler function.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate bytes;
|
|
|
|
/// # extern crate actix_web;
|
|
|
|
/// # extern crate futures;
|
|
|
|
/// #[macro_use] extern crate serde_derive;
|
|
|
|
/// # use std::collections::HashMap;
|
|
|
|
/// use actix_web::{http, App, Query, Path, Result, Json};
|
|
|
|
///
|
|
|
|
/// #[derive(Deserialize)]
|
|
|
|
/// struct Info {
|
|
|
|
/// username: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// /// extract path info using serde
|
|
|
|
/// fn index(info: (Path<Info>, Query<HashMap<String, String>>, Json<Info>)) -> Result<String> {
|
|
|
|
/// Ok(format!("Welcome {}!", info.0.username))
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let app = App::new().resource(
|
|
|
|
/// "/{username}/index.html", // <- define path parameters
|
|
|
|
/// |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
|
|
|
|
/// }
|
|
|
|
/// ```
|
2018-04-04 05:06:18 +00:00
|
|
|
pub fn with<T, F, R>(&mut self, handler: F) -> ExtractorConfig<S, T>
|
2018-04-13 23:02:01 +00:00
|
|
|
where
|
|
|
|
F: Fn(T) -> R + 'static,
|
|
|
|
R: Responder + 'static,
|
|
|
|
T: FromRequest<S> + 'static,
|
2018-03-27 06:10:31 +00:00
|
|
|
{
|
2018-04-04 05:06:18 +00:00
|
|
|
let cfg = ExtractorConfig::default();
|
|
|
|
self.h(With::new(handler, Clone::clone(&cfg)));
|
|
|
|
cfg
|
2018-03-27 06:10:31 +00:00
|
|
|
}
|
2018-03-28 21:24:32 +00:00
|
|
|
|
2018-05-09 23:27:31 +00:00
|
|
|
/// Set async handler function, use request extractor for parameters.
|
2018-05-10 20:04:56 +00:00
|
|
|
/// Also this method needs to be used if your handler function returns
|
|
|
|
/// `impl Future<>`
|
2018-05-09 23:27:31 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate bytes;
|
|
|
|
/// # extern crate actix_web;
|
|
|
|
/// # extern crate futures;
|
|
|
|
/// #[macro_use] extern crate serde_derive;
|
|
|
|
/// use actix_web::{App, Path, Error, http};
|
|
|
|
/// use futures::Future;
|
|
|
|
///
|
|
|
|
/// #[derive(Deserialize)]
|
|
|
|
/// struct Info {
|
|
|
|
/// username: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// /// extract path info using serde
|
|
|
|
/// fn index(info: Path<Info>) -> Box<Future<Item=&'static str, Error=Error>> {
|
|
|
|
/// unimplemented!()
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let app = App::new().resource(
|
|
|
|
/// "/{username}/index.html", // <- define path parameters
|
|
|
|
/// |r| r.method(http::Method::GET)
|
|
|
|
/// .with_async(index)); // <- use `with` extractor
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
pub fn with_async<T, F, R, I, E>(&mut self, handler: F) -> ExtractorConfig<S, T>
|
|
|
|
where
|
|
|
|
F: Fn(T) -> R + 'static,
|
|
|
|
R: Future<Item = I, Error = E> + 'static,
|
|
|
|
I: Responder + 'static,
|
|
|
|
E: Into<Error> + 'static,
|
|
|
|
T: FromRequest<S> + 'static,
|
|
|
|
{
|
|
|
|
let cfg = ExtractorConfig::default();
|
|
|
|
self.h(WithAsync::new(handler, Clone::clone(&cfg)));
|
|
|
|
cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2018-05-06 16:07:30 +00:00
|
|
|
/// Set handler function, use request extractor for both parameters.
|
2018-03-28 21:24:32 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # extern crate bytes;
|
|
|
|
/// # extern crate actix_web;
|
|
|
|
/// # extern crate futures;
|
|
|
|
/// #[macro_use] extern crate serde_derive;
|
2018-03-31 07:16:55 +00:00
|
|
|
/// use actix_web::{App, Query, Path, Result, http};
|
2018-03-28 21:24:32 +00:00
|
|
|
///
|
|
|
|
/// #[derive(Deserialize)]
|
|
|
|
/// struct PParam {
|
|
|
|
/// username: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(Deserialize)]
|
|
|
|
/// struct QParam {
|
|
|
|
/// count: u32,
|
|
|
|
/// }
|
|
|
|
///
|
2018-03-29 04:49:50 +00:00
|
|
|
/// /// extract path and query information using serde
|
2018-03-28 21:24:32 +00:00
|
|
|
/// fn index(p: Path<PParam>, q: Query<QParam>) -> Result<String> {
|
|
|
|
/// Ok(format!("Welcome {}!", p.username))
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
2018-03-31 07:16:55 +00:00
|
|
|
/// let app = App::new().resource(
|
2018-03-31 00:31:18 +00:00
|
|
|
/// "/{username}/index.html", // <- define path parameters
|
|
|
|
/// |r| r.method(http::Method::GET).with2(index)); // <- use `with` extractor
|
2018-03-28 21:24:32 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-04-13 23:02:01 +00:00
|
|
|
pub fn with2<T1, T2, F, R>(
|
2018-05-16 18:00:29 +00:00
|
|
|
&mut self,
|
|
|
|
handler: F,
|
2018-04-13 23:02:01 +00:00
|
|
|
) -> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>)
|
|
|
|
where
|
|
|
|
F: Fn(T1, T2) -> R + 'static,
|
|
|
|
R: Responder + 'static,
|
|
|
|
T1: FromRequest<S> + 'static,
|
|
|
|
T2: FromRequest<S> + 'static,
|
2018-03-28 21:24:32 +00:00
|
|
|
{
|
2018-04-04 05:06:18 +00:00
|
|
|
let cfg1 = ExtractorConfig::default();
|
|
|
|
let cfg2 = ExtractorConfig::default();
|
2018-04-29 16:09:08 +00:00
|
|
|
self.h(With2::new(
|
|
|
|
handler,
|
|
|
|
Clone::clone(&cfg1),
|
|
|
|
Clone::clone(&cfg2),
|
|
|
|
));
|
2018-04-04 05:06:18 +00:00
|
|
|
(cfg1, cfg2)
|
2018-03-28 21:24:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 23:27:31 +00:00
|
|
|
#[doc(hidden)]
|
2018-05-06 16:07:30 +00:00
|
|
|
/// Set handler function, use request extractor for all parameters.
|
2018-04-13 23:02:01 +00:00
|
|
|
pub fn with3<T1, T2, T3, F, R>(
|
2018-05-16 18:00:29 +00:00
|
|
|
&mut self,
|
|
|
|
handler: F,
|
2018-04-29 16:09:08 +00:00
|
|
|
) -> (
|
|
|
|
ExtractorConfig<S, T1>,
|
|
|
|
ExtractorConfig<S, T2>,
|
|
|
|
ExtractorConfig<S, T3>,
|
|
|
|
)
|
2018-04-13 23:02:01 +00:00
|
|
|
where
|
|
|
|
F: Fn(T1, T2, T3) -> R + 'static,
|
|
|
|
R: Responder + 'static,
|
|
|
|
T1: FromRequest<S> + 'static,
|
|
|
|
T2: FromRequest<S> + 'static,
|
|
|
|
T3: FromRequest<S> + 'static,
|
2018-03-28 21:24:32 +00:00
|
|
|
{
|
2018-04-04 05:06:18 +00:00
|
|
|
let cfg1 = ExtractorConfig::default();
|
|
|
|
let cfg2 = ExtractorConfig::default();
|
|
|
|
let cfg3 = ExtractorConfig::default();
|
|
|
|
self.h(With3::new(
|
2018-04-13 23:02:01 +00:00
|
|
|
handler,
|
|
|
|
Clone::clone(&cfg1),
|
|
|
|
Clone::clone(&cfg2),
|
|
|
|
Clone::clone(&cfg3),
|
|
|
|
));
|
2018-04-04 05:06:18 +00:00
|
|
|
(cfg1, cfg2, cfg3)
|
2018-03-28 21:24:32 +00:00
|
|
|
}
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
|
2018-04-13 23:02:01 +00:00
|
|
|
/// `RouteHandler` wrapper. This struct is required because it needs to be
|
|
|
|
/// shared for resource level middlewares.
|
2018-04-29 16:09:08 +00:00
|
|
|
struct InnerHandler<S>(Rc<UnsafeCell<Box<RouteHandler<S>>>>);
|
2018-01-10 04:00:18 +00:00
|
|
|
|
|
|
|
impl<S: 'static> InnerHandler<S> {
|
|
|
|
#[inline]
|
|
|
|
fn new<H: Handler<S>>(h: H) -> Self {
|
2018-05-16 18:00:29 +00:00
|
|
|
InnerHandler(Rc::new(UnsafeCell::new(Box::new(WrapHandler::new(h)))))
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn async<H, R, F, E>(h: H) -> Self
|
2018-04-13 23:02:01 +00:00
|
|
|
where
|
|
|
|
H: Fn(HttpRequest<S>) -> F + 'static,
|
|
|
|
F: Future<Item = R, Error = E> + 'static,
|
|
|
|
R: Responder + 'static,
|
|
|
|
E: Into<Error> + 'static,
|
2018-01-10 04:00:18 +00:00
|
|
|
{
|
2018-05-16 18:00:29 +00:00
|
|
|
InnerHandler(Rc::new(UnsafeCell::new(Box::new(AsyncHandler::new(h)))))
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-05-03 23:22:08 +00:00
|
|
|
pub fn handle(&self, req: HttpRequest<S>) -> AsyncResult<HttpResponse> {
|
2018-04-29 16:09:08 +00:00
|
|
|
// reason: handler is unique per thread, handler get called from async code only
|
|
|
|
let h = unsafe { &mut *self.0.as_ref().get() };
|
2018-01-10 04:00:18 +00:00
|
|
|
h.handle(req)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S> Clone for InnerHandler<S> {
|
|
|
|
#[inline]
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
InnerHandler(Rc::clone(&self.0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compose resource level middlewares with route handler.
|
|
|
|
struct Compose<S: 'static> {
|
|
|
|
info: ComposeInfo<S>,
|
|
|
|
state: ComposeState<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ComposeInfo<S: 'static> {
|
|
|
|
count: usize,
|
|
|
|
req: HttpRequest<S>,
|
|
|
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
|
|
|
handler: InnerHandler<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum ComposeState<S: 'static> {
|
|
|
|
Starting(StartMiddlewares<S>),
|
|
|
|
Handler(WaitingResponse<S>),
|
|
|
|
RunMiddlewares(RunMiddlewares<S>),
|
2018-04-30 03:50:38 +00:00
|
|
|
Finishing(FinishingMiddlewares<S>),
|
|
|
|
Completed(Response<S>),
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> ComposeState<S> {
|
|
|
|
fn poll(&mut self, info: &mut ComposeInfo<S>) -> Option<ComposeState<S>> {
|
|
|
|
match *self {
|
|
|
|
ComposeState::Starting(ref mut state) => state.poll(info),
|
|
|
|
ComposeState::Handler(ref mut state) => state.poll(info),
|
|
|
|
ComposeState::RunMiddlewares(ref mut state) => state.poll(info),
|
2018-04-30 03:50:38 +00:00
|
|
|
ComposeState::Finishing(ref mut state) => state.poll(info),
|
|
|
|
ComposeState::Completed(_) => None,
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> Compose<S> {
|
2018-04-13 23:02:01 +00:00
|
|
|
fn new(
|
2018-05-16 18:00:29 +00:00
|
|
|
req: HttpRequest<S>,
|
|
|
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
|
|
|
handler: InnerHandler<S>,
|
2018-04-13 23:02:01 +00:00
|
|
|
) -> Self {
|
|
|
|
let mut info = ComposeInfo {
|
|
|
|
count: 0,
|
|
|
|
req,
|
|
|
|
mws,
|
|
|
|
handler,
|
|
|
|
};
|
2018-01-10 04:00:18 +00:00
|
|
|
let state = StartMiddlewares::init(&mut info);
|
|
|
|
|
2018-04-29 16:09:08 +00:00
|
|
|
Compose { state, info }
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S> Future for Compose<S> {
|
|
|
|
type Item = HttpResponse;
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
|
|
|
loop {
|
2018-04-30 03:50:38 +00:00
|
|
|
if let ComposeState::Completed(ref mut resp) = self.state {
|
2018-01-10 04:00:18 +00:00
|
|
|
let resp = resp.resp.take().unwrap();
|
2018-04-13 23:02:01 +00:00
|
|
|
return Ok(Async::Ready(resp));
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
if let Some(state) = self.state.poll(&mut self.info) {
|
|
|
|
self.state = state;
|
|
|
|
} else {
|
2018-04-13 23:02:01 +00:00
|
|
|
return Ok(Async::NotReady);
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Middlewares start executor
|
|
|
|
struct StartMiddlewares<S> {
|
|
|
|
fut: Option<Fut>,
|
|
|
|
_s: PhantomData<S>,
|
|
|
|
}
|
|
|
|
|
2018-04-13 23:02:01 +00:00
|
|
|
type Fut = Box<Future<Item = Option<HttpResponse>, Error = Error>>;
|
2018-01-10 04:00:18 +00:00
|
|
|
|
|
|
|
impl<S: 'static> StartMiddlewares<S> {
|
|
|
|
fn init(info: &mut ComposeInfo<S>) -> ComposeState<S> {
|
|
|
|
let len = info.mws.len();
|
|
|
|
loop {
|
|
|
|
if info.count == len {
|
|
|
|
let reply = info.handler.handle(info.req.clone());
|
2018-04-13 23:02:01 +00:00
|
|
|
return WaitingResponse::init(info, reply);
|
2018-01-10 04:00:18 +00:00
|
|
|
} else {
|
|
|
|
match info.mws[info.count].start(&mut info.req) {
|
2018-04-13 23:02:01 +00:00
|
|
|
Ok(MiddlewareStarted::Done) => info.count += 1,
|
|
|
|
Ok(MiddlewareStarted::Response(resp)) => {
|
|
|
|
return RunMiddlewares::init(info, resp)
|
|
|
|
}
|
2018-05-07 23:09:41 +00:00
|
|
|
Ok(MiddlewareStarted::Future(fut)) => {
|
|
|
|
return ComposeState::Starting(StartMiddlewares {
|
|
|
|
fut: Some(fut),
|
|
|
|
_s: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
2018-04-30 03:50:38 +00:00
|
|
|
Err(err) => return FinishingMiddlewares::init(info, err.into()),
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-13 23:02:01 +00:00
|
|
|
fn poll(&mut self, info: &mut ComposeInfo<S>) -> Option<ComposeState<S>> {
|
2018-01-10 04:00:18 +00:00
|
|
|
let len = info.mws.len();
|
|
|
|
'outer: loop {
|
|
|
|
match self.fut.as_mut().unwrap().poll() {
|
2018-04-13 23:02:01 +00:00
|
|
|
Ok(Async::NotReady) => return None,
|
2018-01-10 04:00:18 +00:00
|
|
|
Ok(Async::Ready(resp)) => {
|
|
|
|
info.count += 1;
|
|
|
|
if let Some(resp) = resp {
|
|
|
|
return Some(RunMiddlewares::init(info, resp));
|
|
|
|
}
|
2018-05-16 18:00:29 +00:00
|
|
|
loop {
|
|
|
|
if info.count == len {
|
|
|
|
let reply = info.handler.handle(info.req.clone());
|
|
|
|
return Some(WaitingResponse::init(info, reply));
|
|
|
|
} else {
|
2018-01-10 04:00:18 +00:00
|
|
|
match info.mws[info.count].start(&mut info.req) {
|
2018-04-13 23:02:01 +00:00
|
|
|
Ok(MiddlewareStarted::Done) => info.count += 1,
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareStarted::Response(resp)) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
return Some(RunMiddlewares::init(info, resp));
|
2018-04-13 23:02:01 +00:00
|
|
|
}
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareStarted::Future(fut)) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
self.fut = Some(fut);
|
2018-04-13 23:02:01 +00:00
|
|
|
continue 'outer;
|
|
|
|
}
|
2018-04-30 03:50:38 +00:00
|
|
|
Err(err) => {
|
|
|
|
return Some(FinishingMiddlewares::init(
|
|
|
|
info,
|
|
|
|
err.into(),
|
|
|
|
))
|
|
|
|
}
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-30 03:50:38 +00:00
|
|
|
Err(err) => return Some(FinishingMiddlewares::init(info, err.into())),
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// waiting for response
|
|
|
|
struct WaitingResponse<S> {
|
2018-04-13 23:02:01 +00:00
|
|
|
fut: Box<Future<Item = HttpResponse, Error = Error>>,
|
2018-01-10 04:00:18 +00:00
|
|
|
_s: PhantomData<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> WaitingResponse<S> {
|
|
|
|
#[inline]
|
2018-05-03 23:22:08 +00:00
|
|
|
fn init(
|
2018-05-16 18:00:29 +00:00
|
|
|
info: &mut ComposeInfo<S>,
|
|
|
|
reply: AsyncResult<HttpResponse>,
|
2018-05-03 23:22:08 +00:00
|
|
|
) -> ComposeState<S> {
|
2018-01-10 04:00:18 +00:00
|
|
|
match reply.into() {
|
2018-05-03 23:22:08 +00:00
|
|
|
AsyncResultItem::Err(err) => RunMiddlewares::init(info, err.into()),
|
|
|
|
AsyncResultItem::Ok(resp) => RunMiddlewares::init(info, resp),
|
|
|
|
AsyncResultItem::Future(fut) => ComposeState::Handler(WaitingResponse {
|
2018-04-13 23:02:01 +00:00
|
|
|
fut,
|
|
|
|
_s: PhantomData,
|
|
|
|
}),
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll(&mut self, info: &mut ComposeInfo<S>) -> Option<ComposeState<S>> {
|
|
|
|
match self.fut.poll() {
|
|
|
|
Ok(Async::NotReady) => None,
|
2018-04-13 23:02:01 +00:00
|
|
|
Ok(Async::Ready(response)) => Some(RunMiddlewares::init(info, response)),
|
2018-04-18 21:15:53 +00:00
|
|
|
Err(err) => Some(RunMiddlewares::init(info, err.into())),
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Middlewares response executor
|
|
|
|
struct RunMiddlewares<S> {
|
|
|
|
curr: usize,
|
2018-04-13 23:02:01 +00:00
|
|
|
fut: Option<Box<Future<Item = HttpResponse, Error = Error>>>,
|
2018-01-10 04:00:18 +00:00
|
|
|
_s: PhantomData<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> RunMiddlewares<S> {
|
|
|
|
fn init(info: &mut ComposeInfo<S>, mut resp: HttpResponse) -> ComposeState<S> {
|
|
|
|
let mut curr = 0;
|
|
|
|
let len = info.mws.len();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
resp = match info.mws[curr].response(&mut info.req, resp) {
|
2018-01-10 06:48:35 +00:00
|
|
|
Err(err) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
info.count = curr + 1;
|
2018-04-30 03:50:38 +00:00
|
|
|
return FinishingMiddlewares::init(info, err.into());
|
2018-04-13 23:02:01 +00:00
|
|
|
}
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareResponse::Done(r)) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
curr += 1;
|
|
|
|
if curr == len {
|
2018-04-30 03:50:38 +00:00
|
|
|
return FinishingMiddlewares::init(info, r);
|
2018-01-10 04:00:18 +00:00
|
|
|
} else {
|
|
|
|
r
|
|
|
|
}
|
2018-04-13 23:02:01 +00:00
|
|
|
}
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareResponse::Future(fut)) => {
|
2018-04-13 23:02:01 +00:00
|
|
|
return ComposeState::RunMiddlewares(RunMiddlewares {
|
|
|
|
curr,
|
|
|
|
fut: Some(fut),
|
|
|
|
_s: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
2018-01-10 04:00:18 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2018-04-13 23:02:01 +00:00
|
|
|
|
|
|
|
fn poll(&mut self, info: &mut ComposeInfo<S>) -> Option<ComposeState<S>> {
|
2018-01-10 04:00:18 +00:00
|
|
|
let len = info.mws.len();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
// poll latest fut
|
|
|
|
let mut resp = match self.fut.as_mut().unwrap().poll() {
|
2018-04-13 23:02:01 +00:00
|
|
|
Ok(Async::NotReady) => return None,
|
2018-01-10 04:00:18 +00:00
|
|
|
Ok(Async::Ready(resp)) => {
|
|
|
|
self.curr += 1;
|
|
|
|
resp
|
|
|
|
}
|
2018-04-30 03:50:38 +00:00
|
|
|
Err(err) => return Some(FinishingMiddlewares::init(info, err.into())),
|
2018-01-10 04:00:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if self.curr == len {
|
2018-04-30 03:50:38 +00:00
|
|
|
return Some(FinishingMiddlewares::init(info, resp));
|
2018-01-10 04:00:18 +00:00
|
|
|
} else {
|
|
|
|
match info.mws[self.curr].response(&mut info.req, resp) {
|
2018-04-30 03:50:38 +00:00
|
|
|
Err(err) => {
|
|
|
|
return Some(FinishingMiddlewares::init(info, err.into()))
|
|
|
|
}
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareResponse::Done(r)) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
self.curr += 1;
|
|
|
|
resp = r
|
2018-04-13 23:02:01 +00:00
|
|
|
}
|
2018-01-10 06:48:35 +00:00
|
|
|
Ok(MiddlewareResponse::Future(fut)) => {
|
2018-01-10 04:00:18 +00:00
|
|
|
self.fut = Some(fut);
|
2018-04-13 23:02:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-01-10 04:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 03:50:38 +00:00
|
|
|
/// Middlewares start executor
|
|
|
|
struct FinishingMiddlewares<S> {
|
|
|
|
resp: Option<HttpResponse>,
|
|
|
|
fut: Option<Box<Future<Item = (), Error = Error>>>,
|
|
|
|
_s: PhantomData<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> FinishingMiddlewares<S> {
|
|
|
|
fn init(info: &mut ComposeInfo<S>, resp: HttpResponse) -> ComposeState<S> {
|
|
|
|
if info.count == 0 {
|
|
|
|
Response::init(resp)
|
|
|
|
} else {
|
|
|
|
let mut state = FinishingMiddlewares {
|
|
|
|
resp: Some(resp),
|
|
|
|
fut: None,
|
|
|
|
_s: PhantomData,
|
|
|
|
};
|
|
|
|
if let Some(st) = state.poll(info) {
|
|
|
|
st
|
|
|
|
} else {
|
|
|
|
ComposeState::Finishing(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll(&mut self, info: &mut ComposeInfo<S>) -> Option<ComposeState<S>> {
|
|
|
|
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 None;
|
|
|
|
}
|
|
|
|
self.fut = None;
|
2018-05-05 19:18:43 +00:00
|
|
|
if info.count == 0 {
|
|
|
|
return Some(Response::init(self.resp.take().unwrap()));
|
|
|
|
}
|
2018-04-30 03:50:38 +00:00
|
|
|
|
2018-05-05 19:18:43 +00:00
|
|
|
info.count -= 1;
|
2018-04-30 03:50:38 +00:00
|
|
|
match info.mws[info.count as usize]
|
|
|
|
.finish(&mut info.req, self.resp.as_ref().unwrap())
|
|
|
|
{
|
|
|
|
MiddlewareFinished::Done => {
|
|
|
|
if info.count == 0 {
|
|
|
|
return Some(Response::init(self.resp.take().unwrap()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MiddlewareFinished::Future(fut) => {
|
|
|
|
self.fut = Some(fut);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-10 04:00:18 +00:00
|
|
|
struct Response<S> {
|
|
|
|
resp: Option<HttpResponse>,
|
|
|
|
_s: PhantomData<S>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: 'static> Response<S> {
|
|
|
|
fn init(resp: HttpResponse) -> ComposeState<S> {
|
2018-04-30 03:50:38 +00:00
|
|
|
ComposeState::Completed(Response {
|
2018-04-13 23:02:01 +00:00
|
|
|
resp: Some(resp),
|
|
|
|
_s: PhantomData,
|
|
|
|
})
|
2017-12-05 00:09:22 +00:00
|
|
|
}
|
|
|
|
}
|