1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

update middleware impl

This commit is contained in:
Nikolay Kim 2019-03-04 21:37:57 -08:00
parent 2e79562c9d
commit b6fe1dacf2
7 changed files with 102 additions and 103 deletions

View File

@ -56,8 +56,8 @@ ssl = ["openssl", "actix-server/ssl"]
[dependencies] [dependencies]
actix-codec = "0.1.0" actix-codec = "0.1.0"
actix-service = "0.3.0" actix-service = "0.3.2"
actix-utils = "0.3.0" actix-utils = "0.3.1"
actix-rt = "0.1.0" actix-rt = "0.1.0"
actix-http = { git = "https://github.com/actix/actix-http.git" } actix-http = { git = "https://github.com/actix/actix-http.git" }
@ -99,3 +99,6 @@ serde_derive = "1.0"
lto = true lto = true
opt-level = 3 opt-level = 3
codegen-units = 1 codegen-units = 1
[patch.crates-io]
actix-service = { git = "https://github.com/actix/actix-net.git" }

View File

@ -7,8 +7,8 @@ use actix_http::{Extensions, PayloadStream, Request, Response};
use actix_router::{Path, ResourceDef, ResourceInfo, Router, Url}; use actix_router::{Path, ResourceDef, ResourceInfo, Router, Url};
use actix_service::boxed::{self, BoxedNewService, BoxedService}; use actix_service::boxed::{self, BoxedNewService, BoxedService};
use actix_service::{ use actix_service::{
AndThenNewService, ApplyNewService, IntoNewService, IntoNewTransform, NewService, AndThenNewService, ApplyTransform, IntoNewService, IntoTransform, NewService,
NewTransform, Service, Service, Transform,
}; };
use futures::future::{ok, Either, FutureResult}; use futures::future::{ok, Either, FutureResult};
use futures::{Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
@ -237,17 +237,17 @@ where
>, >,
> >
where where
M: NewTransform< M: Transform<
AppRouting<P>, AppRouting<P>,
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse<B>, Response = ServiceResponse<B>,
Error = (), Error = (),
InitError = (), InitError = (),
>, >,
F: IntoNewTransform<M, AppRouting<P>>, F: IntoTransform<M, AppRouting<P>>,
{ {
let fref = Rc::new(RefCell::new(None)); let fref = Rc::new(RefCell::new(None));
let endpoint = ApplyNewService::new(mw, AppEntry::new(fref.clone())); let endpoint = ApplyTransform::new(mw, AppEntry::new(fref.clone()));
AppRouter { AppRouter {
endpoint, endpoint,
chain: self.chain, chain: self.chain,
@ -480,7 +480,7 @@ where
>, >,
> >
where where
M: NewTransform< M: Transform<
T::Service, T::Service,
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse<B1>, Response = ServiceResponse<B1>,
@ -488,9 +488,9 @@ where
InitError = (), InitError = (),
>, >,
B1: MessageBody, B1: MessageBody,
F: IntoNewTransform<M, T::Service>, F: IntoTransform<M, T::Service>,
{ {
let endpoint = ApplyNewService::new(mw, self.endpoint); let endpoint = ApplyTransform::new(mw, self.endpoint);
AppRouter { AppRouter {
endpoint, endpoint,
chain: self.chain, chain: self.chain,

View File

@ -8,8 +8,9 @@ use actix_http::http::header::{
}; };
use actix_http::http::{HttpTryFrom, StatusCode}; use actix_http::http::{HttpTryFrom, StatusCode};
use actix_http::{Error, Head, ResponseHead}; use actix_http::{Error, Head, ResponseHead};
use actix_service::{IntoNewTransform, Service, Transform}; use actix_service::{Service, Transform};
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use log::trace; use log::trace;
@ -18,7 +19,6 @@ use brotli2::write::BrotliEncoder;
#[cfg(feature = "flate2")] #[cfg(feature = "flate2")]
use flate2::write::{GzEncoder, ZlibEncoder}; use flate2::write::{GzEncoder, ZlibEncoder};
use crate::middleware::MiddlewareFactory;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -37,6 +37,33 @@ impl Default for Compress {
} }
impl<S, P, B> Transform<S> for Compress impl<S, P, B> Transform<S> for Compress
where
P: 'static,
B: MessageBody,
S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>>,
S::Future: 'static,
{
type Request = ServiceRequest<P>;
type Response = ServiceResponse<Encoder<B>>;
type Error = S::Error;
type InitError = ();
type Transform = CompressMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CompressMiddleware {
service,
encoding: self.0,
})
}
}
pub struct CompressMiddleware<S> {
service: S,
encoding: ContentEncoding,
}
impl<S, P, B> Service for CompressMiddleware<S>
where where
P: 'static, P: 'static,
B: MessageBody, B: MessageBody,
@ -49,14 +76,14 @@ where
type Future = CompressResponse<S, P, B>; type Future = CompressResponse<S, P, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(())) self.service.poll_ready()
} }
fn call(&mut self, req: ServiceRequest<P>, srv: &mut S) -> Self::Future { fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
// negotiate content-encoding // negotiate content-encoding
let encoding = if let Some(val) = req.headers.get(ACCEPT_ENCODING) { let encoding = if let Some(val) = req.headers.get(ACCEPT_ENCODING) {
if let Ok(enc) = val.to_str() { if let Ok(enc) = val.to_str() {
AcceptEncoding::parse(enc, self.0) AcceptEncoding::parse(enc, self.encoding)
} else { } else {
ContentEncoding::Identity ContentEncoding::Identity
} }
@ -66,7 +93,7 @@ where
CompressResponse { CompressResponse {
encoding, encoding,
fut: srv.call(req), fut: self.service.call(req),
} }
} }
} }
@ -102,18 +129,6 @@ where
} }
} }
impl<S, P, B> IntoNewTransform<MiddlewareFactory<Compress, S>, S> for Compress
where
P: 'static,
B: MessageBody,
S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>>,
S::Future: 'static,
{
fn into_new_transform(self) -> MiddlewareFactory<Compress, S> {
MiddlewareFactory::new(self)
}
}
enum EncoderBody<B> { enum EncoderBody<B> {
Body(B), Body(B),
Other(Box<dyn MessageBody>), Other(Box<dyn MessageBody>),

View File

@ -3,10 +3,10 @@ use std::rc::Rc;
use actix_http::http::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use actix_http::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
use actix_http::http::{HeaderMap, HttpTryFrom}; use actix_http::http::{HeaderMap, HttpTryFrom};
use actix_service::{IntoNewTransform, Service, Transform}; use actix_service::{Service, Transform};
use futures::{Async, Future, Poll}; use futures::future::{ok, FutureResult};
use futures::{Future, Poll};
use crate::middleware::MiddlewareFactory;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
/// `Middleware` for setting default response headers. /// `Middleware` for setting default response headers.
@ -84,35 +84,49 @@ impl DefaultHeaders {
} }
} }
impl<S, State, B> IntoNewTransform<MiddlewareFactory<DefaultHeaders, S>, S> impl<S, P, B> Transform<S> for DefaultHeaders
for DefaultHeaders
where where
S: Service<Request = ServiceRequest<State>, Response = ServiceResponse<B>>, S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>>,
S::Future: 'static, S::Future: 'static,
{ {
fn into_new_transform(self) -> MiddlewareFactory<DefaultHeaders, S> { type Request = ServiceRequest<P>;
MiddlewareFactory::new(self) type Response = ServiceResponse<B>;
type Error = S::Error;
type InitError = ();
type Transform = DefaultHeadersMiddleware<S>;
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future {
ok(DefaultHeadersMiddleware {
service,
inner: self.inner.clone(),
})
} }
} }
impl<S, State, B> Transform<S> for DefaultHeaders pub struct DefaultHeadersMiddleware<S> {
service: S,
inner: Rc<Inner>,
}
impl<S, P, B> Service for DefaultHeadersMiddleware<S>
where where
S: Service<Request = ServiceRequest<State>, Response = ServiceResponse<B>>, S: Service<Request = ServiceRequest<P>, Response = ServiceResponse<B>>,
S::Future: 'static, S::Future: 'static,
{ {
type Request = ServiceRequest<State>; type Request = ServiceRequest<P>;
type Response = ServiceResponse<B>; type Response = ServiceResponse<B>;
type Error = S::Error; type Error = S::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>; type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(())) self.service.poll_ready()
} }
fn call(&mut self, req: ServiceRequest<State>, srv: &mut S) -> Self::Future { fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
let inner = self.inner.clone(); let inner = self.inner.clone();
Box::new(srv.call(req).map(move |mut res| { Box::new(self.service.call(req).map(move |mut res| {
// set response headers // set response headers
for (key, value) in inner.headers.iter() { for (key, value) in inner.headers.iter() {
if !res.headers().contains_key(key) { if !res.headers().contains_key(key) {
@ -143,32 +157,44 @@ mod tests {
#[test] #[test]
fn test_default_headers() { fn test_default_headers() {
let mut mw = DefaultHeaders::new().header(CONTENT_TYPE, "0001"); let srv = FnService::new(|req: ServiceRequest<_>| {
let mut srv = FnService::new(|req: ServiceRequest<_>| {
req.into_response(HttpResponse::Ok().finish()) req.into_response(HttpResponse::Ok().finish())
}); });
let mut mw = block_on(
DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(srv),
)
.unwrap();
let req = TestRequest::default().to_service(); let req = TestRequest::default().to_service();
let resp = block_on(mw.call(req, &mut srv)).unwrap(); let resp = block_on(mw.call(req)).unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001"); assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
let req = TestRequest::default().to_service(); let req = TestRequest::default().to_service();
let mut srv = FnService::new(|req: ServiceRequest<_>| { let srv = FnService::new(|req: ServiceRequest<_>| {
req.into_response(HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish()) req.into_response(HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish())
}); });
let resp = block_on(mw.call(req, &mut srv)).unwrap(); let mut mw = block_on(
DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(srv),
)
.unwrap();
let resp = block_on(mw.call(req)).unwrap();
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0002"); assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0002");
} }
#[test] #[test]
fn test_content_type() { fn test_content_type() {
let mut mw = DefaultHeaders::new().content_type(); let srv = FnService::new(|req: ServiceRequest<_>| {
let mut srv = FnService::new(|req: ServiceRequest<_>| {
req.into_response(HttpResponse::Ok().finish()) req.into_response(HttpResponse::Ok().finish())
}); });
let mut mw =
block_on(DefaultHeaders::new().content_type().new_transform(srv)).unwrap();
let req = TestRequest::default().to_service(); let req = TestRequest::default().to_service();
let resp = block_on(mw.call(req, &mut srv)).unwrap(); let resp = block_on(mw.call(req)).unwrap();
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
"application/octet-stream" "application/octet-stream"

View File

@ -1,8 +1,3 @@
use std::marker::PhantomData;
use actix_service::{NewTransform, Service, Transform};
use futures::future::{ok, FutureResult};
#[cfg(any(feature = "brotli", feature = "flate2"))] #[cfg(any(feature = "brotli", feature = "flate2"))]
mod compress; mod compress;
#[cfg(any(feature = "brotli", feature = "flate2"))] #[cfg(any(feature = "brotli", feature = "flate2"))]
@ -10,43 +5,3 @@ pub use self::compress::Compress;
mod defaultheaders; mod defaultheaders;
pub use self::defaultheaders::DefaultHeaders; pub use self::defaultheaders::DefaultHeaders;
/// Helper for middleware service factory
pub struct MiddlewareFactory<T, S>
where
T: Transform<S> + Clone,
S: Service,
{
tr: T,
_t: PhantomData<S>,
}
impl<T, S> MiddlewareFactory<T, S>
where
T: Transform<S> + Clone,
S: Service,
{
pub fn new(tr: T) -> Self {
MiddlewareFactory {
tr,
_t: PhantomData,
}
}
}
impl<T, S, C> NewTransform<S, C> for MiddlewareFactory<T, S>
where
T: Transform<S> + Clone,
S: Service,
{
type Request = T::Request;
type Response = T::Response;
type Error = T::Error;
type Transform = T;
type InitError = ();
type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, _: &C) -> Self::Future {
ok(self.tr.clone())
}
}

View File

@ -4,7 +4,7 @@ use std::rc::Rc;
use actix_http::{Error, Response}; use actix_http::{Error, Response};
use actix_service::boxed::{self, BoxedNewService, BoxedService}; use actix_service::boxed::{self, BoxedNewService, BoxedService};
use actix_service::{ use actix_service::{
ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service, ApplyTransform, IntoNewService, IntoTransform, NewService, Service, Transform,
}; };
use futures::future::{ok, Either, FutureResult}; use futures::future::{ok, Either, FutureResult};
use futures::{Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
@ -194,16 +194,16 @@ where
>, >,
> >
where where
M: NewTransform< M: Transform<
T::Service, T::Service,
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse,
Error = (), Error = (),
InitError = (), InitError = (),
>, >,
F: IntoNewTransform<M, T::Service>, F: IntoTransform<M, T::Service>,
{ {
let endpoint = ApplyNewService::new(mw, self.endpoint); let endpoint = ApplyTransform::new(mw, self.endpoint);
Resource { Resource {
endpoint, endpoint,
routes: self.routes, routes: self.routes,

View File

@ -5,7 +5,7 @@ use actix_http::Response;
use actix_router::{ResourceDef, ResourceInfo, Router}; use actix_router::{ResourceDef, ResourceInfo, Router};
use actix_service::boxed::{self, BoxedNewService, BoxedService}; use actix_service::boxed::{self, BoxedNewService, BoxedService};
use actix_service::{ use actix_service::{
ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service, ApplyTransform, IntoNewService, IntoTransform, NewService, Service, Transform,
}; };
use futures::future::{ok, Either, Future, FutureResult}; use futures::future::{ok, Either, Future, FutureResult};
use futures::{Async, Poll}; use futures::{Async, Poll};
@ -251,16 +251,16 @@ where
>, >,
> >
where where
M: NewTransform< M: Transform<
T::Service, T::Service,
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse,
Error = (), Error = (),
InitError = (), InitError = (),
>, >,
F: IntoNewTransform<M, T::Service>, F: IntoTransform<M, T::Service>,
{ {
let endpoint = ApplyNewService::new(mw, self.endpoint); let endpoint = ApplyTransform::new(mw, self.endpoint);
Scope { Scope {
endpoint, endpoint,
rdef: self.rdef, rdef: self.rdef,