mirror of
https://github.com/actix/actix-web.git
synced 2025-02-19 20:36:16 +00:00
Simplify handler (#1843)
This commit is contained in:
parent
2a7f2c1d59
commit
3a192400a6
2 changed files with 63 additions and 130 deletions
184
src/handler.rs
184
src/handler.rs
|
@ -1,4 +1,3 @@
|
||||||
use std::convert::Infallible;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
@ -6,7 +5,7 @@ use std::task::{Context, Poll};
|
||||||
|
|
||||||
use actix_http::{Error, Response};
|
use actix_http::{Error, Response};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_util::future::{ok, Ready};
|
use futures_util::future::{ready, Ready};
|
||||||
use futures_util::ready;
|
use futures_util::ready;
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
|
|
||||||
|
@ -36,9 +35,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
/// Extract arguments from request, run factory function and make response.
|
||||||
pub struct Handler<F, T, R, O>
|
pub struct Handler<F, T, R, O>
|
||||||
where
|
where
|
||||||
F: Factory<T, R, O>,
|
F: Factory<T, R, O>,
|
||||||
|
T: FromRequest,
|
||||||
R: Future<Output = O>,
|
R: Future<Output = O>,
|
||||||
O: Responder,
|
O: Responder,
|
||||||
{
|
{
|
||||||
|
@ -49,6 +50,7 @@ where
|
||||||
impl<F, T, R, O> Handler<F, T, R, O>
|
impl<F, T, R, O> Handler<F, T, R, O>
|
||||||
where
|
where
|
||||||
F: Factory<T, R, O>,
|
F: Factory<T, R, O>,
|
||||||
|
T: FromRequest,
|
||||||
R: Future<Output = O>,
|
R: Future<Output = O>,
|
||||||
O: Responder,
|
O: Responder,
|
||||||
{
|
{
|
||||||
|
@ -63,6 +65,7 @@ where
|
||||||
impl<F, T, R, O> Clone for Handler<F, T, R, O>
|
impl<F, T, R, O> Clone for Handler<F, T, R, O>
|
||||||
where
|
where
|
||||||
F: Factory<T, R, O>,
|
F: Factory<T, R, O>,
|
||||||
|
T: FromRequest,
|
||||||
R: Future<Output = O>,
|
R: Future<Output = O>,
|
||||||
O: Responder,
|
O: Responder,
|
||||||
{
|
{
|
||||||
|
@ -74,172 +77,103 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, T, R, O> Service for Handler<F, T, R, O>
|
impl<F, T, R, O> ServiceFactory for Handler<F, T, R, O>
|
||||||
where
|
where
|
||||||
F: Factory<T, R, O>,
|
F: Factory<T, R, O>,
|
||||||
|
T: FromRequest,
|
||||||
R: Future<Output = O>,
|
R: Future<Output = O>,
|
||||||
O: Responder,
|
O: Responder,
|
||||||
{
|
|
||||||
type Request = (T, HttpRequest);
|
|
||||||
type Response = ServiceResponse;
|
|
||||||
type Error = Infallible;
|
|
||||||
type Future = HandlerServiceResponse<R, O>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, (param, req): (T, HttpRequest)) -> Self::Future {
|
|
||||||
let fut = self.hnd.call(param);
|
|
||||||
HandlerServiceResponse::Future(fut, Some(req))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[pin_project(project = HandlerProj)]
|
|
||||||
pub enum HandlerServiceResponse<T, R>
|
|
||||||
where
|
|
||||||
T: Future<Output = R>,
|
|
||||||
R: Responder,
|
|
||||||
{
|
|
||||||
Future(#[pin] T, Option<HttpRequest>),
|
|
||||||
Responder(#[pin] R::Future, Option<HttpRequest>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, R> Future for HandlerServiceResponse<T, R>
|
|
||||||
where
|
|
||||||
T: Future<Output = R>,
|
|
||||||
R: Responder,
|
|
||||||
{
|
|
||||||
type Output = Result<ServiceResponse, Infallible>;
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
loop {
|
|
||||||
match self.as_mut().project() {
|
|
||||||
HandlerProj::Future(fut, req) => {
|
|
||||||
let res = ready!(fut.poll(cx));
|
|
||||||
let fut = res.respond_to(req.as_ref().unwrap());
|
|
||||||
let state = HandlerServiceResponse::Responder(fut, req.take());
|
|
||||||
self.as_mut().set(state);
|
|
||||||
}
|
|
||||||
HandlerProj::Responder(fut, req) => {
|
|
||||||
let res = ready!(fut.poll(cx));
|
|
||||||
let req = req.take().unwrap();
|
|
||||||
return match res {
|
|
||||||
Ok(res) => Poll::Ready(Ok(ServiceResponse::new(req, res))),
|
|
||||||
Err(e) => {
|
|
||||||
let res: Response = e.into().into();
|
|
||||||
Poll::Ready(Ok(ServiceResponse::new(req, res)))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract arguments from request
|
|
||||||
pub struct Extract<T: FromRequest, S> {
|
|
||||||
service: S,
|
|
||||||
_t: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: FromRequest, S> Extract<T, S> {
|
|
||||||
pub fn new(service: S) -> Self {
|
|
||||||
Extract {
|
|
||||||
service,
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: FromRequest, S> ServiceFactory for Extract<T, S>
|
|
||||||
where
|
|
||||||
S: Service<
|
|
||||||
Request = (T, HttpRequest),
|
|
||||||
Response = ServiceResponse,
|
|
||||||
Error = Infallible,
|
|
||||||
> + Clone,
|
|
||||||
{
|
{
|
||||||
type Request = ServiceRequest;
|
type Request = ServiceRequest;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = ExtractService<T, S>;
|
type Service = Self;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, ()>>;
|
type Future = Ready<Result<Self::Service, ()>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ok(ExtractService {
|
ready(Ok(self.clone()))
|
||||||
_t: PhantomData,
|
|
||||||
service: self.service.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtractService<T: FromRequest, S> {
|
// Handler is both it's ServiceFactory and Service Type.
|
||||||
service: S,
|
impl<F, T, R, O> Service for Handler<F, T, R, O>
|
||||||
_t: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: FromRequest, S> Service for ExtractService<T, S>
|
|
||||||
where
|
where
|
||||||
S: Service<
|
F: Factory<T, R, O>,
|
||||||
Request = (T, HttpRequest),
|
T: FromRequest,
|
||||||
Response = ServiceResponse,
|
R: Future<Output = O>,
|
||||||
Error = Infallible,
|
O: Responder,
|
||||||
> + Clone,
|
|
||||||
{
|
{
|
||||||
type Request = ServiceRequest;
|
type Request = ServiceRequest;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = ExtractResponse<T, S>;
|
type Future = HandlerServiceFuture<F, T, R, O>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
let (req, mut payload) = req.into_parts();
|
let (req, mut payload) = req.into_parts();
|
||||||
let fut = T::from_request(&req, &mut payload);
|
let fut = T::from_request(&req, &mut payload);
|
||||||
ExtractResponse::Future(fut, Some(req), self.service.clone())
|
HandlerServiceFuture::Extract(fut, Some(req), self.hnd.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project(project = ExtractProj)]
|
#[doc(hidden)]
|
||||||
pub enum ExtractResponse<T: FromRequest, S: Service> {
|
#[pin_project(project = HandlerProj)]
|
||||||
Future(#[pin] T::Future, Option<HttpRequest>, S),
|
pub enum HandlerServiceFuture<F, T, R, O>
|
||||||
Response(#[pin] S::Future),
|
where
|
||||||
|
F: Factory<T, R, O>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future<Output = O>,
|
||||||
|
O: Responder,
|
||||||
|
{
|
||||||
|
Extract(#[pin] T::Future, Option<HttpRequest>, F),
|
||||||
|
Handle(#[pin] R, Option<HttpRequest>),
|
||||||
|
Respond(#[pin] O::Future, Option<HttpRequest>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromRequest, S> Future for ExtractResponse<T, S>
|
impl<F, T, R, O> Future for HandlerServiceFuture<F, T, R, O>
|
||||||
where
|
where
|
||||||
S: Service<
|
F: Factory<T, R, O>,
|
||||||
Request = (T, HttpRequest),
|
T: FromRequest,
|
||||||
Response = ServiceResponse,
|
R: Future<Output = O>,
|
||||||
Error = Infallible,
|
O: Responder,
|
||||||
>,
|
|
||||||
{
|
{
|
||||||
|
// Error type in this future is a placeholder type.
|
||||||
|
// all instances of error must be converted to ServiceResponse and return in Ok.
|
||||||
type Output = Result<ServiceResponse, Error>;
|
type Output = Result<ServiceResponse, Error>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
loop {
|
loop {
|
||||||
match self.as_mut().project() {
|
match self.as_mut().project() {
|
||||||
ExtractProj::Future(fut, req, srv) => {
|
HandlerProj::Extract(fut, req, handle) => {
|
||||||
let res = ready!(fut.poll(cx));
|
match ready!(fut.poll(cx)) {
|
||||||
let req = req.take().unwrap();
|
|
||||||
match res {
|
|
||||||
Err(e) => {
|
|
||||||
let req = ServiceRequest::new(req);
|
|
||||||
return Poll::Ready(Ok(req.error_response(e.into())));
|
|
||||||
}
|
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
let fut = srv.call((item, req));
|
let fut = handle.call(item);
|
||||||
self.as_mut().set(ExtractResponse::Response(fut));
|
let state = HandlerServiceFuture::Handle(fut, req.take());
|
||||||
|
self.as_mut().set(state);
|
||||||
}
|
}
|
||||||
}
|
Err(e) => {
|
||||||
|
let res: Response = e.into().into();
|
||||||
|
let req = req.take().unwrap();
|
||||||
|
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
HandlerProj::Handle(fut, req) => {
|
||||||
|
let res = ready!(fut.poll(cx));
|
||||||
|
let fut = res.respond_to(req.as_ref().unwrap());
|
||||||
|
let state = HandlerServiceFuture::Respond(fut, req.take());
|
||||||
|
self.as_mut().set(state);
|
||||||
|
}
|
||||||
|
HandlerProj::Respond(fut, req) => {
|
||||||
|
let res = ready!(fut.poll(cx)).unwrap_or_else(|e| e.into().into());
|
||||||
|
let req = req.take().unwrap();
|
||||||
|
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
||||||
}
|
}
|
||||||
ExtractProj::Response(fut) => return fut.poll(cx).map_err(|_| panic!()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use futures_util::future::{ready, FutureExt, LocalBoxFuture};
|
||||||
|
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::guard::{self, Guard};
|
use crate::guard::{self, Guard};
|
||||||
use crate::handler::{Extract, Factory, Handler};
|
use crate::handler::{Factory, Handler};
|
||||||
use crate::responder::Responder;
|
use crate::responder::Responder;
|
||||||
use crate::service::{ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::HttpResponse;
|
use crate::HttpResponse;
|
||||||
|
@ -51,9 +51,9 @@ impl Route {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Route {
|
pub fn new() -> Route {
|
||||||
Route {
|
Route {
|
||||||
service: Box::new(RouteNewService::new(Extract::new(Handler::new(|| {
|
service: Box::new(RouteNewService::new(Handler::new(|| {
|
||||||
ready(HttpResponse::NotFound())
|
ready(HttpResponse::NotFound())
|
||||||
})))),
|
}))),
|
||||||
guards: Rc::new(Vec::new()),
|
guards: Rc::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,8 +226,7 @@ impl Route {
|
||||||
R: Future<Output = U> + 'static,
|
R: Future<Output = U> + 'static,
|
||||||
U: Responder + 'static,
|
U: Responder + 'static,
|
||||||
{
|
{
|
||||||
self.service =
|
self.service = Box::new(RouteNewService::new(Handler::new(handler)));
|
||||||
Box::new(RouteNewService::new(Extract::new(Handler::new(handler))));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue