From 6d454a36eb226d8836c7ba0be615483747c1db28 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 9 Feb 2022 18:10:43 +0600 Subject: [PATCH] fixes --- ntex/src/web/app.rs | 4 +- ntex/src/web/app_service.rs | 42 +--- ntex/src/web/error.rs | 40 +++- ntex/src/web/mod.rs | 2 +- ntex/src/web/scope.rs | 434 ++++++++++++++++++++---------------- ntex/src/web/service.rs | 55 ++++- ntex/src/web/stack.rs | 37 ++- 7 files changed, 358 insertions(+), 256 deletions(-) diff --git a/ntex/src/web/app.rs b/ntex/src/web/app.rs index ebbe4ca7..26bb7f70 100644 --- a/ntex/src/web/app.rs +++ b/ntex/src/web/app.rs @@ -6,11 +6,11 @@ use crate::service::map_config; use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform}; use crate::util::Extensions; -use super::app_service::{AppFactory, AppFactoryInner, AppRouting, DefaultService}; +use super::app_service::{AppFactory, AppFactoryInner, AppRouting}; use super::boxed::{self, BoxServiceFactory}; use super::config::{AppConfig, ServiceConfig}; use super::error::Error; -use super::service::{create_web_service, WebService, WebServiceWrapper}; +use super::service::{create_web_service, DefaultService, WebService, WebServiceWrapper}; use super::stack::{Filter, Filters, FiltersFactory, Next, Stack}; use super::types::state::{State, StateFactory}; use super::{DefaultError, ErrorRenderer, Resource, Route, WebRequest, WebResponse}; diff --git a/ntex/src/web/app_service.rs b/ntex/src/web/app_service.rs index dbb65233..936353d7 100644 --- a/ntex/src/web/app_service.rs +++ b/ntex/src/web/app_service.rs @@ -1,11 +1,10 @@ -use std::convert::Infallible; use std::task::{Context, Poll}; -use std::{cell::RefCell, future::Future, marker::PhantomData, pin::Pin, rc::Rc}; +use std::{cell::RefCell, convert::Infallible, future::Future, pin::Pin, rc::Rc}; use crate::http::{Request, Response}; use crate::router::{Path, ResourceDef, Router}; use crate::service::{Service, ServiceFactory, Transform}; -use crate::util::{ready, Either, Extensions, Ready}; +use crate::util::{ready, Either, Extensions}; use super::boxed::{BoxService, BoxServiceFactory}; use super::httprequest::{HttpRequest, HttpRequestPool}; @@ -135,43 +134,6 @@ where 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 = Infallible; - type InitError = (); - type Service = Self; - type Future = Ready; - - fn new_service(&self, _: ()) -> Self::Future { - Ready::Ok(DefaultService(PhantomData)) - } -} - -impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService { - type Response = WebResponse; - type Error = Infallible; - 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< diff --git a/ntex/src/web/error.rs b/ntex/src/web/error.rs index 7251cef5..e1afb030 100644 --- a/ntex/src/web/error.rs +++ b/ntex/src/web/error.rs @@ -17,10 +17,33 @@ use crate::util::{BytesMut, Either}; pub use super::error_default::DefaultError; pub use crate::http::error::BlockingError; -pub trait ErrorRenderer: Sized + 'static {} +pub trait ErrorRenderer: Sized + 'static { + #[inline] + /// Generate response for error + /// + /// Internal server error is generated by default. + fn error_response( + err: E, + _: &HttpRequest, + st: StatusCode, + ) -> HttpResponse { + let mut resp = HttpResponse::new(st); + let mut buf = BytesMut::new(); + let _ = write!(Writer(&mut buf), "{}", err); + resp.headers_mut().insert( + header::CONTENT_TYPE, + header::HeaderValue::from_static("text/plain; charset=utf-8"), + ); + resp.set_body(Body::from(buf)) + } +} /// Error that can be rendered to a `Response` -pub trait Error: fmt::Display + fmt::Debug + Sized { +pub trait Error: fmt::Display + fmt::Debug + Sized +where + Err: ErrorRenderer, +{ + #[inline] /// Response's status code /// /// Internal server error is generated by default. @@ -28,18 +51,13 @@ pub trait Error: fmt::Display + fmt::Debug + Sized { StatusCode::INTERNAL_SERVER_ERROR } + #[inline] /// Generate response for error /// /// Internal server error is generated by default. - fn error_response(self, _: &HttpRequest) -> HttpResponse { - let mut resp = HttpResponse::new(self.status_code()); - let mut buf = BytesMut::new(); - let _ = write!(Writer(&mut buf), "{}", self); - resp.headers_mut().insert( - header::CONTENT_TYPE, - header::HeaderValue::from_static("text/plain; charset=utf-8"), - ); - resp.set_body(Body::from(buf)) + fn error_response(self, req: &HttpRequest) -> HttpResponse { + let st = self.status_code(); + ::error_response(self, req, st) } } diff --git a/ntex/src/web/mod.rs b/ntex/src/web/mod.rs index 24f90001..e34e9adf 100644 --- a/ntex/src/web/mod.rs +++ b/ntex/src/web/mod.rs @@ -64,6 +64,7 @@ mod app; mod app_service; +mod boxed; mod config; pub mod error; mod error_default; @@ -80,7 +81,6 @@ mod response; mod rmap; mod route; // mod scope; -mod boxed; mod server; mod service; mod stack; diff --git a/ntex/src/web/scope.rs b/ntex/src/web/scope.rs index 0f0d0b50..5f6fc885 100644 --- a/ntex/src/web/scope.rs +++ b/ntex/src/web/scope.rs @@ -1,29 +1,26 @@ -use std::task::{Context, Poll}; -use std::{cell::RefCell, fmt, future::Future, convert::Infallible, pin::Pin, rc::Rc}; +use std::{ + cell::RefCell, fmt, future::Future, pin::Pin, rc::Rc, task::Context, task::Poll, +}; +use std::{convert::Infallible, marker::PhantomData}; -use crate::http::Response; use crate::router::{IntoPattern, ResourceDef, Router}; -use crate::service::boxed::{self, BoxService, BoxServiceFactory}; -use crate::service::{pipeline_factory, PipelineFactory}; use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform}; -use crate::util::{Either, Extensions, Ready}; +use crate::util::{ready, Extensions}; -use super::config::ServiceConfig; -use super::dev::{WebServiceConfig, WebServiceFactory}; +use super::boxed::{self, BoxService, BoxServiceFactory}; +use super::config::{AppConfig, ServiceConfig}; +use super::error::Error; use super::guard::Guard; use super::rmap::ResourceMap; -use super::service::{AppServiceFactory, ServiceFactoryWrapper}; -use super::stack::{Filter, Next, Stack, MiddlewareStack, Middleware}; +use super::service::{WebService, WebServiceConfig, DefaultService}; +use super::stack::{ + Filter, Filters, FiltersFactory, Middleware, MiddlewareStack, Next, Services, + ServicesFactory, Stack, +}; use super::types::State; use super::{ErrorRenderer, Resource, Route, WebRequest, WebResponse}; type Guards = Vec>; -type HttpService = - BoxService<&'a mut WebRequest<'a, Err>, WebResponse, Err::Container>; -type HttpNewService = - BoxServiceFactory<(), &'a mut WebRequest<'a, Err>, WebResponse, Err::Container, ()>; -type BoxResponse = - Pin>>>; /// Resources scope. /// @@ -54,43 +51,39 @@ type BoxResponse = /// * /{project_id}/path2 - `GET` requests /// * /{project_id}/path3 - `HEAD` requests /// -pub struct Scope> { +pub struct Scope { + service: S, + filter: F, middleware: M, - filter: PipelineFactory>, rdef: Vec, state: Option, - services: Vec>>, + // default: BoxServiceFactory<'a, Err>, guards: Vec>, - default: Rc>>>>, external: Vec, case_insensitive: bool, + _marker: PhantomData, } impl Scope { /// Create a new scope pub fn new(path: T) -> Scope { Scope { + service: Identity, + filter: Filter, middleware: Identity, - filter: pipeline_factory(Filter::new()), rdef: path.patterns(), state: None, guards: Vec::new(), - services: Vec::new(), - default: Rc::new(RefCell::new(None)), + // default: boxed::factory(DefaultService::default()), external: Vec::new(), case_insensitive: false, + _marker: PhantomData, } } } -impl Scope +impl Scope where - T: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, - InitError = (), - >, Err: ErrorRenderer, { /// Add match guard to a scope. @@ -195,24 +188,24 @@ where /// .route("/index.html", web::get().to(|| async { HttpResponse::Ok() })); /// } /// ``` - pub fn configure(mut self, f: F) -> Self + pub fn configure<'a, U>(mut self, f: U) -> Self where - F: FnOnce(&mut ServiceConfig), + U: FnOnce(&mut ServiceConfig<'a, Err>), { - let mut cfg = ServiceConfig::new(); - f(&mut cfg); - self.services.extend(cfg.services); - self.external.extend(cfg.external); + //let mut cfg = ServiceConfig::new(); + //f(&mut cfg); + //self.services.extend(cfg.services); + //self.external.extend(cfg.external); - if !cfg.state.is_empty() { - let mut state = self.state.unwrap_or_else(Extensions::new); + // if !cfg.state.is_empty() { + // let mut state = self.state.unwrap_or_else(Extensions::new); - for value in cfg.state.iter() { - value.create(&mut state); - } + // for value in cfg.state.iter() { + // value.create(&mut state); + // } - self.state = Some(state); - } + // self.state = Some(state); + // } self } @@ -243,13 +236,19 @@ where /// ); /// } /// ``` - pub fn service(mut self, factory: F) -> Self - where - F: WebServiceFactory + 'static, - { - self.services - .push(Box::new(ServiceFactoryWrapper::new(factory))); - self + pub fn service(self, factory: U) -> Scope>, M, F> { + Scope { + service: Services::new(self.service, Next::new(factory)), + filter: self.filter, + middleware: self.middleware, + rdef: self.rdef, + state: self.state, + guards: self.guards, + // default: self.default, + external: self.external, + case_insensitive: self.case_insensitive, + _marker: PhantomData, + } } /// Configure route for a specific path. @@ -273,7 +272,11 @@ where /// ); /// } /// ``` - pub fn route(self, path: &str, mut route: Route) -> Self { + pub fn route( + self, + path: &str, + mut route: Route, + ) -> Scope>>, M, F> { self.service( Resource::new(path) .add_guards(route.take_guards()) @@ -284,18 +287,20 @@ where /// Default service to be used if no matching route could be found. /// /// If default resource is not registered, app's default resource is being used. - pub fn default_service(mut self, f: F) -> Self + pub fn default<'a, T, U>(mut self, f: T) -> Self where - F: IntoServiceFactory>, - S: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Err::Container> - + 'static, - S::InitError: fmt::Debug, + T: IntoServiceFactory>, + U: ServiceFactory<&'a mut WebRequest<'a, Err>, Response = WebResponse> + 'static, + U::Service: 'static, + U::Future: 'static, + U::Error: Error, + U::InitError: fmt::Debug + 'static, { // create and configure default resource - self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory( - f.into_factory() - .map_init_err(|e| log::error!("Cannot construct default service: {:?}", e)), - ))))); + //self.default = + // boxed::factory(f.into_factory().map_init_err(|e| { + // log::error!("Cannot construct default service: {:?}", e) + // })); self } @@ -307,38 +312,18 @@ where /// necessary, across all requests managed by the *Scope*. /// /// This is similar to `App's` filters, but filter get invoked on scope level. - pub fn filter( - self, - filter: F, - ) -> Scope< - Err, - M, - impl ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, - InitError = (), - >, - > - where - U: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, - InitError = (), - >, - F: IntoServiceFactory>, - { + pub fn filter(self, filter: U) -> Scope>> { Scope { - filter: self.filter.and_then(filter.into_factory()), + filter: Filters::new(self.filter, Next::new(filter)), + service: self.service, middleware: self.middleware, rdef: self.rdef, state: self.state, guards: self.guards, - services: self.services, - default: self.default, + // default: self.default, external: self.external, case_insensitive: self.case_insensitive, + _marker: PhantomData, } } @@ -352,46 +337,53 @@ where /// WebResponse. /// /// Use middleware when you need to read or modify *every* request in some way. - pub fn wrap(self, mw: U) -> Scope, T> { + pub fn wrap(self, mw: U) -> Scope, F> { Scope { middleware: Stack::new(self.middleware, mw), filter: self.filter, + service: self.service, rdef: self.rdef, state: self.state, guards: self.guards, - services: self.services, - default: self.default, + // default: self.default, external: self.external, case_insensitive: self.case_insensitive, + _marker: PhantomData, } } } -impl WebServiceFactory for Scope +impl<'a, Err, S, M, F> WebService<'a, Err> for Scope where - T: ServiceFactory< - &'a mut WebRequest<'a, Err>, - Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, - InitError = (), - > + 'static, - M: Transform, Err>> + 'static, + S: ServicesFactory<'a, Err> + 'static, + M: Transform< + ScopeService< + 'a, + >>::Service, + Err, + >, + > + 'static, M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, + >>::Future: 'a, + + F: FiltersFactory<'a, Err> + 'static, Err: ErrorRenderer, { - fn register(mut self, config: &mut WebServiceConfig) { + fn register(mut self, config: &mut WebServiceConfig<'a, Err>) { // update default resource if needed - if self.default.borrow().is_none() { - *self.default.borrow_mut() = Some(config.default_service()); - } + //if self.default.borrow().is_none() { + // *self.default.borrow_mut() = Some(config.default_service()); + //} - // register nested services - let mut cfg = config.clone_config(); - self.services - .into_iter() - .for_each(|mut srv| srv.register(&mut cfg)); + // // register nested services + // let mut cfg: WebServiceConfig<'a, Err> = WebServiceConfig::<'a, _>::new( + // config.config.clone(), + // Rc::new(boxed::factory(DefaultService::default())), + // config.service_state.clone() + // ); + // self.service.register(&mut cfg); - let slesh = self.rdef.iter().any(|s| s.ends_with('/')); + let slash = self.rdef.iter().any(|s| s.ends_with('/')); let mut rmap = ResourceMap::new(ResourceDef::root_prefix(self.rdef.clone())); // external resources @@ -400,33 +392,33 @@ where } // custom app data storage - if let Some(ref mut ext) = self.state { - config.set_service_state(ext); - } + //if let Some(ref mut ext) = self.state { + // config.set_service_state(ext); + //} // complete scope pipeline creation - let router_factory = ScopeRouterFactory { - state: self.state.take().map(Rc::new), - default: self.default.clone(), - case_insensitive: self.case_insensitive, - services: Rc::new( - cfg.into_services() - .1 - .into_iter() - .map(|(rdef, srv, guards, nested)| { - // case for scope prefix ends with '/' and - // resource is empty pattern - let mut rdef = if slesh && rdef.pattern() == "" { - ResourceDef::new("/") - } else { - rdef - }; - rmap.add(&mut rdef, nested); - (rdef, srv, RefCell::new(guards)) - }) - .collect(), - ), - }; + // let router_factory: ScopeRouterFactory<'a, Err> = ScopeRouterFactory { + // state: self.state.take().map(Rc::new), + // // default: self.default.clone(), + // case_insensitive: self.case_insensitive, + // services: Rc::new( + // cfg.into_services() + // .1 + // .into_iter() + // .map(|(rdef, srv, guards, nested)| { + // // case for scope prefix ends with '/' and + // // resource is empty pattern + // let mut rdef = if slesh && rdef.pattern() == "" { + // ResourceDef::new("/") + // } else { + // rdef + // }; + // rmap.add(&mut rdef, nested); + // (rdef, srv, RefCell::new(guards)) + // }) + // .collect(), + // ), + // }; // get guards let guards = if self.guards.is_empty() { @@ -440,9 +432,14 @@ where ResourceDef::root_prefix(self.rdef), guards, ScopeServiceFactory { + slash, + config: config.config.clone(), middleware: Rc::new(MiddlewareStack::new(self.middleware)), - filter: self.filter, - routing: router_factory, + filter: self.filter.create(), + state: self.state.take().map(Rc::new), + // default: self.default.clone(), + case_insensitive: self.case_insensitive, + service: self.service, }, Some(Rc::new(rmap)), ) @@ -450,33 +447,79 @@ where } /// Scope service -struct ScopeServiceFactory { +struct ScopeServiceFactory { + config: AppConfig, middleware: Rc>, filter: F, - routing: ScopeRouterFactory, + service: S, + state: Option>, + slash: bool, + case_insensitive: bool, + // default: Rc>>>>, + // routing: ScopeRouterFactory<'a, Err>, } -impl ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeServiceFactory +impl<'a, Err, S, M, F> ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeServiceFactory where - M: Transform, Err>> + 'static, + S: ServicesFactory<'a, Err> + 'static, + M: Transform> + 'static, M::Service: Service<&'a mut WebRequest<'a, Err>, Response = WebResponse, Error = Infallible>, F: ServiceFactory< &'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, - Error = Err::Container, + Error = Infallible, InitError = (), > + 'static, + F::Service: 'static, + F::Future: 'static, Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type Service = Middleware; type InitError = (); type Future = Pin>>>; fn new_service(&self, _: ()) -> Self::Future { + // register nested services + let mut cfg: WebServiceConfig<'a, Err> = WebServiceConfig::<'a, _>::new( + self.config.clone(), + Rc::new(boxed::factory(DefaultService::default())), + Rc::new(Vec::new()), + ); + + // custom app data storage + if let Some(ref mut ext) = self.state { + cfg.set_service_state(ext); + } + + // complete scope pipeline creation + self.service.register(&mut cfg); + + let router_factory: ScopeRouterFactory<'a, Err> = ScopeRouterFactory { + state: self.state.take(), + // default: self.default.clone(), + case_insensitive: self.case_insensitive, + services: Rc::new( + cfg.into_services() + .1 + .into_iter() + .map(|(rdef, srv, guards, nested)| { + // case for scope prefix ends with '/' and + // resource is empty pattern + let mut rdef = if self.slash && rdef.pattern() == "" { + ResourceDef::new("/") + } else { + rdef + }; + (rdef, srv, RefCell::new(guards)) + }) + .collect(), + ), + }; + let filter_fut = self.filter.new_service(()); - let routing_fut = self.routing.new_service(()); + let routing_fut = router_factory.new_service(()); let middleware = self.middleware.clone(); Box::pin(async move { Ok(middleware.new_transform(ScopeService { @@ -487,24 +530,28 @@ where } } -pub struct ScopeService { +pub struct ScopeService<'a, F, Err: ErrorRenderer> { filter: F, - routing: Rc>, + routing: Rc>, } -impl Service<&'a mut WebRequest<'a, Err>> for ScopeService +impl<'a, F, Err> Service<&'a mut WebRequest<'a, Err>> for ScopeService<'a, F, Err> where - F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>, + F: Service< + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, + Error = Infallible, + >, Err: ErrorRenderer, { type Response = WebResponse; - type Error = Err::Container; - type Future = ScopeServiceResponse; + type Error = Infallible; + type Future = ScopeServiceResponse<'a, F, Err>; #[inline] fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { - let ready1 = self.filter.poll_ready(cx)?.is_ready(); - let ready2 = self.routing.poll_ready(cx)?.is_ready(); + let ready1 = self.filter.poll_ready(cx).is_ready(); + let ready2 = self.routing.poll_ready(cx).is_ready(); if ready1 && ready2 { Poll::Ready(Ok(())) } else { @@ -522,20 +569,24 @@ where } pin_project_lite::pin_project! { - pub struct ScopeServiceResponse>, Err: ErrorRenderer> { + pub struct ScopeServiceResponse<'a, F: Service<&'a mut WebRequest<'a, Err>>, Err: ErrorRenderer> { #[pin] filter: F::Future, - routing: Rc>, - endpoint: Option< as Service<&'a mut WebRequest<'a, Err>>>::Future>, + routing: Rc>, + endpoint: Option< as Service<&'a mut WebRequest<'a, Err>>>::Future>, } } -impl Future for ScopeServiceResponse +impl<'a, F, Err> Future for ScopeServiceResponse<'a, F, Err> where - F: Service<&'a mut WebRequest<'a, Err>, Response = &'a mut WebRequest<'a, Err>, Error = Err::Container>, + F: Service< + &'a mut WebRequest<'a, Err>, + Response = &'a mut WebRequest<'a, Err>, + Error = Infallible, + >, Err: ErrorRenderer, { - type Output = Result; + type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.as_mut().project(); @@ -543,40 +594,44 @@ where if let Some(fut) = this.endpoint.as_mut() { Pin::new(fut).poll(cx) } else { - let res = if let Poll::Ready(res) = this.filter.poll(cx) { - res? - } else { - return Poll::Pending; - }; - *this.endpoint = Some(this.routing.call(res)); + let req = ready!(this.filter.poll(cx)).unwrap(); + *this.endpoint = Some(this.routing.call(req)); self.poll(cx) } } } -struct ScopeRouterFactory { +struct ScopeRouterFactory<'a, Err: ErrorRenderer> { state: Option>, - services: Rc, RefCell>)>>, - default: Rc>>>>, + services: Rc< + Vec<( + ResourceDef, + BoxServiceFactory<'a, Err>, + RefCell>, + )>, + >, + // default: Rc>>>>, case_insensitive: bool, } -impl ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeRouterFactory { +impl<'a, Err: ErrorRenderer> ServiceFactory<&'a mut WebRequest<'a, Err>> + for ScopeRouterFactory<'a, Err> +{ type Response = WebResponse; - type Error = Err::Container; + type Error = Infallible; type InitError = (); - type Service = ScopeRouter; + type Service = ScopeRouter<'a, Err>; type Future = Pin>>>; fn new_service(&self, _: ()) -> Self::Future { let services = self.services.clone(); let case_insensitive = self.case_insensitive; let state = self.state.clone(); - let default_fut = self - .default - .borrow() - .as_ref() - .map(|srv| srv.new_service(())); + // let default_fut = self + // .default + // .borrow() + // .as_ref() + // .map(|srv| srv.new_service(())); Box::pin(async move { // create http services @@ -589,31 +644,31 @@ impl ServiceFactory<&'a mut WebRequest<'a, Err>> for ScopeRo router.rdef(path.clone(), service).2 = guards.borrow_mut().take(); } - let default = if let Some(fut) = default_fut { - Some(fut.await?) - } else { - None - }; + // let default = if let Some(fut) = default_fut { + // Some(fut.await?) + // } else { + // None + // }; Ok(ScopeRouter { state, - default, + // default, router: router.finish(), }) }) } } -struct ScopeRouter { +struct ScopeRouter<'a, Err: ErrorRenderer> { state: Option>, - router: Router, Vec>>, - default: Option>, + router: Router, Vec>>, + // default: Option>, } -impl Service<&'a mut WebRequest<'a, Err>> for ScopeRouter { +impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for ScopeRouter<'a, Err> { type Response = WebResponse; - type Error = Err::Container; - type Future = Either, Ready>; + type Error = Infallible; + type Future = Pin> + 'a>>; #[inline] fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { @@ -621,7 +676,7 @@ impl Service<&'a mut WebRequest<'a, Err>> for ScopeRouter) -> Self::Future { - let res = self.router.recognize_checked(&mut req, |req, guards| { + let res = self.router.recognize_checked(req, |req, guards| { if let Some(guards) = guards { for f in guards { if !f.check(req.head()) { @@ -636,15 +691,10 @@ impl Service<&'a mut WebRequest<'a, Err>> for ScopeRouter: 'static { fn register(self, config: &mut WebServiceConfig<'a, Err>); @@ -43,16 +45,16 @@ type Guards = Vec>; /// Application service configuration pub struct WebServiceConfig<'a, Err: ErrorRenderer> { - config: AppConfig, + pub(super) config: AppConfig, root: bool, - default: Rc>, + pub(super) default: Rc>, services: Vec<( ResourceDef, BoxServiceFactory<'a, Err>, Option, Option>, )>, - service_state: Rc>>, + pub(super) service_state: Rc>>, } impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { @@ -90,7 +92,7 @@ impl<'a, Err: ErrorRenderer> WebServiceConfig<'a, Err> { (self.config, self.services) } - pub(crate) fn clone_config(&self) -> Self { + pub(super) fn clone_config(&'a self) -> WebServiceConfig<'a, Err> { WebServiceConfig { config: self.config.clone(), default: self.default.clone(), @@ -267,6 +269,43 @@ where // } // } +#[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 = Infallible; + type InitError = (); + type Service = Self; + type Future = Ready; + + fn new_service(&self, _: ()) -> Self::Future { + Ready::Ok(DefaultService(PhantomData)) + } +} + +impl<'a, Err: ErrorRenderer> Service<&'a mut WebRequest<'a, Err>> for DefaultService { + type Response = WebResponse; + type Error = Infallible; + 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(HttpResponse::NotFound().finish().into()) + } +} + macro_rules! tuple_web_service({$(($n:tt, $T:ident)),+} => { /// WebServiceFactory implementation for a tuple #[allow(unused_parens)] diff --git a/ntex/src/web/stack.rs b/ntex/src/web/stack.rs index c8ff251b..48790184 100644 --- a/ntex/src/web/stack.rs +++ b/ntex/src/web/stack.rs @@ -3,10 +3,10 @@ use std::{ task::Poll, }; -use crate::service::{dev::AndThenFactory, Service, ServiceFactory, Transform}; +use crate::service::{dev::AndThenFactory, Identity, Service, ServiceFactory, Transform}; use crate::util::{ready, Ready}; -use super::{Error, ErrorRenderer, WebRequest, WebResponse}; +use super::{Error, ErrorRenderer, WebRequest, WebResponse, WebService, WebServiceConfig}; pub struct Stack { inner: Inner, @@ -233,6 +233,7 @@ where > + 'static, First::Service: 'static, First::Future: 'static, + >>::Future: 'a, Second: FiltersFactory<'a, Err>, Second::Service: ServiceFactory< &'a mut WebRequest<'a, Err>, @@ -242,6 +243,7 @@ where >, >>::Service: 'static, >>::Future: 'static, + <>>::Service as Service<&'a mut WebRequest<'a, Err>>>::Future: 'a, { type Service = AndThenFactory; @@ -260,3 +262,34 @@ pub trait FiltersFactory<'a, Err: ErrorRenderer> { fn create(self) -> Self::Service; } + +impl<'a, Err: ErrorRenderer> ServicesFactory<'a, Err> for Identity { + fn register(self, _: &mut WebServiceConfig<'a, Err>) {} +} + +pub struct Services { + first: First, + second: Second, +} + +impl Services { + pub(super) fn new(first: First, second: Second) -> Self { + Services { first, second } + } +} + +impl<'a, First, Second, Err> ServicesFactory<'a, Err> for Services +where + Err: ErrorRenderer, + First: WebService<'a, Err>, + Second: ServicesFactory<'a, Err>, +{ + fn register(self, cfg: &mut WebServiceConfig<'a, Err>) { + self.second.register(cfg); + self.first.register(cfg); + } +} + +pub trait ServicesFactory<'a, Err: ErrorRenderer> { + fn register(self, cfg: &mut WebServiceConfig<'a, Err>); +}