refactor FromRequest trait

This commit is contained in:
Nikolay Kim 2022-02-09 05:37:05 +06:00
parent 0886f27082
commit 52cb7d4219
30 changed files with 655 additions and 724 deletions

View file

@ -2,12 +2,12 @@ use ntex::http;
use ntex::web::{self, middleware, App, HttpRequest, HttpResponse, HttpServer}; use ntex::web::{self, middleware, App, HttpRequest, HttpResponse, HttpServer};
#[web::get("/resource1/{name}/index.html")] #[web::get("/resource1/{name}/index.html")]
async fn index(req: HttpRequest, name: web::types::Path<String>) -> String { async fn index(req: &HttpRequest, name: web::types::Path<String>) -> String {
println!("REQ: {:?}", req); println!("REQ: {:?}", req);
format!("Hello: {}!\r\n", name) format!("Hello: {}!\r\n", name)
} }
async fn index_async(req: HttpRequest) -> &'static str { async fn index_async(req: &HttpRequest) -> &'static str {
println!("REQ: {:?}", req); println!("REQ: {:?}", req);
"Hello world!\r\n" "Hello world!\r\n"
} }

View file

@ -234,6 +234,12 @@ impl<B> Response<B> {
} }
} }
impl<B: MessageBody> fmt::Display for Response<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self)
}
}
impl<B: MessageBody> fmt::Debug for Response<B> { impl<B: MessageBody> fmt::Debug for Response<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = writeln!( let res = writeln!(

View file

@ -2,15 +2,14 @@ use std::{cell::RefCell, convert::Infallible, fmt, future::Future, pin::Pin, rc:
use crate::http::Request; use crate::http::Request;
use crate::router::ResourceDef; use crate::router::ResourceDef;
use crate::service::{map_config, pipeline_factory, PipelineFactory}; use crate::service::map_config;
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform}; use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
use crate::util::Extensions; use crate::util::Extensions;
use super::app_service::{ use super::app_service::{AppFactory, AppFactoryInner, AppRouting, DefaultService};
AppFactory, AppFactoryInner, AppRouting, AppService, DefaultService,
};
use super::boxed::{self, BoxServiceFactory}; use super::boxed::{self, BoxServiceFactory};
use super::config::{AppConfig, ServiceConfig}; use super::config::{AppConfig, ServiceConfig};
use super::error::Error;
use super::service::{create_web_service, WebService, WebServiceWrapper}; use super::service::{create_web_service, WebService, WebServiceWrapper};
use super::stack::{Filter, Filters, FiltersFactory, Next, Stack}; use super::stack::{Filter, Filters, FiltersFactory, Next, Stack};
use super::types::state::{State, StateFactory}; use super::types::state::{State, StateFactory};
@ -267,18 +266,15 @@ where
pub fn default<T, U>(mut self, f: T) -> Self pub fn default<T, U>(mut self, f: T) -> Self
where where
T: IntoServiceFactory<U, &'a mut WebRequest<'a, Err>>, T: IntoServiceFactory<U, &'a mut WebRequest<'a, Err>>,
U: ServiceFactory< U: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static,
&'a mut WebRequest<'a, Err>,
Response = WebResponse,
Error = Err::Container,
> + 'static,
U::Service: 'static, U::Service: 'static,
U::Future: 'static, U::Future: 'static,
U::Error: Error<Err>,
U::InitError: fmt::Debug + 'static, U::InitError: fmt::Debug + 'static,
{ {
// create and configure default resource // create and configure default resource
self.default = self.default =
boxed::factory::<'a, _, _>(f.into_factory().map_init_err(|e| { boxed::factory(f.into_factory().map_init_err(|e| {
log::error!("Cannot construct default service: {:?}", e) log::error!("Cannot construct default service: {:?}", e)
})); }));
@ -343,9 +339,9 @@ where
/// .route("/index.html", web::get().to(index)); /// .route("/index.html", web::get().to(index));
/// } /// }
/// ``` /// ```
pub fn filter<U>(self, filter: U) -> App<'a, M, Filters<F, U>, Err> { pub fn filter<U>(self, filter: U) -> App<'a, M, Filters<F, Next<U>>, Err> {
App { App {
filter: Filters::new(self.filter, filter), filter: Filters::new(self.filter, Next::new(filter)),
middleware: self.middleware, middleware: self.middleware,
state: self.state, state: self.state,
state_factories: self.state_factories, state_factories: self.state_factories,

View file

@ -4,20 +4,15 @@ use std::{cell::RefCell, future::Future, marker::PhantomData, pin::Pin, rc::Rc};
use crate::http::{Request, Response}; use crate::http::{Request, Response};
use crate::router::{Path, ResourceDef, Router}; use crate::router::{Path, ResourceDef, Router};
use crate::service::{ use crate::service::{Service, ServiceFactory, Transform};
fn_service, into_service, PipelineFactory, Service, ServiceFactory, Transform, use crate::util::{ready, Either, Extensions, Ready};
};
use crate::util::{ready, Extensions, Ready};
use super::boxed::{self, BoxService, BoxServiceFactory}; use super::boxed::{BoxService, BoxServiceFactory};
use super::config::AppConfig;
use super::guard::Guard;
use super::httprequest::{HttpRequest, HttpRequestPool}; use super::httprequest::{HttpRequest, HttpRequestPool};
use super::rmap::ResourceMap; use super::service::{WebServiceConfig, WebServiceWrapper};
use super::service::{WebService, WebServiceConfig, WebServiceWrapper};
use super::stack::{Filter, FiltersFactory, Next};
use super::types::state::StateFactory; use super::types::state::StateFactory;
use super::{ErrorContainer, ErrorRenderer, WebRequest, WebResponse}; use super::{config::AppConfig, guard::Guard, rmap::ResourceMap, stack::FiltersFactory};
use super::{ErrorRenderer, WebRequest, WebResponse};
type Guards = Vec<Box<dyn Guard>>; type Guards = Vec<Box<dyn Guard>>;
type BoxResponse<'a> = Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>; type BoxResponse<'a> = Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>;
@ -153,19 +148,19 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for DefaultService<Err> for DefaultService<Err>
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = Self; type Service = Self;
type Future = Ready<Self::Service, Self::InitError>; type Future = Ready<Self::Service, Self::InitError>;
fn new_service(&self, cfg: ()) -> Self::Future { fn new_service(&self, _: ()) -> Self::Future {
Ready::Ok(DefaultService(PhantomData)) Ready::Ok(DefaultService(PhantomData))
} }
} }
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService<Err> { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService<Err> {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = Ready<Self::Response, Self::Error>; type Future = Ready<Self::Response, Self::Error>;
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@ -280,36 +275,46 @@ where
let hnd: WebAppHandler2<'a> = Box::new(move |req: Request| { let hnd: WebAppHandler2<'a> = Box::new(move |req: Request| {
let (head, payload) = req.into_parts(); let (head, payload) = req.into_parts();
let mut req = if let Some(mut req) = pool.get_request() { let http_req;
let inner = Rc::get_mut(&mut req.0).unwrap(); let mut web_req = if let Some(mut req) = pool.get_request() {
inner.path.set(head.uri.clone()); req.request.path.set(head.uri.clone());
inner.head = head; req.request.head = head;
inner.payload = payload; req.payload = payload;
inner.app_state = state.clone(); req.request.app_state = state.clone();
req let web_req = WebRequest::<Err>::new(unsafe {
std::mem::transmute(&mut *req)
});
http_req = Either::Left(req);
web_req
} else { } else {
HttpRequest::new( let mut req = HttpRequest::create(
Path::new(head.uri.clone()), Path::new(head.uri.clone()),
head, head,
payload, payload,
rmap.clone(), rmap.clone(),
config.clone(), config.clone(),
state.clone(), state.clone(),
pool, );
) let web_req = WebRequest::<Err>::new(unsafe {
std::mem::transmute(&mut req)
});
http_req = Either::Right(req);
web_req
}; };
let mut wreq = let fut = service.call(unsafe { std::mem::transmute(&mut web_req) });
WebRequest::<Err>::new(unsafe { std::mem::transmute(&mut req) });
let fut = service.call(unsafe { std::mem::transmute(&mut wreq) });
Box::pin(async move { Box::pin(async move {
let mut res = fut.await.unwrap(); let mut res = fut.await.unwrap();
let head = req.head(); let head = web_req.head();
if head.upgrade() { if head.upgrade() {
res.response.head_mut().set_io(head); res.response.head_mut().set_io(head);
} }
drop(wreq); drop(web_req);
drop(req);
match http_req {
Either::Left(req) => pool.release_boxed(req),
Either::Right(req) => pool.release_unboxed(req),
}
Ok(res) Ok(res)
}) })
}); });
@ -335,7 +340,7 @@ where
F: Service< F: Service<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
>, >,
F::Future: 'a, F::Future: 'a,
Err: ErrorRenderer, Err: ErrorRenderer,
@ -350,7 +355,7 @@ where
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&self, mut req: &'a mut WebRequest<'a, Err>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future {
let r1 = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }; let r1 = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() };
let r2 = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }; let r2 = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() };
@ -358,10 +363,7 @@ where
let router = self.router.clone(); let router = self.router.clone();
Box::pin(async move { Box::pin(async move {
match fut.await { let _ = fut.await.unwrap();
Ok(res) => (),
Err(err) => return Ok(WebResponse::new(err.error_response(&req.req))),
}
let res = router.router.recognize_checked(req, |req, guards| { let res = router.router.recognize_checked(req, |req, guards| {
if let Some(guards) = guards { if let Some(guards) = guards {
@ -375,15 +377,9 @@ where
}); });
if let Some((srv, _info)) = res { if let Some((srv, _info)) = res {
match srv.call(r2).await { srv.call(r2).await
Ok(res) => Ok(res),
Err(err) => Ok(WebResponse::new(err.error_response(&req.req))),
}
} else if let Some(ref default) = router.default { } else if let Some(ref default) = router.default {
match default.call(r2).await { default.call(r2).await
Ok(res) => Ok(res),
Err(err) => Ok(WebResponse::new(err.error_response(&req.req))),
}
} else { } else {
Ok(WebResponse::new(Response::NotFound().finish())) Ok(WebResponse::new(Response::NotFound().finish()))
} }

View file

@ -1,39 +1,37 @@
use std::{ use std::convert::Infallible;
future::Future, marker::PhantomData, pin::Pin, rc::Rc, task::Context, task::Poll, use std::{future::Future, marker::PhantomData, pin::Pin, task::Context, task::Poll};
};
use super::{ErrorRenderer, WebRequest, WebResponse};
use crate::service::{Service, ServiceFactory}; use crate::service::{Service, ServiceFactory};
pub type BoxFuture<'a, Err: ErrorRenderer> = use super::stack::Next;
Pin<Box<dyn Future<Output = Result<WebResponse, Err::Container>> + 'a>>; use super::{Error, ErrorRenderer, WebRequest, WebResponse};
pub type BoxFactoryFuture<'a, Err: ErrorRenderer> = pub(super) type BoxFuture<'a> =
Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>;
pub(super) type BoxFactoryFuture<'a, Err: ErrorRenderer> =
Pin<Box<dyn Future<Output = Result<BoxService<'a, Err>, ()>>>>; Pin<Box<dyn Future<Output = Result<BoxService<'a, Err>, ()>>>>;
pub type BoxService<'a, Err: ErrorRenderer> = Box< pub(super) type BoxService<'a, Err: ErrorRenderer> = Box<
dyn Service< dyn Service<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = WebResponse, Response = WebResponse,
Error = Err::Container, Error = Infallible,
Future = BoxFuture<'a, Err>, Future = BoxFuture<'a>,
> + 'static, > + 'static,
>; >;
pub struct BoxServiceFactory<'a, Err: ErrorRenderer>(Inner<'a, Err>); pub struct BoxServiceFactory<'a, Err: ErrorRenderer>(Inner<'a, Err>);
/// Create boxed service factory /// Create boxed service factory
pub fn factory<'a, T, Err>(factory: T) -> BoxServiceFactory<'a, Err> pub(super) fn factory<'a, T, Err>(factory: T) -> BoxServiceFactory<'a, Err>
where where
Err: ErrorRenderer, Err: ErrorRenderer,
T: ServiceFactory< T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()>
&'a mut WebRequest<'a, Err>, + 'static,
Response = WebResponse,
Error = Err::Container,
InitError = (),
> + 'static,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
T::Error: Error<Err>,
<T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a, <T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
{ {
BoxServiceFactory(FactoryWrapper::boxed(factory)) BoxServiceFactory(FactoryWrapper::boxed(factory))
@ -43,7 +41,7 @@ type Inner<'a, Err: ErrorRenderer + 'static> = Box<
dyn ServiceFactory< dyn ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = WebResponse, Response = WebResponse,
Error = Err::Container, Error = Infallible,
InitError = (), InitError = (),
Service = BoxService<'a, Err>, Service = BoxService<'a, Err>,
Future = BoxFactoryFuture<'a, Err>, Future = BoxFactoryFuture<'a, Err>,
@ -54,7 +52,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for BoxServiceFactory<'a, Err> for BoxServiceFactory<'a, Err>
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = BoxService<'a, Err>; type Service = BoxService<'a, Err>;
type Future = BoxFactoryFuture<'a, Err>; type Future = BoxFactoryFuture<'a, Err>;
@ -72,14 +70,11 @@ struct FactoryWrapper<T, Err> {
impl<'a, T, Err> FactoryWrapper<T, Err> impl<'a, T, Err> FactoryWrapper<T, Err>
where where
Err: ErrorRenderer + 'static, Err: ErrorRenderer + 'static,
T: ServiceFactory< T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()>
&'a mut WebRequest<'a, Err>, + 'static,
Response = WebResponse,
Error = Err::Container,
InitError = (),
> + 'static,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
T::Error: Error<Err>,
<T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a, <T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
{ {
fn boxed(factory: T) -> Inner<'a, Err> { fn boxed(factory: T) -> Inner<'a, Err> {
@ -93,18 +88,15 @@ where
impl<'a, T, Err> ServiceFactory<&'a mut WebRequest<'a, Err>> for FactoryWrapper<T, Err> impl<'a, T, Err> ServiceFactory<&'a mut WebRequest<'a, Err>> for FactoryWrapper<T, Err>
where where
Err: ErrorRenderer + 'static, Err: ErrorRenderer + 'static,
T: ServiceFactory< T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()>
&'a mut WebRequest<'a, Err>, + 'static,
Response = WebResponse,
Error = Err::Container,
InitError = (),
> + 'static,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
T::Error: Error<Err>,
<T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a, <T::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = BoxService<'a, Err>; type Service = BoxService<'a, Err>;
type Future = BoxFactoryFuture<'a, Err>; type Future = BoxFactoryFuture<'a, Err>;
@ -118,30 +110,30 @@ where
} }
} }
struct ServiceWrapper<T, Err>(T, PhantomData<Err>); struct ServiceWrapper<T, Err>(Next<T>, PhantomData<Err>);
impl<'a, T, Err> ServiceWrapper<T, Err> impl<'a, T, Err> ServiceWrapper<T, Err>
where where
Err: ErrorRenderer, Err: ErrorRenderer,
T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static,
+ 'static,
T::Future: 'a, T::Future: 'a,
T::Error: Error<Err>,
{ {
fn boxed(service: T) -> BoxService<'a, Err> { fn boxed(service: T) -> BoxService<'a, Err> {
Box::new(ServiceWrapper(service, PhantomData)) Box::new(ServiceWrapper(Next::new(service), PhantomData))
} }
} }
impl<'a, T, Err> Service<&'a mut WebRequest<'a, Err>> for ServiceWrapper<T, Err> impl<'a, T, Err> Service<&'a mut WebRequest<'a, Err>> for ServiceWrapper<T, Err>
where where
Err: ErrorRenderer, Err: ErrorRenderer,
T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static,
+ 'static,
T::Future: 'a, T::Future: 'a,
T::Error: Error<Err>,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = BoxFuture<'a, Err>; type Future = BoxFuture<'a>;
#[inline] #[inline]
fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {

View file

@ -2,11 +2,10 @@ use std::{net::SocketAddr, rc::Rc};
use crate::router::ResourceDef; use crate::router::ResourceDef;
use super::resource::Resource;
use super::route::Route; use super::route::Route;
use super::service::{create_web_service, WebService, WebServiceWrapper}; use super::service::{create_web_service, WebService, WebServiceWrapper};
use super::types::state::{State, StateFactory}; use super::types::state::{State, StateFactory};
use super::{DefaultError, ErrorRenderer}; use super::{DefaultError, ErrorRenderer, Resource};
/// Application configuration /// Application configuration
#[derive(Clone)] #[derive(Clone)]
@ -87,12 +86,11 @@ impl<'a, Err: ErrorRenderer> ServiceConfig<'a, Err> {
/// ///
/// This is same as `App::route()` method. /// This is same as `App::route()` method.
pub fn route(&mut self, path: &str, mut route: Route<Err>) -> &mut Self { pub fn route(&mut self, path: &str, mut route: Route<Err>) -> &mut Self {
// self.service( self.service(
// Resource::new(path) Resource::new(path)
// .add_guards(route.take_guards()) .add_guards(route.take_guards())
// .route(route), .route(route),
// ) )
self
} }
/// Register http service. /// Register http service.

View file

@ -8,30 +8,19 @@ pub use serde_json::error::Error as JsonError;
#[cfg(feature = "url")] #[cfg(feature = "url")]
pub use url_pkg::ParseError as UrlParseError; pub use url_pkg::ParseError as UrlParseError;
use super::{HttpRequest, HttpResponse}; use super::{HttpRequest, HttpResponse, WebResponse};
use crate::http::body::Body; use crate::http::body::Body;
use crate::http::helpers::Writer; use crate::http::helpers::Writer;
use crate::http::{error, header, StatusCode}; use crate::http::{error, header, StatusCode};
use crate::util::{BytesMut, Either}; use crate::util::{BytesMut, Either};
pub use super::error_default::{DefaultError, Error}; pub use super::error_default::DefaultError;
pub use crate::http::error::BlockingError; pub use crate::http::error::BlockingError;
pub trait ErrorRenderer: Sized + 'static { pub trait ErrorRenderer: Sized + 'static {}
type Container: ErrorContainer;
}
pub trait ErrorContainer: error::ResponseError + Sized {
/// Generate response for error container
fn error_response(&self, req: &HttpRequest) -> HttpResponse;
}
/// Error that can be rendered to a `Response` /// Error that can be rendered to a `Response`
pub trait WebResponseError<Err = DefaultError>: pub trait Error<Err = DefaultError>: fmt::Display + fmt::Debug + Sized {
fmt::Display + fmt::Debug + 'static
where
Err: ErrorRenderer,
{
/// Response's status code /// Response's status code
/// ///
/// Internal server error is generated by default. /// Internal server error is generated by default.
@ -42,7 +31,7 @@ where
/// Generate response for error /// Generate response for error
/// ///
/// Internal server error is generated by default. /// Internal server error is generated by default.
fn error_response(&self, _: &HttpRequest) -> HttpResponse { fn error_response(self, _: &HttpRequest) -> HttpResponse {
let mut resp = HttpResponse::new(self.status_code()); let mut resp = HttpResponse::new(self.status_code());
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", self); let _ = write!(Writer(&mut buf), "{}", self);
@ -54,12 +43,31 @@ where
} }
} }
impl<Err: ErrorRenderer> WebResponseError<Err> for std::convert::Infallible {} impl<Err: ErrorRenderer> Error<Err> for std::convert::Infallible {}
impl<A, B, Err> WebResponseError<Err> for Either<A, B> impl<Err: ErrorRenderer> Error<Err> for WebResponse {
#[inline]
fn error_response(self, _: &HttpRequest) -> HttpResponse {
self.response
}
}
impl<Err: ErrorRenderer> Error<Err> for HttpResponse {
#[inline]
fn status_code(&self) -> StatusCode {
self.status()
}
#[inline]
fn error_response(self, _: &HttpRequest) -> HttpResponse {
self
}
}
impl<A, B, Err> Error<Err> for Either<A, B>
where where
A: WebResponseError<Err>, A: Error<Err>,
B: WebResponseError<Err>, B: Error<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
@ -69,10 +77,10 @@ where
} }
} }
fn error_response(&self, req: &HttpRequest) -> HttpResponse { fn error_response(self, req: &HttpRequest) -> HttpResponse {
match self { match self {
Either::Left(ref a) => a.error_response(req), Either::Left(a) => a.error_response(req),
Either::Right(ref b) => b.error_response(req), Either::Right(b) => b.error_response(req),
} }
} }
} }
@ -245,13 +253,13 @@ where
impl<T: fmt::Display + fmt::Debug + 'static, E> std::error::Error for InternalError<T, E> {} impl<T: fmt::Display + fmt::Debug + 'static, E> std::error::Error for InternalError<T, E> {}
impl<T, E> WebResponseError<E> for InternalError<T, E> impl<T, E> Error<E> for InternalError<T, E>
where where
T: fmt::Debug + fmt::Display + 'static, T: fmt::Debug + fmt::Display + 'static,
E: ErrorRenderer, E: ErrorRenderer,
{ {
fn error_response(&self, _: &HttpRequest) -> HttpResponse { fn error_response(self, _: &HttpRequest) -> HttpResponse {
crate::http::error::ResponseError::error_response(self) crate::http::error::ResponseError::error_response(&self)
} }
} }

View file

@ -1,88 +1,25 @@
//! Web error //! Web error
use std::{fmt, io, io::Write, str::Utf8Error}; use std::{fmt, io, str::Utf8Error};
use serde::de::value::Error as DeError; use serde::de::value::Error as DeError;
use serde_json::error::Error as JsonError; use serde_json::error::Error as JsonError;
use serde_urlencoded::ser::Error as FormError; use serde_urlencoded::ser::Error as FormError;
use crate::http::body::Body;
use crate::http::helpers::Writer;
use crate::http::{self, header, StatusCode}; use crate::http::{self, header, StatusCode};
use crate::util::{timeout::TimeoutError, BytesMut}; use crate::util::timeout::TimeoutError;
use crate::ws::error::HandshakeError; use crate::ws::error::HandshakeError;
use super::error::{self, ErrorContainer, ErrorRenderer, WebResponseError}; use super::error::{self, Error, ErrorRenderer};
use super::{HttpRequest, HttpResponse}; use super::{HttpRequest, HttpResponse};
/// Default error type /// Default error type
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct DefaultError; pub struct DefaultError;
impl ErrorRenderer for DefaultError { impl ErrorRenderer for DefaultError {}
type Container = Error;
}
/// Generic error container for errors that supports `DefaultError` renderer.
#[derive(thiserror::Error)]
pub struct Error {
cause: Box<dyn WebResponseError<DefaultError>>,
}
impl Error {
pub fn new<T: WebResponseError<DefaultError> + 'static>(err: T) -> Error {
Error {
cause: Box::new(err),
}
}
/// Returns the reference to the underlying `WebResponseError`.
pub fn as_response_error(&self) -> &dyn WebResponseError<DefaultError> {
self.cause.as_ref()
}
}
/// `Error` for any error which implements `WebResponseError<DefaultError>`
impl<T: WebResponseError<DefaultError>> From<T> for Error {
fn from(err: T) -> Self {
Error {
cause: Box::new(err),
}
}
}
impl ErrorContainer for Error {
fn error_response(&self, req: &HttpRequest) -> HttpResponse {
self.cause.error_response(req)
}
}
impl crate::http::error::ResponseError for Error {
fn error_response(&self) -> HttpResponse {
let mut resp = HttpResponse::new(self.cause.status_code());
let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", self.cause);
resp.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/plain; charset=utf-8"),
);
resp.set_body(Body::from(buf))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.cause, f)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "web::Error({:?})", &self.cause)
}
}
/// Return `GATEWAY_TIMEOUT` for `TimeoutError` /// Return `GATEWAY_TIMEOUT` for `TimeoutError`
impl<E: WebResponseError<DefaultError>> WebResponseError<DefaultError> for TimeoutError<E> { impl<E: Error<DefaultError>> Error<DefaultError> for TimeoutError<E> {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match self { match self {
TimeoutError::Service(e) => e.status_code(), TimeoutError::Service(e) => e.status_code(),
@ -92,43 +29,37 @@ impl<E: WebResponseError<DefaultError>> WebResponseError<DefaultError> for Timeo
} }
/// `InternalServerError` for `DataExtractorError` /// `InternalServerError` for `DataExtractorError`
impl WebResponseError<DefaultError> for error::DataExtractorError {} impl Error<DefaultError> for error::DataExtractorError {}
/// `InternalServerError` for `JsonError` /// `InternalServerError` for `JsonError`
impl WebResponseError<DefaultError> for JsonError {} impl Error<DefaultError> for JsonError {}
/// `InternalServerError` for `FormError` /// `InternalServerError` for `FormError`
impl WebResponseError<DefaultError> for FormError {} impl Error<DefaultError> for FormError {}
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::Error` /// `InternalServerError` for `openssl::ssl::Error`
impl WebResponseError<DefaultError> for tls_openssl::ssl::Error {} impl Error<DefaultError> for tls_openssl::ssl::Error {}
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::HandshakeError` /// `InternalServerError` for `openssl::ssl::HandshakeError`
impl<T: fmt::Debug + 'static> WebResponseError<DefaultError> impl<T: fmt::Debug + 'static> Error<DefaultError> for tls_openssl::ssl::HandshakeError<T> {}
for tls_openssl::ssl::HandshakeError<T>
{
}
/// Return `BAD_REQUEST` for `de::value::Error` /// Return `BAD_REQUEST` for `de::value::Error`
impl WebResponseError<DefaultError> for DeError { impl Error<DefaultError> for DeError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
} }
/// `InternalServerError` for `Canceled` /// `InternalServerError` for `Canceled`
impl WebResponseError<DefaultError> for crate::http::error::Canceled {} impl Error<DefaultError> for crate::http::error::Canceled {}
/// `InternalServerError` for `BlockingError` /// `InternalServerError` for `BlockingError`
impl<E: fmt::Debug + 'static> WebResponseError<DefaultError> impl<E: fmt::Debug + 'static> Error<DefaultError> for crate::http::error::BlockingError<E> {}
for crate::http::error::BlockingError<E>
{
}
/// Return `BAD_REQUEST` for `Utf8Error` /// Return `BAD_REQUEST` for `Utf8Error`
impl WebResponseError<DefaultError> for Utf8Error { impl Error<DefaultError> for Utf8Error {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
@ -136,10 +67,10 @@ impl WebResponseError<DefaultError> for Utf8Error {
/// Return `InternalServerError` for `HttpError`, /// Return `InternalServerError` for `HttpError`,
/// Response generation can return `HttpError`, so it is internal error /// Response generation can return `HttpError`, so it is internal error
impl WebResponseError<DefaultError> for crate::http::error::HttpError {} impl Error<DefaultError> for crate::http::error::HttpError {}
/// Return `InternalServerError` for `io::Error` /// Return `InternalServerError` for `io::Error`
impl WebResponseError<DefaultError> for io::Error { impl Error<DefaultError> for io::Error {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match self.kind() { match self.kind() {
io::ErrorKind::NotFound => StatusCode::NOT_FOUND, io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
@ -150,10 +81,10 @@ impl WebResponseError<DefaultError> for io::Error {
} }
/// `InternalServerError` for `UrlGeneratorError` /// `InternalServerError` for `UrlGeneratorError`
impl WebResponseError<DefaultError> for error::UrlGenerationError {} impl Error<DefaultError> for error::UrlGenerationError {}
/// Response renderer for `UrlencodedError` /// Response renderer for `UrlencodedError`
impl WebResponseError<DefaultError> for error::UrlencodedError { impl Error<DefaultError> for error::UrlencodedError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match *self { match *self {
error::UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE, error::UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
@ -164,7 +95,7 @@ impl WebResponseError<DefaultError> for error::UrlencodedError {
} }
/// Return `BadRequest` for `JsonPayloadError` /// Return `BadRequest` for `JsonPayloadError`
impl WebResponseError<DefaultError> for error::JsonPayloadError { impl Error<DefaultError> for error::JsonPayloadError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match *self { match *self {
error::JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE, error::JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
@ -174,20 +105,20 @@ impl WebResponseError<DefaultError> for error::JsonPayloadError {
} }
/// Error renderer for `PathError` /// Error renderer for `PathError`
impl WebResponseError<DefaultError> for error::PathError { impl Error<DefaultError> for error::PathError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::NOT_FOUND StatusCode::NOT_FOUND
} }
} }
/// Error renderer `QueryPayloadError` /// Error renderer `QueryPayloadError`
impl WebResponseError<DefaultError> for error::QueryPayloadError { impl Error<DefaultError> for error::QueryPayloadError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
} }
impl WebResponseError<DefaultError> for error::PayloadError { impl Error<DefaultError> for error::PayloadError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
@ -197,7 +128,7 @@ impl WebResponseError<DefaultError> for error::PayloadError {
/// ///
/// - `Overflow` returns `PayloadTooLarge` /// - `Overflow` returns `PayloadTooLarge`
/// - Other errors returns `BadRequest` /// - Other errors returns `BadRequest`
impl WebResponseError<DefaultError> for http::error::PayloadError { impl Error<DefaultError> for http::error::PayloadError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match *self { match *self {
http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE, http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
@ -208,21 +139,21 @@ impl WebResponseError<DefaultError> for http::error::PayloadError {
#[cfg(feature = "cookie")] #[cfg(feature = "cookie")]
/// Return `BadRequest` for `cookie::ParseError` /// Return `BadRequest` for `cookie::ParseError`
impl WebResponseError<DefaultError> for coo_kie::ParseError { impl Error<DefaultError> for coo_kie::ParseError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
} }
/// Return `BadRequest` for `ContentTypeError` /// Return `BadRequest` for `ContentTypeError`
impl WebResponseError<DefaultError> for http::error::ContentTypeError { impl Error<DefaultError> for http::error::ContentTypeError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST StatusCode::BAD_REQUEST
} }
} }
/// Convert `SendRequestError` to a server `Response` /// Convert `SendRequestError` to a server `Response`
impl WebResponseError<DefaultError> for http::client::error::SendRequestError { impl Error<DefaultError> for http::client::error::SendRequestError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match *self { match *self {
http::client::error::SendRequestError::Connect( http::client::error::SendRequestError::Connect(
@ -235,9 +166,9 @@ impl WebResponseError<DefaultError> for http::client::error::SendRequestError {
} }
/// Error renderer for ws::HandshakeError /// Error renderer for ws::HandshakeError
impl WebResponseError<DefaultError> for HandshakeError { impl Error<DefaultError> for HandshakeError {
fn error_response(&self, _: &HttpRequest) -> HttpResponse { fn error_response(self, _: &HttpRequest) -> HttpResponse {
match *self { match self {
HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed() HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed()
.header(header::ALLOW, "GET") .header(header::ALLOW, "GET")
.finish(), .finish(),

View file

@ -1,7 +1,7 @@
//! Request extractors //! Request extractors
use std::{future::Future, pin::Pin, task::Context, task::Poll}; use std::{convert::Infallible, fmt, future::Future, pin::Pin, task::Context, task::Poll};
use super::error::ErrorRenderer; use super::error::{Error, ErrorRenderer};
use super::httprequest::HttpRequest; use super::httprequest::HttpRequest;
use crate::{http::Payload, util::Ready}; use crate::{http::Payload, util::Ready};
@ -17,13 +17,6 @@ pub trait FromRequest<'a, Err>: Sized {
/// Convert request to a Self /// Convert request to a Self
fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future; fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future;
/// Convert request to a Self
///
/// This method uses `Payload::None` as payload stream.
fn extract(req: &'a HttpRequest) -> Self::Future {
Self::from_request(req, &mut Payload::None)
}
} }
/// Optionally extract a field from the request /// Optionally extract a field from the request
@ -75,10 +68,10 @@ impl<'a, T, Err> FromRequest<'a, Err> for Option<T>
where where
T: FromRequest<'a, Err> + 'static, T: FromRequest<'a, Err> + 'static,
T::Future: 'static, T::Future: 'static,
T::Error: fmt::Debug,
Err: ErrorRenderer, Err: ErrorRenderer,
<T as FromRequest<'a, Err>>::Error: Into<Err::Container>,
{ {
type Error = Err::Container; type Error = T::Error;
type Future = Pin<Box<dyn Future<Output = Result<Option<T>, Self::Error>> + 'a>>; type Future = Pin<Box<dyn Future<Output = Result<Option<T>, Self::Error>> + 'a>>;
#[inline] #[inline]
@ -88,7 +81,7 @@ where
match fut.await { match fut.await {
Ok(v) => Ok(Some(v)), Ok(v) => Ok(Some(v)),
Err(e) => { Err(e) => {
log::debug!("Error for Option<T> extractor: {}", e.into()); log::debug!("Error for Option<T> extractor: {:?}", e);
Ok(None) Ok(None)
} }
} }
@ -162,71 +155,124 @@ where
#[doc(hidden)] #[doc(hidden)]
impl<'a, E: ErrorRenderer> FromRequest<'a, E> for () { impl<'a, E: ErrorRenderer> FromRequest<'a, E> for () {
type Error = E::Container; type Error = Infallible;
type Future = Ready<(), E::Container>; type Future = Ready<(), Infallible>;
fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future {
Ok(()).into() Ok(()).into()
} }
} }
// /// FromRequest implementation for a tuple
// #[allow(unused_parens)]
// impl<'a, Err: ErrorRenderer, T> FromRequest<'a, Err> for (T,)
// where
// T: FromRequest<'a, Err> + 'a,
// T::Error: Into<Err::Container>,
// {
// type Error = Err::Container;
// type Future = TupleFromRequest1<'a, Err, T>;
// fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future {
// TupleFromRequest1 {
// items: Default::default(),
// fut1: Some(T::from_request(req, payload)),
// }
// }
// }
// pin_project_lite::pin_project! {
// #[doc(hidden)]
// pub struct TupleFromRequest1<'a, Err: ErrorRenderer, T: FromRequest<'a, Err>> {
// items: (Option<T>,),
// #[pin]
// fut1: Option<T::Future>,
// }
// }
// impl<'a, Err: ErrorRenderer, T: FromRequest<'a, Err>> Future for TupleFromRequest1<'a, Err, T>
// where
// T: FromRequest<'a, Err> + 'a,
// T::Error: Into<Err::Container>,
// {
// type Output = Result<(T,), Err::Container>;
// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// let this = self.project();
// let mut ready = true;
// if this.items.0.is_none() {
// match this.fut1.as_pin_mut().unwrap().poll(cx) {
// Poll::Ready(Ok(item)) => {
// this.items.0 = Some(item);
// }
// Poll::Pending => ready = false,
// Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
// }
// }
// if ready {
// Poll::Ready(Ok((this.items.0.take().unwrap(),)))
// } else {
// Poll::Pending
// }
// }
// }
macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => { macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
/// FromRequest implementation for a tuple /// FromRequest implementation for a tuple
#[allow(unused_parens)] #[allow(unused_parens)]
impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err> + 'static),+> FromRequest<'a, Err> for ($($T,)+) impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err> + 'a),+> FromRequest<'a, Err> for ($($T,)+)
where where
$(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into<Err::Container>),+ $(<$T as FromRequest<'a, Err>>::Error: Error<Err>),+
{ {
type Error = Err::Container; type Error = $crate::web::HttpResponse;
type Future = $fut_type<'a, Err, $($T),+>; type Future = $fut_type<'a, Err, $($T),+>;
fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future {
$fut_type { $fut_type {
items: <($(Option<$T>,)+)>::default(), items: Default::default(),
$($T: $T::from_request(req, payload),)+ $($T: $T::from_request(req, unsafe { (payload as *mut Payload).as_mut().unwrap() }),)+
req, payload,
} }
} }
} }
pin_project_lite::pin_project! { pin_project_lite::pin_project! {
#[doc(hidden)] #[doc(hidden)]
pub struct $fut_type<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> pub struct $fut_type<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+>
{ {
items: ($(Option<$T>,)+), req: &'a HttpRequest,
$(#[pin] $T: $T::Future),+ payload: &'a mut Payload,
} items: ($(Option<$T>,)+),
$(#[pin] $T: $T::Future),+
}
} }
impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> Future for $fut_type<'a, Err, $($T),+> impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> Future for $fut_type<'a, Err, $($T),+>
where where
$(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into<Err::Container>),+ $(<$T as FromRequest<'a, Err>>::Error: Error<Err>),+
{ {
type Output = Result<($($T,)+), Err::Container>; type Output = Result<($($T,)+), $crate::web::HttpResponse>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project(); let this = self.project();
let mut ready = true;
$( $(
if this.items.$n.is_none() { if this.items.$n.is_none() {
match this.$T.poll(cx) { match $crate::util::ready!(this.$T.poll(cx)) {
Poll::Ready(Ok(item)) => { Ok(item) => {
this.items.$n = Some(item); this.items.$n = Some(item);
} }
Poll::Pending => ready = false, Err(e) => return Poll::Ready(Err(e.error_response(this.req))),
Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
} }
} }
)+ )+
if ready { Poll::Ready(Ok(
Poll::Ready(Ok( ($(this.items.$n.take().unwrap(),)+)
($(this.items.$n.take().unwrap(),)+) ))
))
} else {
Poll::Pending
}
} }
} }
}); });
@ -236,16 +282,16 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
mod m { mod m {
use super::*; use super::*;
tuple_from_req!(TupleFromRequest1, (0, A)); tuple_from_req!(TupleFromRequest1, (0, A));
tuple_from_req!(TupleFromRequest2, (0, A), (1, B)); tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
// tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C)); tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
// tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D)); tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
// tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E)); tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
// tuple_from_req!(TupleFromRequest6, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F)); tuple_from_req!(TupleFromRequest6, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
// tuple_from_req!(TupleFromRequest7, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G)); tuple_from_req!(TupleFromRequest7, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
// tuple_from_req!(TupleFromRequest8, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H)); tuple_from_req!(TupleFromRequest8, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
// tuple_from_req!(TupleFromRequest9, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I)); tuple_from_req!(TupleFromRequest9, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
// tuple_from_req!(TupleFromRequest10, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J)); tuple_from_req!(TupleFromRequest10, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,29 +1,27 @@
use std::{ use std::convert::Infallible;
fmt, future::Future, marker::PhantomData, pin::Pin, rc::Rc, task::Context, task::Poll, use std::{future::Future, marker::PhantomData, pin::Pin};
};
use super::error::ErrorRenderer; use super::error::ErrorRenderer;
use super::extract::FromRequest; use super::extract::FromRequest;
use super::httprequest::HttpRequest;
use super::request::WebRequest; use super::request::WebRequest;
use super::responder::Responder; use super::responder::Responder;
use super::response::WebResponse; use super::response::WebResponse;
/// Async fn handler /// Async fn handler
pub trait Handler<T, Err>: Clone + 'static pub trait Handler<'a, T, Err>: Clone + 'static
where where
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Output: Responder<Err>; type Output: Responder<Err>;
type Future: Future<Output = Self::Output> + 'static; type Future: Future<Output = Self::Output> + 'a;
fn call(&self, param: T) -> Self::Future; fn call(&self, param: T) -> Self::Future;
} }
impl<F, R, Err> Handler<(), Err> for F impl<'a, F, R, Err> Handler<'a, (), Err> for F
where where
F: Fn() -> R + Clone + 'static, F: Fn() -> R + Clone + 'static,
R: Future + 'static, R: Future + 'a,
R::Output: Responder<Err>, R::Output: Responder<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
@ -35,13 +33,11 @@ where
} }
} }
pub(super) trait HandlerFn<Err: ErrorRenderer> { pub(super) trait HandlerFn<'a, Err: ErrorRenderer> {
fn call<'b>( fn call(
&self, &self,
_: &'b mut WebRequest<'b, Err>, _: &'a mut WebRequest<'a, Err>,
) -> Pin<Box<dyn Future<Output = Result<WebResponse, Err::Container>> + 'b>>; ) -> Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>;
fn clone_handler(&self) -> Box<dyn HandlerFn<Err>>;
} }
pub(super) struct HandlerWrapper<F, T, Err> { pub(super) struct HandlerWrapper<F, T, Err> {
@ -58,45 +54,38 @@ impl<F, T, Err> HandlerWrapper<F, T, Err> {
} }
} }
impl<'a, F, T, Err> HandlerFn<Err> for HandlerWrapper<F, T, Err> impl<'a, F, T, Err> HandlerFn<'a, Err> for HandlerWrapper<F, T, Err>
where where
F: Handler<T, Err>, F: Handler<'a, T, Err>,
T: FromRequest<'a, Err> + 'static, T: FromRequest<'a, Err> + 'a,
T::Error: Into<Err::Container>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
fn call<'b>( fn call(
&self, &self,
req: &'b mut WebRequest<'b, Err>, req: &'a mut WebRequest<'a, Err>,
) -> Pin<Box<dyn Future<Output = Result<WebResponse, Err::Container>> + 'b>> { ) -> Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>> {
let mut pl = Rc::get_mut(&mut (req.req).0).unwrap().payload.take();
let hnd = self.hnd.clone(); let hnd = self.hnd.clone();
Box::pin(async move { Box::pin(async move {
let params = if let Ok(p) = T::from_request(&req.req, &mut pl).await { let r: &'a mut WebRequest<'a, Err> = unsafe { std::mem::transmute(&mut *req) };
let fut = r.with_params(|req, pl| T::from_request(req, pl));
let params = if let Ok(p) = fut.await {
p p
} else { } else {
panic!(); panic!();
}; };
let result = hnd.call(params).await; let result = hnd.call(params).await;
let response = result.respond_to(&req.req).await; let response = result.respond_to(req.http_request()).await;
Ok(WebResponse::new(response)) Ok(WebResponse::new(response))
}) })
} }
fn clone_handler(&self) -> Box<dyn HandlerFn<Err>> {
Box::new(HandlerWrapper {
hnd: self.hnd.clone(),
_t: PhantomData,
})
}
} }
/// FromRequest trait impl for tuples /// FromRequest trait impl for tuples
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => { macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
impl<Func, $($T,)+ Res, Err> Handler<($($T,)+), Err> for Func impl<'a, Func, $($T,)+ Res, Err> Handler<'a, ($($T,)+), Err> for Func
where Func: Fn($($T,)+) -> Res + Clone + 'static, where Func: Fn($($T,)+) -> Res + Clone + 'static,
Res: Future + 'static, Res: Future + 'a,
Res::Output: Responder<Err>, Res::Output: Responder<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
@ -113,14 +102,14 @@ macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
mod m { mod m {
use super::*; use super::*;
factory_tuple!((0, A)); factory_tuple!((0, A));
factory_tuple!((0, A), (1, B)); factory_tuple!((0, A), (1, B));
factory_tuple!((0, A), (1, B), (2, C)); factory_tuple!((0, A), (1, B), (2, C));
factory_tuple!((0, A), (1, B), (2, C), (3, D)); factory_tuple!((0, A), (1, B), (2, C), (3, D));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J)); factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
} }

View file

@ -1,4 +1,4 @@
use std::{cell::Ref, cell::RefCell, cell::RefMut, fmt, net, rc::Rc}; use std::{cell::Ref, cell::RefCell, cell::RefMut, convert::Infallible, fmt, net, rc::Rc};
use crate::http::{ use crate::http::{
HeaderMap, HttpMessage, Message, Method, Payload, RequestHead, Uri, Version, HeaderMap, HttpMessage, Message, Method, Payload, RequestHead, Uri, Version,
@ -13,40 +13,40 @@ use super::extract::FromRequest;
use super::info::ConnectionInfo; use super::info::ConnectionInfo;
use super::rmap::ResourceMap; use super::rmap::ResourceMap;
#[derive(Clone)] pub(super) struct HttpRequestInner {
/// An HTTP Request pub(crate) request: HttpRequest,
pub struct HttpRequest(pub(crate) Rc<HttpRequestInner>); pub(crate) payload: Payload,
}
pub(crate) struct HttpRequestInner { /// An HTTP Request
pub struct HttpRequest {
pub(crate) head: Message<RequestHead>, pub(crate) head: Message<RequestHead>,
pub(crate) path: Path<Uri>, pub(crate) path: Path<Uri>,
pub(crate) payload: Payload,
pub(crate) app_state: Rc<Extensions>, pub(crate) app_state: Rc<Extensions>,
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
pool: &'static HttpRequestPool,
} }
impl HttpRequest { impl HttpRequest {
#[inline] #[inline]
pub(crate) fn new( pub(super) fn create(
path: Path<Uri>, path: Path<Uri>,
head: Message<RequestHead>, head: Message<RequestHead>,
payload: Payload, payload: Payload,
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
app_state: Rc<Extensions>, app_state: Rc<Extensions>,
pool: &'static HttpRequestPool, ) -> HttpRequestInner {
) -> HttpRequest { HttpRequestInner {
HttpRequest(Rc::new(HttpRequestInner {
head,
path,
payload, payload,
app_state, request: HttpRequest {
rmap, head,
config, path,
pool, app_state,
})) rmap,
config,
},
}
} }
} }
@ -54,14 +54,14 @@ impl HttpRequest {
/// This method returns reference to the request head /// This method returns reference to the request head
#[inline] #[inline]
pub fn head(&self) -> &RequestHead { pub fn head(&self) -> &RequestHead {
&self.0.head &self.head
} }
/// This method returns muttable reference to the request head. /// This method returns muttable reference to the request head.
/// panics if multiple references of http request exists. /// panics if multiple references of http request exists.
#[inline] #[inline]
pub(crate) fn head_mut(&mut self) -> &mut RequestHead { pub(crate) fn head_mut(&mut self) -> &mut RequestHead {
&mut Rc::get_mut(&mut self.0).unwrap().head &mut self.head
} }
/// Request's uri. /// Request's uri.
@ -131,12 +131,12 @@ impl HttpRequest {
/// access the matched value for that segment. /// access the matched value for that segment.
#[inline] #[inline]
pub fn match_info(&self) -> &Path<Uri> { pub fn match_info(&self) -> &Path<Uri> {
&self.0.path &self.path
} }
#[inline] #[inline]
pub(crate) fn match_info_mut(&mut self) -> &mut Path<Uri> { pub(crate) fn match_info_mut(&mut self) -> &mut Path<Uri> {
&mut Rc::get_mut(&mut self.0).unwrap().path &mut self.path
} }
/// Request extensions /// Request extensions
@ -179,7 +179,7 @@ impl HttpRequest {
U: IntoIterator<Item = I>, U: IntoIterator<Item = I>,
I: AsRef<str>, I: AsRef<str>,
{ {
self.0.rmap.url_for(self, name, elements) self.rmap.url_for(self, name, elements)
} }
#[cfg(feature = "url")] #[cfg(feature = "url")]
@ -198,7 +198,7 @@ impl HttpRequest {
#[inline] #[inline]
/// Get a reference to a `ResourceMap` of current application. /// Get a reference to a `ResourceMap` of current application.
pub fn resource_map(&self) -> &ResourceMap { pub fn resource_map(&self) -> &ResourceMap {
&self.0.rmap &self.rmap
} }
/// Get *ConnectionInfo* for the current request. /// Get *ConnectionInfo* for the current request.
@ -213,7 +213,7 @@ impl HttpRequest {
/// App config /// App config
#[inline] #[inline]
pub fn app_config(&self) -> &AppConfig { pub fn app_config(&self) -> &AppConfig {
&self.0.config &self.config
} }
/// Get an application state object stored with `App::state()` or `App::app_state()` /// Get an application state object stored with `App::state()` or `App::app_state()`
@ -225,7 +225,7 @@ impl HttpRequest {
/// let opt_t = req.app_data::<State<T>>(); /// let opt_t = req.app_data::<State<T>>();
/// ``` /// ```
pub fn app_state<T: 'static>(&self) -> Option<&T> { pub fn app_state<T: 'static>(&self) -> Option<&T> {
self.0.app_state.get::<T>() self.app_state.get::<T>()
} }
} }
@ -239,25 +239,13 @@ impl HttpMessage for HttpRequest {
/// Request extensions /// Request extensions
#[inline] #[inline]
fn message_extensions(&self) -> Ref<'_, Extensions> { fn message_extensions(&self) -> Ref<'_, Extensions> {
self.0.head.extensions() self.head.extensions()
} }
/// Mutable reference to a the request's extensions /// Mutable reference to a the request's extensions
#[inline] #[inline]
fn message_extensions_mut(&self) -> RefMut<'_, Extensions> { fn message_extensions_mut(&self) -> RefMut<'_, Extensions> {
self.0.head.extensions_mut() self.head.extensions_mut()
}
}
impl Drop for HttpRequest {
fn drop(&mut self) {
if Rc::strong_count(&self.0) == 1 {
let v = &mut self.0.pool.0.borrow_mut();
if v.len() < 128 {
self.extensions_mut().clear();
v.push(self.0.clone());
}
}
} }
} }
@ -280,13 +268,13 @@ impl Drop for HttpRequest {
/// ); /// );
/// } /// }
/// ``` /// ```
impl<Err: ErrorRenderer> FromRequest<Err> for HttpRequest { impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for &'a HttpRequest {
type Error = Err::Container; type Error = Infallible;
type Future = Ready<Self, Self::Error>; type Future = Ready<Self, Self::Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future {
Ok(req.clone()).into() Ready::Ok(req)
} }
} }
@ -295,8 +283,8 @@ impl fmt::Debug for HttpRequest {
writeln!( writeln!(
f, f,
"\nHttpRequest {:?} {}:{}", "\nHttpRequest {:?} {}:{}",
self.0.head.version, self.head.version,
self.0.head.method, self.head.method,
self.path() self.path()
)?; )?;
if !self.query_string().is_empty() { if !self.query_string().is_empty() {
@ -314,7 +302,8 @@ impl fmt::Debug for HttpRequest {
} }
/// Request's objects pool /// Request's objects pool
pub(crate) struct HttpRequestPool(RefCell<Vec<Rc<HttpRequestInner>>>); #[allow(clippy::vec_box)]
pub(crate) struct HttpRequestPool(RefCell<Vec<Box<HttpRequestInner>>>);
impl HttpRequestPool { impl HttpRequestPool {
pub(crate) fn create() -> &'static HttpRequestPool { pub(crate) fn create() -> &'static HttpRequestPool {
@ -324,11 +313,29 @@ impl HttpRequestPool {
/// Get message from the pool /// Get message from the pool
#[inline] #[inline]
pub(crate) fn get_request(&self) -> Option<HttpRequest> { pub(super) fn get_request(&self) -> Option<Box<HttpRequestInner>> {
self.0.borrow_mut().pop().map(HttpRequest) self.0.borrow_mut().pop()
} }
pub(crate) fn clear(&self) { #[inline]
pub(super) fn release_boxed(&self, req: Box<HttpRequestInner>) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
req.request.extensions_mut().clear();
v.push(req);
}
}
#[inline]
pub(super) fn release_unboxed(&self, req: HttpRequestInner) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
req.request.extensions_mut().clear();
v.push(Box::new(req));
}
}
pub(super) fn clear(&self) {
self.0.borrow_mut().clear() self.0.borrow_mut().clear()
} }
} }

View file

@ -59,9 +59,9 @@ pub struct CompressMiddleware<S> {
encoding: ContentEncoding, encoding: ContentEncoding,
} }
impl<'a, S, E> Service<WebRequest<E>> for CompressMiddleware<S> impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for CompressMiddleware<S>
where where
S: Service<WebRequest<E>, Response = WebResponse>, S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>,
E: ErrorRenderer, E: ErrorRenderer,
{ {
type Response = WebResponse; type Response = WebResponse;
@ -78,7 +78,7 @@ where
self.service.poll_shutdown(cx, is_error) self.service.poll_shutdown(cx, is_error)
} }
fn call(&self, req: WebRequest<E>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future {
// negotiate content-encoding // negotiate content-encoding
let encoding = if let Some(val) = req.headers().get(&ACCEPT_ENCODING) { let encoding = if let Some(val) = req.headers().get(&ACCEPT_ENCODING) {
if let Ok(enc) = val.to_str() { if let Ok(enc) = val.to_str() {
@ -100,7 +100,7 @@ where
pin_project_lite::pin_project! { pin_project_lite::pin_project! {
#[doc(hidden)] #[doc(hidden)]
pub struct CompressResponse<'a, S: Service<WebRequest<E>>, E> pub struct CompressResponse<'a, S: Service<&'a mut WebRequest<'a, E>>, E>
{ {
#[pin] #[pin]
fut: S::Future, fut: S::Future,
@ -111,7 +111,7 @@ pin_project_lite::pin_project! {
impl<'a, S, E> Future for CompressResponse<'a, S, E> impl<'a, S, E> Future for CompressResponse<'a, S, E>
where where
S: Service<WebRequest<E>, Response = WebResponse>, S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>,
E: ErrorRenderer, E: ErrorRenderer,
{ {
type Output = Result<WebResponse, S::Error>; type Output = Result<WebResponse, S::Error>;

View file

@ -5,7 +5,7 @@ use std::{convert::Infallible, convert::TryFrom, future::Future, pin::Pin, rc::R
use crate::http::error::HttpError; use crate::http::error::HttpError;
use crate::http::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE}; use crate::http::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
use crate::service::{Service, Transform}; use crate::service::{Service, Transform};
use crate::web::{WebRequest, WebResponse, ErrorRenderer}; use crate::web::{ErrorRenderer, WebRequest, WebResponse};
/// `Middleware` for setting default response headers. /// `Middleware` for setting default response headers.
/// ///
@ -102,9 +102,9 @@ pub struct DefaultHeadersMiddleware<S> {
inner: Rc<Inner>, inner: Rc<Inner>,
} }
impl<'a, S, E> Service<WebRequest<E>> for DefaultHeadersMiddleware<S> impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for DefaultHeadersMiddleware<S>
where where
S: Service<WebRequest<E>, Response = WebResponse, Error = Infallible>, S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse, Error = Infallible>,
S::Future: 'static, S::Future: 'static,
E: ErrorRenderer, E: ErrorRenderer,
{ {
@ -122,7 +122,7 @@ where
self.service.poll_shutdown(cx, is_error) self.service.poll_shutdown(cx, is_error)
} }
fn call(&self, req: WebRequest<E>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future {
let inner = self.inner.clone(); let inner = self.inner.clone();
let fut = self.service.call(req); let fut = self.service.call(req);

View file

@ -130,9 +130,9 @@ pub struct LoggerMiddleware<S> {
service: S, service: S,
} }
impl<'a, S, E> Service<WebRequest<E>> for LoggerMiddleware<S> impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for LoggerMiddleware<S>
where where
S: Service<WebRequest<E>, Response = WebResponse>, S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>,
E: 'static, E: 'static,
{ {
type Response = WebResponse; type Response = WebResponse;
@ -150,7 +150,7 @@ where
} }
#[inline] #[inline]
fn call(&self, req: WebRequest<E>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future {
if self.inner.exclude.contains(req.path()) { if self.inner.exclude.contains(req.path()) {
Either::Right(self.service.call(req)) Either::Right(self.service.call(req))
} else { } else {
@ -158,7 +158,7 @@ where
let mut format = self.inner.format.clone(); let mut format = self.inner.format.clone();
for unit in &mut format.0 { for unit in &mut format.0 {
unit.render_request(time, &req); unit.render_request(time, req);
} }
Either::Left(LoggerResponse { Either::Left(LoggerResponse {
time, time,
@ -172,7 +172,7 @@ where
pin_project_lite::pin_project! { pin_project_lite::pin_project! {
#[doc(hidden)] #[doc(hidden)]
pub struct LoggerResponse<'a, S: Service<WebRequest<E>>, E> pub struct LoggerResponse<'a, S: Service<&'a mut WebRequest<'a, E>>, E>
{ {
#[pin] #[pin]
fut: S::Future, fut: S::Future,
@ -184,7 +184,7 @@ pin_project_lite::pin_project! {
impl<'a, S, E> Future for LoggerResponse<'a, S, E> impl<'a, S, E> Future for LoggerResponse<'a, S, E>
where where
S: Service<WebRequest<E>, Response = WebResponse>, S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>,
{ {
type Output = Result<WebResponse, S::Error>; type Output = Result<WebResponse, S::Error>;
@ -396,7 +396,7 @@ impl FormatText {
} }
} }
fn render_request<E>(&mut self, now: time::SystemTime, req: &WebRequest<E>) { fn render_request<E>(&mut self, now: time::SystemTime, req: &WebRequest<'_, E>) {
match *self { match *self {
FormatText::RequestLine => { FormatText::RequestLine => {
*self = if req.query_string().is_empty() { *self = if req.query_string().is_empty() {

View file

@ -61,13 +61,6 @@
//! * `compress` - enables content encoding compression support //! * `compress` - enables content encoding compression support
//! * `openssl` - enables ssl support via `openssl` crate //! * `openssl` - enables ssl support via `openssl` crate
//! * `rustls` - enables ssl support via `rustls` crate //! * `rustls` - enables ssl support via `rustls` crate
#![allow(
unused_imports,
unused_variables,
unused_mut,
dead_code,
unreachable_pub
)]
mod app; mod app;
mod app_service; mod app_service;
@ -79,7 +72,7 @@ pub mod guard;
mod handler; mod handler;
mod httprequest; mod httprequest;
mod info; mod info;
//pub mod middleware; pub mod middleware;
mod request; mod request;
mod resource; mod resource;
mod responder; mod responder;
@ -91,7 +84,7 @@ mod boxed;
mod server; mod server;
mod service; mod service;
mod stack; mod stack;
//pub mod test; pub mod test;
pub mod types; pub mod types;
mod util; mod util;
pub mod ws; pub mod ws;
@ -112,9 +105,7 @@ pub use crate::http::ResponseBuilder as HttpResponseBuilder;
pub use self::app::App; pub use self::app::App;
pub use self::config::ServiceConfig; pub use self::config::ServiceConfig;
pub use self::error::{ pub use self::error::{DefaultError, Error, ErrorRenderer};
DefaultError, Error, ErrorContainer, ErrorRenderer, WebResponseError,
};
pub use self::extract::FromRequest; pub use self::extract::FromRequest;
pub use self::handler::Handler; pub use self::handler::Handler;
pub use self::httprequest::HttpRequest; pub use self::httprequest::HttpRequest;
@ -157,15 +148,14 @@ pub mod dev {
where where
T: super::FromRequest<'a, Err>, T: super::FromRequest<'a, Err>,
Err: super::ErrorRenderer, Err: super::ErrorRenderer,
<T as super::FromRequest<'a, Err>>::Error: Into<Err::Container>,
{ {
} }
#[doc(hidden)] #[doc(hidden)]
#[inline(always)] #[inline(always)]
pub fn __assert_handler<Err, Fun, Fut>( pub fn __assert_handler<'a, Err, Fun, Fut>(
f: Fun, f: Fun,
) -> impl Handler<(), Err, Future = Fut, Output = Fut::Output> ) -> impl Handler<'a, (), Err, Future = Fut, Output = Fut::Output>
where where
Err: super::ErrorRenderer, Err: super::ErrorRenderer,
Fun: Fn() -> Fut + Clone + 'static, Fun: Fn() -> Fut + Clone + 'static,
@ -180,11 +170,11 @@ pub mod dev {
#[inline(always)] #[inline(always)]
pub fn $name<'a, Err, Fun, Fut, $($T,)+>( pub fn $name<'a, Err, Fun, Fut, $($T,)+>(
f: Fun, f: Fun,
) -> impl Handler<($($T,)+), Err, Future = Fut, Output = Fut::Output> ) -> impl Handler<'a, ($($T,)+), Err, Future = Fut, Output = Fut::Output>
where where
Err: $crate::web::ErrorRenderer, Err: $crate::web::ErrorRenderer,
Fun: Fn($($T,)+) -> Fut + Clone + 'static, Fun: Fn($($T,)+) -> Fut + Clone + 'static,
Fut: std::future::Future + 'static, Fut: std::future::Future + 'a,
Fut::Output: $crate::web::Responder<Err>, Fut::Output: $crate::web::Responder<Err>,
$($T: $crate::web::FromRequest<'a, Err>),+, $($T: $crate::web::FromRequest<'a, Err>),+,
{ {

View file

@ -1,88 +1,38 @@
use std::{cell::Ref, cell::RefMut, fmt, marker::PhantomData, net, rc::Rc}; use std::{cell::Ref, cell::RefMut, fmt, marker::PhantomData, net, rc::Rc};
use crate::http::{ use crate::http::{
header, HeaderMap, HttpMessage, Method, Payload, RequestHead, Response, Uri, Version, header, HeaderMap, HttpMessage, Method, Payload, RequestHead, Uri, Version,
}; };
use crate::io::{types, IoRef}; use crate::io::{types, IoRef};
use crate::router::{Path, Resource}; use crate::router::{Path, Resource};
use crate::util::Extensions; use crate::util::Extensions;
use super::config::AppConfig; use super::config::AppConfig;
use super::error::{ErrorRenderer, WebResponseError}; use super::error::ErrorRenderer;
use super::httprequest::HttpRequest; use super::httprequest::{HttpRequest, HttpRequestInner};
use super::info::ConnectionInfo; use super::info::ConnectionInfo;
use super::response::WebResponse;
use super::rmap::ResourceMap; use super::rmap::ResourceMap;
/// An service http request /// An service http request
/// ///
/// WebRequest allows mutable access to request's internal structures /// WebRequest allows mutable access to request's internal structures
pub struct WebRequest<'a, Err> { pub struct WebRequest<'a, Err> {
pub(super) req: &'a mut HttpRequest, pub(super) req: &'a mut HttpRequestInner,
_marker: PhantomData<fn(&'a ()) -> &'a Err>, _marker: PhantomData<fn(&'a ()) -> &'a Err>,
} }
impl<'a, Err: ErrorRenderer> WebRequest<'a, Err> {
/// Create web response for error
#[inline]
pub fn render_error<E: WebResponseError<Err>>(self, err: E) -> WebResponse {
WebResponse::new(err.error_response(&self.req))
}
/// Create web response for error
#[inline]
pub fn error_response<E: Into<Err::Container>>(self, err: E) -> WebResponse {
WebResponse::from_err::<Err, E>(err, self.req)
}
}
impl<'a, Err> WebRequest<'a, Err> { impl<'a, Err> WebRequest<'a, Err> {
/// Construct web request /// Construct web request
pub(crate) fn new(req: &'a mut HttpRequest) -> Self { pub(super) fn new(req: &'a mut HttpRequestInner) -> Self {
WebRequest { WebRequest {
req, req,
_marker: PhantomData, _marker: PhantomData,
} }
} }
// /// Deconstruct request into parts /// Http request
// pub fn into_parts(mut self) -> (HttpRequest, Payload) { pub fn http_request(&self) -> &HttpRequest {
// let pl = Rc::get_mut(&mut (self.req).0).unwrap().payload.take(); &self.req.request
// (self.req, pl)
// }
// /// Construct request from parts.
// ///
// /// `WebRequest` can be re-constructed only if `req` hasnt been cloned.
// pub fn from_parts(
// mut req: HttpRequest,
// pl: Payload,
// ) -> Result<Self, (HttpRequest, Payload)> {
// if Rc::strong_count(&req.0) == 1 {
// Rc::get_mut(&mut req.0).unwrap().payload = pl;
// Ok(WebRequest::new(req))
// } else {
// Err((req, pl))
// }
// }
// /// Construct request from request.
// ///
// /// `HttpRequest` implements `Clone` trait via `Rc` type. `WebRequest`
// /// can be re-constructed only if rc's strong pointers count eq 1 and
// /// weak pointers count is 0.
// pub fn from_request(req: HttpRequest) -> Result<Self, HttpRequest> {
// if Rc::strong_count(&req.0) == 1 {
// Ok(WebRequest::new(req))
// } else {
// Err(req)
// }
// }
/// Create web response
#[inline]
pub fn into_response<R: Into<Response>>(self, res: R) -> WebResponse {
WebResponse::new(res.into())
} }
/// Io reference for current connection /// Io reference for current connection
@ -94,13 +44,13 @@ impl<'a, Err> WebRequest<'a, Err> {
/// This method returns reference to the request head /// This method returns reference to the request head
#[inline] #[inline]
pub fn head(&self) -> &RequestHead { pub fn head(&self) -> &RequestHead {
self.req.head() self.req.request.head()
} }
/// This method returns reference to the request head /// This method returns reference to the request head
#[inline] #[inline]
pub fn head_mut(&mut self) -> &mut RequestHead { pub fn head_mut(&mut self) -> &mut RequestHead {
self.req.head_mut() self.req.request.head_mut()
} }
/// Request's uri. /// Request's uri.
@ -180,25 +130,25 @@ impl<'a, Err> WebRequest<'a, Err> {
/// access the matched value for that segment. /// access the matched value for that segment.
#[inline] #[inline]
pub fn match_info(&self) -> &Path<Uri> { pub fn match_info(&self) -> &Path<Uri> {
self.req.match_info() self.req.request.match_info()
} }
#[inline] #[inline]
/// Get a mutable reference to the Path parameters. /// Get a mutable reference to the Path parameters.
pub fn match_info_mut(&mut self) -> &mut Path<Uri> { pub fn match_info_mut(&mut self) -> &mut Path<Uri> {
self.req.match_info_mut() self.req.request.match_info_mut()
} }
#[inline] #[inline]
/// Get a reference to a `ResourceMap` of current application. /// Get a reference to a `ResourceMap` of current application.
pub fn resource_map(&self) -> &ResourceMap { pub fn resource_map(&self) -> &ResourceMap {
self.req.resource_map() self.req.request.resource_map()
} }
/// Service configuration /// Service configuration
#[inline] #[inline]
pub fn app_config(&self) -> &AppConfig { pub fn app_config(&self) -> &AppConfig {
self.req.app_config() self.req.request.app_config()
} }
#[inline] #[inline]
@ -207,37 +157,59 @@ impl<'a, Err> WebRequest<'a, Err> {
/// ///
/// To get state stored with `App::state()` use `web::types::State<T>` as type. /// To get state stored with `App::state()` use `web::types::State<T>` as type.
pub fn app_state<T: 'static>(&self) -> Option<&T> { pub fn app_state<T: 'static>(&self) -> Option<&T> {
(self.req).0.app_state.get::<T>() self.req.request.app_state.get::<T>()
}
#[inline]
/// Get request's payload
pub fn payload(&mut self) -> &Payload {
&self.req.payload
}
#[inline]
/// Get mutable request's payload
pub fn payload_mut(&mut self) -> &mut Payload {
&mut self.req.payload
} }
#[inline] #[inline]
/// Get request's payload /// Get request's payload
pub fn take_payload(&mut self) -> Payload { pub fn take_payload(&mut self) -> Payload {
Rc::get_mut(&mut (self.req).0).unwrap().payload.take() self.req.payload.take()
} }
#[inline] #[inline]
/// Set request payload. /// Set request payload.
pub fn set_payload(&mut self, payload: Payload) { pub fn set_payload(&mut self, payload: Payload) {
Rc::get_mut(&mut (self.req).0).unwrap().payload = payload; self.req.payload = payload;
} }
#[doc(hidden)] #[doc(hidden)]
/// Set new app state container /// Set new app state container
pub fn set_state_container(&mut self, extensions: Rc<Extensions>) { pub fn set_state_container(&mut self, extensions: Rc<Extensions>) {
Rc::get_mut(&mut (self.req).0).unwrap().app_state = extensions; self.req.request.app_state = extensions;
} }
/// Request extensions /// Request extensions
#[inline] #[inline]
pub fn extensions(&self) -> Ref<'_, Extensions> { pub fn extensions(&self) -> Ref<'_, Extensions> {
self.req.extensions() self.req.request.extensions()
} }
/// Mutable reference to a the request's extensions /// Mutable reference to a the request's extensions
#[inline] #[inline]
pub fn extensions_mut(&self) -> RefMut<'_, Extensions> { pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
self.req.extensions_mut() self.req.request.extensions_mut()
}
#[inline]
/// Get request's payload
pub(super) fn with_params<F, R>(&'a mut self, f: F) -> R
where
F: FnOnce(&'a HttpRequest, &'a mut Payload) -> R,
R: 'a,
{
f(&self.req.request, &mut self.req.payload)
} }
} }
@ -261,13 +233,13 @@ impl<'a, Err> HttpMessage for WebRequest<'a, Err> {
/// Request extensions /// Request extensions
#[inline] #[inline]
fn message_extensions(&self) -> Ref<'_, Extensions> { fn message_extensions(&self) -> Ref<'_, Extensions> {
self.req.extensions() self.req.request.extensions()
} }
/// Mutable reference to a the request's extensions /// Mutable reference to a the request's extensions
#[inline] #[inline]
fn message_extensions_mut(&self) -> RefMut<'_, Extensions> { fn message_extensions_mut(&self) -> RefMut<'_, Extensions> {
self.req.extensions_mut() self.req.request.extensions_mut()
} }
} }

View file

@ -1,15 +1,13 @@
use std::convert::Infallible;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::{cell::RefCell, fmt, future::Future, marker::PhantomData, pin::Pin, rc::Rc}; use std::{convert::Infallible, future::Future, pin::Pin, rc::Rc};
use crate::http::Response; use crate::http::Response;
use crate::router::{IntoPattern, ResourceDef}; use crate::router::{IntoPattern, ResourceDef};
use crate::service::{pipeline_factory, PipelineFactory};
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform}; use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
use crate::util::{Either, Extensions, Ready}; use crate::util::{ready, Extensions, Ready};
use super::boxed::{self, BoxService, BoxServiceFactory};
use super::dev::{insert_slash, WebService, WebServiceConfig}; use super::dev::{insert_slash, WebService, WebServiceConfig};
use super::error::Error;
use super::extract::FromRequest; use super::extract::FromRequest;
use super::route::{IntoRoutes, Route, RouteService}; use super::route::{IntoRoutes, Route, RouteService};
use super::stack::{ use super::stack::{
@ -50,7 +48,7 @@ pub struct Resource<Err: ErrorRenderer, M = Identity, F = Filter> {
default: Route<Err>, default: Route<Err>,
} }
impl<'a, Err: ErrorRenderer> Resource<Err> { impl<Err: ErrorRenderer> Resource<Err> {
pub fn new<T: IntoPattern>(path: T) -> Resource<Err> { pub fn new<T: IntoPattern>(path: T) -> Resource<Err> {
Resource { Resource {
routes: Vec::new(), routes: Vec::new(),
@ -148,7 +146,7 @@ where
/// ``` /// ```
pub fn route<R>(mut self, route: R) -> Self pub fn route<R>(mut self, route: R) -> Self
where where
R: IntoRoutes<Err>, R: IntoRoutes<'a, Err>,
{ {
for route in route.routes() { for route in route.routes() {
self.routes.push(route); self.routes.push(route);
@ -217,9 +215,9 @@ where
/// ``` /// ```
pub fn to<H, Args>(mut self, handler: H) -> Self pub fn to<H, Args>(mut self, handler: H) -> Self
where where
H: Handler<Args, Err>, H: Handler<'a, Args, Err>,
Args: FromRequest<Err> + 'static, Args: FromRequest<'a, Err> + 'a,
Args::Error: Into<Err::Container>, Args::Error: Error<Err>,
{ {
self.routes.push(Route::new().to(handler)); self.routes.push(Route::new().to(handler));
self self
@ -266,9 +264,9 @@ where
/// default handler from `App` or `Scope`. /// default handler from `App` or `Scope`.
pub fn default<H, Args>(mut self, handler: H) -> Self pub fn default<H, Args>(mut self, handler: H) -> Self
where where
H: Handler<Args, Err>, H: Handler<'a, Args, Err>,
Args: FromRequest<Err> + 'static, Args: FromRequest<'a, Err> + 'a,
Args::Error: Into<Err::Container>, Args::Error: Error<Err>,
{ {
self.default = Route::new().to(handler); self.default = Route::new().to(handler);
self self
@ -382,7 +380,7 @@ where
F: ServiceFactory< F: ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
InitError = (), InitError = (),
> + 'static, > + 'static,
F::Service: 'static, F::Service: 'static,
@ -390,7 +388,7 @@ where
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Service = Middleware<M::Service, Err>; type Service = Middleware<M::Service, Err>;
type InitError = (); type InitError = ();
type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>; type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>;
@ -418,18 +416,18 @@ where
F: Service< F: Service<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
>, >,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = ResourceServiceResponse<'a, F, Err>; type Future = ResourceServiceResponse<'a, F, Err>;
#[inline] #[inline]
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready1 = self.filter.poll_ready(cx)?.is_ready(); let ready1 = self.filter.poll_ready(cx).is_ready();
let ready2 = self.routing.poll_ready(cx)?.is_ready(); let ready2 = self.routing.poll_ready(cx).is_ready();
if ready1 && ready2 { if ready1 && ready2 {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} else { } else {
@ -439,9 +437,12 @@ where
fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future {
ResourceServiceResponse { ResourceServiceResponse {
filter: self.filter.call(req), filter: self
.filter
.call(unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }),
routing: self.routing.clone(), routing: self.routing.clone(),
endpoint: None, endpoint: None,
req,
} }
} }
} }
@ -452,6 +453,7 @@ pin_project_lite::pin_project! {
filter: F::Future, filter: F::Future,
routing: Rc<ResourceRouter<Err>>, routing: Rc<ResourceRouter<Err>>,
endpoint: Option<<ResourceRouter<Err> as Service<&'a mut WebRequest<'a, Err>>>::Future>, endpoint: Option<<ResourceRouter<Err> as Service<&'a mut WebRequest<'a, Err>>>::Future>,
req: &'a mut WebRequest<'a, Err>,
} }
} }
@ -460,11 +462,11 @@ where
F: Service< F: Service<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
>, >,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Output = Result<WebResponse, Err::Container>; type Output = Result<WebResponse, Infallible>;
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> {
let this = self.as_mut().project(); let this = self.as_mut().project();
@ -472,12 +474,8 @@ where
if let Some(fut) = this.endpoint.as_mut() { if let Some(fut) = this.endpoint.as_mut() {
Pin::new(fut).poll(cx) Pin::new(fut).poll(cx)
} else { } else {
let res = if let Poll::Ready(res) = this.filter.poll(cx) { let req = ready!(this.filter.poll(cx)).unwrap();
res? *this.endpoint = Some(this.routing.call(req));
} else {
return Poll::Pending;
};
*this.endpoint = Some(this.routing.call(res));
self.poll(cx) self.poll(cx)
} }
} }
@ -493,7 +491,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>>
for ResourceRouterFactory<Err> for ResourceRouterFactory<Err>
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = ResourceRouter<Err>; type Service = ResourceRouter<Err>;
type Future = Ready<Self::Service, Self::InitError>; type Future = Ready<Self::Service, Self::InitError>;
@ -519,15 +517,15 @@ struct ResourceRouter<Err: ErrorRenderer> {
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ResourceRouter<Err> { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ResourceRouter<Err> {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<WebResponse, Err::Container>> + 'a>>; type Future = Pin<Box<dyn Future<Output = Result<WebResponse, Infallible>> + 'a>>;
#[inline] #[inline]
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} }
fn call(&self, mut req: &'a mut WebRequest<'a, Err>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future {
for route in self.routes.iter() { for route in self.routes.iter() {
if route.check(req) { if route.check(req) {
if let Some(ref state) = self.state { if let Some(ref state) = self.state {

View file

@ -5,10 +5,8 @@ use crate::http::header::{HeaderMap, HeaderName, HeaderValue};
use crate::http::{error::HttpError, Response, ResponseBuilder, StatusCode}; use crate::http::{error::HttpError, Response, ResponseBuilder, StatusCode};
use crate::util::{Bytes, BytesMut, Either}; use crate::util::{Bytes, BytesMut, Either};
use super::error::{ use super::error::{DefaultError, Error, ErrorRenderer, InternalError};
DefaultError, ErrorContainer, ErrorRenderer, InternalError, WebResponseError, use super::{HttpRequest, WebResponse};
};
use super::httprequest::HttpRequest;
pub struct Ready<T>(Option<T>); pub struct Ready<T>(Option<T>);
@ -126,7 +124,7 @@ where
impl<T, E, Err> Responder<Err> for Result<T, E> impl<T, E, Err> Responder<Err> for Result<T, E>
where where
T: Responder<Err>, T: Responder<Err>,
E: Into<Err::Container>, E: Error<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Future = Either<T::Future, Ready<Response>>; type Future = Either<T::Future, Ready<Response>>;
@ -134,7 +132,7 @@ where
fn respond_to(self, req: &HttpRequest) -> Self::Future { fn respond_to(self, req: &HttpRequest) -> Self::Future {
match self { match self {
Ok(val) => Either::Left(val.respond_to(req)), Ok(val) => Either::Left(val.respond_to(req)),
Err(e) => Either::Right(Ready(Some(e.into().error_response(req)))), Err(e) => Either::Right(Ready(Some(WebResponse::from_err(e, req).into()))),
} }
} }
} }

View file

@ -3,7 +3,7 @@ use std::fmt;
use crate::http::body::{Body, MessageBody, ResponseBody}; use crate::http::body::{Body, MessageBody, ResponseBody};
use crate::http::{HeaderMap, Response, ResponseHead, StatusCode}; use crate::http::{HeaderMap, Response, ResponseHead, StatusCode};
use super::error::{ErrorContainer, ErrorRenderer}; use super::error::{Error, ErrorRenderer};
use super::httprequest::HttpRequest; use super::httprequest::HttpRequest;
/// An service http response /// An service http response
@ -18,21 +18,18 @@ impl WebResponse {
} }
/// Create web response from the error /// Create web response from the error
pub fn from_err<Err: ErrorRenderer, E: Into<Err::Container>>( pub fn from_err<Err: ErrorRenderer, E: Error<Err>>(
err: E, err: E,
request: &HttpRequest, request: &HttpRequest,
) -> Self { ) -> Self {
let err = err.into(); if err.status_code() == StatusCode::INTERNAL_SERVER_ERROR {
let res: Response = err.error_response(request);
if res.head().status == StatusCode::INTERNAL_SERVER_ERROR {
log::error!("Internal Server Error: {:?}", err); log::error!("Internal Server Error: {:?}", err);
} else { } else {
log::debug!("Error in response: {:?}", err); log::debug!("Error in response: {:?}", err);
} }
WebResponse { WebResponse {
response: res.into_body(), response: err.error_response(request).into_body(),
} }
} }
@ -102,6 +99,12 @@ impl From<WebResponse> for Response<Body> {
} }
} }
impl fmt::Display for WebResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self)
}
}
impl fmt::Debug for WebResponse { impl fmt::Debug for WebResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = writeln!( let res = writeln!(

View file

@ -1,18 +1,19 @@
use std::{future::Future, mem, pin::Pin, rc::Rc, task::Context, task::Poll}; use std::convert::Infallible;
use std::{cell::Cell, future::Future, mem, pin::Pin, rc::Rc, task::Context, task::Poll};
use crate::{http::Method, service::Service, service::ServiceFactory, util::Ready}; use crate::{http::Method, service::Service, service::ServiceFactory, util::Ready};
use super::error_default::DefaultError; use super::error_default::DefaultError;
use super::guard::{self, Guard}; use super::guard::{self, Guard};
use super::handler::{Handler, HandlerFn, HandlerWrapper}; use super::handler::{Handler, HandlerFn, HandlerWrapper};
use super::{ErrorRenderer, FromRequest, HttpResponse, WebRequest, WebResponse}; use super::{Error, ErrorRenderer, FromRequest, HttpResponse, WebRequest, WebResponse};
/// Resource route definition /// Resource route definition
/// ///
/// Route uses builder-like pattern for configuration. /// Route uses builder-like pattern for configuration.
/// If handler is not explicitly set, default *404 Not Found* handler is used. /// If handler is not explicitly set, default *404 Not Found* handler is used.
pub struct Route<Err: ErrorRenderer = DefaultError> { pub struct Route<Err: ErrorRenderer = DefaultError> {
handler: Box<dyn HandlerFn<Err>>, handler: Cell<Option<Box<dyn HandlerFn<'static, Err>>>>,
methods: Vec<Method>, methods: Vec<Method>,
guards: Rc<Vec<Box<dyn Guard>>>, guards: Rc<Vec<Box<dyn Guard>>>,
} }
@ -21,7 +22,9 @@ impl<'a, Err: ErrorRenderer> Route<Err> {
/// Create new route which matches any request. /// Create new route which matches any request.
pub fn new() -> Route<Err> { pub fn new() -> Route<Err> {
Route { Route {
handler: Box::new(HandlerWrapper::new(|| async { HttpResponse::NotFound() })), handler: Cell::new(Some(Box::new(HandlerWrapper::new(|| async {
HttpResponse::NotFound()
})))),
methods: Vec::new(), methods: Vec::new(),
guards: Rc::new(Vec::new()), guards: Rc::new(Vec::new()),
} }
@ -39,7 +42,7 @@ impl<'a, Err: ErrorRenderer> Route<Err> {
pub(super) fn service(&self) -> RouteService<Err> { pub(super) fn service(&self) -> RouteService<Err> {
RouteService { RouteService {
handler: self.handler.clone_handler(), handler: self.handler.take().unwrap(),
guards: self.guards.clone(), guards: self.guards.clone(),
methods: self.methods.clone(), methods: self.methods.clone(),
} }
@ -48,7 +51,7 @@ impl<'a, Err: ErrorRenderer> Route<Err> {
impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Route<Err> { impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Route<Err> {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = RouteService<Err>; type Service = RouteService<Err>;
type Future = Ready<Self::Service, ()>; type Future = Ready<Self::Service, ()>;
@ -59,7 +62,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Rou
} }
pub struct RouteService<Err: ErrorRenderer> { pub struct RouteService<Err: ErrorRenderer> {
handler: Box<dyn HandlerFn<Err>>, handler: Box<dyn HandlerFn<'static, Err>>,
methods: Vec<Method>, methods: Vec<Method>,
guards: Rc<Vec<Box<dyn Guard>>>, guards: Rc<Vec<Box<dyn Guard>>>,
} }
@ -81,7 +84,7 @@ impl<Err: ErrorRenderer> RouteService<Err> {
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteService<Err> { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteService<Err> {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + 'a>>; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + 'a>>;
#[inline] #[inline]
@ -91,7 +94,9 @@ impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteServi
#[inline] #[inline]
fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future {
self.handler.call(req) let handler: &dyn HandlerFn<'a, Err> =
unsafe { std::mem::transmute(&*self.handler) };
handler.call(req)
} }
} }
@ -178,29 +183,31 @@ impl<Err: ErrorRenderer> Route<Err> {
/// ); /// );
/// } /// }
/// ``` /// ```
pub fn to<F, Args>(mut self, handler: F) -> Self pub fn to<'a, F, Args>(self, handler: F) -> Self
where where
F: Handler<Args, Err>, F: Handler<'a, Args, Err>,
Args: FromRequest<'a, Err> + 'static, Args: FromRequest<'a, Err> + 'a,
Args::Error: Into<Err::Container>, Args::Error: Error<Err>,
{ {
self.handler = Box::new(HandlerWrapper::new(handler)); let handler: Box<dyn HandlerFn<'a, Err>> = Box::new(HandlerWrapper::new(handler));
self.handler
.set(Some(unsafe { std::mem::transmute(handler) }));
self self
} }
} }
/// Convert object to a vec of routes /// Convert object to a vec of routes
pub trait IntoRoutes<Err: ErrorRenderer> { pub trait IntoRoutes<'a, Err: ErrorRenderer> {
fn routes(self) -> Vec<Route<Err>>; fn routes(self) -> Vec<Route<Err>>;
} }
impl<Err: ErrorRenderer> IntoRoutes<Err> for Route<Err> { impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for Route<Err> {
fn routes(self) -> Vec<Route<Err>> { fn routes(self) -> Vec<Route<Err>> {
vec![self] vec![self]
} }
} }
impl<Err: ErrorRenderer> IntoRoutes<Err> for Vec<Route<Err>> { impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for Vec<Route<Err>> {
fn routes(self) -> Vec<Route<Err>> { fn routes(self) -> Vec<Route<Err>> {
self self
} }
@ -209,7 +216,7 @@ impl<Err: ErrorRenderer> IntoRoutes<Err> for Vec<Route<Err>> {
macro_rules! tuple_routes({$(($n:tt, $T:ty)),+} => { macro_rules! tuple_routes({$(($n:tt, $T:ty)),+} => {
/// IntoRoutes implementation for a tuple /// IntoRoutes implementation for a tuple
#[allow(unused_parens)] #[allow(unused_parens)]
impl<Err: ErrorRenderer> IntoRoutes<Err> for ($($T,)+) { impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for ($($T,)+) {
fn routes(self) -> Vec<Route<Err>> { fn routes(self) -> Vec<Route<Err>> {
vec![$(self.$n,)+] vec![$(self.$n,)+]
} }
@ -219,7 +226,7 @@ macro_rules! tuple_routes({$(($n:tt, $T:ty)),+} => {
macro_rules! array_routes({$num:tt, $($T:ident),+} => { macro_rules! array_routes({$num:tt, $($T:ident),+} => {
/// IntoRoutes implementation for an array /// IntoRoutes implementation for an array
#[allow(unused_parens)] #[allow(unused_parens)]
impl<Err: ErrorRenderer> IntoRoutes<Err> for [Route<Err>; $num] impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for [Route<Err>; $num]
where where
Err: ErrorRenderer, Err: ErrorRenderer,
{ {

View file

@ -1,16 +1,13 @@
use std::task::{Context, Poll}; use std::rc::Rc;
use std::{convert::Infallible, future::Future, marker::PhantomData, pin::Pin, rc::Rc};
use crate::router::{IntoPattern, ResourceDef}; use crate::router::{IntoPattern, ResourceDef};
use crate::service::{IntoServiceFactory, Service, ServiceFactory}; use crate::service::{IntoServiceFactory, ServiceFactory};
use crate::util::Extensions; use crate::util::Extensions;
use super::boxed::{self, BoxServiceFactory}; use super::boxed::{self, BoxServiceFactory};
use super::config::AppConfig;
use super::dev::insert_slash;
use super::rmap::ResourceMap;
use super::types::state::StateFactory; use super::types::state::StateFactory;
use super::{guard::Guard, ErrorRenderer, WebRequest, WebResponse}; use super::{config::AppConfig, dev::insert_slash, rmap::ResourceMap};
use super::{error::Error, guard::Guard, ErrorRenderer, WebRequest, WebResponse};
pub trait WebService<'a, Err: ErrorRenderer>: 'static { pub trait WebService<'a, Err: ErrorRenderer>: 'static {
fn register(self, config: &mut WebServiceConfig<'a, Err>); fn register(self, config: &mut WebServiceConfig<'a, Err>);
@ -60,7 +57,7 @@ pub struct WebServiceConfig<'a, Err: ErrorRenderer> {
impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
/// Crate server settings instance /// Crate server settings instance
pub(crate) fn new( pub(super) fn new(
config: AppConfig, config: AppConfig,
default: Rc<BoxServiceFactory<'a, Err>>, default: Rc<BoxServiceFactory<'a, Err>>,
service_state: Rc<Vec<Box<dyn StateFactory>>>, service_state: Rc<Vec<Box<dyn StateFactory>>>,
@ -79,7 +76,7 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
self.root self.root
} }
pub(crate) fn into_services( pub(super) fn into_services(
self, self,
) -> ( ) -> (
AppConfig, AppConfig,
@ -132,11 +129,11 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
S: ServiceFactory< S: ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = WebResponse, Response = WebResponse,
Error = Err::Container,
InitError = (), InitError = (),
> + 'static, > + 'static,
S::Future: 'static, S::Future: 'static,
S::Service: 'static, S::Service: 'static,
S::Error: Error<Err>,
{ {
self.services self.services
.push((rdef, boxed::factory(factory), guards, nested)); .push((rdef, boxed::factory(factory), guards, nested));
@ -158,7 +155,8 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> {
/// .finish(my_service) /// .finish(my_service)
/// ); /// );
/// ``` /// ```
pub struct WebServiceAdapter { pub struct WebServiceAdapter<T = ()> {
srv: T,
rdef: Vec<String>, rdef: Vec<String>,
name: Option<String>, name: Option<String>,
guards: Vec<Box<dyn Guard>>, guards: Vec<Box<dyn Guard>>,
@ -168,6 +166,7 @@ impl WebServiceAdapter {
/// Create new `WebServiceAdapter` instance. /// Create new `WebServiceAdapter` instance.
pub fn new<T: IntoPattern>(path: T) -> Self { pub fn new<T: IntoPattern>(path: T) -> Self {
WebServiceAdapter { WebServiceAdapter {
srv: (),
rdef: path.patterns(), rdef: path.patterns(),
name: None, name: None,
guards: Vec::new(), guards: Vec::new(),
@ -205,65 +204,54 @@ impl WebServiceAdapter {
self self
} }
// /// Set a service factory implementation and generate web service. /// Set a service factory implementation and generate web service.
// pub fn finish<'a, T, F, Err>(self, service: F) -> impl WebServiceFactory<'a, Err> pub fn finish<'a, T, F, Err>(self, service: F) -> WebServiceAdapter<T>
// where where
// F: IntoServiceFactory<T, &'a mut WebRequest<'a, Err>>, F: IntoServiceFactory<T, &'a mut WebRequest<'a, Err>>,
// T: ServiceFactory< T: ServiceFactory<
// &'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
// Response = WebResponse, Response = WebResponse,
// Error = Err::Container, InitError = (),
// InitError = (), >,
// > + 'static, T::Error: Error<Err>,
// Err: ErrorRenderer, Err: ErrorRenderer,
// { {
// WebServiceImpl { WebServiceAdapter {
// srv: service.into_factory(), srv: service.into_factory(),
// rdef: self.rdef, rdef: self.rdef,
// name: self.name, name: self.name,
// guards: self.guards, guards: self.guards,
// _t: PhantomData, }
// } }
// }
} }
// struct WebServiceImpl<T> { impl<'a, T, Err> WebService<'a, Err> for WebServiceAdapter<T>
// srv: T, where
// rdef: Vec<String>, T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()>
// name: Option<String>, + 'static,
// guards: Vec<Box<dyn Guard>>, T::Future: 'static,
// } T::Service: 'static,
T::Error: Error<Err>,
Err: ErrorRenderer,
{
fn register(mut self, config: &mut WebServiceConfig<'a, Err>) {
let guards = if self.guards.is_empty() {
None
} else {
Some(std::mem::take(&mut self.guards))
};
// impl<'a, T, Err> WebServiceFactory<'a, Err> for WebServiceImpl<T> let mut rdef = if config.is_root() || !self.rdef.is_empty() {
// where ResourceDef::new(insert_slash(self.rdef))
// T: ServiceFactory< } else {
// &'a mut WebRequest<'a, Err>, ResourceDef::new(self.rdef)
// Response = WebResponse, };
// Error = Err::Container, if let Some(ref name) = self.name {
// InitError = (), *rdef.name_mut() = name.clone();
// > + 'static, }
// T::Future: 'static, config.register_service(rdef, guards, self.srv, None)
// T::Service: 'static, }
// Err: ErrorRenderer, }
// {
// fn register(mut self, config: &mut WebServiceConfig<'a, Err>) {
// let guards = if self.guards.is_empty() {
// None
// } else {
// Some(std::mem::take(&mut self.guards))
// };
// let mut rdef = if config.is_root() || !self.rdef.is_empty() {
// ResourceDef::new(insert_slash(self.rdef))
// } else {
// ResourceDef::new(self.rdef)
// };
// if let Some(ref name) = self.name {
// *rdef.name_mut() = name.clone();
// }
// config.register_service(rdef, guards, self.srv, None)
// }
// }
// /// WebServiceFactory implementation for a Vec<T> // /// WebServiceFactory implementation for a Vec<T>
// #[allow(unused_parens)] // #[allow(unused_parens)]

View file

@ -1,16 +1,12 @@
use std::{ use std::{
convert::Infallible, future::Future, marker::PhantomData, pin::Pin, rc::Rc, convert::Infallible, future::Future, marker::PhantomData, pin::Pin, task::Context,
task::Context, task::Poll, task::Poll,
}; };
use crate::service::{ use crate::service::{dev::AndThenFactory, Service, ServiceFactory, Transform};
dev::AndThenFactory, pipeline_factory, PipelineFactory, Service, ServiceFactory,
Transform,
};
use crate::util::{ready, Ready}; use crate::util::{ready, Ready};
use super::httprequest::HttpRequest; use super::{Error, ErrorRenderer, WebRequest, WebResponse};
use super::{ErrorContainer, ErrorRenderer, WebRequest, WebResponse};
pub struct Stack<Inner, Outer> { pub struct Stack<Inner, Outer> {
inner: Inner, inner: Inner,
@ -75,7 +71,7 @@ where
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Err::Container; type Error = Infallible;
type Future = MiddlewareResponse<'a, S, Err>; type Future = MiddlewareResponse<'a, S, Err>;
#[inline] #[inline]
@ -104,7 +100,7 @@ where
S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Output = Result<WebResponse, Err::Container>; type Output = Result<WebResponse, Infallible>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(Ok(ready!(self.project().fut.poll(cx)).unwrap())) Poll::Ready(Ok(ready!(self.project().fut.poll(cx)).unwrap()))
@ -124,13 +120,13 @@ impl<S> Next<S> {
impl<'a, S, Err> Service<&'a mut WebRequest<'a, Err>> for Next<S> impl<'a, S, Err> Service<&'a mut WebRequest<'a, Err>> for Next<S>
where where
S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static,
S::Error: Into<Err::Container> + 'static, S::Error: Error<Err>,
S::Future: 'a, S::Future: 'a,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Response = WebResponse; type Response = WebResponse;
type Error = Infallible; type Error = Infallible;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + 'a>>; type Future = NextResponse<'a, S, Err>;
#[inline] #[inline]
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@ -142,13 +138,10 @@ where
fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future {
let r = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }; let r = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() };
let fut = self.next.call(r); NextResponse {
Box::pin(async move { req,
match fut.await { fut: self.next.call(r),
Ok(res) => Ok(res), }
Err(err) => Ok(WebResponse::new(err.into().error_response(&req.req))),
}
})
} }
} }
@ -163,7 +156,7 @@ pin_project_lite::pin_project! {
impl<'a, S, Err> Future for NextResponse<'a, S, Err> impl<'a, S, Err> Future for NextResponse<'a, S, Err>
where where
S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse>, S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse>,
S::Error: Into<Err::Container>, S::Error: Error<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Output = Result<WebResponse, Infallible>; type Output = Result<WebResponse, Infallible>;
@ -173,8 +166,7 @@ where
match ready!(this.fut.poll(cx)) { match ready!(this.fut.poll(cx)) {
Ok(res) => Poll::Ready(Ok(res)), Ok(res) => Poll::Ready(Ok(res)),
Err(err) => { Err(err) => {
let req = this.req.req.clone(); Poll::Ready(Ok(WebResponse::from_err(err, this.req.http_request())))
Poll::Ready(Ok(WebResponse::new(err.into().error_response(&req))))
} }
} }
} }
@ -192,7 +184,7 @@ impl<'a, Err: ErrorRenderer> FiltersFactory<'a, Err> for Filter {
impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Filter { impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Filter {
type Response = &'a mut WebRequest<'a, Err>; type Response = &'a mut WebRequest<'a, Err>;
type Error = Err::Container; type Error = Infallible;
type InitError = (); type InitError = ();
type Service = Filter; type Service = Filter;
type Future = Ready<Filter, ()>; type Future = Ready<Filter, ()>;
@ -205,7 +197,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Fil
impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for Filter { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for Filter {
type Response = &'a mut WebRequest<'a, Err>; type Response = &'a mut WebRequest<'a, Err>;
type Error = Err::Container; type Error = Infallible;
type Future = Ready<Self::Response, Self::Error>; type Future = Ready<Self::Response, Self::Error>;
#[inline] #[inline]
@ -236,7 +228,7 @@ where
First: ServiceFactory< First: ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
InitError = (), InitError = (),
> + 'static, > + 'static,
First::Service: 'static, First::Service: 'static,
@ -245,7 +237,7 @@ where
Second::Service: ServiceFactory< Second::Service: ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
InitError = (), InitError = (),
>, >,
<Second::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Service: 'static, <Second::Service as ServiceFactory<&'a mut WebRequest<'a, Err>>>::Service: 'static,
@ -262,7 +254,7 @@ pub trait FiltersFactory<'a, Err: ErrorRenderer> {
type Service: ServiceFactory< type Service: ServiceFactory<
&'a mut WebRequest<'a, Err>, &'a mut WebRequest<'a, Err>,
Response = &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>,
Error = Err::Container, Error = Infallible,
InitError = (), InitError = (),
> + 'static; > + 'static;

View file

@ -25,24 +25,29 @@ use crate::{io::Sealed, rt::System, server::Server};
use crate::web::config::AppConfig; use crate::web::config::AppConfig;
use crate::web::error::{DefaultError, ErrorRenderer}; use crate::web::error::{DefaultError, ErrorRenderer};
use crate::web::httprequest::{HttpRequest, HttpRequestPool}; use crate::web::httprequest::HttpRequest;
use crate::web::rmap::ResourceMap; use crate::web::rmap::ResourceMap;
use crate::web::{FromRequest, HttpResponse, Responder, WebRequest, WebResponse}; use crate::web::{FromRequest, HttpResponse, Responder, WebRequest, WebResponse};
/// Create service that always responds with `HttpResponse::Ok()` /// Create service that always responds with `HttpResponse::Ok()`
pub fn ok_service<Err: ErrorRenderer>( pub fn ok_service<'a, Err: ErrorRenderer>() -> impl Service<
) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> &'a mut WebRequest<'a, Err>,
{ Response = WebResponse,
Error = std::convert::Infallible,
> {
default_service::<Err>(StatusCode::OK) default_service::<Err>(StatusCode::OK)
} }
/// Create service that responds with response with specified status code /// Create service that responds with response with specified status code
pub fn default_service<Err: ErrorRenderer>( pub fn default_service<'a, Err: ErrorRenderer>(
status_code: StatusCode, status_code: StatusCode,
) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> ) -> impl Service<
{ &'a mut WebRequest<'a, Err>,
(move |req: &'a mut WebRequest<'a, Err>| { Response = WebResponse,
Ready::Ok(req.into_response(HttpResponse::build(status_code).finish())) Error = std::convert::Infallible,
> {
(move |_: &'a mut WebRequest<'a, Err>| {
Ready::Ok(HttpResponse::build(status_code).finish().into())
}) })
.into_service() .into_service()
} }
@ -249,11 +254,11 @@ where
} }
/// Helper method for extractors testing /// Helper method for extractors testing
pub async fn from_request<T: FromRequest<DefaultError>>( pub fn from_request<'a, T: FromRequest<'a, DefaultError>>(
req: &HttpRequest, req: &'a HttpRequest,
payload: &mut Payload, payload: &'a mut Payload,
) -> Result<T, T::Error> { ) -> T::Future {
T::from_request(req, payload).await T::from_request(req, payload)
} }
/// Helper method for responders testing /// Helper method for responders testing
@ -456,25 +461,25 @@ impl TestRequest {
self.req.finish() self.req.finish()
} }
/// Complete request creation and generate `WebRequest` instance // /// Complete request creation and generate `WebRequest` instance
pub fn to_srv_request(mut self) -> WebRequest<DefaultError> { // pub fn to_srv_request(&'_ mut self) -> &'_ mut WebRequest<'_, DefaultError> {
let (head, payload) = self.req.finish().into_parts(); // let (head, payload) = self.req.finish().into_parts();
*self.path.get_mut() = head.uri.clone(); // *self.path.get_mut() = head.uri.clone();
WebRequest::new(HttpRequest::new( // WebRequest::new(HttpRequest::new(
self.path, // self.path,
head, // head,
payload, // payload,
Rc::new(self.rmap), // Rc::new(self.rmap),
self.config.clone(), // self.config.clone(),
Rc::new(self.app_state), // Rc::new(self.app_state),
HttpRequestPool::create(), // HttpRequestPool::create(),
)) // ))
} // }
/// Complete request creation and generate `WebResponse` instance /// Complete request creation and generate `WebResponse` instance
pub fn to_srv_response(self, res: HttpResponse) -> WebResponse { pub fn to_srv_response(self, res: HttpResponse) -> WebResponse {
self.to_srv_request().into_response(res) res.into()
} }
/// Complete request creation and generate `HttpRequest` instance /// Complete request creation and generate `HttpRequest` instance
@ -482,15 +487,15 @@ impl TestRequest {
let (head, payload) = self.req.finish().into_parts(); let (head, payload) = self.req.finish().into_parts();
*self.path.get_mut() = head.uri.clone(); *self.path.get_mut() = head.uri.clone();
HttpRequest::new( HttpRequest::create(
self.path, self.path,
head, head,
payload, payload,
Rc::new(self.rmap), Rc::new(self.rmap),
self.config.clone(), self.config.clone(),
Rc::new(self.app_state), Rc::new(self.app_state),
HttpRequestPool::create(),
) )
.request
} }
/// Complete request creation and generate `HttpRequest` and `Payload` instances /// Complete request creation and generate `HttpRequest` and `Payload` instances
@ -498,15 +503,15 @@ impl TestRequest {
let (head, payload) = self.req.finish().into_parts(); let (head, payload) = self.req.finish().into_parts();
*self.path.get_mut() = head.uri.clone(); *self.path.get_mut() = head.uri.clone();
let req = HttpRequest::new( let req = HttpRequest::create(
self.path, self.path,
head, head,
Payload::None, Payload::None,
Rc::new(self.rmap), Rc::new(self.rmap),
self.config.clone(), self.config.clone(),
Rc::new(self.app_state), Rc::new(self.app_state),
HttpRequestPool::create(), )
); .request;
(req, payload) (req, payload)
} }

View file

@ -9,7 +9,7 @@ use crate::http::encoding::Decoder;
use crate::http::header::{CONTENT_LENGTH, CONTENT_TYPE}; use crate::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
use crate::http::{HttpMessage, Payload, Response, StatusCode}; use crate::http::{HttpMessage, Payload, Response, StatusCode};
use crate::util::{stream_recv, BytesMut}; use crate::util::{stream_recv, BytesMut};
use crate::web::error::{ErrorRenderer, UrlencodedError, WebResponseError}; use crate::web::error::{Error, ErrorRenderer, UrlencodedError};
use crate::web::responder::{Ready, Responder}; use crate::web::responder::{Ready, Responder};
use crate::web::{FromRequest, HttpRequest}; use crate::web::{FromRequest, HttpRequest};
@ -95,16 +95,16 @@ impl<T> ops::DerefMut for Form<T> {
} }
} }
impl<T, Err> FromRequest<Err> for Form<T> impl<'a, T, Err> FromRequest<'a, Err> for Form<T>
where where
T: DeserializeOwned + 'static, T: DeserializeOwned + 'a,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Error = UrlencodedError; type Error = UrlencodedError;
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>; type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>> + 'a>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future {
let limit = req let limit = req
.app_state::<FormConfig>() .app_state::<FormConfig>()
.map(|c| c.limit) .map(|c| c.limit)
@ -134,7 +134,7 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
impl<T: Serialize, Err: ErrorRenderer> Responder<Err> for Form<T> impl<T: Serialize, Err: ErrorRenderer> Responder<Err> for Form<T>
where where
Err::Container: From<serde_urlencoded::ser::Error>, serde_urlencoded::ser::Error: Error<Err>,
{ {
type Future = Ready<Response>; type Future = Ready<Response>;
@ -208,7 +208,7 @@ impl Default for FormConfig {
/// * content type is not `application/x-www-form-urlencoded` /// * content type is not `application/x-www-form-urlencoded`
/// * content-length is greater than 32k /// * content-length is greater than 32k
/// ///
struct UrlEncoded<U> { struct UrlEncoded<'a, U> {
#[cfg(feature = "compress")] #[cfg(feature = "compress")]
stream: Option<Decoder<Payload>>, stream: Option<Decoder<Payload>>,
#[cfg(not(feature = "compress"))] #[cfg(not(feature = "compress"))]
@ -217,12 +217,12 @@ struct UrlEncoded<U> {
length: Option<usize>, length: Option<usize>,
encoding: &'static Encoding, encoding: &'static Encoding,
err: Option<UrlencodedError>, err: Option<UrlencodedError>,
fut: Option<Pin<Box<dyn Future<Output = Result<U, UrlencodedError>>>>>, fut: Option<Pin<Box<dyn Future<Output = Result<U, UrlencodedError>> + 'a>>>,
} }
impl<U> UrlEncoded<U> { impl<'a, U> UrlEncoded<'a, U> {
/// Create a new future to URL encode a request /// Create a new future to URL encode a request
fn new(req: &HttpRequest, payload: &mut Payload) -> UrlEncoded<U> { fn new(req: &'a HttpRequest, payload: &'a mut Payload) -> UrlEncoded<'a, U> {
// check content type // check content type
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" { if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
return Self::err(UrlencodedError::ContentType); return Self::err(UrlencodedError::ContentType);
@ -278,9 +278,9 @@ impl<U> UrlEncoded<U> {
} }
} }
impl<U> Future for UrlEncoded<U> impl<'a, U> Future for UrlEncoded<'a, U>
where where
U: DeserializeOwned + 'static, U: DeserializeOwned + 'a,
{ {
type Output = Result<U, UrlencodedError>; type Output = Result<U, UrlencodedError>;

View file

@ -8,7 +8,7 @@ use crate::http::encoding::Decoder;
use crate::http::header::CONTENT_LENGTH; use crate::http::header::CONTENT_LENGTH;
use crate::http::{HttpMessage, Payload, Response, StatusCode}; use crate::http::{HttpMessage, Payload, Response, StatusCode};
use crate::util::{stream_recv, BytesMut}; use crate::util::{stream_recv, BytesMut};
use crate::web::error::{ErrorRenderer, JsonError, JsonPayloadError, WebResponseError}; use crate::web::error::{Error, ErrorRenderer, JsonError, JsonPayloadError};
use crate::web::responder::{Ready, Responder}; use crate::web::responder::{Ready, Responder};
use crate::web::{FromRequest, HttpRequest}; use crate::web::{FromRequest, HttpRequest};
@ -110,7 +110,7 @@ where
impl<T: Serialize, Err: ErrorRenderer> Responder<Err> for Json<T> impl<T: Serialize, Err: ErrorRenderer> Responder<Err> for Json<T>
where where
Err::Container: From<JsonError>, JsonError: Error<Err>,
{ {
type Future = Ready<Response>; type Future = Ready<Response>;
@ -158,15 +158,15 @@ where
/// ); /// );
/// } /// }
/// ``` /// ```
impl<T, Err: ErrorRenderer> FromRequest<Err> for Json<T> impl<'a, T, Err: ErrorRenderer> FromRequest<'a, Err> for Json<T>
where where
T: DeserializeOwned + 'static, T: DeserializeOwned + 'a,
{ {
type Error = JsonPayloadError; type Error = JsonPayloadError;
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>; type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>> + 'a>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future {
let req2 = req.clone(); let req2 = req.clone();
let (limit, ctype) = req let (limit, ctype) = req
.app_state::<JsonConfig>() .app_state::<JsonConfig>()
@ -260,7 +260,7 @@ impl Default for JsonConfig {
/// * content type is not `application/json` /// * content type is not `application/json`
/// (unless specified in [`JsonConfig`](struct.JsonConfig.html)) /// (unless specified in [`JsonConfig`](struct.JsonConfig.html))
/// * content length is greater than 256k /// * content length is greater than 256k
struct JsonBody<U> { struct JsonBody<'a, U> {
limit: usize, limit: usize,
length: Option<usize>, length: Option<usize>,
#[cfg(feature = "compress")] #[cfg(feature = "compress")]
@ -268,17 +268,17 @@ struct JsonBody<U> {
#[cfg(not(feature = "compress"))] #[cfg(not(feature = "compress"))]
stream: Option<Payload>, stream: Option<Payload>,
err: Option<JsonPayloadError>, err: Option<JsonPayloadError>,
fut: Option<Pin<Box<dyn Future<Output = Result<U, JsonPayloadError>>>>>, fut: Option<Pin<Box<dyn Future<Output = Result<U, JsonPayloadError>> + 'a>>>,
} }
impl<U> JsonBody<U> impl<'a, U> JsonBody<'a, U>
where where
U: DeserializeOwned + 'static, U: DeserializeOwned + 'a,
{ {
/// Create `JsonBody` for request. /// Create `JsonBody` for request.
fn new( fn new(
req: &HttpRequest, req: &'a HttpRequest,
payload: &mut Payload, payload: &'a mut Payload,
ctype: Option<Arc<dyn Fn(mime::Mime) -> bool + Send + Sync>>, ctype: Option<Arc<dyn Fn(mime::Mime) -> bool + Send + Sync>>,
) -> Self { ) -> Self {
// check content-type // check content-type
@ -327,9 +327,9 @@ where
} }
} }
impl<U> Future for JsonBody<U> impl<'a, U> Future for JsonBody<'a, U>
where where
U: DeserializeOwned + 'static, U: DeserializeOwned + 'a,
{ {
type Output = Result<U, JsonPayloadError>; type Output = Result<U, JsonPayloadError>;

View file

@ -149,15 +149,15 @@ impl<T: fmt::Display> fmt::Display for Path<T> {
/// ); /// );
/// } /// }
/// ``` /// ```
impl<T, Err: ErrorRenderer> FromRequest<Err> for Path<T> impl<'a, T, Err: ErrorRenderer> FromRequest<'a, Err> for Path<T>
where where
T: de::DeserializeOwned, T: de::DeserializeOwned + 'a,
{ {
type Error = PathError; type Error = PathError;
type Future = Ready<Self, Self::Error>; type Future = Ready<Self, Self::Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future {
Ready::from( Ready::from(
de::Deserialize::deserialize(PathDeserializer::new(req.match_info())) de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
.map(|inner| Path { inner }) .map(|inner| Path { inner })

View file

@ -1,5 +1,5 @@
//! Payload/Bytes/String extractors //! Payload/Bytes/String extractors
use std::{future::Future, pin::Pin, str, task::Context, task::Poll}; use std::{convert::Infallible, future::Future, pin::Pin, str, task::Context, task::Poll};
use encoding_rs::UTF_8; use encoding_rs::UTF_8;
use mime::Mime; use mime::Mime;
@ -105,12 +105,15 @@ impl Stream for Payload {
/// ); /// );
/// } /// }
/// ``` /// ```
impl<Err: ErrorRenderer> FromRequest<Err> for Payload { impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for Payload {
type Error = Err::Container; type Error = Infallible;
type Future = Ready<Payload, Self::Error>; type Future = Ready<Payload, Self::Error>;
#[inline] #[inline]
fn from_request(_: &HttpRequest, payload: &mut crate::http::Payload) -> Self::Future { fn from_request(
_: &'a HttpRequest,
payload: &'a mut crate::http::Payload,
) -> Self::Future {
Ready::Ok(Payload(payload.take())) Ready::Ok(Payload(payload.take()))
} }
} }
@ -139,15 +142,18 @@ impl<Err: ErrorRenderer> FromRequest<Err> for Payload {
/// ); /// );
/// } /// }
/// ``` /// ```
impl<Err: ErrorRenderer> FromRequest<Err> for Bytes { impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for Bytes {
type Error = PayloadError; type Error = PayloadError;
type Future = Either< type Future = Either<
Pin<Box<dyn Future<Output = Result<Bytes, Self::Error>>>>, Pin<Box<dyn Future<Output = Result<Bytes, Self::Error>> + 'a>>,
Ready<Bytes, Self::Error>, Ready<Bytes, Self::Error>,
>; >;
#[inline] #[inline]
fn from_request(req: &HttpRequest, payload: &mut crate::http::Payload) -> Self::Future { fn from_request(
req: &'a HttpRequest,
payload: &'a mut crate::http::Payload,
) -> Self::Future {
let tmp; let tmp;
let cfg = if let Some(cfg) = req.app_state::<PayloadConfig>() { let cfg = if let Some(cfg) = req.app_state::<PayloadConfig>() {
cfg cfg
@ -193,15 +199,18 @@ impl<Err: ErrorRenderer> FromRequest<Err> for Bytes {
/// ); /// );
/// } /// }
/// ``` /// ```
impl<Err: ErrorRenderer> FromRequest<Err> for String { impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for String {
type Error = PayloadError; type Error = PayloadError;
type Future = Either< type Future = Either<
Pin<Box<dyn Future<Output = Result<String, Self::Error>>>>, Pin<Box<dyn Future<Output = Result<String, Self::Error>> + 'a>>,
Ready<String, Self::Error>, Ready<String, Self::Error>,
>; >;
#[inline] #[inline]
fn from_request(req: &HttpRequest, payload: &mut crate::http::Payload) -> Self::Future { fn from_request(
req: &'a HttpRequest,
payload: &'a mut crate::http::Payload,
) -> Self::Future {
let tmp; let tmp;
let cfg = if let Some(cfg) = req.app_state::<PayloadConfig>() { let cfg = if let Some(cfg) = req.app_state::<PayloadConfig>() {
cfg cfg

View file

@ -122,16 +122,16 @@ impl<T: fmt::Display> fmt::Display for Query<T> {
/// .route(web::get().to(index))); // <- use `Query` extractor /// .route(web::get().to(index))); // <- use `Query` extractor
/// } /// }
/// ``` /// ```
impl<T, Err> FromRequest<Err> for Query<T> impl<'a, T, Err> FromRequest<'a, Err> for Query<T>
where where
T: de::DeserializeOwned, T: de::DeserializeOwned + 'a,
Err: ErrorRenderer, Err: ErrorRenderer,
{ {
type Error = QueryPayloadError; type Error = QueryPayloadError;
type Future = Ready<Self, Self::Error>; type Future = Ready<Self, Self::Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future {
serde_urlencoded::from_str::<T>(req.query_string()) serde_urlencoded::from_str::<T>(req.query_string())
.map(|val| Ready::Ok(Query(val))) .map(|val| Ready::Ok(Query(val)))
.unwrap_or_else(move |e| { .unwrap_or_else(move |e| {

View file

@ -97,12 +97,12 @@ impl<T> Clone for State<T> {
} }
} }
impl<T: 'static, E: ErrorRenderer> FromRequest<E> for State<T> { impl<'a, T: 'static, E: ErrorRenderer> FromRequest<'a, E> for State<T> {
type Error = DataExtractorError; type Error = DataExtractorError;
type Future = Ready<Self, Self::Error>; type Future = Ready<Self, Self::Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future {
if let Some(st) = req.app_state::<State<T>>() { if let Some(st) = req.app_state::<State<T>>() {
Ready::Ok(st.clone()) Ready::Ok(st.clone())
} else { } else {

View file

@ -10,7 +10,7 @@ use crate::http::{Method, Request, Response};
use crate::service::{IntoServiceFactory, ServiceFactory}; use crate::service::{IntoServiceFactory, ServiceFactory};
use super::config::AppConfig; use super::config::AppConfig;
use super::error::ErrorRenderer; use super::error::{Error, ErrorRenderer};
use super::extract::FromRequest; use super::extract::FromRequest;
use super::handler::Handler; use super::handler::Handler;
use super::resource::Resource; use super::resource::Resource;
@ -79,7 +79,7 @@ pub fn resource<T: IntoPattern, Err: ErrorRenderer>(path: T) -> Resource<Err> {
// } // }
/// Create *route* without configuration. /// Create *route* without configuration.
pub fn route<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn route<Err: ErrorRenderer>() -> Route<Err> {
Route::new() Route::new()
} }
@ -97,7 +97,7 @@ pub fn route<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `GET` route gets added: /// In the above example, one `GET` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn get<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn get<Err: ErrorRenderer>() -> Route<Err> {
method(Method::GET) method(Method::GET)
} }
@ -115,7 +115,7 @@ pub fn get<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `POST` route gets added: /// In the above example, one `POST` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn post<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn post<Err: ErrorRenderer>() -> Route<Err> {
method(Method::POST) method(Method::POST)
} }
@ -133,7 +133,7 @@ pub fn post<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `PUT` route gets added: /// In the above example, one `PUT` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn put<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn put<Err: ErrorRenderer>() -> Route<Err> {
method(Method::PUT) method(Method::PUT)
} }
@ -151,7 +151,7 @@ pub fn put<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `PATCH` route gets added: /// In the above example, one `PATCH` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn patch<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn patch<Err: ErrorRenderer>() -> Route<Err> {
method(Method::PATCH) method(Method::PATCH)
} }
@ -169,7 +169,7 @@ pub fn patch<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `DELETE` route gets added: /// In the above example, one `DELETE` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn delete<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn delete<Err: ErrorRenderer>() -> Route<Err> {
method(Method::DELETE) method(Method::DELETE)
} }
@ -187,7 +187,7 @@ pub fn delete<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `HEAD` route gets added: /// In the above example, one `HEAD` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn head<'a, Err: ErrorRenderer>() -> Route<Err> { pub fn head<Err: ErrorRenderer>() -> Route<Err> {
method(Method::HEAD) method(Method::HEAD)
} }
@ -205,7 +205,7 @@ pub fn head<'a, Err: ErrorRenderer>() -> Route<Err> {
/// In the above example, one `GET` route gets added: /// In the above example, one `GET` route gets added:
/// * /{project_id} /// * /{project_id}
/// ///
pub fn method<'a, Err: ErrorRenderer>(method: Method) -> Route<Err> { pub fn method<Err: ErrorRenderer>(method: Method) -> Route<Err> {
Route::new().method(method) Route::new().method(method)
} }
@ -224,10 +224,10 @@ pub fn method<'a, Err: ErrorRenderer>(method: Method) -> Route<Err> {
/// ``` /// ```
pub fn to<'a, F, Args, Err>(handler: F) -> Route<Err> pub fn to<'a, F, Args, Err>(handler: F) -> Route<Err>
where where
F: Handler<Args, Err>, F: Handler<'a, Args, Err>,
Args: FromRequest<Err> + 'static, Args: FromRequest<'a, Err> + 'a,
Args::Error: Error<Err>,
Err: ErrorRenderer, Err: ErrorRenderer,
Err::Container: From<Args::Error>,
{ {
Route::new().to(handler) Route::new().to(handler)
} }