diff --git a/ntex/examples/basic.rs b/ntex/examples/basic.rs index a4c8fe85..0b803fef 100644 --- a/ntex/examples/basic.rs +++ b/ntex/examples/basic.rs @@ -2,12 +2,12 @@ use ntex::http; use ntex::web::{self, middleware, App, HttpRequest, HttpResponse, HttpServer}; #[web::get("/resource1/{name}/index.html")] -async fn index(req: HttpRequest, name: web::types::Path) -> String { +async fn index(req: &HttpRequest, name: web::types::Path) -> String { println!("REQ: {:?}", req); format!("Hello: {}!\r\n", name) } -async fn index_async(req: HttpRequest) -> &'static str { +async fn index_async(req: &HttpRequest) -> &'static str { println!("REQ: {:?}", req); "Hello world!\r\n" } diff --git a/ntex/src/http/response.rs b/ntex/src/http/response.rs index 42cea3cd..adc91217 100644 --- a/ntex/src/http/response.rs +++ b/ntex/src/http/response.rs @@ -234,6 +234,12 @@ impl Response { } } +impl fmt::Display for Response { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "{:?}", self) + } +} + impl fmt::Debug for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let res = writeln!( diff --git a/ntex/src/web/app.rs b/ntex/src/web/app.rs index 2d4118cb..ebbe4ca7 100644 --- a/ntex/src/web/app.rs +++ b/ntex/src/web/app.rs @@ -2,15 +2,14 @@ use std::{cell::RefCell, convert::Infallible, fmt, future::Future, pin::Pin, rc: use crate::http::Request; 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::util::Extensions; -use super::app_service::{ - AppFactory, AppFactoryInner, AppRouting, AppService, DefaultService, -}; +use super::app_service::{AppFactory, AppFactoryInner, AppRouting, DefaultService}; use super::boxed::{self, BoxServiceFactory}; use super::config::{AppConfig, ServiceConfig}; +use super::error::Error; use super::service::{create_web_service, WebService, WebServiceWrapper}; use super::stack::{Filter, Filters, FiltersFactory, Next, Stack}; use super::types::state::{State, StateFactory}; @@ -267,18 +266,15 @@ where pub fn default(mut self, f: T) -> Self where T: IntoServiceFactory>, - U: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = WebResponse, - Error = Err::Container, - > + 'static, + U: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, U::Service: 'static, U::Future: 'static, + U::Error: Error, U::InitError: fmt::Debug + 'static, { // create and configure default resource 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) })); @@ -343,9 +339,9 @@ where /// .route("/index.html", web::get().to(index)); /// } /// ``` - pub fn filter(self, filter: U) -> App<'a, M, Filters, Err> { + pub fn filter(self, filter: U) -> App<'a, M, Filters>, Err> { App { - filter: Filters::new(self.filter, filter), + filter: Filters::new(self.filter, Next::new(filter)), middleware: self.middleware, state: self.state, state_factories: self.state_factories, diff --git a/ntex/src/web/app_service.rs b/ntex/src/web/app_service.rs index c52d5ccb..5ef9382e 100644 --- a/ntex/src/web/app_service.rs +++ b/ntex/src/web/app_service.rs @@ -4,20 +4,15 @@ use std::{cell::RefCell, future::Future, marker::PhantomData, pin::Pin, rc::Rc}; use crate::http::{Request, Response}; use crate::router::{Path, ResourceDef, Router}; -use crate::service::{ - fn_service, into_service, PipelineFactory, Service, ServiceFactory, Transform, -}; -use crate::util::{ready, Extensions, Ready}; +use crate::service::{Service, ServiceFactory, Transform}; +use crate::util::{ready, Either, Extensions, Ready}; -use super::boxed::{self, BoxService, BoxServiceFactory}; -use super::config::AppConfig; -use super::guard::Guard; +use super::boxed::{BoxService, BoxServiceFactory}; use super::httprequest::{HttpRequest, HttpRequestPool}; -use super::rmap::ResourceMap; -use super::service::{WebService, WebServiceConfig, WebServiceWrapper}; -use super::stack::{Filter, FiltersFactory, Next}; +use super::service::{WebServiceConfig, WebServiceWrapper}; 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>; type BoxResponse<'a> = Pin> + 'a>>; @@ -153,19 +148,19 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for DefaultService { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = Self; type Future = Ready; - fn new_service(&self, cfg: ()) -> Self::Future { + fn new_service(&self, _: ()) -> Self::Future { Ready::Ok(DefaultService(PhantomData)) } } impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Future = Ready; fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { @@ -280,36 +275,46 @@ where let hnd: WebAppHandler2<'a> = Box::new(move |req: Request| { let (head, payload) = req.into_parts(); - let mut req = if let Some(mut req) = pool.get_request() { - let inner = Rc::get_mut(&mut req.0).unwrap(); - inner.path.set(head.uri.clone()); - inner.head = head; - inner.payload = payload; - inner.app_state = state.clone(); - req + let http_req; + let mut web_req = if let Some(mut req) = pool.get_request() { + req.request.path.set(head.uri.clone()); + req.request.head = head; + req.payload = payload; + req.request.app_state = state.clone(); + let web_req = WebRequest::::new(unsafe { + std::mem::transmute(&mut *req) + }); + http_req = Either::Left(req); + web_req } else { - HttpRequest::new( + let mut req = HttpRequest::create( Path::new(head.uri.clone()), head, payload, rmap.clone(), config.clone(), state.clone(), - pool, - ) + ); + let web_req = WebRequest::::new(unsafe { + std::mem::transmute(&mut req) + }); + http_req = Either::Right(req); + web_req }; - let mut wreq = - WebRequest::::new(unsafe { std::mem::transmute(&mut req) }); - let fut = service.call(unsafe { std::mem::transmute(&mut wreq) }); + let fut = service.call(unsafe { std::mem::transmute(&mut web_req) }); Box::pin(async move { let mut res = fut.await.unwrap(); - let head = req.head(); + let head = web_req.head(); if head.upgrade() { res.response.head_mut().set_io(head); } - drop(wreq); - drop(req); + drop(web_req); + + match http_req { + Either::Left(req) => pool.release_boxed(req), + Either::Right(req) => pool.release_unboxed(req), + } Ok(res) }) }); @@ -335,7 +340,7 @@ where F: Service< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, >, F::Future: 'a, Err: ErrorRenderer, @@ -350,7 +355,7 @@ where 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 r2 = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }; @@ -358,10 +363,7 @@ where let router = self.router.clone(); Box::pin(async move { - match fut.await { - Ok(res) => (), - Err(err) => return Ok(WebResponse::new(err.error_response(&req.req))), - } + let _ = fut.await.unwrap(); let res = router.router.recognize_checked(req, |req, guards| { if let Some(guards) = guards { @@ -375,15 +377,9 @@ where }); if let Some((srv, _info)) = res { - match srv.call(r2).await { - Ok(res) => Ok(res), - Err(err) => Ok(WebResponse::new(err.error_response(&req.req))), - } + srv.call(r2).await } else if let Some(ref default) = router.default { - match default.call(r2).await { - Ok(res) => Ok(res), - Err(err) => Ok(WebResponse::new(err.error_response(&req.req))), - } + default.call(r2).await } else { Ok(WebResponse::new(Response::NotFound().finish())) } diff --git a/ntex/src/web/boxed.rs b/ntex/src/web/boxed.rs index 32f2579b..0bd89122 100644 --- a/ntex/src/web/boxed.rs +++ b/ntex/src/web/boxed.rs @@ -1,39 +1,37 @@ -use std::{ - future::Future, marker::PhantomData, pin::Pin, rc::Rc, task::Context, task::Poll, -}; +use std::convert::Infallible; +use std::{future::Future, marker::PhantomData, pin::Pin, task::Context, task::Poll}; -use super::{ErrorRenderer, WebRequest, WebResponse}; use crate::service::{Service, ServiceFactory}; -pub type BoxFuture<'a, Err: ErrorRenderer> = - Pin> + 'a>>; +use super::stack::Next; +use super::{Error, ErrorRenderer, WebRequest, WebResponse}; -pub type BoxFactoryFuture<'a, Err: ErrorRenderer> = +pub(super) type BoxFuture<'a> = + Pin> + 'a>>; + +pub(super) type BoxFactoryFuture<'a, Err: ErrorRenderer> = Pin, ()>>>>; -pub type BoxService<'a, Err: ErrorRenderer> = Box< +pub(super) type BoxService<'a, Err: ErrorRenderer> = Box< dyn Service< &'a mut WebRequest<'a, Err>, Response = WebResponse, - Error = Err::Container, - Future = BoxFuture<'a, Err>, + Error = Infallible, + Future = BoxFuture<'a>, > + 'static, >; pub struct BoxServiceFactory<'a, Err: ErrorRenderer>(Inner<'a, Err>); /// 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 Err: ErrorRenderer, - T: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = WebResponse, - Error = Err::Container, - InitError = (), - > + 'static, + T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()> + + 'static, T::Future: 'static, T::Service: 'static, + T::Error: Error, >>::Future: 'a, { BoxServiceFactory(FactoryWrapper::boxed(factory)) @@ -43,7 +41,7 @@ type Inner<'a, Err: ErrorRenderer + 'static> = Box< dyn ServiceFactory< &'a mut WebRequest<'a, Err>, Response = WebResponse, - Error = Err::Container, + Error = Infallible, InitError = (), Service = BoxService<'a, Err>, Future = BoxFactoryFuture<'a, Err>, @@ -54,7 +52,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for BoxServiceFactory<'a, Err> { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = BoxService<'a, Err>; type Future = BoxFactoryFuture<'a, Err>; @@ -72,14 +70,11 @@ struct FactoryWrapper { impl<'a, T, Err> FactoryWrapper where Err: ErrorRenderer + 'static, - T: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = WebResponse, - Error = Err::Container, - InitError = (), - > + 'static, + T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()> + + 'static, T::Future: 'static, T::Service: 'static, + T::Error: Error, >>::Future: 'a, { fn boxed(factory: T) -> Inner<'a, Err> { @@ -93,18 +88,15 @@ where impl<'a, T, Err> ServiceFactory<&'a mut WebRequest<'a, Err>> for FactoryWrapper where Err: ErrorRenderer + 'static, - T: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = WebResponse, - Error = Err::Container, - InitError = (), - > + 'static, + T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()> + + 'static, T::Future: 'static, T::Service: 'static, + T::Error: Error, >>::Future: 'a, { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = BoxService<'a, Err>; type Future = BoxFactoryFuture<'a, Err>; @@ -118,30 +110,30 @@ where } } -struct ServiceWrapper(T, PhantomData); +struct ServiceWrapper(Next, PhantomData); impl<'a, T, Err> ServiceWrapper where Err: ErrorRenderer, - T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> - + 'static, + T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, T::Future: 'a, + T::Error: Error, { 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 where Err: ErrorRenderer, - T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> - + 'static, + T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, T::Future: 'a, + T::Error: Error, { type Response = WebResponse; - type Error = Err::Container; - type Future = BoxFuture<'a, Err>; + type Error = Infallible; + type Future = BoxFuture<'a>; #[inline] fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { diff --git a/ntex/src/web/config.rs b/ntex/src/web/config.rs index 2957ae1e..7028d92f 100644 --- a/ntex/src/web/config.rs +++ b/ntex/src/web/config.rs @@ -2,11 +2,10 @@ use std::{net::SocketAddr, rc::Rc}; use crate::router::ResourceDef; -use super::resource::Resource; use super::route::Route; use super::service::{create_web_service, WebService, WebServiceWrapper}; use super::types::state::{State, StateFactory}; -use super::{DefaultError, ErrorRenderer}; +use super::{DefaultError, ErrorRenderer, Resource}; /// Application configuration #[derive(Clone)] @@ -87,12 +86,11 @@ impl<'a, Err: ErrorRenderer> ServiceConfig<'a, Err> { /// /// This is same as `App::route()` method. pub fn route(&mut self, path: &str, mut route: Route) -> &mut Self { - // self.service( - // Resource::new(path) - // .add_guards(route.take_guards()) - // .route(route), - // ) - self + self.service( + Resource::new(path) + .add_guards(route.take_guards()) + .route(route), + ) } /// Register http service. diff --git a/ntex/src/web/error.rs b/ntex/src/web/error.rs index f9d4e7d5..7251cef5 100644 --- a/ntex/src/web/error.rs +++ b/ntex/src/web/error.rs @@ -8,30 +8,19 @@ pub use serde_json::error::Error as JsonError; #[cfg(feature = "url")] pub use url_pkg::ParseError as UrlParseError; -use super::{HttpRequest, HttpResponse}; +use super::{HttpRequest, HttpResponse, WebResponse}; use crate::http::body::Body; use crate::http::helpers::Writer; use crate::http::{error, header, StatusCode}; 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 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; -} +pub trait ErrorRenderer: Sized + 'static {} /// Error that can be rendered to a `Response` -pub trait WebResponseError: - fmt::Display + fmt::Debug + 'static -where - Err: ErrorRenderer, -{ +pub trait Error: fmt::Display + fmt::Debug + Sized { /// Response's status code /// /// Internal server error is generated by default. @@ -42,7 +31,7 @@ where /// Generate response for error /// /// 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 buf = BytesMut::new(); let _ = write!(Writer(&mut buf), "{}", self); @@ -54,12 +43,31 @@ where } } -impl WebResponseError for std::convert::Infallible {} +impl Error for std::convert::Infallible {} -impl WebResponseError for Either +impl Error for WebResponse { + #[inline] + fn error_response(self, _: &HttpRequest) -> HttpResponse { + self.response + } +} + +impl Error for HttpResponse { + #[inline] + fn status_code(&self) -> StatusCode { + self.status() + } + + #[inline] + fn error_response(self, _: &HttpRequest) -> HttpResponse { + self + } +} + +impl Error for Either where - A: WebResponseError, - B: WebResponseError, + A: Error, + B: Error, Err: ErrorRenderer, { 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 { - Either::Left(ref a) => a.error_response(req), - Either::Right(ref b) => b.error_response(req), + Either::Left(a) => a.error_response(req), + Either::Right(b) => b.error_response(req), } } } @@ -245,13 +253,13 @@ where impl std::error::Error for InternalError {} -impl WebResponseError for InternalError +impl Error for InternalError where T: fmt::Debug + fmt::Display + 'static, E: ErrorRenderer, { - fn error_response(&self, _: &HttpRequest) -> HttpResponse { - crate::http::error::ResponseError::error_response(self) + fn error_response(self, _: &HttpRequest) -> HttpResponse { + crate::http::error::ResponseError::error_response(&self) } } diff --git a/ntex/src/web/error_default.rs b/ntex/src/web/error_default.rs index 615ab5b7..ae8d0dff 100644 --- a/ntex/src/web/error_default.rs +++ b/ntex/src/web/error_default.rs @@ -1,88 +1,25 @@ //! 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_json::error::Error as JsonError; 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::util::{timeout::TimeoutError, BytesMut}; +use crate::util::timeout::TimeoutError; use crate::ws::error::HandshakeError; -use super::error::{self, ErrorContainer, ErrorRenderer, WebResponseError}; +use super::error::{self, Error, ErrorRenderer}; use super::{HttpRequest, HttpResponse}; /// Default error type #[derive(Clone, Copy, Default)] pub struct 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>, -} - -impl Error { - pub fn new + 'static>(err: T) -> Error { - Error { - cause: Box::new(err), - } - } - - /// Returns the reference to the underlying `WebResponseError`. - pub fn as_response_error(&self) -> &dyn WebResponseError { - self.cause.as_ref() - } -} - -/// `Error` for any error which implements `WebResponseError` -impl> From 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) - } -} +impl ErrorRenderer for DefaultError {} /// Return `GATEWAY_TIMEOUT` for `TimeoutError` -impl> WebResponseError for TimeoutError { +impl> Error for TimeoutError { fn status_code(&self) -> StatusCode { match self { TimeoutError::Service(e) => e.status_code(), @@ -92,43 +29,37 @@ impl> WebResponseError for Timeo } /// `InternalServerError` for `DataExtractorError` -impl WebResponseError for error::DataExtractorError {} +impl Error for error::DataExtractorError {} /// `InternalServerError` for `JsonError` -impl WebResponseError for JsonError {} +impl Error for JsonError {} /// `InternalServerError` for `FormError` -impl WebResponseError for FormError {} +impl Error for FormError {} #[cfg(feature = "openssl")] /// `InternalServerError` for `openssl::ssl::Error` -impl WebResponseError for tls_openssl::ssl::Error {} +impl Error for tls_openssl::ssl::Error {} #[cfg(feature = "openssl")] /// `InternalServerError` for `openssl::ssl::HandshakeError` -impl WebResponseError - for tls_openssl::ssl::HandshakeError -{ -} +impl Error for tls_openssl::ssl::HandshakeError {} /// Return `BAD_REQUEST` for `de::value::Error` -impl WebResponseError for DeError { +impl Error for DeError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } } /// `InternalServerError` for `Canceled` -impl WebResponseError for crate::http::error::Canceled {} +impl Error for crate::http::error::Canceled {} /// `InternalServerError` for `BlockingError` -impl WebResponseError - for crate::http::error::BlockingError -{ -} +impl Error for crate::http::error::BlockingError {} /// Return `BAD_REQUEST` for `Utf8Error` -impl WebResponseError for Utf8Error { +impl Error for Utf8Error { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } @@ -136,10 +67,10 @@ impl WebResponseError for Utf8Error { /// Return `InternalServerError` for `HttpError`, /// Response generation can return `HttpError`, so it is internal error -impl WebResponseError for crate::http::error::HttpError {} +impl Error for crate::http::error::HttpError {} /// Return `InternalServerError` for `io::Error` -impl WebResponseError for io::Error { +impl Error for io::Error { fn status_code(&self) -> StatusCode { match self.kind() { io::ErrorKind::NotFound => StatusCode::NOT_FOUND, @@ -150,10 +81,10 @@ impl WebResponseError for io::Error { } /// `InternalServerError` for `UrlGeneratorError` -impl WebResponseError for error::UrlGenerationError {} +impl Error for error::UrlGenerationError {} /// Response renderer for `UrlencodedError` -impl WebResponseError for error::UrlencodedError { +impl Error for error::UrlencodedError { fn status_code(&self) -> StatusCode { match *self { error::UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE, @@ -164,7 +95,7 @@ impl WebResponseError for error::UrlencodedError { } /// Return `BadRequest` for `JsonPayloadError` -impl WebResponseError for error::JsonPayloadError { +impl Error for error::JsonPayloadError { fn status_code(&self) -> StatusCode { match *self { error::JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE, @@ -174,20 +105,20 @@ impl WebResponseError for error::JsonPayloadError { } /// Error renderer for `PathError` -impl WebResponseError for error::PathError { +impl Error for error::PathError { fn status_code(&self) -> StatusCode { StatusCode::NOT_FOUND } } /// Error renderer `QueryPayloadError` -impl WebResponseError for error::QueryPayloadError { +impl Error for error::QueryPayloadError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } } -impl WebResponseError for error::PayloadError { +impl Error for error::PayloadError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } @@ -197,7 +128,7 @@ impl WebResponseError for error::PayloadError { /// /// - `Overflow` returns `PayloadTooLarge` /// - Other errors returns `BadRequest` -impl WebResponseError for http::error::PayloadError { +impl Error for http::error::PayloadError { fn status_code(&self) -> StatusCode { match *self { http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE, @@ -208,21 +139,21 @@ impl WebResponseError for http::error::PayloadError { #[cfg(feature = "cookie")] /// Return `BadRequest` for `cookie::ParseError` -impl WebResponseError for coo_kie::ParseError { +impl Error for coo_kie::ParseError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } } /// Return `BadRequest` for `ContentTypeError` -impl WebResponseError for http::error::ContentTypeError { +impl Error for http::error::ContentTypeError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST } } /// Convert `SendRequestError` to a server `Response` -impl WebResponseError for http::client::error::SendRequestError { +impl Error for http::client::error::SendRequestError { fn status_code(&self) -> StatusCode { match *self { http::client::error::SendRequestError::Connect( @@ -235,9 +166,9 @@ impl WebResponseError for http::client::error::SendRequestError { } /// Error renderer for ws::HandshakeError -impl WebResponseError for HandshakeError { - fn error_response(&self, _: &HttpRequest) -> HttpResponse { - match *self { +impl Error for HandshakeError { + fn error_response(self, _: &HttpRequest) -> HttpResponse { + match self { HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed() .header(header::ALLOW, "GET") .finish(), diff --git a/ntex/src/web/extract.rs b/ntex/src/web/extract.rs index 0071952c..d6135cb2 100644 --- a/ntex/src/web/extract.rs +++ b/ntex/src/web/extract.rs @@ -1,7 +1,7 @@ //! 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 crate::{http::Payload, util::Ready}; @@ -17,13 +17,6 @@ pub trait FromRequest<'a, Err>: Sized { /// Convert request to a Self 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 @@ -75,10 +68,10 @@ impl<'a, T, Err> FromRequest<'a, Err> for Option where T: FromRequest<'a, Err> + 'static, T::Future: 'static, + T::Error: fmt::Debug, Err: ErrorRenderer, - >::Error: Into, { - type Error = Err::Container; + type Error = T::Error; type Future = Pin, Self::Error>> + 'a>>; #[inline] @@ -88,7 +81,7 @@ where match fut.await { Ok(v) => Ok(Some(v)), Err(e) => { - log::debug!("Error for Option extractor: {}", e.into()); + log::debug!("Error for Option extractor: {:?}", e); Ok(None) } } @@ -162,71 +155,124 @@ where #[doc(hidden)] impl<'a, E: ErrorRenderer> FromRequest<'a, E> for () { - type Error = E::Container; - type Future = Ready<(), E::Container>; + type Error = Infallible; + type Future = Ready<(), Infallible>; fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future { 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, +// { +// 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,), +// #[pin] +// fut1: Option, +// } +// } + +// impl<'a, Err: ErrorRenderer, T: FromRequest<'a, Err>> Future for TupleFromRequest1<'a, Err, T> +// where +// T: FromRequest<'a, Err> + 'a, +// T::Error: Into, +// { +// type Output = Result<(T,), Err::Container>; + +// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { +// 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)),+} => { /// FromRequest implementation for a tuple #[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 - $(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into),+ + $(<$T as FromRequest<'a, Err>>::Error: Error),+ { - type Error = Err::Container; + type Error = $crate::web::HttpResponse; type Future = $fut_type<'a, Err, $($T),+>; fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future { $fut_type { - items: <($(Option<$T>,)+)>::default(), - $($T: $T::from_request(req, payload),)+ + items: Default::default(), + $($T: $T::from_request(req, unsafe { (payload as *mut Payload).as_mut().unwrap() }),)+ + req, payload, } } } pin_project_lite::pin_project! { #[doc(hidden)] - pub struct $fut_type<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> - { - items: ($(Option<$T>,)+), - $(#[pin] $T: $T::Future),+ - } + pub struct $fut_type<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> + { + req: &'a HttpRequest, + 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),+> where - $(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into),+ + $(<$T as FromRequest<'a, Err>>::Error: Error),+ { - type Output = Result<($($T,)+), Err::Container>; + type Output = Result<($($T,)+), $crate::web::HttpResponse>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); - let mut ready = true; $( if this.items.$n.is_none() { - match this.$T.poll(cx) { - Poll::Ready(Ok(item)) => { + match $crate::util::ready!(this.$T.poll(cx)) { + Ok(item) => { this.items.$n = Some(item); } - Poll::Pending => ready = false, - Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), + Err(e) => return Poll::Ready(Err(e.error_response(this.req))), } } )+ - if ready { - Poll::Ready(Ok( - ($(this.items.$n.take().unwrap(),)+) - )) - } else { - Poll::Pending - } + Poll::Ready(Ok( + ($(this.items.$n.take().unwrap(),)+) + )) } } }); @@ -236,16 +282,16 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => { mod m { use super::*; -tuple_from_req!(TupleFromRequest1, (0, A)); -tuple_from_req!(TupleFromRequest2, (0, A), (1, B)); -// 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!(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!(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!(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!(TupleFromRequest1, (0, A)); + tuple_from_req!(TupleFromRequest2, (0, A), (1, B)); + 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!(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!(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!(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)); } #[cfg(test)] diff --git a/ntex/src/web/handler.rs b/ntex/src/web/handler.rs index a990fcdd..0e79e0cc 100644 --- a/ntex/src/web/handler.rs +++ b/ntex/src/web/handler.rs @@ -1,29 +1,27 @@ -use std::{ - fmt, future::Future, marker::PhantomData, pin::Pin, rc::Rc, task::Context, task::Poll, -}; +use std::convert::Infallible; +use std::{future::Future, marker::PhantomData, pin::Pin}; use super::error::ErrorRenderer; use super::extract::FromRequest; -use super::httprequest::HttpRequest; use super::request::WebRequest; use super::responder::Responder; use super::response::WebResponse; /// Async fn handler -pub trait Handler: Clone + 'static +pub trait Handler<'a, T, Err>: Clone + 'static where Err: ErrorRenderer, { type Output: Responder; - type Future: Future + 'static; + type Future: Future + 'a; fn call(&self, param: T) -> Self::Future; } -impl Handler<(), Err> for F +impl<'a, F, R, Err> Handler<'a, (), Err> for F where F: Fn() -> R + Clone + 'static, - R: Future + 'static, + R: Future + 'a, R::Output: Responder, Err: ErrorRenderer, { @@ -35,13 +33,11 @@ where } } -pub(super) trait HandlerFn { - fn call<'b>( +pub(super) trait HandlerFn<'a, Err: ErrorRenderer> { + fn call( &self, - _: &'b mut WebRequest<'b, Err>, - ) -> Pin> + 'b>>; - - fn clone_handler(&self) -> Box>; + _: &'a mut WebRequest<'a, Err>, + ) -> Pin> + 'a>>; } pub(super) struct HandlerWrapper { @@ -58,45 +54,38 @@ impl HandlerWrapper { } } -impl<'a, F, T, Err> HandlerFn for HandlerWrapper +impl<'a, F, T, Err> HandlerFn<'a, Err> for HandlerWrapper where - F: Handler, - T: FromRequest<'a, Err> + 'static, - T::Error: Into, + F: Handler<'a, T, Err>, + T: FromRequest<'a, Err> + 'a, Err: ErrorRenderer, { - fn call<'b>( + fn call( &self, - req: &'b mut WebRequest<'b, Err>, - ) -> Pin> + 'b>> { - let mut pl = Rc::get_mut(&mut (req.req).0).unwrap().payload.take(); + req: &'a mut WebRequest<'a, Err>, + ) -> Pin> + 'a>> { let hnd = self.hnd.clone(); 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 } else { panic!(); }; 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)) }) } - - fn clone_handler(&self) -> Box> { - Box::new(HandlerWrapper { - hnd: self.hnd.clone(), - _t: PhantomData, - }) - } } /// FromRequest trait impl for tuples macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => { - impl Handler<($($T,)+), Err> for Func + impl<'a, Func, $($T,)+ Res, Err> Handler<'a, ($($T,)+), Err> for Func where Func: Fn($($T,)+) -> Res + Clone + 'static, - Res: Future + 'static, + Res: Future + 'a, Res::Output: Responder, Err: ErrorRenderer, { @@ -113,14 +102,14 @@ macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => { mod m { use super::*; -factory_tuple!((0, A)); -factory_tuple!((0, A), (1, B)); -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), (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), (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), (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)); + factory_tuple!((0, A), (1, B)); + 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), (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), (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), (8, I)); + factory_tuple!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J)); } diff --git a/ntex/src/web/httprequest.rs b/ntex/src/web/httprequest.rs index df72da87..0bb3af53 100644 --- a/ntex/src/web/httprequest.rs +++ b/ntex/src/web/httprequest.rs @@ -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::{ HeaderMap, HttpMessage, Message, Method, Payload, RequestHead, Uri, Version, @@ -13,40 +13,40 @@ use super::extract::FromRequest; use super::info::ConnectionInfo; use super::rmap::ResourceMap; -#[derive(Clone)] -/// An HTTP Request -pub struct HttpRequest(pub(crate) Rc); +pub(super) struct HttpRequestInner { + pub(crate) request: HttpRequest, + pub(crate) payload: Payload, +} -pub(crate) struct HttpRequestInner { +/// An HTTP Request +pub struct HttpRequest { pub(crate) head: Message, pub(crate) path: Path, - pub(crate) payload: Payload, pub(crate) app_state: Rc, rmap: Rc, config: AppConfig, - pool: &'static HttpRequestPool, } impl HttpRequest { #[inline] - pub(crate) fn new( + pub(super) fn create( path: Path, head: Message, payload: Payload, rmap: Rc, config: AppConfig, app_state: Rc, - pool: &'static HttpRequestPool, - ) -> HttpRequest { - HttpRequest(Rc::new(HttpRequestInner { - head, - path, + ) -> HttpRequestInner { + HttpRequestInner { payload, - app_state, - rmap, - config, - pool, - })) + request: HttpRequest { + head, + path, + app_state, + rmap, + config, + }, + } } } @@ -54,14 +54,14 @@ impl HttpRequest { /// This method returns reference to the request head #[inline] pub fn head(&self) -> &RequestHead { - &self.0.head + &self.head } /// This method returns muttable reference to the request head. /// panics if multiple references of http request exists. #[inline] pub(crate) fn head_mut(&mut self) -> &mut RequestHead { - &mut Rc::get_mut(&mut self.0).unwrap().head + &mut self.head } /// Request's uri. @@ -131,12 +131,12 @@ impl HttpRequest { /// access the matched value for that segment. #[inline] pub fn match_info(&self) -> &Path { - &self.0.path + &self.path } #[inline] pub(crate) fn match_info_mut(&mut self) -> &mut Path { - &mut Rc::get_mut(&mut self.0).unwrap().path + &mut self.path } /// Request extensions @@ -179,7 +179,7 @@ impl HttpRequest { U: IntoIterator, I: AsRef, { - self.0.rmap.url_for(self, name, elements) + self.rmap.url_for(self, name, elements) } #[cfg(feature = "url")] @@ -198,7 +198,7 @@ impl HttpRequest { #[inline] /// Get a reference to a `ResourceMap` of current application. pub fn resource_map(&self) -> &ResourceMap { - &self.0.rmap + &self.rmap } /// Get *ConnectionInfo* for the current request. @@ -213,7 +213,7 @@ impl HttpRequest { /// App config #[inline] pub fn app_config(&self) -> &AppConfig { - &self.0.config + &self.config } /// 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::>(); /// ``` pub fn app_state(&self) -> Option<&T> { - self.0.app_state.get::() + self.app_state.get::() } } @@ -239,25 +239,13 @@ impl HttpMessage for HttpRequest { /// Request extensions #[inline] fn message_extensions(&self) -> Ref<'_, Extensions> { - self.0.head.extensions() + self.head.extensions() } /// Mutable reference to a the request's extensions #[inline] fn message_extensions_mut(&self) -> RefMut<'_, Extensions> { - self.0.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()); - } - } + self.head.extensions_mut() } } @@ -280,13 +268,13 @@ impl Drop for HttpRequest { /// ); /// } /// ``` -impl FromRequest for HttpRequest { - type Error = Err::Container; +impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for &'a HttpRequest { + type Error = Infallible; type Future = Ready; #[inline] - fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { - Ok(req.clone()).into() + fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future { + Ready::Ok(req) } } @@ -295,8 +283,8 @@ impl fmt::Debug for HttpRequest { writeln!( f, "\nHttpRequest {:?} {}:{}", - self.0.head.version, - self.0.head.method, + self.head.version, + self.head.method, self.path() )?; if !self.query_string().is_empty() { @@ -314,7 +302,8 @@ impl fmt::Debug for HttpRequest { } /// Request's objects pool -pub(crate) struct HttpRequestPool(RefCell>>); +#[allow(clippy::vec_box)] +pub(crate) struct HttpRequestPool(RefCell>>); impl HttpRequestPool { pub(crate) fn create() -> &'static HttpRequestPool { @@ -324,11 +313,29 @@ impl HttpRequestPool { /// Get message from the pool #[inline] - pub(crate) fn get_request(&self) -> Option { - self.0.borrow_mut().pop().map(HttpRequest) + pub(super) fn get_request(&self) -> Option> { + self.0.borrow_mut().pop() } - pub(crate) fn clear(&self) { + #[inline] + pub(super) fn release_boxed(&self, req: Box) { + 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() } } diff --git a/ntex/src/web/middleware/compress.rs b/ntex/src/web/middleware/compress.rs index a8328f33..9e1a238f 100644 --- a/ntex/src/web/middleware/compress.rs +++ b/ntex/src/web/middleware/compress.rs @@ -59,9 +59,9 @@ pub struct CompressMiddleware { encoding: ContentEncoding, } -impl<'a, S, E> Service> for CompressMiddleware +impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for CompressMiddleware where - S: Service, Response = WebResponse>, + S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>, E: ErrorRenderer, { type Response = WebResponse; @@ -78,7 +78,7 @@ where self.service.poll_shutdown(cx, is_error) } - fn call(&self, req: WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future { // negotiate content-encoding let encoding = if let Some(val) = req.headers().get(&ACCEPT_ENCODING) { if let Ok(enc) = val.to_str() { @@ -100,7 +100,7 @@ where pin_project_lite::pin_project! { #[doc(hidden)] - pub struct CompressResponse<'a, S: Service>, E> + pub struct CompressResponse<'a, S: Service<&'a mut WebRequest<'a, E>>, E> { #[pin] fut: S::Future, @@ -111,7 +111,7 @@ pin_project_lite::pin_project! { impl<'a, S, E> Future for CompressResponse<'a, S, E> where - S: Service, Response = WebResponse>, + S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>, E: ErrorRenderer, { type Output = Result; diff --git a/ntex/src/web/middleware/defaultheaders.rs b/ntex/src/web/middleware/defaultheaders.rs index 24713a4e..8cd39e8f 100644 --- a/ntex/src/web/middleware/defaultheaders.rs +++ b/ntex/src/web/middleware/defaultheaders.rs @@ -5,7 +5,7 @@ use std::{convert::Infallible, convert::TryFrom, future::Future, pin::Pin, rc::R use crate::http::error::HttpError; use crate::http::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE}; use crate::service::{Service, Transform}; -use crate::web::{WebRequest, WebResponse, ErrorRenderer}; +use crate::web::{ErrorRenderer, WebRequest, WebResponse}; /// `Middleware` for setting default response headers. /// @@ -102,9 +102,9 @@ pub struct DefaultHeadersMiddleware { inner: Rc, } -impl<'a, S, E> Service> for DefaultHeadersMiddleware +impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for DefaultHeadersMiddleware where - S: Service, Response = WebResponse, Error = Infallible>, + S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse, Error = Infallible>, S::Future: 'static, E: ErrorRenderer, { @@ -122,7 +122,7 @@ where self.service.poll_shutdown(cx, is_error) } - fn call(&self, req: WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future { let inner = self.inner.clone(); let fut = self.service.call(req); diff --git a/ntex/src/web/middleware/logger.rs b/ntex/src/web/middleware/logger.rs index 68ad59b3..778a7f6f 100644 --- a/ntex/src/web/middleware/logger.rs +++ b/ntex/src/web/middleware/logger.rs @@ -130,9 +130,9 @@ pub struct LoggerMiddleware { service: S, } -impl<'a, S, E> Service> for LoggerMiddleware +impl<'a, S, E> Service<&'a mut WebRequest<'a, E>> for LoggerMiddleware where - S: Service, Response = WebResponse>, + S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>, E: 'static, { type Response = WebResponse; @@ -150,7 +150,7 @@ where } #[inline] - fn call(&self, req: WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, E>) -> Self::Future { if self.inner.exclude.contains(req.path()) { Either::Right(self.service.call(req)) } else { @@ -158,7 +158,7 @@ where let mut format = self.inner.format.clone(); for unit in &mut format.0 { - unit.render_request(time, &req); + unit.render_request(time, req); } Either::Left(LoggerResponse { time, @@ -172,7 +172,7 @@ where pin_project_lite::pin_project! { #[doc(hidden)] - pub struct LoggerResponse<'a, S: Service>, E> + pub struct LoggerResponse<'a, S: Service<&'a mut WebRequest<'a, E>>, E> { #[pin] fut: S::Future, @@ -184,7 +184,7 @@ pin_project_lite::pin_project! { impl<'a, S, E> Future for LoggerResponse<'a, S, E> where - S: Service, Response = WebResponse>, + S: Service<&'a mut WebRequest<'a, E>, Response = WebResponse>, { type Output = Result; @@ -396,7 +396,7 @@ impl FormatText { } } - fn render_request(&mut self, now: time::SystemTime, req: &WebRequest) { + fn render_request(&mut self, now: time::SystemTime, req: &WebRequest<'_, E>) { match *self { FormatText::RequestLine => { *self = if req.query_string().is_empty() { diff --git a/ntex/src/web/mod.rs b/ntex/src/web/mod.rs index 56d7d08e..24f90001 100644 --- a/ntex/src/web/mod.rs +++ b/ntex/src/web/mod.rs @@ -61,13 +61,6 @@ //! * `compress` - enables content encoding compression support //! * `openssl` - enables ssl support via `openssl` crate //! * `rustls` - enables ssl support via `rustls` crate -#![allow( - unused_imports, - unused_variables, - unused_mut, - dead_code, - unreachable_pub -)] mod app; mod app_service; @@ -79,7 +72,7 @@ pub mod guard; mod handler; mod httprequest; mod info; -//pub mod middleware; +pub mod middleware; mod request; mod resource; mod responder; @@ -91,7 +84,7 @@ mod boxed; mod server; mod service; mod stack; -//pub mod test; +pub mod test; pub mod types; mod util; pub mod ws; @@ -112,9 +105,7 @@ pub use crate::http::ResponseBuilder as HttpResponseBuilder; pub use self::app::App; pub use self::config::ServiceConfig; -pub use self::error::{ - DefaultError, Error, ErrorContainer, ErrorRenderer, WebResponseError, -}; +pub use self::error::{DefaultError, Error, ErrorRenderer}; pub use self::extract::FromRequest; pub use self::handler::Handler; pub use self::httprequest::HttpRequest; @@ -157,15 +148,14 @@ pub mod dev { where T: super::FromRequest<'a, Err>, Err: super::ErrorRenderer, - >::Error: Into, { } #[doc(hidden)] #[inline(always)] - pub fn __assert_handler( + pub fn __assert_handler<'a, Err, Fun, Fut>( f: Fun, - ) -> impl Handler<(), Err, Future = Fut, Output = Fut::Output> + ) -> impl Handler<'a, (), Err, Future = Fut, Output = Fut::Output> where Err: super::ErrorRenderer, Fun: Fn() -> Fut + Clone + 'static, @@ -180,11 +170,11 @@ pub mod dev { #[inline(always)] pub fn $name<'a, Err, Fun, Fut, $($T,)+>( f: Fun, - ) -> impl Handler<($($T,)+), Err, Future = Fut, Output = Fut::Output> + ) -> impl Handler<'a, ($($T,)+), Err, Future = Fut, Output = Fut::Output> where Err: $crate::web::ErrorRenderer, Fun: Fn($($T,)+) -> Fut + Clone + 'static, - Fut: std::future::Future + 'static, + Fut: std::future::Future + 'a, Fut::Output: $crate::web::Responder, $($T: $crate::web::FromRequest<'a, Err>),+, { diff --git a/ntex/src/web/request.rs b/ntex/src/web/request.rs index cea31dd2..3ee3139e 100644 --- a/ntex/src/web/request.rs +++ b/ntex/src/web/request.rs @@ -1,88 +1,38 @@ use std::{cell::Ref, cell::RefMut, fmt, marker::PhantomData, net, rc::Rc}; 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::router::{Path, Resource}; use crate::util::Extensions; use super::config::AppConfig; -use super::error::{ErrorRenderer, WebResponseError}; -use super::httprequest::HttpRequest; +use super::error::ErrorRenderer; +use super::httprequest::{HttpRequest, HttpRequestInner}; use super::info::ConnectionInfo; -use super::response::WebResponse; use super::rmap::ResourceMap; /// An service http request /// /// WebRequest allows mutable access to request's internal structures pub struct WebRequest<'a, Err> { - pub(super) req: &'a mut HttpRequest, + pub(super) req: &'a mut HttpRequestInner, _marker: PhantomData &'a Err>, } -impl<'a, Err: ErrorRenderer> WebRequest<'a, Err> { - /// Create web response for error - #[inline] - pub fn render_error>(self, err: E) -> WebResponse { - WebResponse::new(err.error_response(&self.req)) - } - - /// Create web response for error - #[inline] - pub fn error_response>(self, err: E) -> WebResponse { - WebResponse::from_err::(err, self.req) - } -} - impl<'a, Err> WebRequest<'a, Err> { /// Construct web request - pub(crate) fn new(req: &'a mut HttpRequest) -> Self { + pub(super) fn new(req: &'a mut HttpRequestInner) -> Self { WebRequest { req, _marker: PhantomData, } } - // /// Deconstruct request into parts - // pub fn into_parts(mut self) -> (HttpRequest, Payload) { - // let pl = Rc::get_mut(&mut (self.req).0).unwrap().payload.take(); - // (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 { - // 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 { - // if Rc::strong_count(&req.0) == 1 { - // Ok(WebRequest::new(req)) - // } else { - // Err(req) - // } - // } - - /// Create web response - #[inline] - pub fn into_response>(self, res: R) -> WebResponse { - WebResponse::new(res.into()) + /// Http request + pub fn http_request(&self) -> &HttpRequest { + &self.req.request } /// Io reference for current connection @@ -94,13 +44,13 @@ impl<'a, Err> WebRequest<'a, Err> { /// This method returns reference to the request head #[inline] pub fn head(&self) -> &RequestHead { - self.req.head() + self.req.request.head() } /// This method returns reference to the request head #[inline] pub fn head_mut(&mut self) -> &mut RequestHead { - self.req.head_mut() + self.req.request.head_mut() } /// Request's uri. @@ -180,25 +130,25 @@ impl<'a, Err> WebRequest<'a, Err> { /// access the matched value for that segment. #[inline] pub fn match_info(&self) -> &Path { - self.req.match_info() + self.req.request.match_info() } #[inline] /// Get a mutable reference to the Path parameters. pub fn match_info_mut(&mut self) -> &mut Path { - self.req.match_info_mut() + self.req.request.match_info_mut() } #[inline] /// Get a reference to a `ResourceMap` of current application. pub fn resource_map(&self) -> &ResourceMap { - self.req.resource_map() + self.req.request.resource_map() } /// Service configuration #[inline] pub fn app_config(&self) -> &AppConfig { - self.req.app_config() + self.req.request.app_config() } #[inline] @@ -207,37 +157,59 @@ impl<'a, Err> WebRequest<'a, Err> { /// /// To get state stored with `App::state()` use `web::types::State` as type. pub fn app_state(&self) -> Option<&T> { - (self.req).0.app_state.get::() + self.req.request.app_state.get::() + } + + #[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] /// Get request's payload pub fn take_payload(&mut self) -> Payload { - Rc::get_mut(&mut (self.req).0).unwrap().payload.take() + self.req.payload.take() } #[inline] /// Set request 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)] /// Set new app state container pub fn set_state_container(&mut self, extensions: Rc) { - Rc::get_mut(&mut (self.req).0).unwrap().app_state = extensions; + self.req.request.app_state = extensions; } /// Request extensions #[inline] pub fn extensions(&self) -> Ref<'_, Extensions> { - self.req.extensions() + self.req.request.extensions() } /// Mutable reference to a the request's extensions #[inline] 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(&'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 #[inline] fn message_extensions(&self) -> Ref<'_, Extensions> { - self.req.extensions() + self.req.request.extensions() } /// Mutable reference to a the request's extensions #[inline] fn message_extensions_mut(&self) -> RefMut<'_, Extensions> { - self.req.extensions_mut() + self.req.request.extensions_mut() } } diff --git a/ntex/src/web/resource.rs b/ntex/src/web/resource.rs index 6e8cf039..c3d5d2c1 100644 --- a/ntex/src/web/resource.rs +++ b/ntex/src/web/resource.rs @@ -1,15 +1,13 @@ -use std::convert::Infallible; 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::router::{IntoPattern, ResourceDef}; -use crate::service::{pipeline_factory, PipelineFactory}; 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::error::Error; use super::extract::FromRequest; use super::route::{IntoRoutes, Route, RouteService}; use super::stack::{ @@ -50,7 +48,7 @@ pub struct Resource { default: Route, } -impl<'a, Err: ErrorRenderer> Resource { +impl Resource { pub fn new(path: T) -> Resource { Resource { routes: Vec::new(), @@ -148,7 +146,7 @@ where /// ``` pub fn route(mut self, route: R) -> Self where - R: IntoRoutes, + R: IntoRoutes<'a, Err>, { for route in route.routes() { self.routes.push(route); @@ -217,9 +215,9 @@ where /// ``` pub fn to(mut self, handler: H) -> Self where - H: Handler, - Args: FromRequest + 'static, - Args::Error: Into, + H: Handler<'a, Args, Err>, + Args: FromRequest<'a, Err> + 'a, + Args::Error: Error, { self.routes.push(Route::new().to(handler)); self @@ -266,9 +264,9 @@ where /// default handler from `App` or `Scope`. pub fn default(mut self, handler: H) -> Self where - H: Handler, - Args: FromRequest + 'static, - Args::Error: Into, + H: Handler<'a, Args, Err>, + Args: FromRequest<'a, Err> + 'a, + Args::Error: Error, { self.default = Route::new().to(handler); self @@ -382,7 +380,7 @@ where F: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, InitError = (), > + 'static, F::Service: 'static, @@ -390,7 +388,7 @@ where Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Service = Middleware; type InitError = (); type Future = Pin>>>; @@ -418,18 +416,18 @@ where F: Service< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, >, Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Future = ResourceServiceResponse<'a, F, Err>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { - let ready1 = self.filter.poll_ready(cx)?.is_ready(); - let ready2 = self.routing.poll_ready(cx)?.is_ready(); + let ready1 = self.filter.poll_ready(cx).is_ready(); + let ready2 = self.routing.poll_ready(cx).is_ready(); if ready1 && ready2 { Poll::Ready(Ok(())) } else { @@ -439,9 +437,12 @@ where fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { ResourceServiceResponse { - filter: self.filter.call(req), + filter: self + .filter + .call(unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }), routing: self.routing.clone(), endpoint: None, + req, } } } @@ -452,6 +453,7 @@ pin_project_lite::pin_project! { filter: F::Future, routing: Rc>, endpoint: Option< as Service<&'a mut WebRequest<'a, Err>>>::Future>, + req: &'a mut WebRequest<'a, Err>, } } @@ -460,11 +462,11 @@ where F: Service< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, >, Err: ErrorRenderer, { - type Output = Result; + type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.as_mut().project(); @@ -472,12 +474,8 @@ where if let Some(fut) = this.endpoint.as_mut() { Pin::new(fut).poll(cx) } else { - let res = if let Poll::Ready(res) = this.filter.poll(cx) { - res? - } else { - return Poll::Pending; - }; - *this.endpoint = Some(this.routing.call(res)); + let req = ready!(this.filter.poll(cx)).unwrap(); + *this.endpoint = Some(this.routing.call(req)); self.poll(cx) } } @@ -493,7 +491,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for ResourceRouterFactory { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = ResourceRouter; type Future = Ready; @@ -519,15 +517,15 @@ struct ResourceRouter { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ResourceRouter { type Response = WebResponse; - type Error = Err::Container; - type Future = Pin> + 'a>>; + type Error = Infallible; + type Future = Pin> + 'a>>; #[inline] fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { 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() { if route.check(req) { if let Some(ref state) = self.state { diff --git a/ntex/src/web/responder.rs b/ntex/src/web/responder.rs index 017d644c..c39eeafe 100644 --- a/ntex/src/web/responder.rs +++ b/ntex/src/web/responder.rs @@ -5,10 +5,8 @@ use crate::http::header::{HeaderMap, HeaderName, HeaderValue}; use crate::http::{error::HttpError, Response, ResponseBuilder, StatusCode}; use crate::util::{Bytes, BytesMut, Either}; -use super::error::{ - DefaultError, ErrorContainer, ErrorRenderer, InternalError, WebResponseError, -}; -use super::httprequest::HttpRequest; +use super::error::{DefaultError, Error, ErrorRenderer, InternalError}; +use super::{HttpRequest, WebResponse}; pub struct Ready(Option); @@ -126,7 +124,7 @@ where impl Responder for Result where T: Responder, - E: Into, + E: Error, Err: ErrorRenderer, { type Future = Either>; @@ -134,7 +132,7 @@ where fn respond_to(self, req: &HttpRequest) -> Self::Future { match self { 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()))), } } } diff --git a/ntex/src/web/response.rs b/ntex/src/web/response.rs index 6bf9e4b2..6c72f0ec 100644 --- a/ntex/src/web/response.rs +++ b/ntex/src/web/response.rs @@ -3,7 +3,7 @@ use std::fmt; use crate::http::body::{Body, MessageBody, ResponseBody}; use crate::http::{HeaderMap, Response, ResponseHead, StatusCode}; -use super::error::{ErrorContainer, ErrorRenderer}; +use super::error::{Error, ErrorRenderer}; use super::httprequest::HttpRequest; /// An service http response @@ -18,21 +18,18 @@ impl WebResponse { } /// Create web response from the error - pub fn from_err>( + pub fn from_err>( err: E, request: &HttpRequest, ) -> Self { - let err = err.into(); - let res: Response = err.error_response(request); - - if res.head().status == StatusCode::INTERNAL_SERVER_ERROR { + if err.status_code() == StatusCode::INTERNAL_SERVER_ERROR { log::error!("Internal Server Error: {:?}", err); } else { log::debug!("Error in response: {:?}", err); } WebResponse { - response: res.into_body(), + response: err.error_response(request).into_body(), } } @@ -102,6 +99,12 @@ impl From for Response { } } +impl fmt::Display for WebResponse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "{:?}", self) + } +} + impl fmt::Debug for WebResponse { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let res = writeln!( diff --git a/ntex/src/web/route.rs b/ntex/src/web/route.rs index b429c01a..bdc1f7fa 100644 --- a/ntex/src/web/route.rs +++ b/ntex/src/web/route.rs @@ -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 super::error_default::DefaultError; use super::guard::{self, Guard}; use super::handler::{Handler, HandlerFn, HandlerWrapper}; -use super::{ErrorRenderer, FromRequest, HttpResponse, WebRequest, WebResponse}; +use super::{Error, ErrorRenderer, FromRequest, HttpResponse, WebRequest, WebResponse}; /// Resource route definition /// /// Route uses builder-like pattern for configuration. /// If handler is not explicitly set, default *404 Not Found* handler is used. pub struct Route { - handler: Box>, + handler: Cell>>>, methods: Vec, guards: Rc>>, } @@ -21,7 +22,9 @@ impl<'a, Err: ErrorRenderer> Route { /// Create new route which matches any request. pub fn new() -> Route { Route { - handler: Box::new(HandlerWrapper::new(|| async { HttpResponse::NotFound() })), + handler: Cell::new(Some(Box::new(HandlerWrapper::new(|| async { + HttpResponse::NotFound() + })))), methods: Vec::new(), guards: Rc::new(Vec::new()), } @@ -39,7 +42,7 @@ impl<'a, Err: ErrorRenderer> Route { pub(super) fn service(&self) -> RouteService { RouteService { - handler: self.handler.clone_handler(), + handler: self.handler.take().unwrap(), guards: self.guards.clone(), methods: self.methods.clone(), } @@ -48,7 +51,7 @@ impl<'a, Err: ErrorRenderer> Route { impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Route { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = RouteService; type Future = Ready; @@ -59,7 +62,7 @@ impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Rou } pub struct RouteService { - handler: Box>, + handler: Box>, methods: Vec, guards: Rc>>, } @@ -81,7 +84,7 @@ impl RouteService { impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteService { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Future = Pin> + 'a>>; #[inline] @@ -91,7 +94,9 @@ impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteServi #[inline] 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 Route { /// ); /// } /// ``` - pub fn to(mut self, handler: F) -> Self + pub fn to<'a, F, Args>(self, handler: F) -> Self where - F: Handler, - Args: FromRequest<'a, Err> + 'static, - Args::Error: Into, + F: Handler<'a, Args, Err>, + Args: FromRequest<'a, Err> + 'a, + Args::Error: Error, { - self.handler = Box::new(HandlerWrapper::new(handler)); + let handler: Box> = Box::new(HandlerWrapper::new(handler)); + self.handler + .set(Some(unsafe { std::mem::transmute(handler) })); self } } /// Convert object to a vec of routes -pub trait IntoRoutes { +pub trait IntoRoutes<'a, Err: ErrorRenderer> { fn routes(self) -> Vec>; } -impl IntoRoutes for Route { +impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for Route { fn routes(self) -> Vec> { vec![self] } } -impl IntoRoutes for Vec> { +impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for Vec> { fn routes(self) -> Vec> { self } @@ -209,7 +216,7 @@ impl IntoRoutes for Vec> { macro_rules! tuple_routes({$(($n:tt, $T:ty)),+} => { /// IntoRoutes implementation for a tuple #[allow(unused_parens)] - impl IntoRoutes for ($($T,)+) { + impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for ($($T,)+) { fn routes(self) -> Vec> { vec![$(self.$n,)+] } @@ -219,7 +226,7 @@ macro_rules! tuple_routes({$(($n:tt, $T:ty)),+} => { macro_rules! array_routes({$num:tt, $($T:ident),+} => { /// IntoRoutes implementation for an array #[allow(unused_parens)] - impl IntoRoutes for [Route; $num] + impl<'a, Err: ErrorRenderer> IntoRoutes<'a, Err> for [Route; $num] where Err: ErrorRenderer, { diff --git a/ntex/src/web/service.rs b/ntex/src/web/service.rs index 1eafd90f..0b40f768 100644 --- a/ntex/src/web/service.rs +++ b/ntex/src/web/service.rs @@ -1,16 +1,13 @@ -use std::task::{Context, Poll}; -use std::{convert::Infallible, future::Future, marker::PhantomData, pin::Pin, rc::Rc}; +use std::rc::Rc; use crate::router::{IntoPattern, ResourceDef}; -use crate::service::{IntoServiceFactory, Service, ServiceFactory}; +use crate::service::{IntoServiceFactory, ServiceFactory}; use crate::util::Extensions; 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::{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 { 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> { /// Crate server settings instance - pub(crate) fn new( + pub(super) fn new( config: AppConfig, default: Rc>, service_state: Rc>>, @@ -79,7 +76,7 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { self.root } - pub(crate) fn into_services( + pub(super) fn into_services( self, ) -> ( AppConfig, @@ -132,11 +129,11 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { S: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = WebResponse, - Error = Err::Container, InitError = (), > + 'static, S::Future: 'static, S::Service: 'static, + S::Error: Error, { self.services .push((rdef, boxed::factory(factory), guards, nested)); @@ -158,7 +155,8 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { /// .finish(my_service) /// ); /// ``` -pub struct WebServiceAdapter { +pub struct WebServiceAdapter { + srv: T, rdef: Vec, name: Option, guards: Vec>, @@ -168,6 +166,7 @@ impl WebServiceAdapter { /// Create new `WebServiceAdapter` instance. pub fn new(path: T) -> Self { WebServiceAdapter { + srv: (), rdef: path.patterns(), name: None, guards: Vec::new(), @@ -205,65 +204,54 @@ impl WebServiceAdapter { self } - // /// Set a service factory implementation and generate web service. - // pub fn finish<'a, T, F, Err>(self, service: F) -> impl WebServiceFactory<'a, Err> - // where - // F: IntoServiceFactory>, - // T: ServiceFactory< - // &'a mut WebRequest<'a, Err>, - // Response = WebResponse, - // Error = Err::Container, - // InitError = (), - // > + 'static, - // Err: ErrorRenderer, - // { - // WebServiceImpl { - // srv: service.into_factory(), - // rdef: self.rdef, - // name: self.name, - // guards: self.guards, - // _t: PhantomData, - // } - // } + /// Set a service factory implementation and generate web service. + pub fn finish<'a, T, F, Err>(self, service: F) -> WebServiceAdapter + where + F: IntoServiceFactory>, + T: ServiceFactory< + &'a mut WebRequest<'a, Err>, + Response = WebResponse, + InitError = (), + >, + T::Error: Error, + Err: ErrorRenderer, + { + WebServiceAdapter { + srv: service.into_factory(), + rdef: self.rdef, + name: self.name, + guards: self.guards, + } + } } -// struct WebServiceImpl { -// srv: T, -// rdef: Vec, -// name: Option, -// guards: Vec>, -// } +impl<'a, T, Err> WebService<'a, Err> for WebServiceAdapter +where + T: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, InitError = ()> + + 'static, + T::Future: 'static, + T::Service: 'static, + T::Error: Error, + 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 -// where -// T: ServiceFactory< -// &'a mut WebRequest<'a, Err>, -// Response = WebResponse, -// Error = Err::Container, -// InitError = (), -// > + 'static, -// T::Future: 'static, -// 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) -// } -// } + 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 // #[allow(unused_parens)] diff --git a/ntex/src/web/stack.rs b/ntex/src/web/stack.rs index 8d63b792..c8ff251b 100644 --- a/ntex/src/web/stack.rs +++ b/ntex/src/web/stack.rs @@ -1,16 +1,12 @@ use std::{ - convert::Infallible, future::Future, marker::PhantomData, pin::Pin, rc::Rc, - task::Context, task::Poll, + convert::Infallible, future::Future, marker::PhantomData, pin::Pin, task::Context, + task::Poll, }; -use crate::service::{ - dev::AndThenFactory, pipeline_factory, PipelineFactory, Service, ServiceFactory, - Transform, -}; +use crate::service::{dev::AndThenFactory, Service, ServiceFactory, Transform}; use crate::util::{ready, Ready}; -use super::httprequest::HttpRequest; -use super::{ErrorContainer, ErrorRenderer, WebRequest, WebResponse}; +use super::{Error, ErrorRenderer, WebRequest, WebResponse}; pub struct Stack { inner: Inner, @@ -75,7 +71,7 @@ where Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Future = MiddlewareResponse<'a, S, Err>; #[inline] @@ -104,7 +100,7 @@ where S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, Err: ErrorRenderer, { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { Poll::Ready(Ok(ready!(self.project().fut.poll(cx)).unwrap())) @@ -124,13 +120,13 @@ impl Next { impl<'a, S, Err> Service<&'a mut WebRequest<'a, Err>> for Next where S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, - S::Error: Into + 'static, + S::Error: Error, S::Future: 'a, Err: ErrorRenderer, { type Response = WebResponse; type Error = Infallible; - type Future = Pin> + 'a>>; + type Future = NextResponse<'a, S, Err>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { @@ -142,13 +138,10 @@ where fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { let r = unsafe { (req as *mut WebRequest<'a, Err>).as_mut().unwrap() }; - let fut = self.next.call(r); - Box::pin(async move { - match fut.await { - Ok(res) => Ok(res), - Err(err) => Ok(WebResponse::new(err.into().error_response(&req.req))), - } - }) + NextResponse { + req, + fut: self.next.call(r), + } } } @@ -163,7 +156,7 @@ pin_project_lite::pin_project! { impl<'a, S, Err> Future for NextResponse<'a, S, Err> where S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse>, - S::Error: Into, + S::Error: Error, Err: ErrorRenderer, { type Output = Result; @@ -173,8 +166,7 @@ where match ready!(this.fut.poll(cx)) { Ok(res) => Poll::Ready(Ok(res)), Err(err) => { - let req = this.req.req.clone(); - Poll::Ready(Ok(WebResponse::new(err.into().error_response(&req)))) + Poll::Ready(Ok(WebResponse::from_err(err, this.req.http_request()))) } } } @@ -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 { type Response = &'a mut WebRequest<'a, Err>; - type Error = Err::Container; + type Error = Infallible; type InitError = (); type Service = Filter; type Future = Ready; @@ -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 { type Response = &'a mut WebRequest<'a, Err>; - type Error = Err::Container; + type Error = Infallible; type Future = Ready; #[inline] @@ -236,7 +228,7 @@ where First: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, InitError = (), > + 'static, First::Service: 'static, @@ -245,7 +237,7 @@ where Second::Service: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, InitError = (), >, >>::Service: 'static, @@ -262,7 +254,7 @@ pub trait FiltersFactory<'a, Err: ErrorRenderer> { type Service: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, InitError = (), > + 'static; diff --git a/ntex/src/web/test.rs b/ntex/src/web/test.rs index e2465582..019d3c06 100644 --- a/ntex/src/web/test.rs +++ b/ntex/src/web/test.rs @@ -25,24 +25,29 @@ use crate::{io::Sealed, rt::System, server::Server}; use crate::web::config::AppConfig; 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::{FromRequest, HttpResponse, Responder, WebRequest, WebResponse}; /// Create service that always responds with `HttpResponse::Ok()` -pub fn ok_service( -) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> -{ +pub fn ok_service<'a, Err: ErrorRenderer>() -> impl Service< + &'a mut WebRequest<'a, Err>, + Response = WebResponse, + Error = std::convert::Infallible, +> { default_service::(StatusCode::OK) } /// Create service that responds with response with specified status code -pub fn default_service( +pub fn default_service<'a, Err: ErrorRenderer>( status_code: StatusCode, -) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> -{ - (move |req: &'a mut WebRequest<'a, Err>| { - Ready::Ok(req.into_response(HttpResponse::build(status_code).finish())) +) -> impl Service< + &'a mut WebRequest<'a, Err>, + Response = WebResponse, + Error = std::convert::Infallible, +> { + (move |_: &'a mut WebRequest<'a, Err>| { + Ready::Ok(HttpResponse::build(status_code).finish().into()) }) .into_service() } @@ -249,11 +254,11 @@ where } /// Helper method for extractors testing -pub async fn from_request>( - req: &HttpRequest, - payload: &mut Payload, -) -> Result { - T::from_request(req, payload).await +pub fn from_request<'a, T: FromRequest<'a, DefaultError>>( + req: &'a HttpRequest, + payload: &'a mut Payload, +) -> T::Future { + T::from_request(req, payload) } /// Helper method for responders testing @@ -456,25 +461,25 @@ impl TestRequest { self.req.finish() } - /// Complete request creation and generate `WebRequest` instance - pub fn to_srv_request(mut self) -> WebRequest { - let (head, payload) = self.req.finish().into_parts(); - *self.path.get_mut() = head.uri.clone(); + // /// Complete request creation and generate `WebRequest` instance + // pub fn to_srv_request(&'_ mut self) -> &'_ mut WebRequest<'_, DefaultError> { + // let (head, payload) = self.req.finish().into_parts(); + // *self.path.get_mut() = head.uri.clone(); - WebRequest::new(HttpRequest::new( - self.path, - head, - payload, - Rc::new(self.rmap), - self.config.clone(), - Rc::new(self.app_state), - HttpRequestPool::create(), - )) - } + // WebRequest::new(HttpRequest::new( + // self.path, + // head, + // payload, + // Rc::new(self.rmap), + // self.config.clone(), + // Rc::new(self.app_state), + // HttpRequestPool::create(), + // )) + // } /// Complete request creation and generate `WebResponse` instance 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 @@ -482,15 +487,15 @@ impl TestRequest { let (head, payload) = self.req.finish().into_parts(); *self.path.get_mut() = head.uri.clone(); - HttpRequest::new( + HttpRequest::create( self.path, head, payload, Rc::new(self.rmap), self.config.clone(), Rc::new(self.app_state), - HttpRequestPool::create(), ) + .request } /// Complete request creation and generate `HttpRequest` and `Payload` instances @@ -498,15 +503,15 @@ impl TestRequest { let (head, payload) = self.req.finish().into_parts(); *self.path.get_mut() = head.uri.clone(); - let req = HttpRequest::new( + let req = HttpRequest::create( self.path, head, Payload::None, Rc::new(self.rmap), self.config.clone(), Rc::new(self.app_state), - HttpRequestPool::create(), - ); + ) + .request; (req, payload) } diff --git a/ntex/src/web/types/form.rs b/ntex/src/web/types/form.rs index fabcd222..2e84a519 100644 --- a/ntex/src/web/types/form.rs +++ b/ntex/src/web/types/form.rs @@ -9,7 +9,7 @@ use crate::http::encoding::Decoder; use crate::http::header::{CONTENT_LENGTH, CONTENT_TYPE}; use crate::http::{HttpMessage, Payload, Response, StatusCode}; 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::{FromRequest, HttpRequest}; @@ -95,16 +95,16 @@ impl ops::DerefMut for Form { } } -impl FromRequest for Form +impl<'a, T, Err> FromRequest<'a, Err> for Form where - T: DeserializeOwned + 'static, + T: DeserializeOwned + 'a, Err: ErrorRenderer, { type Error = UrlencodedError; - type Future = Pin>>>; + type Future = Pin> + 'a>>; #[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 .app_state::() .map(|c| c.limit) @@ -134,7 +134,7 @@ impl fmt::Display for Form { impl Responder for Form where - Err::Container: From, + serde_urlencoded::ser::Error: Error, { type Future = Ready; @@ -208,7 +208,7 @@ impl Default for FormConfig { /// * content type is not `application/x-www-form-urlencoded` /// * content-length is greater than 32k /// -struct UrlEncoded { +struct UrlEncoded<'a, U> { #[cfg(feature = "compress")] stream: Option>, #[cfg(not(feature = "compress"))] @@ -217,12 +217,12 @@ struct UrlEncoded { length: Option, encoding: &'static Encoding, err: Option, - fut: Option>>>>, + fut: Option> + 'a>>>, } -impl UrlEncoded { +impl<'a, U> UrlEncoded<'a, U> { /// Create a new future to URL encode a request - fn new(req: &HttpRequest, payload: &mut Payload) -> UrlEncoded { + fn new(req: &'a HttpRequest, payload: &'a mut Payload) -> UrlEncoded<'a, U> { // check content type if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" { return Self::err(UrlencodedError::ContentType); @@ -278,9 +278,9 @@ impl UrlEncoded { } } -impl Future for UrlEncoded +impl<'a, U> Future for UrlEncoded<'a, U> where - U: DeserializeOwned + 'static, + U: DeserializeOwned + 'a, { type Output = Result; diff --git a/ntex/src/web/types/json.rs b/ntex/src/web/types/json.rs index d1b3e10b..e53b5f0f 100644 --- a/ntex/src/web/types/json.rs +++ b/ntex/src/web/types/json.rs @@ -8,7 +8,7 @@ use crate::http::encoding::Decoder; use crate::http::header::CONTENT_LENGTH; use crate::http::{HttpMessage, Payload, Response, StatusCode}; 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::{FromRequest, HttpRequest}; @@ -110,7 +110,7 @@ where impl Responder for Json where - Err::Container: From, + JsonError: Error, { type Future = Ready; @@ -158,15 +158,15 @@ where /// ); /// } /// ``` -impl FromRequest for Json +impl<'a, T, Err: ErrorRenderer> FromRequest<'a, Err> for Json where - T: DeserializeOwned + 'static, + T: DeserializeOwned + 'a, { type Error = JsonPayloadError; - type Future = Pin>>>; + type Future = Pin> + 'a>>; #[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 (limit, ctype) = req .app_state::() @@ -260,7 +260,7 @@ impl Default for JsonConfig { /// * content type is not `application/json` /// (unless specified in [`JsonConfig`](struct.JsonConfig.html)) /// * content length is greater than 256k -struct JsonBody { +struct JsonBody<'a, U> { limit: usize, length: Option, #[cfg(feature = "compress")] @@ -268,17 +268,17 @@ struct JsonBody { #[cfg(not(feature = "compress"))] stream: Option, err: Option, - fut: Option>>>>, + fut: Option> + 'a>>>, } -impl JsonBody +impl<'a, U> JsonBody<'a, U> where - U: DeserializeOwned + 'static, + U: DeserializeOwned + 'a, { /// Create `JsonBody` for request. fn new( - req: &HttpRequest, - payload: &mut Payload, + req: &'a HttpRequest, + payload: &'a mut Payload, ctype: Option bool + Send + Sync>>, ) -> Self { // check content-type @@ -327,9 +327,9 @@ where } } -impl Future for JsonBody +impl<'a, U> Future for JsonBody<'a, U> where - U: DeserializeOwned + 'static, + U: DeserializeOwned + 'a, { type Output = Result; diff --git a/ntex/src/web/types/path.rs b/ntex/src/web/types/path.rs index 73254710..32c69a88 100644 --- a/ntex/src/web/types/path.rs +++ b/ntex/src/web/types/path.rs @@ -149,15 +149,15 @@ impl fmt::Display for Path { /// ); /// } /// ``` -impl FromRequest for Path +impl<'a, T, Err: ErrorRenderer> FromRequest<'a, Err> for Path where - T: de::DeserializeOwned, + T: de::DeserializeOwned + 'a, { type Error = PathError; type Future = Ready; #[inline] - fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { + fn from_request(req: &'a HttpRequest, _: &'a mut Payload) -> Self::Future { Ready::from( de::Deserialize::deserialize(PathDeserializer::new(req.match_info())) .map(|inner| Path { inner }) diff --git a/ntex/src/web/types/payload.rs b/ntex/src/web/types/payload.rs index 4634cd0d..2b4933ae 100644 --- a/ntex/src/web/types/payload.rs +++ b/ntex/src/web/types/payload.rs @@ -1,5 +1,5 @@ //! 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 mime::Mime; @@ -105,12 +105,15 @@ impl Stream for Payload { /// ); /// } /// ``` -impl FromRequest for Payload { - type Error = Err::Container; +impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for Payload { + type Error = Infallible; type Future = Ready; #[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())) } } @@ -139,15 +142,18 @@ impl FromRequest for Payload { /// ); /// } /// ``` -impl FromRequest for Bytes { +impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for Bytes { type Error = PayloadError; type Future = Either< - Pin>>>, + Pin> + 'a>>, Ready, >; #[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 cfg = if let Some(cfg) = req.app_state::() { cfg @@ -193,15 +199,18 @@ impl FromRequest for Bytes { /// ); /// } /// ``` -impl FromRequest for String { +impl<'a, Err: ErrorRenderer> FromRequest<'a, Err> for String { type Error = PayloadError; type Future = Either< - Pin>>>, + Pin> + 'a>>, Ready, >; #[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 cfg = if let Some(cfg) = req.app_state::() { cfg diff --git a/ntex/src/web/types/query.rs b/ntex/src/web/types/query.rs index 438e6ce9..3eea0fb0 100644 --- a/ntex/src/web/types/query.rs +++ b/ntex/src/web/types/query.rs @@ -122,16 +122,16 @@ impl fmt::Display for Query { /// .route(web::get().to(index))); // <- use `Query` extractor /// } /// ``` -impl FromRequest for Query +impl<'a, T, Err> FromRequest<'a, Err> for Query where - T: de::DeserializeOwned, + T: de::DeserializeOwned + 'a, Err: ErrorRenderer, { type Error = QueryPayloadError; type Future = Ready; #[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::(req.query_string()) .map(|val| Ready::Ok(Query(val))) .unwrap_or_else(move |e| { diff --git a/ntex/src/web/types/state.rs b/ntex/src/web/types/state.rs index 495f9989..88c3d4b2 100644 --- a/ntex/src/web/types/state.rs +++ b/ntex/src/web/types/state.rs @@ -97,12 +97,12 @@ impl Clone for State { } } -impl FromRequest for State { +impl<'a, T: 'static, E: ErrorRenderer> FromRequest<'a, E> for State { type Error = DataExtractorError; type Future = Ready; #[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::>() { Ready::Ok(st.clone()) } else { diff --git a/ntex/src/web/util.rs b/ntex/src/web/util.rs index dbb56a23..05b80404 100644 --- a/ntex/src/web/util.rs +++ b/ntex/src/web/util.rs @@ -10,7 +10,7 @@ use crate::http::{Method, Request, Response}; use crate::service::{IntoServiceFactory, ServiceFactory}; use super::config::AppConfig; -use super::error::ErrorRenderer; +use super::error::{Error, ErrorRenderer}; use super::extract::FromRequest; use super::handler::Handler; use super::resource::Resource; @@ -79,7 +79,7 @@ pub fn resource(path: T) -> Resource { // } /// Create *route* without configuration. -pub fn route<'a, Err: ErrorRenderer>() -> Route { +pub fn route() -> Route { Route::new() } @@ -97,7 +97,7 @@ pub fn route<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `GET` route gets added: /// * /{project_id} /// -pub fn get<'a, Err: ErrorRenderer>() -> Route { +pub fn get() -> Route { method(Method::GET) } @@ -115,7 +115,7 @@ pub fn get<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `POST` route gets added: /// * /{project_id} /// -pub fn post<'a, Err: ErrorRenderer>() -> Route { +pub fn post() -> Route { method(Method::POST) } @@ -133,7 +133,7 @@ pub fn post<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `PUT` route gets added: /// * /{project_id} /// -pub fn put<'a, Err: ErrorRenderer>() -> Route { +pub fn put() -> Route { method(Method::PUT) } @@ -151,7 +151,7 @@ pub fn put<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `PATCH` route gets added: /// * /{project_id} /// -pub fn patch<'a, Err: ErrorRenderer>() -> Route { +pub fn patch() -> Route { method(Method::PATCH) } @@ -169,7 +169,7 @@ pub fn patch<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `DELETE` route gets added: /// * /{project_id} /// -pub fn delete<'a, Err: ErrorRenderer>() -> Route { +pub fn delete() -> Route { method(Method::DELETE) } @@ -187,7 +187,7 @@ pub fn delete<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `HEAD` route gets added: /// * /{project_id} /// -pub fn head<'a, Err: ErrorRenderer>() -> Route { +pub fn head() -> Route { method(Method::HEAD) } @@ -205,7 +205,7 @@ pub fn head<'a, Err: ErrorRenderer>() -> Route { /// In the above example, one `GET` route gets added: /// * /{project_id} /// -pub fn method<'a, Err: ErrorRenderer>(method: Method) -> Route { +pub fn method(method: Method) -> Route { Route::new().method(method) } @@ -224,10 +224,10 @@ pub fn method<'a, Err: ErrorRenderer>(method: Method) -> Route { /// ``` pub fn to<'a, F, Args, Err>(handler: F) -> Route where - F: Handler, - Args: FromRequest + 'static, + F: Handler<'a, Args, Err>, + Args: FromRequest<'a, Err> + 'a, + Args::Error: Error, Err: ErrorRenderer, - Err::Container: From, { Route::new().to(handler) }