mirror of
https://github.com/ntex-rs/ntex.git
synced 2025-04-04 21:37:58 +03:00
Refactor web middleware registration and management procedure
This commit is contained in:
parent
fe13bf8281
commit
5ccd6ffca2
25 changed files with 235 additions and 483 deletions
|
@ -1,5 +1,9 @@
|
|||
# Changes
|
||||
|
||||
## [0.4.0] - 2021-09-15
|
||||
|
||||
* Refactor web middleware registration and management procedure.
|
||||
|
||||
## [0.4.0-b.13] - 2021-09-12
|
||||
|
||||
* Fix update timer wheel bucket calculation
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex"
|
||||
version = "0.4.0-b.13"
|
||||
version = "0.4.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Framework for composable network services"
|
||||
readme = "README.md"
|
||||
|
@ -46,7 +46,7 @@ http-framework = ["h2", "http", "httparse",
|
|||
ntex-codec = "0.5.1"
|
||||
ntex-rt = "0.3.1"
|
||||
ntex-router = "0.5.1"
|
||||
ntex-service = "0.2.0-b.0"
|
||||
ntex-service = "0.2.0"
|
||||
ntex-macros = "0.1.3"
|
||||
ntex-util = "0.1.1"
|
||||
ntex-bytes = "0.1.4"
|
||||
|
|
|
@ -114,7 +114,7 @@ mod tests {
|
|||
#[crate::rt_test]
|
||||
async fn test_openssl_connect() {
|
||||
let server = crate::server::test_server(|| {
|
||||
crate::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
crate::service::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
});
|
||||
|
||||
let ssl = SslConnector::builder(SslMethod::tls()).unwrap();
|
||||
|
|
|
@ -109,7 +109,7 @@ mod tests {
|
|||
#[crate::rt_test]
|
||||
async fn test_rustls_connect() {
|
||||
let server = crate::server::test_server(|| {
|
||||
crate::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
crate::service::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
});
|
||||
|
||||
let mut config = ClientConfig::new();
|
||||
|
|
|
@ -227,7 +227,7 @@ mod tests {
|
|||
#[crate::rt_test]
|
||||
async fn test_connect() {
|
||||
let server = crate::server::test_server(|| {
|
||||
crate::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
crate::service::fn_service(|_| async { Ok::<_, ()>(()) })
|
||||
});
|
||||
|
||||
let srv = Connector::default();
|
||||
|
|
|
@ -580,7 +580,7 @@ mod tests {
|
|||
let (disp, _) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(|msg: DispatchItem<BytesCodec>| async move {
|
||||
crate::service::fn_service(|msg: DispatchItem<BytesCodec>| async move {
|
||||
sleep(Millis(50)).await;
|
||||
if let DispatchItem::Item(msg) = msg {
|
||||
Ok::<_, ()>(Some(msg.freeze()))
|
||||
|
@ -609,7 +609,7 @@ mod tests {
|
|||
let (disp, st) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(|msg: DispatchItem<BytesCodec>| async move {
|
||||
crate::service::fn_service(|msg: DispatchItem<BytesCodec>| async move {
|
||||
if let DispatchItem::Item(msg) = msg {
|
||||
Ok::<_, ()>(Some(msg.freeze()))
|
||||
} else {
|
||||
|
@ -645,7 +645,7 @@ mod tests {
|
|||
let (disp, state) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(|_: DispatchItem<BytesCodec>| async move {
|
||||
crate::service::fn_service(|_: DispatchItem<BytesCodec>| async move {
|
||||
Err::<Option<Bytes>, _>(())
|
||||
}),
|
||||
);
|
||||
|
@ -686,7 +686,7 @@ mod tests {
|
|||
let (disp, state) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
crate::service::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
let data = data2.clone();
|
||||
async move {
|
||||
match msg {
|
||||
|
@ -754,7 +754,7 @@ mod tests {
|
|||
let (disp, state) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
crate::service::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
let data = data2.clone();
|
||||
async move {
|
||||
match msg {
|
||||
|
@ -805,7 +805,7 @@ mod tests {
|
|||
let (disp, _) = Dispatcher::debug(
|
||||
server,
|
||||
BytesCodec,
|
||||
crate::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
crate::service::fn_service(move |msg: DispatchItem<BytesCodec>| {
|
||||
handled2.store(true, Relaxed);
|
||||
async move {
|
||||
sleep(Millis(50)).await;
|
||||
|
|
|
@ -815,10 +815,12 @@ mod tests {
|
|||
}),
|
||||
ExpectHandler,
|
||||
None,
|
||||
Some(boxed::service(crate::into_service(move |(req, _)| {
|
||||
data2.set(true);
|
||||
Box::pin(async move { Ok(req) })
|
||||
}))),
|
||||
Some(boxed::service(crate::service::into_service(
|
||||
move |(req, _)| {
|
||||
data2.set(true);
|
||||
Box::pin(async move { Ok(req) })
|
||||
},
|
||||
))),
|
||||
)),
|
||||
None,
|
||||
None,
|
||||
|
|
|
@ -11,10 +11,8 @@ use crate::http::error::{DispatchError, ResponseError};
|
|||
use crate::http::helpers::DataFactory;
|
||||
use crate::http::request::Request;
|
||||
use crate::http::response::Response;
|
||||
use crate::rt::net::TcpStream;
|
||||
use crate::{
|
||||
pipeline_factory, time::Millis, IntoServiceFactory, Service, ServiceFactory,
|
||||
};
|
||||
use crate::service::{pipeline_factory, IntoServiceFactory, Service, ServiceFactory};
|
||||
use crate::{rt::net::TcpStream, time::Millis};
|
||||
|
||||
use super::codec::Codec;
|
||||
use super::dispatcher::Dispatcher;
|
||||
|
|
|
@ -12,12 +12,12 @@ use crate::http::helpers::DataFactory;
|
|||
use crate::http::request::Request;
|
||||
use crate::http::response::Response;
|
||||
use crate::rt::net::TcpStream;
|
||||
use crate::time::Millis;
|
||||
use crate::util::Bytes;
|
||||
use crate::{
|
||||
use crate::service::{
|
||||
fn_factory, fn_service, pipeline_factory, IntoServiceFactory, Service,
|
||||
ServiceFactory,
|
||||
};
|
||||
use crate::time::Millis;
|
||||
use crate::util::Bytes;
|
||||
|
||||
use super::dispatcher::Dispatcher;
|
||||
|
||||
|
@ -99,7 +99,7 @@ mod openssl {
|
|||
use crate::server::SslError;
|
||||
|
||||
use super::*;
|
||||
use crate::{fn_factory, fn_service};
|
||||
use crate::service::{fn_factory, fn_service};
|
||||
|
||||
impl<S, B> H2Service<SslStream<TcpStream>, S, B>
|
||||
where
|
||||
|
|
|
@ -46,7 +46,9 @@ pub mod util;
|
|||
pub mod web;
|
||||
pub mod ws;
|
||||
|
||||
pub use self::service::*;
|
||||
pub use self::service::{
|
||||
IntoService, IntoServiceFactory, Service, ServiceFactory, Transform,
|
||||
};
|
||||
|
||||
pub use futures_core::stream::Stream;
|
||||
pub use futures_sink::Sink;
|
||||
|
|
|
@ -626,6 +626,7 @@ impl Future for LowresTimerDriver {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::time::Millis;
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_timer() {
|
||||
|
|
|
@ -46,9 +46,9 @@ impl<S, E> Transform<S> for Buffer<E>
|
|||
where
|
||||
S: Service<Error = E>,
|
||||
{
|
||||
type Transform = BufferService<S, E>;
|
||||
type Service = BufferService<S, E>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
BufferService {
|
||||
size: self.buf_size,
|
||||
inner: Rc::new(Inner {
|
||||
|
|
|
@ -28,9 +28,9 @@ impl<S> Transform<S> for InFlight
|
|||
where
|
||||
S: Service,
|
||||
{
|
||||
type Transform = InFlightService<S>;
|
||||
type Service = InFlightService<S>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
InFlightService::new(self.max_inflight, service)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ mod tests {
|
|||
let disp = Dispatcher::new(
|
||||
decoder,
|
||||
encoder,
|
||||
crate::fn_service(move |_| {
|
||||
crate::service::fn_service(move |_| {
|
||||
counter2.set(counter2.get() + 1);
|
||||
async { Ok(Some(ws::Message::Text(ByteString::from_static("test")))) }
|
||||
}),
|
||||
|
|
|
@ -86,9 +86,9 @@ impl<S> Transform<S> for Timeout
|
|||
where
|
||||
S: Service,
|
||||
{
|
||||
type Transform = TimeoutService<S>;
|
||||
type Service = TimeoutService<S>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
TimeoutService {
|
||||
service,
|
||||
timeout: self.timeout,
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::{cell::RefCell, fmt, future::Future, pin::Pin, rc::Rc};
|
|||
use crate::http::Request;
|
||||
use crate::router::ResourceDef;
|
||||
use crate::service::boxed::{self, BoxServiceFactory};
|
||||
use crate::service::{apply, apply_fn_factory, pipeline_factory};
|
||||
use crate::service::{IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::service::{map_config, pipeline_factory};
|
||||
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::util::{Either, Extensions, Ready};
|
||||
|
||||
use super::app_service::{AppEntry, AppFactory, AppRoutingFactory};
|
||||
|
@ -24,8 +24,9 @@ type FnDataFactory =
|
|||
|
||||
/// Application builder - structure that follows the builder pattern
|
||||
/// for building application instances.
|
||||
pub struct App<T, Err: ErrorRenderer = DefaultError> {
|
||||
endpoint: T,
|
||||
pub struct App<M, S, Err: ErrorRenderer = DefaultError> {
|
||||
middleware: M,
|
||||
endpoint: S,
|
||||
services: Vec<Box<dyn AppServiceFactory<Err>>>,
|
||||
default: Option<Rc<HttpNewService<Err>>>,
|
||||
factory_ref: Rc<RefCell<Option<AppRoutingFactory<Err>>>>,
|
||||
|
@ -37,11 +38,12 @@ pub struct App<T, Err: ErrorRenderer = DefaultError> {
|
|||
case_insensitive: bool,
|
||||
}
|
||||
|
||||
impl App<AppEntry<DefaultError>, DefaultError> {
|
||||
impl App<Identity, AppEntry<DefaultError>, DefaultError> {
|
||||
/// Create application builder. Application can be configured with a builder-like pattern.
|
||||
pub fn new() -> Self {
|
||||
let fref = Rc::new(RefCell::new(None));
|
||||
App {
|
||||
middleware: Identity,
|
||||
endpoint: AppEntry::new(fref.clone()),
|
||||
data: Vec::new(),
|
||||
data_factories: Vec::new(),
|
||||
|
@ -56,11 +58,12 @@ impl App<AppEntry<DefaultError>, DefaultError> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Err: ErrorRenderer> App<AppEntry<Err>, Err> {
|
||||
impl<Err: ErrorRenderer> App<Identity, AppEntry<Err>, Err> {
|
||||
/// Create application builder with custom error renderer.
|
||||
pub fn with(err: Err) -> Self {
|
||||
let fref = Rc::new(RefCell::new(None));
|
||||
App {
|
||||
middleware: Identity,
|
||||
endpoint: AppEntry::new(fref.clone()),
|
||||
data: Vec::new(),
|
||||
data_factories: Vec::new(),
|
||||
|
@ -75,16 +78,16 @@ impl<Err: ErrorRenderer> App<AppEntry<Err>, Err> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Err> App<T, Err>
|
||||
impl<M, S, Err> App<M, S, Err>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
T::Future: 'static,
|
||||
S::Future: 'static,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
/// Set application data. Application data could be accessed
|
||||
|
@ -359,6 +362,7 @@ where
|
|||
self,
|
||||
filter: F,
|
||||
) -> App<
|
||||
M,
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
|
@ -388,6 +392,7 @@ where
|
|||
|
||||
App {
|
||||
endpoint,
|
||||
middleware: self.middleware,
|
||||
data: self.data,
|
||||
data_factories: self.data_factories,
|
||||
services: self.services,
|
||||
|
@ -410,10 +415,7 @@ where
|
|||
///
|
||||
/// Notice that the keyword for registering middleware is `wrap`. As you
|
||||
/// register middleware using `wrap` in the App builder, imagine wrapping
|
||||
/// layers around an inner App. The first middleware layer exposed to a
|
||||
/// Request is the outermost layer-- the *last* registered in
|
||||
/// the builder chain. Consequently, the *first* middleware registered
|
||||
/// in the builder chain is the *last* to execute during request processing.
|
||||
/// layers around an inner App.
|
||||
///
|
||||
/// ```rust
|
||||
/// use ntex::http::header::{CONTENT_TYPE, HeaderValue};
|
||||
|
@ -429,90 +431,10 @@ where
|
|||
/// .route("/index.html", web::get().to(index));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn wrap<M>(
|
||||
self,
|
||||
mw: M,
|
||||
) -> App<
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
Err,
|
||||
>
|
||||
where
|
||||
M: Transform<T::Service>,
|
||||
M::Transform: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
{
|
||||
pub fn wrap<U>(self, mw: U) -> App<Stack<M, U>, S, Err> {
|
||||
App {
|
||||
endpoint: apply(mw, self.endpoint),
|
||||
data: self.data,
|
||||
data_factories: self.data_factories,
|
||||
services: self.services,
|
||||
default: self.default,
|
||||
factory_ref: self.factory_ref,
|
||||
external: self.external,
|
||||
extensions: self.extensions,
|
||||
error_renderer: self.error_renderer,
|
||||
case_insensitive: self.case_insensitive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers middleware, in the form of a closure, that runs during inbound
|
||||
/// and/or outbound processing in the request lifecycle (request -> response),
|
||||
/// modifying request/response as necessary, across all requests managed by
|
||||
/// the *Application*.
|
||||
///
|
||||
/// Use middleware when you need to read or modify *every* request or response in some way.
|
||||
///
|
||||
/// ```rust
|
||||
/// use ntex::{web, Service};
|
||||
/// use ntex::http::header::{CONTENT_TYPE, HeaderValue};
|
||||
///
|
||||
/// async fn index() -> &'static str {
|
||||
/// "Welcome!"
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = web::App::new()
|
||||
/// .wrap_fn(|req, srv| {
|
||||
/// let fut = srv.call(req);
|
||||
/// async {
|
||||
/// let mut res = fut.await?;
|
||||
/// res.headers_mut().insert(
|
||||
/// CONTENT_TYPE, HeaderValue::from_static("text/plain"),
|
||||
/// );
|
||||
/// Ok(res)
|
||||
/// }
|
||||
/// })
|
||||
/// .route("/index.html", web::get().to(index));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn wrap_fn<F, R>(
|
||||
self,
|
||||
mw: F,
|
||||
) -> App<
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
Err,
|
||||
>
|
||||
where
|
||||
F: Fn(WebRequest<Err>, &T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<WebResponse, Err::Container>>,
|
||||
{
|
||||
App {
|
||||
endpoint: apply_fn_factory(self.endpoint, mw),
|
||||
middleware: Stack::new(self.middleware, mw),
|
||||
endpoint: self.endpoint,
|
||||
data: self.data,
|
||||
data_factories: self.data_factories,
|
||||
services: self.services,
|
||||
|
@ -532,7 +454,26 @@ where
|
|||
self.case_insensitive = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, S, Err> App<M, S, Err>
|
||||
where
|
||||
M: Transform<S::Service> + 'static,
|
||||
M::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
S::Future: 'static,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
/// Construct service factory with default `AppConfig`, suitable for `http::HttpService`.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
|
@ -557,10 +498,10 @@ where
|
|||
Config = (),
|
||||
Request = Request,
|
||||
Response = WebResponse,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
Error = S::Error,
|
||||
InitError = S::InitError,
|
||||
> {
|
||||
crate::map_config(self.into_factory(), move |_| Default::default())
|
||||
map_config(self.into_factory(), move |_| Default::default())
|
||||
}
|
||||
|
||||
/// Construct service factory suitable for `http::HttpService`.
|
||||
|
@ -588,27 +529,34 @@ where
|
|||
Config = (),
|
||||
Request = Request,
|
||||
Response = WebResponse,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
Error = S::Error,
|
||||
InitError = S::InitError,
|
||||
> {
|
||||
crate::map_config(self.into_factory(), move |_| cfg.clone())
|
||||
map_config(self.into_factory(), move |_| cfg.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Err> IntoServiceFactory<AppFactory<T, Err>> for App<T, Err>
|
||||
impl<M, S, Err> IntoServiceFactory<AppFactory<M, S, Err>> for App<M, S, Err>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
M: Transform<S::Service> + 'static,
|
||||
M::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
T::Future: 'static,
|
||||
S::Future: 'static,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
fn into_factory(self) -> AppFactory<T, Err> {
|
||||
fn into_factory(self) -> AppFactory<M, S, Err> {
|
||||
AppFactory {
|
||||
middleware: Rc::new(self.middleware),
|
||||
data: Rc::new(self.data),
|
||||
data_factories: Rc::new(self.data_factories),
|
||||
endpoint: self.endpoint,
|
||||
|
@ -622,16 +570,41 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Stack<Inner, Outer> {
|
||||
inner: Inner,
|
||||
outer: Outer,
|
||||
}
|
||||
|
||||
impl<Inner, Outer> Stack<Inner, Outer> {
|
||||
pub(super) fn new(inner: Inner, outer: Outer) -> Self {
|
||||
Stack { inner, outer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, Inner, Outer> Transform<S> for Stack<Inner, Outer>
|
||||
where
|
||||
Inner: Transform<S>,
|
||||
Outer: Transform<Inner::Service>,
|
||||
{
|
||||
type Service = Outer::Service;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
self.outer.new_transform(self.inner.new_transform(service))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::header::{self, HeaderValue};
|
||||
use crate::http::{Method, StatusCode};
|
||||
use crate::web::middleware::DefaultHeaders;
|
||||
use crate::web::request::WebRequest;
|
||||
use crate::service::{fn_service, Service};
|
||||
use crate::util::Bytes;
|
||||
use crate::web::test::{call_service, init_service, read_body, TestRequest};
|
||||
use crate::web::{self, DefaultError, HttpRequest, HttpResponse};
|
||||
use crate::{fn_service, util::Bytes, Service};
|
||||
use crate::web::{
|
||||
self, middleware::DefaultHeaders, request::WebRequest, DefaultError,
|
||||
HttpRequest, HttpResponse,
|
||||
};
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_default_resource() {
|
||||
|
@ -777,60 +750,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_wrap_fn() {
|
||||
let srv = init_service(
|
||||
App::new()
|
||||
.wrap_fn(|req, srv| {
|
||||
let fut = srv.call(req);
|
||||
async move {
|
||||
let mut res = fut.await?;
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("0001"),
|
||||
);
|
||||
Ok(res)
|
||||
}
|
||||
})
|
||||
.service(web::resource("/test").to(|| async { HttpResponse::Ok() })),
|
||||
)
|
||||
.await;
|
||||
let req = TestRequest::with_uri("/test").to_request();
|
||||
let resp = call_service(&srv, req).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("0001")
|
||||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_router_wrap_fn() {
|
||||
let srv = init_service(
|
||||
App::new()
|
||||
.route("/test", web::get().to(|| async { HttpResponse::Ok() }))
|
||||
.wrap_fn(|req, srv| {
|
||||
let fut = srv.call(req);
|
||||
async {
|
||||
let mut res = fut.await?;
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("0001"),
|
||||
);
|
||||
Ok(res)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let req = TestRequest::with_uri("/test").to_request();
|
||||
let resp = call_service(&srv, req).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("0001")
|
||||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_case_insensitive_router() {
|
||||
let srv = init_service(
|
||||
|
|
|
@ -4,8 +4,8 @@ use std::{cell::RefCell, future::Future, marker::PhantomData, pin::Pin, rc::Rc};
|
|||
use crate::http::{Request, Response};
|
||||
use crate::router::{Path, ResourceDef, ResourceInfo, Router};
|
||||
use crate::service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use crate::service::{fn_service, Service, ServiceFactory, Transform};
|
||||
use crate::util::Extensions;
|
||||
use crate::{fn_service, Service, ServiceFactory};
|
||||
|
||||
use super::config::AppConfig;
|
||||
use super::error::ErrorRenderer;
|
||||
|
@ -29,19 +29,20 @@ type FnDataFactory =
|
|||
|
||||
/// Service factory to convert `Request` to a `WebRequest<S>`.
|
||||
/// It also executes data factories.
|
||||
pub struct AppFactory<T, Err: ErrorRenderer>
|
||||
pub struct AppFactory<T, S, Err: ErrorRenderer>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
T::Future: 'static,
|
||||
S::Future: 'static,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
pub(super) endpoint: T,
|
||||
pub(super) middleware: Rc<T>,
|
||||
pub(super) endpoint: S,
|
||||
pub(super) extensions: RefCell<Option<Extensions>>,
|
||||
pub(super) data: Rc<Vec<Box<dyn DataFactory>>>,
|
||||
pub(super) data_factories: Rc<Vec<FnDataFactory>>,
|
||||
|
@ -52,23 +53,29 @@ where
|
|||
pub(super) case_insensitive: bool,
|
||||
}
|
||||
|
||||
impl<T, Err> ServiceFactory for AppFactory<T, Err>
|
||||
impl<T, S, Err> ServiceFactory for AppFactory<T, S, Err>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
T: Transform<S::Service> + 'static,
|
||||
T::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
T::Future: 'static,
|
||||
S::Future: 'static,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
type Config = AppConfig;
|
||||
type Request = Request;
|
||||
type Response = WebResponse;
|
||||
type Error = T::Error;
|
||||
type InitError = T::InitError;
|
||||
type Error = S::Error;
|
||||
type InitError = S::InitError;
|
||||
type Service = AppFactoryService<T::Service, Err>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::InitError>>>>;
|
||||
|
||||
|
@ -127,6 +134,7 @@ where
|
|||
.borrow_mut()
|
||||
.take()
|
||||
.unwrap_or_else(Extensions::new);
|
||||
let middleware = self.middleware.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
// main service
|
||||
|
@ -145,9 +153,9 @@ where
|
|||
}
|
||||
|
||||
Ok(AppFactoryService {
|
||||
service,
|
||||
rmap,
|
||||
config,
|
||||
service: middleware.new_transform(service),
|
||||
data: Rc::new(extensions),
|
||||
pool: HttpRequestPool::create(),
|
||||
_t: PhantomData,
|
||||
|
|
|
@ -50,9 +50,9 @@ where
|
|||
S: Service<Request = WebRequest<E>, Response = WebResponse>,
|
||||
E: ErrorRenderer,
|
||||
{
|
||||
type Transform = CompressMiddleware<S, E>;
|
||||
type Service = CompressMiddleware<S, E>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
CompressMiddleware {
|
||||
service,
|
||||
encoding: self.enc,
|
||||
|
|
|
@ -91,9 +91,9 @@ where
|
|||
S: Service<Request = WebRequest<E>, Response = WebResponse>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Transform = DefaultHeadersMiddleware<S, E>;
|
||||
type Service = DefaultHeadersMiddleware<S, E>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
DefaultHeadersMiddleware {
|
||||
service,
|
||||
inner: self.inner.clone(),
|
||||
|
|
|
@ -118,9 +118,9 @@ impl<S, Err> Transform<S> for Logger
|
|||
where
|
||||
S: Service<Request = WebRequest<Err>, Response = WebResponse>,
|
||||
{
|
||||
type Transform = LoggerMiddleware<S>;
|
||||
type Service = LoggerMiddleware<S>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Transform {
|
||||
fn new_transform(&self, service: S) -> Self::Service {
|
||||
LoggerMiddleware {
|
||||
service,
|
||||
inner: self.inner.clone(),
|
||||
|
|
|
@ -5,8 +5,8 @@ use std::{
|
|||
use crate::http::Response;
|
||||
use crate::router::{IntoPattern, ResourceDef};
|
||||
use crate::service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use crate::service::{apply, apply_fn_factory, pipeline_factory};
|
||||
use crate::service::{IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::service::{apply, dev::ApplyTransform, pipeline_factory};
|
||||
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::util::{Either, Extensions, Ready};
|
||||
|
||||
use super::dev::{insert_slesh, WebServiceConfig, WebServiceFactory};
|
||||
|
@ -18,7 +18,7 @@ use super::request::WebRequest;
|
|||
use super::responder::Responder;
|
||||
use super::response::WebResponse;
|
||||
use super::route::{IntoRoutes, Route, RouteService};
|
||||
use super::types::Data;
|
||||
use super::{app::Stack, types::Data};
|
||||
|
||||
type HttpService<Err: ErrorRenderer> =
|
||||
BoxService<WebRequest<Err>, WebResponse, Err::Container>;
|
||||
|
@ -47,8 +47,9 @@ type HttpNewService<Err: ErrorRenderer> =
|
|||
///
|
||||
/// If no matching route could be found, *405* response code get returned.
|
||||
/// Default behavior could be overriden with `default_resource()` method.
|
||||
pub struct Resource<Err: ErrorRenderer, T = ResourceEndpoint<Err>> {
|
||||
pub struct Resource<Err: ErrorRenderer, T = ResourceEndpoint<Err>, U = Identity> {
|
||||
endpoint: T,
|
||||
middleware: U,
|
||||
rdef: Vec<String>,
|
||||
name: Option<String>,
|
||||
routes: Vec<Route<Err>>,
|
||||
|
@ -67,6 +68,7 @@ impl<Err: ErrorRenderer> Resource<Err> {
|
|||
rdef: path.patterns(),
|
||||
name: None,
|
||||
endpoint: ResourceEndpoint::new(fref.clone()),
|
||||
middleware: Identity,
|
||||
factory_ref: fref,
|
||||
guards: Vec::new(),
|
||||
data: None,
|
||||
|
@ -75,7 +77,7 @@ impl<Err: ErrorRenderer> Resource<Err> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Err, T> Resource<Err, T>
|
||||
impl<Err, T, U> Resource<Err, T, U>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
Config = (),
|
||||
|
@ -163,9 +165,9 @@ where
|
|||
/// # async fn post_handler() -> web::HttpResponseBuilder { web::HttpResponse::Ok() }
|
||||
/// # async fn delete_handler() -> web::HttpResponseBuilder { web::HttpResponse::Ok() }
|
||||
/// ```
|
||||
pub fn route<U>(mut self, route: U) -> Self
|
||||
pub fn route<R>(mut self, route: R) -> Self
|
||||
where
|
||||
U: IntoRoutes<Err>,
|
||||
R: IntoRoutes<Err>,
|
||||
{
|
||||
for route in route.routes() {
|
||||
self.routes.push(route);
|
||||
|
@ -198,14 +200,14 @@ where
|
|||
/// ));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn data<U: 'static>(self, data: U) -> Self {
|
||||
pub fn data<D: 'static>(self, data: D) -> Self {
|
||||
self.app_data(Data::new(data))
|
||||
}
|
||||
|
||||
/// Set or override application data.
|
||||
///
|
||||
/// This method overrides data stored with [`App::app_data()`](#method.app_data)
|
||||
pub fn app_data<U: 'static>(mut self, data: U) -> Self {
|
||||
pub fn app_data<D: 'static>(mut self, data: D) -> Self {
|
||||
if self.data.is_none() {
|
||||
self.data = Some(Extensions::new());
|
||||
}
|
||||
|
@ -258,6 +260,7 @@ where
|
|||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
U,
|
||||
>
|
||||
where
|
||||
F: ServiceFactory<
|
||||
|
@ -279,6 +282,7 @@ where
|
|||
|
||||
Resource {
|
||||
endpoint,
|
||||
middleware: self.middleware,
|
||||
rdef: self.rdef,
|
||||
name: self.name,
|
||||
guards: self.guards,
|
||||
|
@ -296,92 +300,10 @@ where
|
|||
/// type (i.e modify response's body).
|
||||
///
|
||||
/// **Note**: middlewares get called in opposite order of middlewares registration.
|
||||
pub fn wrap<M>(
|
||||
self,
|
||||
mw: M,
|
||||
) -> Resource<
|
||||
Err,
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
>
|
||||
where
|
||||
M: Transform<T::Service>,
|
||||
M::Transform: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
{
|
||||
pub fn wrap<M>(self, mw: M) -> Resource<Err, T, Stack<U, M>> {
|
||||
Resource {
|
||||
endpoint: apply(mw, self.endpoint),
|
||||
rdef: self.rdef,
|
||||
name: self.name,
|
||||
guards: self.guards,
|
||||
routes: self.routes,
|
||||
default: self.default,
|
||||
data: self.data,
|
||||
factory_ref: self.factory_ref,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a resource middleware function.
|
||||
///
|
||||
/// This function accepts instance of `WebRequest` type and
|
||||
/// mutable reference to the next middleware in chain.
|
||||
///
|
||||
/// This is similar to `App's` middlewares, but middleware get invoked on resource level.
|
||||
/// Resource level middlewares are not allowed to change response
|
||||
/// type (i.e modify response's body).
|
||||
///
|
||||
/// ```rust
|
||||
/// use ntex::service::Service;
|
||||
/// use ntex::web::{self, App};
|
||||
/// use ntex::http::header::{CONTENT_TYPE, HeaderValue};
|
||||
///
|
||||
/// async fn index() -> &'static str {
|
||||
/// "Welcome!"
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = App::new().service(
|
||||
/// web::resource("/index.html")
|
||||
/// .wrap_fn(|req, srv| {
|
||||
/// let fut = srv.call(req);
|
||||
/// async {
|
||||
/// let mut res = fut.await?;
|
||||
/// res.headers_mut().insert(
|
||||
/// CONTENT_TYPE, HeaderValue::from_static("text/plain"),
|
||||
/// );
|
||||
/// Ok(res)
|
||||
/// }
|
||||
/// })
|
||||
/// .route(web::get().to(index)));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn wrap_fn<F, R>(
|
||||
self,
|
||||
mw: F,
|
||||
) -> Resource<
|
||||
Err,
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
>
|
||||
where
|
||||
F: Fn(WebRequest<Err>, &T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<WebResponse, Err::Container>>,
|
||||
{
|
||||
Resource {
|
||||
endpoint: apply_fn_factory(self.endpoint, mw),
|
||||
middleware: Stack::new(self.middleware, mw),
|
||||
endpoint: self.endpoint,
|
||||
rdef: self.rdef,
|
||||
name: self.name,
|
||||
guards: self.guards,
|
||||
|
@ -395,16 +317,16 @@ where
|
|||
/// Default service to be used if no matching route could be found.
|
||||
/// By default *405* response get returned. Resource does not use
|
||||
/// default handler from `App` or `Scope`.
|
||||
pub fn default_service<F, U>(mut self, f: F) -> Self
|
||||
pub fn default_service<F, S>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
U: ServiceFactory<
|
||||
F: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
> + 'static,
|
||||
U::InitError: fmt::Debug,
|
||||
S::InitError: fmt::Debug,
|
||||
{
|
||||
// create and configure default resource
|
||||
self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory(
|
||||
|
@ -417,7 +339,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Err, T> WebServiceFactory<Err> for Resource<Err, T>
|
||||
impl<Err, T, U> WebServiceFactory<Err> for Resource<Err, T, U>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
Config = (),
|
||||
|
@ -426,6 +348,12 @@ where
|
|||
Error = Err::Container,
|
||||
InitError = (),
|
||||
> + 'static,
|
||||
U: Transform<T::Service> + 'static,
|
||||
U::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
fn register(mut self, config: &mut WebServiceConfig<Err>) {
|
||||
|
@ -446,11 +374,23 @@ where
|
|||
if let Some(ref mut ext) = self.data {
|
||||
config.set_service_data(ext);
|
||||
}
|
||||
config.register_service(rdef, guards, self, None)
|
||||
|
||||
*self.factory_ref.borrow_mut() = Some(ResourceFactory {
|
||||
routes: self.routes,
|
||||
data: self.data.map(Rc::new),
|
||||
default: self.default,
|
||||
});
|
||||
|
||||
config.register_service(
|
||||
rdef,
|
||||
guards,
|
||||
apply(self.middleware, self.endpoint),
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Err, T> IntoServiceFactory<T> for Resource<Err, T>
|
||||
impl<Err, T, U> IntoServiceFactory<ApplyTransform<U, T>> for Resource<Err, T, U>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
Config = (),
|
||||
|
@ -459,16 +399,22 @@ where
|
|||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
U: Transform<T::Service> + 'static,
|
||||
U::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
fn into_factory(self) -> T {
|
||||
fn into_factory(self) -> ApplyTransform<U, T> {
|
||||
*self.factory_ref.borrow_mut() = Some(ResourceFactory {
|
||||
routes: self.routes,
|
||||
data: self.data.map(Rc::new),
|
||||
default: self.default,
|
||||
});
|
||||
|
||||
self.endpoint
|
||||
apply(self.middleware, self.endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,10 +525,11 @@ mod tests {
|
|||
use crate::http::{Method, StatusCode};
|
||||
use crate::time::{sleep, Millis};
|
||||
use crate::web::middleware::DefaultHeaders;
|
||||
use crate::web::request::WebRequest;
|
||||
use crate::web::test::{call_service, init_service, TestRequest};
|
||||
use crate::web::{self, guard, App, DefaultError, HttpResponse};
|
||||
use crate::{fn_service, util::Either, Service};
|
||||
use crate::web::{
|
||||
self, guard, request::WebRequest, App, DefaultError, HttpResponse,
|
||||
};
|
||||
use crate::{service::fn_service, util::Either};
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_filter() {
|
||||
|
@ -625,36 +572,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_middleware_fn() {
|
||||
let srv = init_service(
|
||||
App::new().service(
|
||||
web::resource("/test")
|
||||
.wrap_fn(|req, srv| {
|
||||
let fut = srv.call(req);
|
||||
async {
|
||||
fut.await.map(|mut res| {
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
HeaderValue::from_static("0001"),
|
||||
);
|
||||
res
|
||||
})
|
||||
}
|
||||
})
|
||||
.route(web::get().to(|| async { HttpResponse::Ok() })),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
let req = TestRequest::with_uri("/test").to_request();
|
||||
let resp = call_service(&srv, req).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("0001")
|
||||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_to() {
|
||||
let srv =
|
||||
|
|
|
@ -5,10 +5,11 @@ use std::{
|
|||
use crate::http::Response;
|
||||
use crate::router::{IntoPattern, ResourceDef, ResourceInfo, Router};
|
||||
use crate::service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use crate::service::{apply, apply_fn_factory, pipeline_factory};
|
||||
use crate::service::{IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::service::{apply, pipeline_factory};
|
||||
use crate::service::{Identity, IntoServiceFactory, Service, ServiceFactory, Transform};
|
||||
use crate::util::{Either, Extensions, Ready};
|
||||
|
||||
use super::app::Stack;
|
||||
use super::config::ServiceConfig;
|
||||
use super::dev::{WebServiceConfig, WebServiceFactory};
|
||||
use super::error::ErrorRenderer;
|
||||
|
@ -58,8 +59,9 @@ type BoxedResponse<Err: ErrorRenderer> =
|
|||
/// * /{project_id}/path2 - `GET` requests
|
||||
/// * /{project_id}/path3 - `HEAD` requests
|
||||
///
|
||||
pub struct Scope<Err: ErrorRenderer, T = ScopeEndpoint<Err>> {
|
||||
pub struct Scope<Err: ErrorRenderer, T = ScopeEndpoint<Err>, U = Identity> {
|
||||
endpoint: T,
|
||||
middleware: U,
|
||||
rdef: Vec<String>,
|
||||
data: Option<Extensions>,
|
||||
services: Vec<Box<dyn AppServiceFactory<Err>>>,
|
||||
|
@ -76,6 +78,7 @@ impl<Err: ErrorRenderer> Scope<Err> {
|
|||
let fref = Rc::new(RefCell::new(None));
|
||||
Scope {
|
||||
endpoint: ScopeEndpoint::new(fref.clone()),
|
||||
middleware: Identity,
|
||||
rdef: path.patterns(),
|
||||
data: None,
|
||||
guards: Vec::new(),
|
||||
|
@ -88,7 +91,7 @@ impl<Err: ErrorRenderer> Scope<Err> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Err, T> Scope<Err, T>
|
||||
impl<Err, T, U> Scope<Err, T, U>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
Config = (),
|
||||
|
@ -150,14 +153,14 @@ where
|
|||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
pub fn data<U: 'static>(self, data: U) -> Self {
|
||||
pub fn data<D: 'static>(self, data: D) -> Self {
|
||||
self.app_data(Data::new(data))
|
||||
}
|
||||
|
||||
/// Set or override application data.
|
||||
///
|
||||
/// This method overrides data stored with [`App::app_data()`](#method.app_data)
|
||||
pub fn app_data<U: 'static>(mut self, data: U) -> Self {
|
||||
pub fn app_data<D: 'static>(mut self, data: D) -> Self {
|
||||
if self.data.is_none() {
|
||||
self.data = Some(Extensions::new());
|
||||
}
|
||||
|
@ -290,16 +293,16 @@ 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<F, U>(mut self, f: F) -> Self
|
||||
pub fn default_service<F, S>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
U: ServiceFactory<
|
||||
F: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
> + 'static,
|
||||
U::InitError: fmt::Debug,
|
||||
S::InitError: fmt::Debug,
|
||||
{
|
||||
// create and configure default resource
|
||||
self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory(
|
||||
|
@ -330,6 +333,7 @@ where
|
|||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
U,
|
||||
>
|
||||
where
|
||||
F: ServiceFactory<
|
||||
|
@ -351,6 +355,7 @@ where
|
|||
|
||||
Scope {
|
||||
endpoint,
|
||||
middleware: self.middleware,
|
||||
rdef: self.rdef,
|
||||
data: self.data,
|
||||
guards: self.guards,
|
||||
|
@ -366,98 +371,16 @@ where
|
|||
///
|
||||
/// That runs during inbound processing in the request
|
||||
/// lifecycle (request -> response), modifying request as
|
||||
/// necessary, across all requests managed by the *Scope*. Scope-level
|
||||
/// necessary, across all requests managed by the *Scope*. Scope-level
|
||||
/// middleware is more limited in what it can modify, relative to Route or
|
||||
/// Application level middleware, in that Scope-level middleware can not modify
|
||||
/// WebResponse.
|
||||
///
|
||||
/// Use middleware when you need to read or modify *every* request in some way.
|
||||
pub fn wrap<M>(
|
||||
self,
|
||||
mw: M,
|
||||
) -> Scope<
|
||||
Err,
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
>
|
||||
where
|
||||
M: Transform<T::Service>,
|
||||
M::Transform: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
{
|
||||
pub fn wrap<M>(self, mw: M) -> Scope<Err, T, Stack<U, M>> {
|
||||
Scope {
|
||||
endpoint: apply(mw, self.endpoint),
|
||||
rdef: self.rdef,
|
||||
data: self.data,
|
||||
guards: self.guards,
|
||||
services: self.services,
|
||||
default: self.default,
|
||||
external: self.external,
|
||||
factory_ref: self.factory_ref,
|
||||
case_insensitive: self.case_insensitive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers middleware, in the form of a closure.
|
||||
///
|
||||
/// That runs during inbound processing in the request lifecycle (request -> response),
|
||||
/// modifying request as necessary, across all requests managed by the *Scope*.
|
||||
/// Scope-level middleware is more limited in what it can modify, relative
|
||||
/// to Route or Application level middleware, in that Scope-level middleware
|
||||
/// can not modify WebResponse.
|
||||
///
|
||||
/// ```rust
|
||||
/// use ntex::service::Service;
|
||||
/// use ntex::web;
|
||||
/// use ntex::http::header::{CONTENT_TYPE, HeaderValue};
|
||||
///
|
||||
/// async fn index() -> &'static str {
|
||||
/// "Welcome!"
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = web::App::new().service(
|
||||
/// web::scope("/app")
|
||||
/// .wrap_fn(|req, srv| {
|
||||
/// let fut = srv.call(req);
|
||||
/// async {
|
||||
/// let mut res = fut.await?;
|
||||
/// res.headers_mut().insert(
|
||||
/// CONTENT_TYPE, HeaderValue::from_static("text/plain"),
|
||||
/// );
|
||||
/// Ok(res)
|
||||
/// }
|
||||
/// })
|
||||
/// .route("/index.html", web::get().to(index)));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn wrap_fn<F, R>(
|
||||
self,
|
||||
mw: F,
|
||||
) -> Scope<
|
||||
Err,
|
||||
impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
InitError = (),
|
||||
>,
|
||||
>
|
||||
where
|
||||
F: Fn(WebRequest<Err>, &T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<WebResponse, Err::Container>>,
|
||||
{
|
||||
Scope {
|
||||
endpoint: apply_fn_factory(self.endpoint, mw),
|
||||
endpoint: self.endpoint,
|
||||
middleware: Stack::new(self.middleware, mw),
|
||||
rdef: self.rdef,
|
||||
data: self.data,
|
||||
guards: self.guards,
|
||||
|
@ -470,7 +393,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Err, T> WebServiceFactory<Err> for Scope<Err, T>
|
||||
impl<Err, T, U> WebServiceFactory<Err> for Scope<Err, T, U>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
Config = (),
|
||||
|
@ -479,6 +402,12 @@ where
|
|||
Error = Err::Container,
|
||||
InitError = (),
|
||||
> + 'static,
|
||||
U: Transform<T::Service> + 'static,
|
||||
U::Service: Service<
|
||||
Request = WebRequest<Err>,
|
||||
Response = WebResponse,
|
||||
Error = Err::Container,
|
||||
>,
|
||||
Err: ErrorRenderer,
|
||||
{
|
||||
fn register(mut self, config: &mut WebServiceConfig<Err>) {
|
||||
|
@ -541,7 +470,7 @@ where
|
|||
config.register_service(
|
||||
ResourceDef::root_prefix(self.rdef),
|
||||
guards,
|
||||
self.endpoint,
|
||||
apply(self.middleware, self.endpoint),
|
||||
Some(Rc::new(rmap)),
|
||||
)
|
||||
}
|
||||
|
@ -1208,34 +1137,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_middleware_fn() {
|
||||
let srv = init_service(
|
||||
App::new().service(
|
||||
web::scope("app")
|
||||
.wrap_fn(|req, srv| {
|
||||
let fut = srv.call(req);
|
||||
async move {
|
||||
let mut res = fut.await?;
|
||||
res.headers_mut()
|
||||
.insert(CONTENT_TYPE, HeaderValue::from_static("0001"));
|
||||
Ok(res)
|
||||
}
|
||||
})
|
||||
.route("/test", web::get().to(|| async { HttpResponse::Ok() })),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
let req = TestRequest::with_uri("/app/test").to_request();
|
||||
let resp = call_service(&srv, req).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("0001")
|
||||
);
|
||||
}
|
||||
|
||||
#[crate::rt_test]
|
||||
async fn test_override_data() {
|
||||
let srv = init_service(App::new().data(1usize).service(
|
||||
|
|
|
@ -10,11 +10,11 @@ use crate::http::Protocol;
|
|||
use crate::http::{
|
||||
body::MessageBody, HttpService, KeepAlive, Request, Response, ResponseError,
|
||||
};
|
||||
#[cfg(unix)]
|
||||
use crate::pipeline_factory;
|
||||
use crate::server::{Server, ServerBuilder};
|
||||
#[cfg(unix)]
|
||||
use crate::service::pipeline_factory;
|
||||
use crate::time::Seconds;
|
||||
use crate::{map_config, IntoServiceFactory, Service, ServiceFactory};
|
||||
use crate::{service::map_config, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
use super::config::AppConfig;
|
||||
|
||||
|
|
|
@ -18,12 +18,12 @@ use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
|||
use crate::http::test::TestRequest as HttpTestRequest;
|
||||
use crate::http::{HttpService, Method, Payload, Request, StatusCode, Uri, Version};
|
||||
use crate::router::{Path, ResourceDef};
|
||||
use crate::service::{
|
||||
map_config, IntoService, IntoServiceFactory, Service, ServiceFactory,
|
||||
};
|
||||
use crate::time::{sleep, Millis, Seconds};
|
||||
use crate::util::{next, Bytes, BytesMut, Extensions, Ready};
|
||||
use crate::{
|
||||
map_config, rt::System, server::Server, IntoService, IntoServiceFactory, Service,
|
||||
ServiceFactory, Stream,
|
||||
};
|
||||
use crate::{rt::System, server::Server, Stream};
|
||||
|
||||
use crate::web::config::AppConfig;
|
||||
use crate::web::dev::{WebRequest, WebResponse};
|
||||
|
|
|
@ -238,7 +238,7 @@ async fn test_bind_uds() {
|
|||
let client = client::Client::build()
|
||||
.connector(
|
||||
client::Connector::default()
|
||||
.connector(ntex::fn_service(|_| async {
|
||||
.connector(ntex::service::fn_service(|_| async {
|
||||
let stream =
|
||||
ntex::rt::net::UnixStream::connect("/tmp/uds-test").await?;
|
||||
Ok((stream, ntex::http::Protocol::Http1))
|
||||
|
@ -292,7 +292,7 @@ async fn test_listen_uds() {
|
|||
let client = client::Client::build()
|
||||
.connector(
|
||||
client::Connector::default()
|
||||
.connector(ntex::fn_service(|_| async {
|
||||
.connector(ntex::service::fn_service(|_| async {
|
||||
let stream =
|
||||
ntex::rt::net::UnixStream::connect("/tmp/uds-test2").await?;
|
||||
Ok((stream, ntex::http::Protocol::Http1))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue