From 0886f270822dd396dda88fa9fc4b0e3e83361c87 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 9 Feb 2022 00:22:45 +0600 Subject: [PATCH] stopping point --- ntex-macros/src/route.rs | 6 +- ntex-service/src/lib.rs | 14 +- ntex-service/src/map_err.rs | 42 +- ntex-service/src/map_init_err.rs | 32 +- ntex-service/src/pipeline.rs | 9 +- ntex/examples/basic.rs | 42 ++ ntex/examples/client.rs | 25 + ntex/examples/echo.rs | 35 ++ ntex/examples/echo2.rs | 31 ++ ntex/examples/hello-world.rs | 27 ++ ntex/examples/uds.rs | 47 ++ ntex/src/http/error.rs | 2 + ntex/src/web/app.rs | 268 +++++------ ntex/src/web/app_service.rs | 559 +++++++++++----------- ntex/src/web/boxed.rs | 28 +- ntex/src/web/config.rs | 11 +- ntex/src/web/extract.rs | 45 +- ntex/src/web/handler.rs | 8 +- ntex/src/web/httprequest.rs | 8 +- ntex/src/web/middleware/compress.rs | 8 +- ntex/src/web/middleware/defaultheaders.rs | 7 +- ntex/src/web/middleware/logger.rs | 9 +- ntex/src/web/mod.rs | 104 ++-- ntex/src/web/request.rs | 88 ++-- ntex/src/web/resource.rs | 134 +++--- ntex/src/web/response.rs | 58 +-- ntex/src/web/route.rs | 10 +- ntex/src/web/scope.rs | 56 +-- ntex/src/web/service.rs | 221 +++++---- ntex/src/web/stack.rs | 122 ++--- ntex/src/web/test.rs | 20 +- 31 files changed, 1074 insertions(+), 1002 deletions(-) create mode 100644 ntex/examples/basic.rs create mode 100644 ntex/examples/client.rs create mode 100644 ntex/examples/echo.rs create mode 100644 ntex/examples/echo2.rs create mode 100644 ntex/examples/hello-world.rs create mode 100644 ntex/examples/uds.rs diff --git a/ntex-macros/src/route.rs b/ntex-macros/src/route.rs index 8d69eb9e..4f812b9c 100644 --- a/ntex-macros/src/route.rs +++ b/ntex-macros/src/route.rs @@ -151,9 +151,9 @@ impl Route { #[allow(non_camel_case_types)] pub struct #name; - impl ntex::web::dev::WebServiceFactory<#error> for #name + impl<'a> ntex::web::WebService<'a, #error> for #name { - fn register(self, __config: &mut ntex::web::dev::WebServiceConfig<#error>) { + fn register(self, __config: &mut ntex::web::WebServiceConfig<'a, #error>) { #ast let __resource = ntex::web::Resource::new(#path) @@ -162,7 +162,7 @@ impl Route { #(.guard(ntex::web::guard::fn_guard(#extra_guards)))* .to(#name); - ntex::web::dev::WebServiceFactory::register(__resource, __config) + ntex::web::WebService::register(__resource, __config) } } }; diff --git a/ntex-service/src/lib.rs b/ntex-service/src/lib.rs index b664f004..a2226535 100644 --- a/ntex-service/src/lib.rs +++ b/ntex-service/src/lib.rs @@ -135,7 +135,7 @@ pub trait Service { /// /// Note that this function consumes the receiving service and returns a /// wrapped version of it. - fn map_err(self, f: F) -> crate::dev::MapErr + fn map_err(self, f: F) -> crate::dev::MapErr where Self: Sized, F: Fn(Self::Error) -> E, @@ -185,23 +185,17 @@ pub trait ServiceFactory { #[inline] /// Map this service's error to a different error, returning a new service. - fn map_err( - self, - f: F, - ) -> crate::map_err::MapErrServiceFactory + fn map_err(self, f: F) -> crate::map_err::MapErrServiceFactory where Self: Sized, F: Fn(Self::Error) -> E + Clone, { - crate::map_err::MapErrServiceFactory::<_, _, Cfg, _, _>::new(self, f) + crate::map_err::MapErrServiceFactory::new(self, f) } #[inline] /// Map this factory's init error to a different error, returning a new service. - fn map_init_err( - self, - f: F, - ) -> crate::map_init_err::MapInitErr + fn map_init_err(self, f: F) -> crate::map_init_err::MapInitErr where Self: Sized, F: Fn(Self::InitError) -> E + Clone, diff --git a/ntex-service/src/map_err.rs b/ntex-service/src/map_err.rs index b581013e..07ed063e 100644 --- a/ntex-service/src/map_err.rs +++ b/ntex-service/src/map_err.rs @@ -6,19 +6,15 @@ use super::{Service, ServiceFactory}; /// error. /// /// This is created by the `ServiceExt::map_err` method. -pub struct MapErr { +pub struct MapErr { service: A, f: F, - _t: PhantomData E>, + _t: PhantomData, } -impl MapErr { +impl MapErr { /// Create new `MapErr` combinator - pub(crate) fn new(service: A, f: F) -> Self - where - A: Service, - F: Fn(A::Error) -> E, - { + pub(crate) fn new(service: A, f: F) -> Self { Self { service, f, @@ -27,7 +23,7 @@ impl MapErr { } } -impl Clone for MapErr +impl Clone for MapErr where A: Clone, F: Clone, @@ -42,7 +38,7 @@ where } } -impl Service for MapErr +impl Service for MapErr where A: Service, F: Fn(A::Error) -> E + Clone, @@ -106,21 +102,13 @@ where /// service's error. /// /// This is created by the `NewServiceExt::map_err` method. -pub struct MapErrServiceFactory -where - A: ServiceFactory, - F: Fn(A::Error) -> E + Clone, -{ +pub struct MapErrServiceFactory { a: A, f: F, - e: PhantomData E>, + e: PhantomData<(C, E)>, } -impl MapErrServiceFactory -where - A: ServiceFactory, - F: Fn(A::Error) -> E + Clone, -{ +impl MapErrServiceFactory { /// Create new `MapErr` new service instance pub(crate) fn new(a: A, f: F) -> Self { Self { @@ -131,10 +119,10 @@ where } } -impl Clone for MapErrServiceFactory +impl Clone for MapErrServiceFactory where - A: ServiceFactory + Clone, - F: Fn(A::Error) -> E + Clone, + A: Clone, + F: Clone, { fn clone(&self) -> Self { Self { @@ -145,7 +133,7 @@ where } } -impl ServiceFactory for MapErrServiceFactory +impl ServiceFactory for MapErrServiceFactory where A: ServiceFactory, F: Fn(A::Error) -> E + Clone, @@ -153,7 +141,7 @@ where type Response = A::Response; type Error = E; - type Service = MapErr; + type Service = MapErr; type InitError = A::InitError; type Future = MapErrServiceFuture; @@ -190,7 +178,7 @@ where A: ServiceFactory, F: Fn(A::Error) -> E + Clone, { - type Output = Result, A::InitError>; + type Output = Result, A::InitError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); diff --git a/ntex-service/src/map_init_err.rs b/ntex-service/src/map_init_err.rs index f37b57f6..167b7c64 100644 --- a/ntex-service/src/map_init_err.rs +++ b/ntex-service/src/map_init_err.rs @@ -3,17 +3,13 @@ use std::{future::Future, marker::PhantomData, pin::Pin, task::Context, task::Po use super::ServiceFactory; /// `MapInitErr` service combinator -pub struct MapInitErr { +pub struct MapInitErr { a: A, f: F, - e: PhantomData E>, + e: PhantomData, } -impl MapInitErr -where - A: ServiceFactory, - F: Fn(A::InitError) -> E, -{ +impl MapInitErr { /// Create new `MapInitErr` combinator pub(crate) fn new(a: A, f: F) -> Self { Self { @@ -24,7 +20,7 @@ where } } -impl Clone for MapInitErr +impl Clone for MapInitErr where A: Clone, F: Clone, @@ -38,7 +34,7 @@ where } } -impl ServiceFactory for MapInitErr +impl ServiceFactory for MapInitErr where A: ServiceFactory, F: Fn(A::InitError) -> E + Clone, @@ -48,7 +44,7 @@ where type Service = A::Service; type InitError = E; - type Future = MapInitErrFuture; + type Future = MapInitErrFuture; fn new_service(&self, cfg: C) -> Self::Future { MapInitErrFuture { @@ -59,23 +55,23 @@ where } pin_project_lite::pin_project! { - pub struct MapInitErrFuture + pub struct MapInitErrFuture where - A: ServiceFactory, - F: Fn(A::InitError) -> E, + F: Fn(Err) -> E, + Fut: Future>, { f: F, #[pin] - fut: A::Future, + fut: Fut, } } -impl Future for MapInitErrFuture +impl Future for MapInitErrFuture where - A: ServiceFactory, - F: Fn(A::InitError) -> E, + F: Fn(Err) -> E, + Fut: Future>, { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); diff --git a/ntex-service/src/pipeline.rs b/ntex-service/src/pipeline.rs index 99ae266f..b9154bb6 100644 --- a/ntex-service/src/pipeline.rs +++ b/ntex-service/src/pipeline.rs @@ -105,7 +105,7 @@ impl, R> Pipeline { /// /// Note that this function consumes the receiving service and returns a /// wrapped version of it. - pub fn map_err(self, f: F) -> Pipeline, R> + pub fn map_err(self, f: F) -> Pipeline, R> where Self: Sized, F: Fn(T::Error) -> E, @@ -228,7 +228,7 @@ impl, R, C> PipelineFactory { pub fn map_err( self, f: F, - ) -> PipelineFactory, R, C> + ) -> PipelineFactory, R, C> where Self: Sized, F: Fn(T::Error) -> E + Clone, @@ -240,10 +240,7 @@ impl, R, C> PipelineFactory { } /// Map this factory's init error to a different error, returning a new service. - pub fn map_init_err( - self, - f: F, - ) -> PipelineFactory, R, C> + pub fn map_init_err(self, f: F) -> PipelineFactory, R, C> where Self: Sized, F: Fn(T::InitError) -> E + Clone, diff --git a/ntex/examples/basic.rs b/ntex/examples/basic.rs new file mode 100644 index 00000000..a4c8fe85 --- /dev/null +++ b/ntex/examples/basic.rs @@ -0,0 +1,42 @@ +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 { + println!("REQ: {:?}", req); + format!("Hello: {}!\r\n", name) +} + +async fn index_async(req: HttpRequest) -> &'static str { + println!("REQ: {:?}", req); + "Hello world!\r\n" +} + +#[web::get("/")] +async fn no_params() -> &'static str { + "Hello world!\r\n" +} + +#[ntex::main] +async fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "ntex=trace"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + .wrap(middleware::Logger::default()) + .service((index, no_params)) + .service( + web::resource("/resource2/index.html") + .wrap(middleware::DefaultHeaders::new().header("X-Version-R2", "0.3")) + .default(|| async { HttpResponse::MethodNotAllowed() }) + .route(web::get().to(index_async)), + ) + .service(web::resource("/test1.html").to(|| async { "Test\r\n" })) + }) + .bind("0.0.0.0:8081")? + .workers(4) + .keep_alive(http::KeepAlive::Disabled) + .run() + .await +} diff --git a/ntex/examples/client.rs b/ntex/examples/client.rs new file mode 100644 index 00000000..e5ecbf13 --- /dev/null +++ b/ntex/examples/client.rs @@ -0,0 +1,25 @@ +use ntex::http::client::{error::SendRequestError, Client}; + +#[ntex::main] +async fn main() -> Result<(), SendRequestError> { + std::env::set_var("RUST_LOG", "ntex=trace"); + env_logger::init(); + + let client = Client::new(); + + // Create request builder, configure request and send + let mut response = client + .get("https://www.rust-lang.org/") + .header("User-Agent", "ntex") + .send() + .await?; + + // server http response + println!("Response: {:?}", response); + + // read response body + let body = response.body().await.unwrap(); + println!("Downloaded: {:?} bytes", body.len()); + + Ok(()) +} diff --git a/ntex/examples/echo.rs b/ntex/examples/echo.rs new file mode 100644 index 00000000..b4cc3883 --- /dev/null +++ b/ntex/examples/echo.rs @@ -0,0 +1,35 @@ +use std::{env, io}; + +use futures_util::StreamExt; +use log::info; +use ntex::http::header::HeaderValue; +use ntex::http::{HttpService, Request, Response}; +use ntex::{server::Server, time::Seconds, util::BytesMut}; + +#[ntex::main] +async fn main() -> io::Result<()> { + env::set_var("RUST_LOG", "echo=info"); + env_logger::init(); + + Server::build() + .bind("echo", "127.0.0.1:8080", |_| { + HttpService::build() + .client_timeout(Seconds(1)) + .disconnect_timeout(Seconds(1)) + .finish(|mut req: Request| async move { + let mut body = BytesMut::new(); + while let Some(item) = req.payload().next().await { + body.extend_from_slice(&item.unwrap()); + } + + info!("request body: {:?}", body); + Ok::<_, io::Error>( + Response::Ok() + .header("x-head", HeaderValue::from_static("dummy value!")) + .body(body), + ) + }) + })? + .run() + .await +} diff --git a/ntex/examples/echo2.rs b/ntex/examples/echo2.rs new file mode 100644 index 00000000..7acbe0d6 --- /dev/null +++ b/ntex/examples/echo2.rs @@ -0,0 +1,31 @@ +use std::{env, io}; + +use futures_util::StreamExt; +use log::info; +use ntex::http::{header::HeaderValue, HttpService, Request, Response}; +use ntex::{server::Server, util::BytesMut}; + +async fn handle_request(mut req: Request) -> Result { + let mut body = BytesMut::new(); + while let Some(item) = req.payload().next().await { + body.extend_from_slice(&item.unwrap()) + } + + info!("request body: {:?}", body); + Ok(Response::Ok() + .header("x-head", HeaderValue::from_static("dummy value!")) + .body(body)) +} + +#[ntex::main] +async fn main() -> io::Result<()> { + env::set_var("RUST_LOG", "echo=info"); + env_logger::init(); + + Server::build() + .bind("echo", "127.0.0.1:8080", |_| { + HttpService::build().finish(handle_request) + })? + .run() + .await +} diff --git a/ntex/examples/hello-world.rs b/ntex/examples/hello-world.rs new file mode 100644 index 00000000..9bd51e96 --- /dev/null +++ b/ntex/examples/hello-world.rs @@ -0,0 +1,27 @@ +use std::{env, io}; + +use log::info; +use ntex::http::header::HeaderValue; +use ntex::http::{HttpService, Response}; +use ntex::{server::Server, time::Seconds, util::Ready}; + +#[ntex::main] +async fn main() -> io::Result<()> { + env::set_var("RUST_LOG", "ntex=trace,hello_world=info"); + env_logger::init(); + + Server::build() + .bind("hello-world", "127.0.0.1:8080", |_| { + HttpService::build() + .client_timeout(Seconds(1)) + .disconnect_timeout(Seconds(1)) + .finish(|_req| { + info!("{:?}", _req); + let mut res = Response::Ok(); + res.header("x-head", HeaderValue::from_static("dummy value!")); + Ready::Ok::<_, io::Error>(res.body("Hello world!")) + }) + })? + .run() + .await +} diff --git a/ntex/examples/uds.rs b/ntex/examples/uds.rs new file mode 100644 index 00000000..eb4fcb9d --- /dev/null +++ b/ntex/examples/uds.rs @@ -0,0 +1,47 @@ +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 { + println!("REQ: {:?}", req); + format!("Hello: {}!\r\n", name) +} + +async fn index_async(req: HttpRequest) -> Result<&'static str, std::io::Error> { + println!("REQ: {:?}", req); + Ok("Hello world!\r\n") +} + +#[web::get("/")] +async fn no_params() -> &'static str { + "Hello world!\r\n" +} + +#[cfg(unix)] +#[ntex::main] +async fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "ntex=info"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) + .wrap(middleware::Logger::default()) + .service((index, no_params)) + .service( + web::resource("/resource2/index.html") + .wrap(middleware::DefaultHeaders::new().header("X-Version-R2", "0.3")) + .default_service( + web::route().to(|| async { HttpResponse::MethodNotAllowed() }), + ) + .route(web::get().to(index_async)), + ) + .service(web::resource("/test1.html").to(|| async { "Test\r\n" })) + }) + .bind_uds("/tmp/uds-test")? + .workers(1) + .run() + .await +} + +#[cfg(not(unix))] +fn main() {} diff --git a/ntex/src/http/error.rs b/ntex/src/http/error.rs index e383e098..aac56ada 100644 --- a/ntex/src/http/error.rs +++ b/ntex/src/http/error.rs @@ -28,6 +28,8 @@ pub trait ResponseError: fmt::Display + fmt::Debug { } } +impl ResponseError for std::convert::Infallible {} + impl<'a, T: ResponseError> ResponseError for &'a T { fn error_response(&self) -> Response { (*self).error_response() diff --git a/ntex/src/web/app.rs b/ntex/src/web/app.rs index 34115af3..2d4118cb 100644 --- a/ntex/src/web/app.rs +++ b/ntex/src/web/app.rs @@ -6,11 +6,13 @@ use crate::service::{map_config, pipeline_factory, PipelineFactory}; use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform}; use crate::util::Extensions; -use super::app_service::{AppFactory, AppService}; +use super::app_service::{ + AppFactory, AppFactoryInner, AppRouting, AppService, DefaultService, +}; use super::boxed::{self, BoxServiceFactory}; use super::config::{AppConfig, ServiceConfig}; -use super::service::{AppServiceFactory, ServiceFactoryWrapper, WebServiceFactory}; -use super::stack::{Filter, Next, Stack}; +use super::service::{create_web_service, WebService, WebServiceWrapper}; +use super::stack::{Filter, Filters, FiltersFactory, Next, Stack}; use super::types::state::{State, StateFactory}; use super::{DefaultError, ErrorRenderer, Resource, Route, WebRequest, WebResponse}; @@ -21,9 +23,9 @@ type FnStateFactory = /// for building application instances. pub struct App<'a, M, F, Err: ErrorRenderer = DefaultError> { middleware: M, - filter: PipelineFactory>, - services: Vec>>, - default: Option>>, + filter: F, + services: Vec>>, + default: BoxServiceFactory<'a, Err>, state: Vec>, state_factories: Vec, external: Vec, @@ -32,53 +34,44 @@ pub struct App<'a, M, F, Err: ErrorRenderer = DefaultError> { case_insensitive: bool, } -impl<'a> App<'a, Identity, Filter, DefaultError> { +impl<'a> App<'a, Identity, Filter, DefaultError> { /// Create application builder. Application can be configured with a builder-like pattern. pub fn new() -> Self { - // App { - // middleware: Identity, - // filter: pipeline_factory(Filter::new()), - // state: Vec::new(), - // state_factories: Vec::new(), - // services: Vec::new(), - // default: None, - // external: Vec::new(), - // extensions: Extensions::new(), - // error_renderer: DefaultError, - // case_insensitive: false, - // } - todo!() + App { + filter: Filter, + middleware: Identity, + state: Vec::new(), + state_factories: Vec::new(), + services: Vec::new(), + default: boxed::factory(DefaultService::default()), + external: Vec::new(), + extensions: Extensions::new(), + error_renderer: DefaultError, + case_insensitive: false, + } } } -impl<'a, Err: ErrorRenderer> App<'a, Identity, Filter, Err> { +impl<'a, Err: ErrorRenderer> App<'a, Identity, Filter, Err> { /// Create application builder with custom error renderer. pub fn with(err: Err) -> Self { - // App { - // middleware: Identity, - // filter: pipeline_factory(Filter::new()), - // state: Vec::new(), - // state_factories: Vec::new(), - // services: Vec::new(), - // default: None, - // external: Vec::new(), - // extensions: Extensions::new(), - // error_renderer: err, - // case_insensitive: false, - // } - todo!() + App { + filter: Filter, + middleware: Identity, + state: Vec::new(), + state_factories: Vec::new(), + services: Vec::new(), + default: boxed::factory(DefaultService::default()), + external: Vec::new(), + extensions: Extensions::new(), + error_renderer: err, + case_insensitive: false, + } } } -impl<'a, M, T, Err> App<'a, M, T, Err> +impl<'a, M, F, Err> App<'a, M, F, Err> where - T: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - >, - T::Future: 'static, Err: ErrorRenderer, { /// Set application state. Application state could be accessed @@ -119,9 +112,9 @@ where /// Set application state factory. This function is /// similar to `.state()` but it accepts state factory. State object get /// constructed asynchronously during application initialization. - pub fn state_factory(mut self, state: F) -> Self + pub fn state_factory(mut self, state: T) -> Self where - F: Fn() -> Out + 'static, + T: Fn() -> Out + 'static, Out: Future> + 'static, D: 'static, E: fmt::Debug, @@ -181,9 +174,9 @@ where /// .route("/index.html", web::get().to(|| async { HttpResponse::Ok() })); /// } /// ``` - pub fn configure(mut self, f: F) -> Self + pub fn configure(mut self, f: U) -> Self where - F: FnOnce(&mut ServiceConfig<'a, Err>), + U: FnOnce(&mut ServiceConfig<'a, Err>), { let mut cfg = ServiceConfig::new(); f(&mut cfg); @@ -213,12 +206,11 @@ where /// } /// ``` pub fn route(self, path: &str, mut route: Route) -> 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. @@ -230,12 +222,11 @@ where /// * *Resource* is an entry in resource table which corresponds to requested URL. /// * *Scope* is a set of resources with common root path. /// * "StaticFiles" is a service for static files support - pub fn service(mut self, factory: F) -> Self + pub fn service(mut self, factory: U) -> Self where - F: WebServiceFactory<'a, Err> + 'static, + U: WebService<'a, Err> + 'static, { - self.services - .push(Box::new(ServiceFactoryWrapper::new(factory))); + self.services.push(create_web_service(factory)); self } @@ -268,25 +259,28 @@ where /// let app = App::new() /// .service( /// web::resource("/index.html").to(|| async { HttpResponse::Ok() })) - /// .default_service( + /// .default( /// web::to(|| async { HttpResponse::NotFound() }) /// ); /// } /// ``` - pub fn default_service(mut self, f: F) -> Self + pub fn default(mut self, f: T) -> Self where - F: IntoServiceFactory>, + T: IntoServiceFactory>, U: ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, > + 'static, - U::InitError: fmt::Debug, + U::Service: 'static, + U::Future: 'static, + U::InitError: fmt::Debug + 'static, { - // // create and configure default resource - // self.default = Some(Rc::new(boxed::factory(f.into_factory().map_init_err( - // |e| log::error!("Cannot construct default service: {:?}", e), - // )))); + // create and configure default resource + self.default = + boxed::factory::<'a, _, _>(f.into_factory().map_init_err(|e| { + log::error!("Cannot construct default service: {:?}", e) + })); self } @@ -349,31 +343,9 @@ where /// .route("/index.html", web::get().to(index)); /// } /// ``` - pub fn filter( - self, - filter: U, - ) -> App< - 'a, - M, - impl ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - >, - Err, - > - where - S: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - >, - U: IntoServiceFactory>, - { + pub fn filter(self, filter: U) -> App<'a, M, Filters, Err> { App { - filter: self.filter.and_then(filter.into_factory()), + filter: Filters::new(self.filter, filter), middleware: self.middleware, state: self.state, state_factories: self.state_factories, @@ -412,7 +384,7 @@ where /// .route("/index.html", web::get().to(index)); /// } /// ``` - pub fn wrap(self, mw: U) -> App<'a, Stack, T, Err> { + pub fn wrap(self, mw: U) -> App<'a, Stack, F, Err> { App { middleware: Stack::new(self.middleware, mw), filter: self.filter, @@ -438,15 +410,18 @@ where impl<'a, M, F, Err> App<'a, M, F, Err> where - M: Transform, Err>> + 'static, - M::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), + M: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, > + 'static, + M::Service: + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, Err: ErrorRenderer, { /// Construct service factory with default `AppConfig`, suitable for `http::HttpService`. @@ -469,13 +444,9 @@ where /// ``` pub fn finish( self, - ) -> impl ServiceFactory< - Request, - Response = WebResponse, - Error = Err::Container, - InitError = (), - > + 'a { - IntoServiceFactory::, Request, ()>::into_factory(self) + ) -> impl ServiceFactory + { + IntoServiceFactory::::into_factory(self) } /// Construct service factory suitable for `http::HttpService`. @@ -499,82 +470,85 @@ where pub fn with_config( self, cfg: AppConfig, - ) -> impl ServiceFactory< - Request, - Response = WebResponse, - Error = Err::Container, - InitError = (), - > + 'a { - let app = AppFactory { - filter: self.filter, + ) -> impl ServiceFactory + { + let app = AppFactoryInner { + filter: Some(self.filter), middleware: Rc::new(self.middleware), state: Rc::new(self.state), state_factories: Rc::new(self.state_factories), services: Rc::new(RefCell::new(self.services)), external: RefCell::new(self.external), - default: self.default, + default: Some(self.default), extensions: RefCell::new(Some(self.extensions)), case_insensitive: self.case_insensitive, }; - map_config(app, move |_| cfg.clone()) + map_config(AppFactory::new(app), move |_| cfg.clone()) } } -impl<'a, M, F, Err> IntoServiceFactory, Request, AppConfig> +impl<'a, M, F, Err> IntoServiceFactory for App<'a, M, F, Err> where - M: Transform, Err>> + 'static, + M: 'static, + M: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, + >, M::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - > + 'static, + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, Err: ErrorRenderer, { - fn into_factory(self) -> AppFactory<'a, M, F, Err> { - AppFactory { - filter: self.filter, + fn into_factory(self) -> AppFactory { + AppFactory::new(AppFactoryInner { + filter: Some(self.filter), middleware: Rc::new(self.middleware), state: Rc::new(self.state), state_factories: Rc::new(self.state_factories), services: Rc::new(RefCell::new(self.services)), external: RefCell::new(self.external), - default: self.default, + default: Some(self.default), extensions: RefCell::new(Some(self.extensions)), case_insensitive: self.case_insensitive, - } + }) } } -impl<'a, M, F, Err> IntoServiceFactory, Request, ()> - for App<'a, M, F, Err> +impl<'a, M, F, Err> IntoServiceFactory for App<'a, M, F, Err> where - M: Transform, Err>> + 'static, + M: 'static, + M: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, + >, M::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - > + 'static, + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, Err: ErrorRenderer, { - fn into_factory(self) -> AppFactory<'a, M, F, Err> { - AppFactory { - filter: self.filter, + fn into_factory(self) -> AppFactory { + AppFactory::new(AppFactoryInner { + filter: Some(self.filter), middleware: Rc::new(self.middleware), state: Rc::new(self.state), state_factories: Rc::new(self.state_factories), services: Rc::new(RefCell::new(self.services)), external: RefCell::new(self.external), - default: self.default, + default: Some(self.default), extensions: RefCell::new(Some(self.extensions)), case_insensitive: self.case_insensitive, - } + }) } } @@ -611,12 +585,10 @@ mod tests { .service(web::resource("/test").to(|| async { HttpResponse::Ok() })) .service( web::resource("/test2") - .default_service(|r: WebRequest| async move { - Ok(r.into_response(HttpResponse::Created())) - }) + .default(|| async move { HttpResponse::Created() }) .route(web::get().to(|| async { HttpResponse::Ok() })), ) - .default_service(|r: WebRequest| async move { + .default(|r: WebRequest<'_, DefaultError>| async move { Ok(r.into_response(HttpResponse::MethodNotAllowed())) }) .with_config(Default::default()) diff --git a/ntex/src/web/app_service.rs b/ntex/src/web/app_service.rs index e4bd2692..c52d5ccb 100644 --- a/ntex/src/web/app_service.rs +++ b/ntex/src/web/app_service.rs @@ -7,106 +7,198 @@ use crate::router::{Path, ResourceDef, Router}; use crate::service::{ fn_service, into_service, PipelineFactory, Service, ServiceFactory, Transform, }; -use crate::util::{ready, Extensions}; +use crate::util::{ready, Extensions, Ready}; use super::boxed::{self, BoxService, BoxServiceFactory}; use super::config::AppConfig; use super::guard::Guard; use super::httprequest::{HttpRequest, HttpRequestPool}; use super::rmap::ResourceMap; -use super::service::{AppServiceFactory, WebServiceConfig}; -use super::stack::Next; +use super::service::{WebService, WebServiceConfig, WebServiceWrapper}; +use super::stack::{Filter, FiltersFactory, Next}; use super::types::state::StateFactory; -use super::{ErrorRenderer, WebRequest, WebResponse}; +use super::{ErrorContainer, ErrorRenderer, WebRequest, WebResponse}; type Guards = Vec>; -type BoxResponse<'a, Err: ErrorRenderer> = - Pin> + 'a>>; +type BoxResponse<'a> = Pin> + 'a>>; type FnStateFactory = Box Pin, ()>>>>>; -/// Service factory to convert `Request` to a `WebRequest`. +/// Service factory for converting `Request` to a `WebResponse>`. +/// /// It also executes state factories. -pub struct AppFactory<'a, T, F, Err: ErrorRenderer> -where - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - > + 'static, - Err: ErrorRenderer, -{ - pub(super) middleware: Rc, - pub(super) filter: PipelineFactory>, - pub(super) extensions: RefCell>, - pub(super) state: Rc>>, - pub(super) state_factories: Rc>, - pub(super) services: Rc>>>>, - pub(super) default: Option>>, - pub(super) external: RefCell>, - pub(super) case_insensitive: bool, +pub struct AppFactory(WebAppFactory); + +pub struct AppService(WebAppHandler); + +type WebAppFactory = + Box Pin>>>>; +type WebAppHandler = + Box Pin>>>>; +type WebAppHandler2<'a> = Box< + dyn Fn(Request) -> Pin> + 'a>> + + 'a, +>; + +impl AppFactory { + pub(super) fn new<'a, M, F, Err: ErrorRenderer>( + app: AppFactoryInner<'a, M, F, Err>, + ) -> Self + where + M: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, + > + 'static, + M::Service: Service< + &'a mut WebRequest<'a, Err>, + Response = WebResponse, + Error = Infallible, + >, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, + Err: ErrorRenderer, + { + let app = RefCell::new(app); + let b: Box< + dyn Fn(AppConfig) -> Pin>>> + 'a, + > = Box::new(move |cfg| { + let fut = app.borrow_mut().create(cfg); + Box::pin(async move { Ok(AppService(fut.await?)) }) + }); + AppFactory(unsafe { std::mem::transmute(b) }) + } } -impl<'a, T, F, Err> ServiceFactory for AppFactory<'a, T, F, Err> -where - T: Transform, Err>> + 'static, - T::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - > + 'static, - Err: ErrorRenderer, -{ +impl ServiceFactory for AppFactory { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); - type Service = AppFactoryService<'a, T::Service, Err>; - type Future = - Pin> + 'a>>; + type Service = AppService; + type Future = Pin>>>; fn new_service(&self, _: ()) -> Self::Future { ServiceFactory::::new_service(self, AppConfig::default()) } } -impl<'a, T, F, Err> ServiceFactory for AppFactory<'a, T, F, Err> +impl ServiceFactory for AppFactory { + type Response = WebResponse; + type Error = Infallible; + type InitError = (); + type Service = AppService; + type Future = Pin>>>; + + fn new_service(&self, cfg: AppConfig) -> Self::Future { + (&*self.0)(cfg) + } +} + +impl Service for AppService { + type Response = WebResponse; + type Error = Infallible; + type Future = Pin>>>; + + fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&self, req: Request) -> Self::Future { + (&*self.0)(req) + } +} + +/// Service factory to convert `Request` to a `WebRequest`. +/// It also executes state factories. +pub(super) struct AppFactoryInner<'a, M, F, Err: ErrorRenderer> where - T: Transform, Err>> + 'static, - T::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - InitError = (), - > + 'static, + M: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, + >, + M::Service: + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err>, + >>::Service: 'static, + >>::Future: 'static, Err: ErrorRenderer, +{ + pub(super) middleware: Rc, + pub(super) filter: Option, + pub(super) extensions: RefCell>, + pub(super) state: Rc>>, + pub(super) state_factories: Rc>, + pub(super) services: Rc>>>>, + pub(super) default: Option>, + pub(super) external: RefCell>, + pub(super) case_insensitive: bool, +} + +#[derive(Copy, Clone)] +pub(super) struct DefaultService(PhantomData); + +impl Default for DefaultService { + fn default() -> Self { + DefaultService(PhantomData) + } +} + +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> + for DefaultService { type Response = WebResponse; type Error = Err::Container; type InitError = (); - type Service = AppFactoryService<'a, T::Service, Err>; - type Future = - Pin> + 'a>>; + type Service = Self; + type Future = Ready; - fn new_service(&self, config: AppConfig) -> Self::Future { + fn new_service(&self, cfg: ()) -> 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 Future = Ready; + + fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&self, _: &'a mut WebRequest<'a, Err>) -> Self::Future { + Ready::Ok(Response::NotFound().finish().into()) + } +} + +impl<'a, T, F, Err> AppFactoryInner<'a, T, F, Err> +where + T: Transform< + AppRouting< + 'a, + >>::Service, + Err, + >, + > + 'static, + T::Service: + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, + Err: ErrorRenderer + 'static, +{ + pub(super) fn create( + &mut self, + config: AppConfig, + ) -> Pin>>> { // update resource default service - let default = self.default.clone().unwrap_or_else(|| panic!()); - - // .unwrap_or_else(|| { - // Rc::new(boxed::factory(into_service( - // |req: &'a mut WebRequest| { - // let res = req.into_response(Response::NotFound().finish()); - // async move { - // Ok(res) - // } - // } - // ))) - // }); + let default = Rc::new(self.default.take().unwrap()); // App config let mut config = WebServiceConfig::new(config, default.clone(), self.state.clone()); @@ -142,7 +234,7 @@ where let rmap = Rc::new(rmap); rmap.finish(rmap.clone()); - let filter_fut = self.filter.new_service(()); + let filter_fut = self.filter.take().unwrap().create().new_service(()); let state = self.state.clone(); let state_factories = self.state_factories.clone(); let mut extensions = self @@ -152,251 +244,150 @@ where .unwrap_or_else(Extensions::new); let middleware = self.middleware.clone(); - Box::pin(async move { - // create http services - for (path, factory, guards) in &mut services.iter() { - let service = factory.new_service(()).await?; - router.rdef(path.clone(), service).2 = guards.borrow_mut().take(); - } + let f: Pin> + 'a>> = + Box::pin(async move { + // create http services + for (path, factory, guards) in &mut services.iter() { + let service = factory.new_service(()).await?; + router.rdef(path.clone(), service).2 = guards.borrow_mut().take(); + } - let routing = AppRouting { - router: router.finish(), - default: Some(default_fut.await?), - }; + // router + let routing = AppRouting { + filter: filter_fut.await?, + router: Rc::new(AppRouter { + router: router.finish(), + default: Some(default_fut.await?), + }), + }; - // main service - let service = AppService { - filter: filter_fut.await?, - routing: Rc::new(routing), - }; - - // create app state container - for f in state.iter() { - f.create(&mut extensions); - } - - // async state factories - for fut in state_factories.iter() { - if let Ok(f) = fut().await { + // create app state container + for f in state.iter() { f.create(&mut extensions); } - } - Ok(AppFactoryService { - rmap, - config, - service: middleware.new_transform(Next::new(service)), - state: Rc::new(extensions), - pool: HttpRequestPool::create(), - _t: PhantomData, - }) - }) + // async state factories + for fut in state_factories.iter() { + if let Ok(f) = fut().await { + f.create(&mut extensions); + } + } + + let service = middleware.new_transform(routing); + let state = Rc::new(extensions); + let pool = HttpRequestPool::create(); + + 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 + } else { + HttpRequest::new( + Path::new(head.uri.clone()), + head, + payload, + rmap.clone(), + config.clone(), + state.clone(), + pool, + ) + }; + let mut wreq = + WebRequest::::new(unsafe { std::mem::transmute(&mut req) }); + let fut = service.call(unsafe { std::mem::transmute(&mut wreq) }); + Box::pin(async move { + let mut res = fut.await.unwrap(); + + let head = req.head(); + if head.upgrade() { + res.response.head_mut().set_io(head); + } + drop(wreq); + drop(req); + Ok(res) + }) + }); + Ok(unsafe { std::mem::transmute(hnd) }) + }); + unsafe { std::mem::transmute(f) } } } -/// Service to convert `Request` to a `WebRequest` -pub struct AppFactoryService<'a, T, Err> -where - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - Err: ErrorRenderer, -{ - service: T, - rmap: Rc, - config: AppConfig, - state: Rc, - pool: &'static HttpRequestPool, - _t: PhantomData<&'a Err>, +pub struct AppRouting<'a, F, Err: ErrorRenderer> { + filter: F, + router: Rc>, } -impl<'a, T, Err> Service for AppFactoryService<'a, T, Err> -where - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - Err: ErrorRenderer, -{ - type Response = WebResponse; - type Error = Err::Container; - type Future = AppFactoryServiceResponse<'a, T, Err>; - - #[inline] - fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { - let _ = ready!(self.service.poll_ready(cx)); - Poll::Ready(Ok(())) - } - - #[inline] - fn poll_shutdown(&self, cx: &mut Context<'_>, is_error: bool) -> Poll<()> { - self.service.poll_shutdown(cx, is_error) - } - - fn call(&self, req: Request) -> Self::Future { - let (head, payload) = req.into_parts(); - - let req = if let Some(mut req) = self.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 = self.state.clone(); - req - } else { - HttpRequest::new( - Path::new(head.uri.clone()), - head, - payload, - self.rmap.clone(), - self.config.clone(), - self.state.clone(), - self.pool, - ) - }; - let mut req = WebRequest::new(req); - let fut = self.service.call(&mut req); - - AppFactoryServiceResponse { fut, req } - } -} - -impl<'a, T, Err> Drop for AppFactoryService<'a, T, Err> -where - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - Err: ErrorRenderer, -{ - fn drop(&mut self) { - self.pool.clear(); - } -} - -pin_project_lite::pin_project! { - pub struct AppFactoryServiceResponse<'a, T: Service<&'a mut WebRequest>, Err>{ - #[pin] - fut: T::Future, - req: WebRequest, - } -} - -impl<'a, T, Err> Future for AppFactoryServiceResponse<'a, T, Err> -where - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - Err: ErrorRenderer, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Poll::Ready(Ok(ready!(self.project().fut.poll(cx)).unwrap())) - } -} - -struct AppRouting<'a, Err: ErrorRenderer> { +struct AppRouter<'a, Err: ErrorRenderer> { router: Router, Guards>, default: Option>, } -impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for AppRouting<'a, Err> { - type Response = WebResponse; - type Error = Err::Container; - type Future = BoxResponse<'a, Err>; - - #[inline] - fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&self, mut req: &'a mut WebRequest) -> Self::Future { - let res = self.router.recognize_checked(req, |req, guards| { - if let Some(guards) = guards { - for f in guards { - if !f.check(req.head()) { - return false; - } - } - } - true - }); - - if let Some((srv, _info)) = res { - srv.call(req) - } else if let Some(ref default) = self.default { - default.call(req) - } else { - let req = req.into_parts().0; - Box::pin(async { Ok(WebResponse::new(Response::NotFound().finish())) }) - } - } -} - -/// Web app service -pub struct AppService<'a, F, Err: ErrorRenderer> { - filter: F, - routing: Rc>, -} - -impl<'a, F, Err> Service<&'a mut WebRequest> for AppService<'a, F, Err> +impl<'a, F, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> + for AppRouting<'a, F, Err> where F: Service< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, >, + F::Future: 'a, Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; - type Future = AppServiceResponse<'a, F, Err>; + type Error = Infallible; + type Future = BoxResponse<'a>; #[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(); - if ready1 && ready2 { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } + let _ = ready!(self.filter.poll_ready(cx)); + Poll::Ready(Ok(())) } - fn call(&self, req: &'a mut WebRequest) -> Self::Future { - AppServiceResponse { - filter: self.filter.call(req), - routing: self.routing.clone(), - endpoint: None, - } - } -} + fn call(&self, mut 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() }; -pin_project_lite::pin_project! { - pub struct AppServiceResponse<'a, F: Service<&'a mut WebRequest>, Err: ErrorRenderer> { - #[pin] - filter: F::Future, - routing: Rc>, - endpoint: Option>, - } -} + let fut = self.filter.call(r1); + let router = self.router.clone(); -impl<'a, F, Err> Future for AppServiceResponse<'a, F, Err> -where - F: Service< - &'a mut WebRequest, - Response = &'a mut WebRequest, - Error = Err::Container, - >, - Err: ErrorRenderer, -{ - type Output = Result; + Box::pin(async move { + match fut.await { + Ok(res) => (), + Err(err) => return Ok(WebResponse::new(err.error_response(&req.req))), + } - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.as_mut().project(); + let res = router.router.recognize_checked(req, |req, guards| { + if let Some(guards) = guards { + for f in guards { + if !f.check(req.head()) { + return false; + } + } + } + true + }); - 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? + 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))), + } + } 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))), + } } else { - return Poll::Pending; - }; - *this.endpoint = Some(this.routing.call(res)); - self.poll(cx) - } + Ok(WebResponse::new(Response::NotFound().finish())) + } + }) } } diff --git a/ntex/src/web/boxed.rs b/ntex/src/web/boxed.rs index e2b98b70..32f2579b 100644 --- a/ntex/src/web/boxed.rs +++ b/ntex/src/web/boxed.rs @@ -13,7 +13,7 @@ pub type BoxFactoryFuture<'a, Err: ErrorRenderer> = pub type BoxService<'a, Err: ErrorRenderer> = Box< dyn Service< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, Future = BoxFuture<'a, Err>, @@ -27,21 +27,21 @@ pub fn factory<'a, T, Err>(factory: T) -> BoxServiceFactory<'a, Err> where Err: ErrorRenderer, T: ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, InitError = (), > + 'static, T::Future: 'static, T::Service: 'static, - >>::Future: 'a, + >>::Future: 'a, { BoxServiceFactory(FactoryWrapper::boxed(factory)) } type Inner<'a, Err: ErrorRenderer + 'static> = Box< dyn ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, InitError = (), @@ -50,7 +50,7 @@ type Inner<'a, Err: ErrorRenderer + 'static> = Box< > + 'static, >; -impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest> +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for BoxServiceFactory<'a, Err> { type Response = WebResponse; @@ -73,14 +73,14 @@ impl<'a, T, Err> FactoryWrapper where Err: ErrorRenderer + 'static, T: ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, InitError = (), > + 'static, T::Future: 'static, T::Service: 'static, - >>::Future: 'a, + >>::Future: 'a, { fn boxed(factory: T) -> Inner<'a, Err> { Box::new(Self { @@ -90,18 +90,18 @@ where } } -impl<'a, T, Err> ServiceFactory<&'a mut WebRequest> for FactoryWrapper +impl<'a, T, Err> ServiceFactory<&'a mut WebRequest<'a, Err>> for FactoryWrapper where Err: ErrorRenderer + 'static, T: ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, InitError = (), > + 'static, T::Future: 'static, T::Service: 'static, - >>::Future: 'a, + >>::Future: 'a, { type Response = WebResponse; type Error = Err::Container; @@ -123,7 +123,7 @@ struct ServiceWrapper(T, PhantomData); impl<'a, T, Err> ServiceWrapper where Err: ErrorRenderer, - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Err::Container> + T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> + 'static, T::Future: 'a, { @@ -132,10 +132,10 @@ where } } -impl<'a, T, Err> Service<&'a mut WebRequest> for ServiceWrapper +impl<'a, T, Err> Service<&'a mut WebRequest<'a, Err>> for ServiceWrapper where Err: ErrorRenderer, - T: Service<&'a mut WebRequest, Response = WebResponse, Error = Err::Container> + T: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> + 'static, T::Future: 'a, { @@ -154,7 +154,7 @@ where } #[inline] - fn call(&self, req: &'a mut WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { Box::pin(self.0.call(req)) } } diff --git a/ntex/src/web/config.rs b/ntex/src/web/config.rs index e52b9468..2957ae1e 100644 --- a/ntex/src/web/config.rs +++ b/ntex/src/web/config.rs @@ -4,7 +4,7 @@ use crate::router::ResourceDef; use super::resource::Resource; use super::route::Route; -use super::service::{AppServiceFactory, ServiceFactoryWrapper, WebServiceFactory}; +use super::service::{create_web_service, WebService, WebServiceWrapper}; use super::types::state::{State, StateFactory}; use super::{DefaultError, ErrorRenderer}; @@ -60,7 +60,7 @@ impl Default for AppConfig { /// to set of external methods. This could help with /// modularization of big application configuration. pub struct ServiceConfig<'a, Err = DefaultError> { - pub(super) services: Vec>>, + pub(super) services: Vec>>, pub(super) state: Vec>, pub(super) external: Vec, } @@ -100,10 +100,9 @@ impl<'a, Err: ErrorRenderer> ServiceConfig<'a, Err> { /// This is same as `App::service()` method. pub fn service(&mut self, factory: F) -> &mut Self where - F: WebServiceFactory<'a, Err> + 'static, + F: WebService<'a, Err> + 'static, { - self.services - .push(Box::new(ServiceFactoryWrapper::new(factory))); + self.services.push(create_web_service(factory)); self } @@ -136,7 +135,7 @@ mod tests { #[crate::rt_test] async fn test_configure_state() { - let cfg = |cfg: &mut ServiceConfig<_>| { + let cfg = |cfg: &mut ServiceConfig<'_, _>| { cfg.state(10usize); }; diff --git a/ntex/src/web/extract.rs b/ntex/src/web/extract.rs index d256bf84..0071952c 100644 --- a/ntex/src/web/extract.rs +++ b/ntex/src/web/extract.rs @@ -8,20 +8,20 @@ use crate::{http::Payload, util::Ready}; /// Trait implemented by types that can be extracted from request. /// /// Types that implement this trait can be used with `Route` handlers. -pub trait FromRequest: Sized { +pub trait FromRequest<'a, Err>: Sized { /// The associated error which can be returned. type Error; /// Future that resolves to a Self - type Future: Future>; + type Future: Future> + 'a; /// Convert request to a Self - fn from_request(req: &HttpRequest, payload: &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: &HttpRequest) -> Self::Future { + fn extract(req: &'a HttpRequest) -> Self::Future { Self::from_request(req, &mut Payload::None) } } @@ -71,18 +71,18 @@ pub trait FromRequest: Sized { /// ); /// } /// ``` -impl FromRequest for Option +impl<'a, T, Err> FromRequest<'a, Err> for Option where - T: FromRequest + 'static, + T: FromRequest<'a, Err> + 'static, T::Future: 'static, Err: ErrorRenderer, - >::Error: Into, + >::Error: Into, { type Error = Err::Container; - type Future = Pin, Self::Error>>>>; + type Future = Pin, Self::Error>> + '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 fut = T::from_request(req, payload); Box::pin(async move { match fut.await { @@ -139,18 +139,17 @@ where /// ); /// } /// ``` -impl FromRequest for Result +impl<'a, T, E> FromRequest<'a, E> for Result where - T: FromRequest + 'static, - T::Error: 'static, - T::Future: 'static, + T: FromRequest<'a, E> + 'static, E: ErrorRenderer, { type Error = T::Error; - type Future = Pin, Self::Error>>>>; + type Future = + Pin, Self::Error>> + '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 fut = T::from_request(req, payload); Box::pin(async move { match fut.await { @@ -162,7 +161,7 @@ where } #[doc(hidden)] -impl FromRequest for () { +impl<'a, E: ErrorRenderer> FromRequest<'a, E> for () { type Error = E::Container; type Future = Ready<(), E::Container>; @@ -175,14 +174,14 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => { /// FromRequest implementation for a tuple #[allow(unused_parens)] - impl + 'static),+> FromRequest for ($($T,)+) + impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err> + 'static),+> FromRequest<'a, Err> for ($($T,)+) where - $(<$T as $crate::web::FromRequest>::Error: Into),+ + $(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into),+ { type Error = Err::Container; - type Future = $fut_type; + type Future = $fut_type<'a, Err, $($T),+>; - fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { + fn from_request(req: &'a HttpRequest, payload: &'a mut Payload) -> Self::Future { $fut_type { items: <($(Option<$T>,)+)>::default(), $($T: $T::from_request(req, payload),)+ @@ -192,16 +191,16 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => { pin_project_lite::pin_project! { #[doc(hidden)] - pub struct $fut_type),+> + pub struct $fut_type<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> { items: ($(Option<$T>,)+), $(#[pin] $T: $T::Future),+ } } - impl),+> Future for $fut_type + impl<'a, Err: ErrorRenderer, $($T: FromRequest<'a, Err>),+> Future for $fut_type<'a, Err, $($T),+> where - $(<$T as $crate::web::FromRequest>::Error: Into),+ + $(<$T as $crate::web::FromRequest<'a, Err>>::Error: Into),+ { type Output = Result<($($T,)+), Err::Container>; diff --git a/ntex/src/web/handler.rs b/ntex/src/web/handler.rs index 76fff3a9..a990fcdd 100644 --- a/ntex/src/web/handler.rs +++ b/ntex/src/web/handler.rs @@ -38,7 +38,7 @@ where pub(super) trait HandlerFn { fn call<'b>( &self, - _: &'b mut WebRequest, + _: &'b mut WebRequest<'b, Err>, ) -> Pin> + 'b>>; fn clone_handler(&self) -> Box>; @@ -58,16 +58,16 @@ impl HandlerWrapper { } } -impl HandlerFn for HandlerWrapper +impl<'a, F, T, Err> HandlerFn for HandlerWrapper where F: Handler, - T: FromRequest + 'static, + T: FromRequest<'a, Err> + 'static, T::Error: Into, Err: ErrorRenderer, { fn call<'b>( &self, - req: &'b mut WebRequest, + req: &'b mut WebRequest<'b, Err>, ) -> Pin> + 'b>> { let mut pl = Rc::get_mut(&mut (req.req).0).unwrap().payload.take(); let hnd = self.hnd.clone(); diff --git a/ntex/src/web/httprequest.rs b/ntex/src/web/httprequest.rs index 92fbc6ad..df72da87 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, rc::Weak}; +use std::{cell::Ref, cell::RefCell, cell::RefMut, fmt, net, rc::Rc}; use crate::http::{ HeaderMap, HttpMessage, Message, Method, Payload, RequestHead, Uri, Version, @@ -17,8 +17,6 @@ use super::rmap::ResourceMap; /// An HTTP Request pub struct HttpRequest(pub(crate) Rc); -pub(super) struct WeakHttpRequest(pub(super) Weak); - pub(crate) struct HttpRequestInner { pub(crate) head: Message, pub(crate) path: Path, @@ -50,10 +48,6 @@ impl HttpRequest { pool, })) } - - pub(super) fn downgrade(&self) -> WeakHttpRequest { - WeakHttpRequest(Rc::downgrade(&self.0)) - } } impl HttpRequest { diff --git a/ntex/src/web/middleware/compress.rs b/ntex/src/web/middleware/compress.rs index a32d47b4..a8328f33 100644 --- a/ntex/src/web/middleware/compress.rs +++ b/ntex/src/web/middleware/compress.rs @@ -59,14 +59,14 @@ pub struct CompressMiddleware { encoding: ContentEncoding, } -impl Service> for CompressMiddleware +impl<'a, S, E> Service> for CompressMiddleware where S: Service, Response = WebResponse>, E: ErrorRenderer, { type Response = WebResponse; type Error = S::Error; - type Future = CompressResponse; + type Future = CompressResponse<'a, S, E>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { @@ -100,7 +100,7 @@ where pin_project_lite::pin_project! { #[doc(hidden)] - pub struct CompressResponse>, E> + pub struct CompressResponse<'a, S: Service>, E> { #[pin] fut: S::Future, @@ -109,7 +109,7 @@ pin_project_lite::pin_project! { } } -impl Future for CompressResponse +impl<'a, S, E> Future for CompressResponse<'a, S, E> where S: Service, Response = WebResponse>, E: ErrorRenderer, diff --git a/ntex/src/web/middleware/defaultheaders.rs b/ntex/src/web/middleware/defaultheaders.rs index 17dfc329..24713a4e 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}; +use crate::web::{WebRequest, WebResponse, ErrorRenderer}; /// `Middleware` for setting default response headers. /// @@ -102,14 +102,15 @@ pub struct DefaultHeadersMiddleware { inner: Rc, } -impl Service> for DefaultHeadersMiddleware +impl<'a, S, E> Service> for DefaultHeadersMiddleware where S: Service, Response = WebResponse, Error = Infallible>, S::Future: 'static, + E: ErrorRenderer, { type Response = WebResponse; type Error = Infallible; - type Future = Pin>>>; + type Future = Pin> + 'a>>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { diff --git a/ntex/src/web/middleware/logger.rs b/ntex/src/web/middleware/logger.rs index 12ccdf41..68ad59b3 100644 --- a/ntex/src/web/middleware/logger.rs +++ b/ntex/src/web/middleware/logger.rs @@ -130,13 +130,14 @@ pub struct LoggerMiddleware { service: S, } -impl Service> for LoggerMiddleware +impl<'a, S, E> Service> for LoggerMiddleware where S: Service, Response = WebResponse>, + E: 'static, { type Response = WebResponse; type Error = S::Error; - type Future = Either, S::Future>; + type Future = Either, S::Future>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { @@ -171,7 +172,7 @@ where pin_project_lite::pin_project! { #[doc(hidden)] - pub struct LoggerResponse>, E> + pub struct LoggerResponse<'a, S: Service>, E> { #[pin] fut: S::Future, @@ -181,7 +182,7 @@ pin_project_lite::pin_project! { } } -impl Future for LoggerResponse +impl<'a, S, E> Future for LoggerResponse<'a, S, E> where S: Service, Response = WebResponse>, { diff --git a/ntex/src/web/mod.rs b/ntex/src/web/mod.rs index 080277f4..56d7d08e 100644 --- a/ntex/src/web/mod.rs +++ b/ntex/src/web/mod.rs @@ -79,7 +79,7 @@ pub mod guard; mod handler; mod httprequest; mod info; -pub mod middleware; +//pub mod middleware; mod request; mod resource; mod responder; @@ -91,7 +91,7 @@ mod boxed; mod server; mod service; mod stack; -pub mod test; +//pub mod test; pub mod types; mod util; pub mod ws; @@ -125,7 +125,7 @@ pub use self::response::WebResponse; pub use self::route::Route; // pub use self::scope::Scope; pub use self::server::HttpServer; -pub use self::service::WebServiceFactory; +pub use self::service::{WebService, WebServiceConfig}; pub use self::util::*; pub mod dev { @@ -139,7 +139,7 @@ pub mod dev { pub use crate::web::info::ConnectionInfo; pub use crate::web::rmap::ResourceMap; pub use crate::web::route::IntoRoutes; - pub use crate::web::service::{WebServiceAdapter, WebServiceConfig, WebServiceFactory}; + pub use crate::web::service::{WebService, WebServiceAdapter, WebServiceConfig}; pub use crate::web::stack::Stack; pub(crate) fn insert_slash(mut patterns: Vec) -> Vec { @@ -151,55 +151,55 @@ pub mod dev { patterns } - // #[doc(hidden)] - // #[inline(always)] - // pub fn __assert_extractor<'a, Err, T>() - // where - // T: super::FromRequest<'a, Err>, - // Err: super::ErrorRenderer, - // >::Error: Into, - // { - // } + #[doc(hidden)] + #[inline(always)] + pub fn __assert_extractor<'a, Err, T>() + where + T: super::FromRequest<'a, Err>, + Err: super::ErrorRenderer, + >::Error: Into, + { + } - // #[doc(hidden)] - // #[inline(always)] - // pub fn __assert_handler( - // f: Fun, - // ) -> impl Handler<(), Err, Future = Fut, Output = Fut::Output> - // where - // Err: super::ErrorRenderer, - // Fun: Fn() -> Fut + Clone + 'static, - // Fut: std::future::Future + 'static, - // Fut::Output: super::Responder, - // { - // f - // } + #[doc(hidden)] + #[inline(always)] + pub fn __assert_handler( + f: Fun, + ) -> impl Handler<(), Err, Future = Fut, Output = Fut::Output> + where + Err: super::ErrorRenderer, + Fun: Fn() -> Fut + Clone + 'static, + Fut: std::future::Future + 'static, + Fut::Output: super::Responder, + { + f + } - // macro_rules! assert_handler ({ $name:ident, $($T:ident),+} => { - // #[doc(hidden)] - // #[inline(always)] - // pub fn $name<'a, Err, Fun, Fut, $($T,)+>( - // f: Fun, - // ) -> impl Handler<($($T,)+), Err, Future = Fut, Output = Fut::Output> - // where - // Err: $crate::web::ErrorRenderer, - // Fun: Fn($($T,)+) -> Fut + Clone + 'static, - // Fut: std::future::Future + 'static, - // Fut::Output: $crate::web::Responder, - // $($T: $crate::web::FromRequest<'a, Err>),+, - // { - // f - // } - // }); + macro_rules! assert_handler ({ $name:ident, $($T:ident),+} => { + #[doc(hidden)] + #[inline(always)] + pub fn $name<'a, Err, Fun, Fut, $($T,)+>( + f: Fun, + ) -> impl Handler<($($T,)+), Err, Future = Fut, Output = Fut::Output> + where + Err: $crate::web::ErrorRenderer, + Fun: Fn($($T,)+) -> Fut + Clone + 'static, + Fut: std::future::Future + 'static, + Fut::Output: $crate::web::Responder, + $($T: $crate::web::FromRequest<'a, Err>),+, + { + f + } + }); - // assert_handler!(__assert_handler1, A); - // assert_handler!(__assert_handler2, A, B); - // assert_handler!(__assert_handler3, A, B, C); - // assert_handler!(__assert_handler4, A, B, C, D); - // assert_handler!(__assert_handler5, A, B, C, D, E); - // assert_handler!(__assert_handler6, A, B, C, D, E, F); - // assert_handler!(__assert_handler7, A, B, C, D, E, F, G); - // assert_handler!(__assert_handler8, A, B, C, D, E, F, G, H); - // assert_handler!(__assert_handler9, A, B, C, D, E, F, G, H, I); - // assert_handler!(__assert_handler10, A, B, C, D, E, F, G, H, I, J); + assert_handler!(__assert_handler1, A); + assert_handler!(__assert_handler2, A, B); + assert_handler!(__assert_handler3, A, B, C); + assert_handler!(__assert_handler4, A, B, C, D); + assert_handler!(__assert_handler5, A, B, C, D, E); + assert_handler!(__assert_handler6, A, B, C, D, E, F); + assert_handler!(__assert_handler7, A, B, C, D, E, F, G); + assert_handler!(__assert_handler8, A, B, C, D, E, F, G, H); + assert_handler!(__assert_handler9, A, B, C, D, E, F, G, H, I); + assert_handler!(__assert_handler10, A, B, C, D, E, F, G, H, I, J); } diff --git a/ntex/src/web/request.rs b/ntex/src/web/request.rs index a96ff623..cea31dd2 100644 --- a/ntex/src/web/request.rs +++ b/ntex/src/web/request.rs @@ -9,7 +9,7 @@ use crate::util::Extensions; use super::config::AppConfig; use super::error::{ErrorRenderer, WebResponseError}; -use super::httprequest::{HttpRequest, WeakHttpRequest}; +use super::httprequest::HttpRequest; use super::info::ConnectionInfo; use super::response::WebResponse; use super::rmap::ResourceMap; @@ -17,12 +17,12 @@ use super::rmap::ResourceMap; /// An service http request /// /// WebRequest allows mutable access to request's internal structures -pub struct WebRequest { - pub(super) req: HttpRequest, - _t: PhantomData, +pub struct WebRequest<'a, Err> { + pub(super) req: &'a mut HttpRequest, + _marker: PhantomData &'a Err>, } -impl WebRequest { +impl<'a, Err: ErrorRenderer> WebRequest<'a, Err> { /// Create web response for error #[inline] pub fn render_error>(self, err: E) -> WebResponse { @@ -36,52 +36,48 @@ impl WebRequest { } } -impl WebRequest { +impl<'a, Err> WebRequest<'a, Err> { /// Construct web request - pub(crate) fn new(req: HttpRequest) -> Self { + pub(crate) fn new(req: &'a mut HttpRequest) -> Self { WebRequest { req, - _t: PhantomData, + _marker: PhantomData, } } - pub(super) fn weak_request(&self) -> WeakHttpRequest { - self.req.downgrade() - } + // /// 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) + // } - /// 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 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) - } - } + // /// 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] @@ -245,7 +241,7 @@ impl WebRequest { } } -impl Resource for WebRequest { +impl<'a, Err> Resource for WebRequest<'a, Err> { fn path(&self) -> &str { self.match_info().path() } @@ -255,7 +251,7 @@ impl Resource for WebRequest { } } -impl HttpMessage for WebRequest { +impl<'a, Err> HttpMessage for WebRequest<'a, Err> { #[inline] /// Returns Request's headers. fn message_headers(&self) -> &HeaderMap { @@ -275,7 +271,7 @@ impl HttpMessage for WebRequest { } } -impl fmt::Debug for WebRequest { +impl<'a, Err: ErrorRenderer> fmt::Debug for WebRequest<'a, Err> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!( f, diff --git a/ntex/src/web/resource.rs b/ntex/src/web/resource.rs index 15026559..6e8cf039 100644 --- a/ntex/src/web/resource.rs +++ b/ntex/src/web/resource.rs @@ -9,7 +9,7 @@ use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Tran use crate::util::{Either, Extensions, Ready}; use super::boxed::{self, BoxService, BoxServiceFactory}; -use super::dev::{insert_slash, WebServiceConfig, WebServiceFactory}; +use super::dev::{insert_slash, WebService, WebServiceConfig}; use super::extract::FromRequest; use super::route::{IntoRoutes, Route, RouteService}; use super::stack::{ @@ -39,9 +39,9 @@ use super::{guard::Guard, types::State, ErrorRenderer, Handler, WebRequest, WebR /// /// If no matching route could be found, *405* response code get returned. /// Default behavior could be overriden with `default_resource()` method. -pub struct Resource> { - middleware: M, +pub struct Resource { filter: F, + middleware: M, rdef: Vec, name: Option, routes: Vec>, @@ -56,8 +56,8 @@ impl<'a, Err: ErrorRenderer> Resource { routes: Vec::new(), rdef: path.patterns(), name: None, + filter: Filter, middleware: Identity, - filter: Filter::new(), guards: Vec::new(), state: None, default: Route::new().to(|| async { Response::MethodNotAllowed().finish() }), @@ -228,7 +228,7 @@ where /// Register request filter. /// /// This is similar to `App's` filters, but filter get invoked on resource level. - pub fn filter(self, filter: U) -> Resource> { + pub fn filter(self, filter: U) -> Resource> { Resource { filter: Filters::new(self.filter, filter), middleware: self.middleware, @@ -248,7 +248,7 @@ where /// type (i.e modify response's body). /// /// **Note**: middlewares get called in opposite order of middlewares registration. - pub fn wrap(self, mw: U) -> Resource, F> { + pub fn wrap(self, mw: U) -> Resource, F> { Resource { middleware: Stack::new(self.middleware, mw), filter: self.filter, @@ -275,22 +275,21 @@ where } } -impl<'a, Err, M, F> WebServiceFactory<'a, Err> for Resource +impl<'a, Err, M, F> WebService<'a, Err> for Resource where M: Transform< Next< ResourceService< - >>::Service, + >>::Service, Err, >, - Err, >, > + 'static, M::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, - F: FiltersFactory<'a, Err>, - >>::Service: 'static, - >>::Future: 'static, + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, Err: ErrorRenderer, { fn register(mut self, config: &mut WebServiceConfig<'a, Err>) { @@ -331,50 +330,41 @@ where } } -// impl<'a, Err, M, F> Resource -// where -// F: FiltersFactory<'a, Err>, -// M: Transform>>::Service, Err>, Err>> + 'static, -// M::Service: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, -// Err: ErrorRenderer, -// { -// pub fn finish(self) -> impl ServiceFactory<&'a mut WebRequest, Response = WebResponse, Error = Err::Container, InitError = ()> { -// let router_factory = ResourceRouterFactory { -// routes: self.routes, -// state: self.state.map(Rc::new), -// default: self.default, -// }; +impl<'a, Err, M, F> + IntoServiceFactory< + ResourceServiceFactory, + &'a mut WebRequest<'a, Err>, + > for Resource +where + M: Transform< + Next< + ResourceService< + >>::Service, + Err, + >, + >, + > + 'static, + M::Service: + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + F: FiltersFactory<'a, Err> + 'static, + >>::Service: 'static, + >>::Future: 'static, + Err: ErrorRenderer, +{ + fn into_factory(self) -> ResourceServiceFactory { + let router_factory = ResourceRouterFactory { + routes: self.routes, + state: self.state.map(Rc::new), + default: self.default, + }; -// ResourceServiceFactory::<'a, Err, _, _> { -// middleware: Rc::new(MiddlewareStack::new(self.middleware)), -// filter: self.filter.create(), -// routing: router_factory, -// } -// } -// } - -// impl<'a, Err, M, F> -// IntoServiceFactory, &'a mut WebRequest> for Resource -// where -// F: FiltersFactory<'a, Err>, -// M: Transform>>::Service, Err>, Err>> + 'static, -// M::Service: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, -// Err: ErrorRenderer, -// { -// fn into_factory(self) -> ResourceServiceFactory<'a, Err, M, F::Service> { -// let router_factory = ResourceRouterFactory { -// routes: self.routes, -// state: self.state.map(Rc::new), -// default: self.default, -// }; - -// ResourceServiceFactory { -// middleware: Rc::new(MiddlewareStack::new(self.middleware)), -// filter: self.filter.create(), -// routing: router_factory, -// } -// } -// } + ResourceServiceFactory { + middleware: Rc::new(MiddlewareStack::new(self.middleware)), + filter: self.filter.create(), + routing: router_factory, + } + } +} /// Resource service pub struct ResourceServiceFactory { @@ -383,15 +373,15 @@ pub struct ResourceServiceFactory { routing: ResourceRouterFactory, } -impl<'a, Err, M, F> ServiceFactory<&'a mut WebRequest> +impl<'a, Err, M, F> ServiceFactory<&'a mut WebRequest<'a, Err>> for ResourceServiceFactory where - M: Transform, Err>> + 'static, + M: Transform>> + 'static, M::Service: - Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, + Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, F: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), > + 'static, @@ -423,11 +413,11 @@ pub struct ResourceService { routing: Rc>, } -impl<'a, F, Err> Service<&'a mut WebRequest> for ResourceService +impl<'a, F, Err> Service<&'a mut WebRequest<'a, Err>> for ResourceService where F: Service< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, >, Err: ErrorRenderer, @@ -447,7 +437,7 @@ where } } - fn call(&self, req: &'a mut WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { ResourceServiceResponse { filter: self.filter.call(req), routing: self.routing.clone(), @@ -457,19 +447,19 @@ where } pin_project_lite::pin_project! { - pub struct ResourceServiceResponse<'a, F: Service<&'a mut WebRequest>, Err: ErrorRenderer> { + pub struct ResourceServiceResponse<'a, F: Service<&'a mut WebRequest<'a, Err>>, Err: ErrorRenderer> { #[pin] filter: F::Future, routing: Rc>, - endpoint: Option< as Service<&'a mut WebRequest>>::Future>, + endpoint: Option< as Service<&'a mut WebRequest<'a, Err>>>::Future>, } } impl<'a, F, Err> Future for ResourceServiceResponse<'a, F, Err> where F: Service< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, >, Err: ErrorRenderer, @@ -499,7 +489,7 @@ struct ResourceRouterFactory { default: Route, } -impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest> +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for ResourceRouterFactory { type Response = WebResponse; @@ -527,7 +517,7 @@ struct ResourceRouter { default: RouteService, } -impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for ResourceRouter { +impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ResourceRouter { type Response = WebResponse; type Error = Err::Container; type Future = Pin> + 'a>>; @@ -537,7 +527,7 @@ impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for ResourceRouter Poll::Ready(Ok(())) } - fn call(&self, mut req: &'a mut WebRequest) -> Self::Future { + fn call(&self, mut 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/response.rs b/ntex/src/web/response.rs index 7c88e5a1..6bf9e4b2 100644 --- a/ntex/src/web/response.rs +++ b/ntex/src/web/response.rs @@ -8,8 +8,7 @@ use super::httprequest::HttpRequest; /// An service http response pub struct WebResponse { - // request: HttpRequest, - response: Response, + pub(super) response: Response, } impl WebResponse { @@ -21,10 +20,10 @@ impl WebResponse { /// Create web response from the error pub fn from_err>( err: E, - request: HttpRequest, + request: &HttpRequest, ) -> Self { let err = err.into(); - let res: Response = err.error_response(&request); + let res: Response = err.error_response(request); if res.head().status == StatusCode::INTERNAL_SERVER_ERROR { log::error!("Internal Server Error: {:?}", err); @@ -37,29 +36,12 @@ impl WebResponse { } } - /// Create web response for error - #[inline] - pub fn error_response>( - self, - err: E, - ) -> Self { - // Self::from_err::(err) //, self.request) - todo!() - } - /// Create web response #[inline] pub fn into_response(self, response: Response) -> WebResponse { WebResponse::new(response) } - /// Get reference to original request - #[inline] - pub fn request(&self) -> &HttpRequest { - //&self.request - todo!() - } - /// Get reference to response #[inline] pub fn response(&self) -> &Response { @@ -90,21 +72,6 @@ impl WebResponse { self.response.headers_mut() } - /// Execute closure and in case of error convert it to response. - pub fn checked_expr(mut self, f: F) -> Self - where - F: FnOnce(&mut Self) -> Result<(), E>, - E: Into, - Err: ErrorRenderer, - { - if let Err(err) = f(&mut self) { - let res: Response = err.into().into(); - WebResponse::new(res) //, self.request) - } else { - self - } - } - /// Extract response body pub fn take_body(&mut self) -> ResponseBody { self.response.take_body() @@ -115,21 +82,22 @@ impl WebResponse { where F: FnOnce(&mut ResponseHead, ResponseBody) -> ResponseBody, { - let response = self.response.map_body(f); - WebResponse { - response, - // request: self.request, + response: self.response.map_body(f), } } } +impl From> for WebResponse { + #[inline] + fn from(response: Response) -> WebResponse { + WebResponse { response } + } +} + impl From for Response { - fn from(mut res: WebResponse) -> Response { - let head = res.response.head_mut(); - // if res.request.head().upgrade() { - // head.set_io(res.request.head()); - // } + #[inline] + fn from(res: WebResponse) -> Response { res.response } } diff --git a/ntex/src/web/route.rs b/ntex/src/web/route.rs index 57448827..b429c01a 100644 --- a/ntex/src/web/route.rs +++ b/ntex/src/web/route.rs @@ -46,7 +46,7 @@ impl<'a, Err: ErrorRenderer> Route { } } -impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest> for Route { +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Route { type Response = WebResponse; type Error = Err::Container; type InitError = (); @@ -65,7 +65,7 @@ pub struct RouteService { } impl RouteService { - pub fn check(&self, req: &mut WebRequest) -> bool { + pub fn check(&self, req: &'_ mut WebRequest<'_, Err>) -> bool { if !self.methods.is_empty() && !self.methods.contains(&req.head().method) { return false; } @@ -79,7 +79,7 @@ impl RouteService { } } -impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for RouteService { +impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for RouteService { type Response = WebResponse; type Error = Err::Container; type Future = Pin> + 'a>>; @@ -90,7 +90,7 @@ impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for RouteService) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { self.handler.call(req) } } @@ -181,7 +181,7 @@ impl Route { pub fn to(mut self, handler: F) -> Self where F: Handler, - Args: FromRequest + 'static, + Args: FromRequest<'a, Err> + 'static, Args::Error: Into, { self.handler = Box::new(HandlerWrapper::new(handler)); diff --git a/ntex/src/web/scope.rs b/ntex/src/web/scope.rs index a2ed5ec0..0f0d0b50 100644 --- a/ntex/src/web/scope.rs +++ b/ntex/src/web/scope.rs @@ -19,9 +19,9 @@ use super::{ErrorRenderer, Resource, Route, WebRequest, WebResponse}; type Guards = Vec>; type HttpService = - BoxService, WebResponse, Err::Container>; + BoxService<&'a mut WebRequest<'a, Err>, WebResponse, Err::Container>; type HttpNewService = - BoxServiceFactory<(), WebRequest, WebResponse, Err::Container, ()>; + BoxServiceFactory<(), &'a mut WebRequest<'a, Err>, WebResponse, Err::Container, ()>; type BoxResponse = Pin>>>; @@ -56,7 +56,7 @@ type BoxResponse = /// pub struct Scope> { middleware: M, - filter: PipelineFactory>, + filter: PipelineFactory>, rdef: Vec, state: Option, services: Vec>>, @@ -86,8 +86,8 @@ impl Scope { impl Scope where T: ServiceFactory< - WebRequest, - Response = WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), >, @@ -286,8 +286,8 @@ where /// If default resource is not registered, app's default resource is being used. pub fn default_service(mut self, f: F) -> Self where - F: IntoServiceFactory>, - S: ServiceFactory, Response = WebResponse, Error = Err::Container> + F: IntoServiceFactory>, + S: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> + 'static, S::InitError: fmt::Debug, { @@ -314,20 +314,20 @@ where Err, M, impl ServiceFactory< - WebRequest, - Response = WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), >, > where U: ServiceFactory< - WebRequest, - Response = WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), >, - F: IntoServiceFactory>, + F: IntoServiceFactory>, { Scope { filter: self.filter.and_then(filter.into_factory()), @@ -370,13 +370,13 @@ where impl WebServiceFactory for Scope where T: ServiceFactory< - WebRequest, - Response = WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), > + 'static, M: Transform, Err>> + 'static, - M::Service: Service, Response = WebResponse, Error = Infallible>, + M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, Err: ErrorRenderer, { fn register(mut self, config: &mut WebServiceConfig) { @@ -456,13 +456,13 @@ struct ScopeServiceFactory { routing: ScopeRouterFactory, } -impl ServiceFactory> for ScopeServiceFactory +impl ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeServiceFactory where M: Transform, Err>> + 'static, - M::Service: Service, Response = WebResponse, Error = Infallible>, + M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, F: ServiceFactory< - WebRequest, - Response = WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), > + 'static, @@ -492,9 +492,9 @@ pub struct ScopeService { routing: Rc>, } -impl Service> for ScopeService +impl Service<&'a mut WebRequest<'a, Err>> for ScopeService where - F: Service, Response = WebRequest, Error = Err::Container>, + F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>, Err: ErrorRenderer, { type Response = WebResponse; @@ -512,7 +512,7 @@ where } } - fn call(&self, req: WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { ScopeServiceResponse { filter: self.filter.call(req), routing: self.routing.clone(), @@ -522,17 +522,17 @@ where } pin_project_lite::pin_project! { - pub struct ScopeServiceResponse>, Err: ErrorRenderer> { + pub struct ScopeServiceResponse>, Err: ErrorRenderer> { #[pin] filter: F::Future, routing: Rc>, - endpoint: Option< as Service>>::Future>, + endpoint: Option< as Service<&'a mut WebRequest<'a, Err>>>::Future>, } } impl Future for ScopeServiceResponse where - F: Service, Response = WebRequest, Error = Err::Container>, + F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>, Err: ErrorRenderer, { type Output = Result; @@ -561,7 +561,7 @@ struct ScopeRouterFactory { case_insensitive: bool, } -impl ServiceFactory> for ScopeRouterFactory { +impl ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeRouterFactory { type Response = WebResponse; type Error = Err::Container; type InitError = (); @@ -610,7 +610,7 @@ struct ScopeRouter { default: Option>, } -impl Service> for ScopeRouter { +impl Service<&'a mut WebRequest<'a, Err>> for ScopeRouter { type Response = WebResponse; type Error = Err::Container; type Future = Either, Ready>; @@ -620,7 +620,7 @@ impl Service> for ScopeRouter { Poll::Ready(Ok(())) } - fn call(&self, mut req: WebRequest) -> Self::Future { + fn call(&self, mut req: &'a mut WebRequest<'a, Err>) -> Self::Future { let res = self.router.recognize_checked(&mut req, |req, guards| { if let Some(guards) = guards { for f in guards { diff --git a/ntex/src/web/service.rs b/ntex/src/web/service.rs index 4ac034d4..1eafd90f 100644 --- a/ntex/src/web/service.rs +++ b/ntex/src/web/service.rs @@ -1,7 +1,8 @@ -use std::{marker::PhantomData, rc::Rc}; +use std::task::{Context, Poll}; +use std::{convert::Infallible, future::Future, marker::PhantomData, pin::Pin, rc::Rc}; use crate::router::{IntoPattern, ResourceDef}; -use crate::service::{IntoServiceFactory, ServiceFactory}; +use crate::service::{IntoServiceFactory, Service, ServiceFactory}; use crate::util::Extensions; use super::boxed::{self, BoxServiceFactory}; @@ -11,33 +12,31 @@ use super::rmap::ResourceMap; use super::types::state::StateFactory; use super::{guard::Guard, ErrorRenderer, WebRequest, WebResponse}; -pub trait WebServiceFactory<'a, Err: ErrorRenderer> { +pub trait WebService<'a, Err: ErrorRenderer>: 'static { fn register(self, config: &mut WebServiceConfig<'a, Err>); } -pub(super) trait AppServiceFactory<'a, Err: ErrorRenderer> { +pub(super) trait WebServiceWrapper<'a, Err: ErrorRenderer> { fn register(&mut self, config: &mut WebServiceConfig<'a, Err>); } -pub(super) struct ServiceFactoryWrapper { - factory: Option, -} - -impl ServiceFactoryWrapper { - pub(super) fn new(factory: T) -> Self { - Self { - factory: Some(factory), - } - } -} - -impl<'a, T, Err> AppServiceFactory<'a, Err> for ServiceFactoryWrapper +pub(super) fn create_web_service<'a, T, Err>(svc: T) -> Box> where + T: WebService<'a, Err> + 'static, + Err: ErrorRenderer, +{ + Box::new(WebServiceWrapperInner(Some(svc))) +} + +struct WebServiceWrapperInner(Option); + +impl<'a, T, Err> WebServiceWrapper<'a, Err> for WebServiceWrapperInner +where + T: WebService<'a, Err> + 'static, Err: ErrorRenderer, - T: WebServiceFactory<'a, Err>, { fn register(&mut self, config: &mut WebServiceConfig<'a, Err>) { - if let Some(item) = self.factory.take() { + if let Some(item) = self.0.take() { item.register(config) } } @@ -131,7 +130,7 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { nested: Option>, ) where S: ServiceFactory< - &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container, InitError = (), @@ -209,9 +208,9 @@ impl WebServiceAdapter { // /// 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>, + // F: IntoServiceFactory>, // T: ServiceFactory< - // &'a mut WebRequest, + // &'a mut WebRequest<'a, Err>, // Response = WebResponse, // Error = Err::Container, // InitError = (), @@ -228,62 +227,62 @@ impl WebServiceAdapter { // } } -struct WebServiceImpl { - srv: T, - rdef: Vec, - name: Option, - guards: Vec>, -} +// struct WebServiceImpl { +// srv: T, +// rdef: Vec, +// name: Option, +// guards: Vec>, +// } -impl<'a, T, Err> WebServiceFactory<'a, Err> for WebServiceImpl -where - T: ServiceFactory< - &'a mut WebRequest, - 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)) - }; +// 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)] -impl<'a, Err, T> WebServiceFactory<'a, Err> for Vec -where - Err: ErrorRenderer, - T: WebServiceFactory<'a, Err> + 'static, -{ - fn register(mut self, config: &mut WebServiceConfig<'a, Err>) { - for service in self.drain(..) { - service.register(config); - } - } -} +// /// WebServiceFactory implementation for a Vec +// #[allow(unused_parens)] +// impl<'a, Err, T> WebServiceFactory<'a, Err> for Vec +// where +// Err: ErrorRenderer, +// T: WebServiceFactory<'a, Err> + 'static, +// { +// fn register(mut self, config: &mut WebServiceConfig<'a, Err>) { +// for service in self.drain(..) { +// service.register(config); +// } +// } +// } macro_rules! tuple_web_service({$(($n:tt, $T:ident)),+} => { /// WebServiceFactory implementation for a tuple #[allow(unused_parens)] - impl<'a, Err: ErrorRenderer, $($T: WebServiceFactory<'a, Err> + 'static),+> WebServiceFactory<'a, Err> for ($($T,)+) { + impl<'a, Err: ErrorRenderer, $($T: WebService<'a, Err> + 'static),+> WebService<'a, Err> for ($($T,)+) { fn register(self, config: &mut WebServiceConfig<'a, Err>) { $( self.$n.register(config); @@ -295,10 +294,10 @@ macro_rules! tuple_web_service({$(($n:tt, $T:ident)),+} => { macro_rules! array_web_service({$num:tt, $($T:ident),+} => { /// WebServiceFactory implementation for an array #[allow(unused_parens)] - impl<'a, Err, T> WebServiceFactory<'a, Err> for [T; $num] + impl<'a, Err, T> WebService<'a, Err> for [T; $num] where Err: ErrorRenderer, - T: WebServiceFactory<'a, Err> + 'static, + T: WebService<'a, Err> + 'static, { fn register(self, config: &mut WebServiceConfig<'a, Err>) { let [$($T,)+] = self; @@ -315,45 +314,45 @@ macro_rules! array_web_service({$num:tt, $($T:ident),+} => { mod m { use super::*; -array_web_service!(1,A); -array_web_service!(2,A,B); -array_web_service!(3,A,B,C); -array_web_service!(4,A,B,C,D); -array_web_service!(5,A,B,C,D,E); -array_web_service!(6,A,B,C,D,E,F); -array_web_service!(7,A,B,C,D,E,F,G); -array_web_service!(8,A,B,C,D,E,F,G,H); -array_web_service!(9,A,B,C,D,E,F,G,H,I); -array_web_service!(10,A,B,C,D,E,F,G,H,I,J); -array_web_service!(11,A,B,C,D,E,F,G,H,I,J,K); -array_web_service!(12,A,B,C,D,E,F,G,H,I,J,K,L); -array_web_service!(13,A,B,C,D,E,F,G,H,I,J,K,L,M); -array_web_service!(14,A,B,C,D,E,F,G,H,I,J,K,L,M,N); -array_web_service!(15,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O); -array_web_service!(16,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P); + array_web_service!(1,A); + array_web_service!(2,A,B); + array_web_service!(3,A,B,C); + array_web_service!(4,A,B,C,D); + array_web_service!(5,A,B,C,D,E); + array_web_service!(6,A,B,C,D,E,F); + array_web_service!(7,A,B,C,D,E,F,G); + array_web_service!(8,A,B,C,D,E,F,G,H); + array_web_service!(9,A,B,C,D,E,F,G,H,I); + array_web_service!(10,A,B,C,D,E,F,G,H,I,J); + array_web_service!(11,A,B,C,D,E,F,G,H,I,J,K); + array_web_service!(12,A,B,C,D,E,F,G,H,I,J,K,L); + array_web_service!(13,A,B,C,D,E,F,G,H,I,J,K,L,M); + array_web_service!(14,A,B,C,D,E,F,G,H,I,J,K,L,M,N); + array_web_service!(15,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O); + array_web_service!(16,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P); -tuple_web_service!((0,A)); -tuple_web_service!((0,A),(1,B)); -tuple_web_service!((0,A),(1,B),(2,C)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T),(20,V)); -tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T),(20,V),(21,X)); + tuple_web_service!((0,A)); + tuple_web_service!((0,A),(1,B)); + tuple_web_service!((0,A),(1,B),(2,C)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T),(20,V)); + tuple_web_service!((0,A),(1,B),(2,C),(3,D),(4,E),(5,F),(6,G),(7,H),(8,I),(9,J),(10,K),(11,L),(12,M),(13,N),(14,O),(15,P),(16,Q),(17,R),(18,S),(19,T),(20,V),(21,X)); } #[cfg(test)] diff --git a/ntex/src/web/stack.rs b/ntex/src/web/stack.rs index 91c8c1e1..8d63b792 100644 --- a/ntex/src/web/stack.rs +++ b/ntex/src/web/stack.rs @@ -9,32 +9,24 @@ use crate::service::{ }; use crate::util::{ready, Ready}; -use super::httprequest::{HttpRequest, WeakHttpRequest}; +use super::httprequest::HttpRequest; use super::{ErrorContainer, ErrorRenderer, WebRequest, WebResponse}; -pub struct Stack { +pub struct Stack { inner: Inner, outer: Outer, - _t: PhantomData, } -impl Stack { +impl Stack { pub(super) fn new(inner: Inner, outer: Outer) -> Self { - Stack { - inner, - outer, - _t: PhantomData, - } + Stack { inner, outer } } } -impl Transform for Stack +impl Transform for Stack where - Err: ErrorRenderer, Inner: Transform, - Inner::Service: Service, Response = WebResponse>, - >>::Error: Into, - Outer: Transform>, + Outer: Transform>, { type Service = Outer::Service; @@ -77,9 +69,9 @@ pub struct Middleware { _t: PhantomData, } -impl<'a, S, Err> Service<&'a mut WebRequest> for Middleware +impl<'a, S, Err> Service<&'a mut WebRequest<'a, Err>> for Middleware where - S: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, + S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, Err: ErrorRenderer, { type Response = WebResponse; @@ -93,7 +85,7 @@ where } #[inline] - fn call(&self, req: &'a mut WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { MiddlewareResponse { fut: self.md.call(req), } @@ -101,7 +93,7 @@ where } pin_project_lite::pin_project! { - pub struct MiddlewareResponse<'a, S: Service<&'a mut WebRequest>, Err> { + pub struct MiddlewareResponse<'a, S: Service<&'a mut WebRequest<'a, Err>>, Err> { #[pin] fut: S::Future, } @@ -109,7 +101,7 @@ pin_project_lite::pin_project! { impl<'a, S, Err> Future for MiddlewareResponse<'a, S, Err> where - S: Service<&'a mut WebRequest, Response = WebResponse, Error = Infallible>, + S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, Err: ErrorRenderer, { type Output = Result; @@ -119,23 +111,19 @@ where } } -pub struct Next { - inner: Rc, - _t: PhantomData, +pub struct Next { + next: S, } -impl Next { - pub(super) fn new(inner: S) -> Self { - Next { - inner: Rc::new(inner), - _t: PhantomData, - } +impl Next { + pub(super) fn new(next: S) -> Self { + Next { next } } } -impl<'a, S, Err> Service<&'a mut WebRequest> for Next +impl<'a, S, Err> Service<&'a mut WebRequest<'a, Err>> for Next where - S: Service<&'a mut WebRequest, Response = WebResponse> + 'static, + S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, S::Error: Into + 'static, S::Future: 'a, Err: ErrorRenderer, @@ -146,16 +134,17 @@ where #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { - let _ = ready!(self.inner.poll_ready(cx)); + let _ = ready!(self.next.poll_ready(cx)); Poll::Ready(Ok(())) } #[inline] - fn call(&self, req: &'a mut WebRequest) -> Self::Future { - let next = self.inner.clone(); + 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 { - let result = next.call(req).await; - match result { + match fut.await { Ok(res) => Ok(res), Err(err) => Ok(WebResponse::new(err.into().error_response(&req.req))), } @@ -164,16 +153,16 @@ where } pin_project_lite::pin_project! { - pub struct NextResponse<'a, S: Service<&'a mut WebRequest>, Err> { + pub struct NextResponse<'a, S: Service<&'a mut WebRequest<'a, Err>>, Err> { #[pin] fut: S::Future, - req: &'a mut WebRequest, + req: &'a mut WebRequest<'a, Err>, } } impl<'a, S, Err> Future for NextResponse<'a, S, Err> where - S: Service<&'a mut WebRequest, Response = WebResponse>, + S: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse>, S::Error: Into, Err: ErrorRenderer, { @@ -191,37 +180,31 @@ where } } -pub struct Filter(PhantomData); +pub struct Filter; -impl Filter { - pub(super) fn new() -> Self { - Filter(PhantomData) - } -} - -impl<'a, Err: ErrorRenderer> FiltersFactory<'a, Err> for Filter { - type Service = Filter; +impl<'a, Err: ErrorRenderer> FiltersFactory<'a, Err> for Filter { + type Service = Filter; fn create(self) -> Self::Service { self } } -impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest> for Filter { - type Response = &'a mut WebRequest; +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> for Filter { + type Response = &'a mut WebRequest<'a, Err>; type Error = Err::Container; type InitError = (); - type Service = Filter; - type Future = Ready, ()>; + type Service = Filter; + type Future = Ready; #[inline] fn new_service(&self, _: ()) -> Self::Future { - Ready::Ok(Filter(PhantomData)) + Ready::Ok(Filter) } } -impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for Filter { - type Response = &'a mut WebRequest; +impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for Filter { + type Response = &'a mut WebRequest<'a, Err>; type Error = Err::Container; type Future = Ready; @@ -231,33 +214,28 @@ impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest> for Filter { } #[inline] - fn call(&self, req: &'a mut WebRequest) -> Self::Future { + fn call(&self, req: &'a mut WebRequest<'a, Err>) -> Self::Future { Ready::Ok(req) } } -pub struct Filters { +pub struct Filters { first: First, second: Second, - _t: PhantomData, } -impl Filters { +impl Filters { pub(super) fn new(first: First, second: Second) -> Self { - Filters { - first, - second, - _t: PhantomData, - } + Filters { first, second } } } -impl<'a, First, Second, Err> FiltersFactory<'a, Err> for Filters +impl<'a, First, Second, Err> FiltersFactory<'a, Err> for Filters where Err: ErrorRenderer, First: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), > + 'static, @@ -265,13 +243,13 @@ where First::Future: 'static, Second: FiltersFactory<'a, Err>, Second::Service: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), >, - >>::Service: 'static, - >>::Future: 'static, + >>::Service: 'static, + >>::Future: 'static, { type Service = AndThenFactory; @@ -282,8 +260,8 @@ where pub trait FiltersFactory<'a, Err: ErrorRenderer> { type Service: ServiceFactory< - &'a mut WebRequest, - Response = &'a mut WebRequest, + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, Error = Err::Container, InitError = (), > + 'static; diff --git a/ntex/src/web/test.rs b/ntex/src/web/test.rs index c8438617..e2465582 100644 --- a/ntex/src/web/test.rs +++ b/ntex/src/web/test.rs @@ -31,7 +31,7 @@ use crate::web::{FromRequest, HttpResponse, Responder, WebRequest, WebResponse}; /// Create service that always responds with `HttpResponse::Ok()` pub fn ok_service( -) -> impl Service, Response = WebResponse, Error = std::convert::Infallible> +) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> { default_service::(StatusCode::OK) } @@ -39,9 +39,9 @@ pub fn ok_service( /// Create service that responds with response with specified status code pub fn default_service( status_code: StatusCode, -) -> impl Service, Response = WebResponse, Error = std::convert::Infallible> +) -> impl Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = std::convert::Infallible> { - (move |req: WebRequest| { + (move |req: &'a mut WebRequest<'a, Err>| { Ready::Ok(req.into_response(HttpResponse::build(status_code).finish())) }) .into_service() @@ -248,13 +248,13 @@ where .unwrap_or_else(|_| panic!("read_response_json failed during deserialization")) } -// /// Helper method for extractors testing -// pub async fn from_request<'a, T: FromRequest<'a, DefaultError>>( -// req: &'a HttpRequest, -// payload: &'a mut Payload, -// ) -> Result { -// T::from_request(req, payload).await -// } +/// Helper method for extractors testing +pub async fn from_request>( + req: &HttpRequest, + payload: &mut Payload, +) -> Result { + T::from_request(req, payload).await +} /// Helper method for responders testing pub async fn respond_to>(