1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-27 17:22:57 +01:00

fix doctest ci (#188)

This commit is contained in:
Rob Ede 2021-06-27 07:02:38 +01:00 committed by GitHub
parent 64eec6e550
commit 20ef05c36e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 255 additions and 206 deletions

9
.cargo/config.toml Normal file
View File

@ -0,0 +1,9 @@
[alias]
chk = "check --workspace --all-features --tests --examples --bins"
lint = "clippy --workspace --tests --examples"
ci-min = "hack check --workspace --no-default-features"
ci-min-test = "hack check --workspace --no-default-features --tests --examples"
ci-default = "check --workspace --bins --tests --examples"
ci-full = "check --workspace --all-features --bins --tests --examples"
ci-test = "test --workspace --all-features --lib --tests --no-fail-fast"
ci-doctest = "hack test --workspace --all-features --doc --no-fail-fast"

View File

@ -31,21 +31,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
# # install OpenSSL on Windows
# - name: Set vcpkg root
# if: matrix.target.triple == 'x86_64-pc-windows-msvc'
# run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
# - name: Install OpenSSL
# if: matrix.target.triple == 'x86_64-pc-windows-msvc'
# run: vcpkg install openssl:x64-windows
- name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}-${{ matrix.target.triple }}
profile: minimal
override: true
- name: Install ${{ matrix.version }} - name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -68,21 +53,32 @@ jobs:
- name: check minimal - name: check minimal
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with: { command: ci-min }
command: hack
args: --clean-per-run check --workspace --no-default-features --tests - name: check minimal + tests
uses: actions-rs/cargo@v1
with: { command: ci-min-test }
- name: check default
uses: actions-rs/cargo@v1
with: { command: ci-default }
- name: check full - name: check full
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with: { command: ci-full }
command: check
args: --workspace --bins --examples --tests
- name: tests - name: tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
timeout-minutes: 40
with: { command: ci-test }
# only run on Linux due to unknown issue with running doc tests on macOS
- name: doc tests
uses: actions-rs/cargo@v1
timeout-minutes: 40
with: with:
command: test command: ci-doctest
args: -v --workspace --all-features --no-fail-fast -- --nocapture args: -- --nocapture
- name: Generate coverage file - name: Generate coverage file
if: > if: >
@ -101,7 +97,7 @@ jobs:
- name: Clear the cargo caches - name: Clear the cargo caches
run: | run: |
cargo install cargo-cache --no-default-features --features ci-autoclean cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache cargo-cache
build_and_test_other: build_and_test_other:
@ -122,21 +118,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
# # install OpenSSL on Windows
# - name: Set vcpkg root
# if: matrix.target.triple == 'x86_64-pc-windows-msvc'
# run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
# - name: Install OpenSSL
# if: matrix.target.triple == 'x86_64-pc-windows-msvc'
# run: vcpkg install openssl:x64-windows
- name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}-${{ matrix.target.triple }}
profile: minimal
override: true
- name: Install ${{ matrix.version }} - name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -159,26 +140,28 @@ jobs:
- name: check minimal - name: check minimal
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with: { command: ci-min }
command: hack
args: --clean-per-run check --workspace --no-default-features --tests - name: check minimal + tests
uses: actions-rs/cargo@v1
with: { command: ci-min-test }
- name: check default
uses: actions-rs/cargo@v1
with: { command: ci-default }
- name: check full - name: check full
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with: { command: ci-full }
command: check
args: --workspace --bins --examples --tests
- name: tests - name: tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
timeout-minutes: 40
with: with:
command: test command: ci-test
args: -v args: --exclude=actix-redis -- --nocapture
--workspace --all-features --no-fail-fast
--exclude=actix-redis
-- --nocapture
- name: Clear the cargo caches - name: Clear the cargo caches
run: | run: |
cargo install cargo-cache --no-default-features --features ci-autoclean cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache cargo-cache

View File

@ -1,12 +1,13 @@
[workspace] [workspace]
members = [ members = [
"actix-cors", "actix-cors",
"actix-identity", "actix-identity",
"actix-protobuf", "actix-protobuf",
"actix-protobuf/examples/prost-example", # TODO: move this example to examples repo
"actix-redis", # "actix-protobuf/examples/prost-example",
"actix-session", "actix-redis",
"actix-web-httpauth", "actix-session",
"actix-web-httpauth",
] ]
[patch.crates-io] [patch.crates-io]

View File

@ -28,8 +28,8 @@ These crates are provided by the community.
| [actix-limitation] | [![crates.io](https://img.shields.io/crates/v/actix-limitation?label=latest)](https://crates.io/crates/actix-limitation) [![Documentation](https://docs.rs/actix-limitation/badge.svg)](https://docs.rs/actix-limitation) [![dependency status](https://deps.rs/crate/actix-limitation/0.1.4/status.svg)](https://deps.rs/crate/actix-limitation/0.1.4) | Rate-limiting using a fixed window counter for arbitrary keys, backed by Redis. | | [actix-limitation] | [![crates.io](https://img.shields.io/crates/v/actix-limitation?label=latest)](https://crates.io/crates/actix-limitation) [![Documentation](https://docs.rs/actix-limitation/badge.svg)](https://docs.rs/actix-limitation) [![dependency status](https://deps.rs/crate/actix-limitation/0.1.4/status.svg)](https://deps.rs/crate/actix-limitation/0.1.4) | Rate-limiting using a fixed window counter for arbitrary keys, backed by Redis. |
| [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)](https://crates.io/crates/actix-casbin) [![Documentation](https://docs.rs/actix-casbin/badge.svg)](https://docs.rs/actix-casbin) [![dependency status](https://deps.rs/crate/actix-casbin/0.4.2/status.svg)](https://deps.rs/crate/actix-casbin/0.4.2) | Authorization library that supports access control models like ACL, RBAC & ABAC. | | [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)](https://crates.io/crates/actix-casbin) [![Documentation](https://docs.rs/actix-casbin/badge.svg)](https://docs.rs/actix-casbin) [![dependency status](https://deps.rs/crate/actix-casbin/0.4.2/status.svg)](https://deps.rs/crate/actix-casbin/0.4.2) | Authorization library that supports access control models like ACL, RBAC & ABAC. |
| [actix-web-static-files] | [![crates.io](https://img.shields.io/crates/v/actix-web-static-files?label=latest)](https://crates.io/crates/actix-web-static-files) [![Documentation](https://docs.rs/actix-web-static-files/badge.svg)](https://docs.rs/actix-web-static-files) [![dependency status](https://deps.rs/crate/actix-web-static-files/3.0.5/status.svg)](https://deps.rs/crate/actix-web-static-files/3.0.5) | Static files as embedded resources. | | [actix-web-static-files] | [![crates.io](https://img.shields.io/crates/v/actix-web-static-files?label=latest)](https://crates.io/crates/actix-web-static-files) [![Documentation](https://docs.rs/actix-web-static-files/badge.svg)](https://docs.rs/actix-web-static-files) [![dependency status](https://deps.rs/crate/actix-web-static-files/3.0.5/status.svg)](https://deps.rs/crate/actix-web-static-files/3.0.5) | Static files as embedded resources. |
| [actix-web-grants] | [![crates.io](https://img.shields.io/crates/v/actix-web-grants?label=latest)](https://crates.io/crates/actix-web-grants) [![Documentation](https://docs.rs/actix-web-grants/badge.svg)](https://docs.rs/actix-web-grants) [![dependency status](https://deps.rs/crate/actix-web-grants/2.0.1/status.svg)](https://deps.rs/crate/actix-web-grants) | Extension for validating user authorities. | | [actix-web-grants] | [![crates.io](https://img.shields.io/crates/v/actix-web-grants?label=latest)](https://crates.io/crates/actix-web-grants) [![Documentation](https://docs.rs/actix-web-grants/badge.svg)](https://docs.rs/actix-web-grants) [![dependency status](https://deps.rs/crate/actix-web-grants/2.0.1/status.svg)](https://deps.rs/crate/actix-web-grants/2.0.1) | Extension for validating user authorities. |
| [aliri_actix] | [![crates.io](https://img.shields.io/crates/v/aliri_actix?label=latest)](https://crates.io/crates/aliri_actix) [![Documentation](https://docs.rs/aliri_actix/badge.svg)](https://docs.rs/aliri_actix) [![dependency status](https://deps.rs/crate/aliri_actix/0.5.0/status.svg)](https://deps.rs/crate/aliri_actix/0.5.0) | Endpoint authorization and authentication using scoped OAuth2 JWT tokens. | | [aliri_actix] | [![crates.io](https://img.shields.io/crates/v/aliri_actix?label=latest)](https://crates.io/crates/aliri_actix) [![Documentation](https://docs.rs/aliri_actix/badge.svg)](https://docs.rs/aliri_actix) [![dependency status](https://deps.rs/crate/aliri_actix/0.5.0/status.svg)](https://deps.rs/crate/aliri_actix/0.5.0) | Endpoint authorization and authentication using scoped OAuth2 JWT tokens. |
To add a crate to this list, submit a pull request. To add a crate to this list, submit a pull request.

View File

@ -6,11 +6,9 @@ authors = [
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
] ]
description = "Cross-Origin Resource Sharing (CORS) controls for Actix Web" description = "Cross-Origin Resource Sharing (CORS) controls for Actix Web"
readme = "README.md"
keywords = ["actix", "cors", "web", "security", "crossorigin"] keywords = ["actix", "cors", "web", "security", "crossorigin"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras.git" repository = "https://github.com/actix/actix-extras"
documentation = "https://docs.rs/actix-cors"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2018" edition = "2018"
@ -19,14 +17,14 @@ name = "actix_cors"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-web = { version = "4.0.0-beta.5", default-features = false } actix-web = { version = "4.0.0-beta.8", default-features = false }
actix-service = "2.0.0-beta.5" actix-service = "2.0.0"
derive_more = "0.99.5" derive_more = "0.99.5"
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }
log = "0.4" log = "0.4"
once_cell = "1" once_cell = "1"
tinyvec = { version = "1", features = ["alloc"] } smallvec = "1.6"
[dev-dependencies] [dev-dependencies]
actix-rt = "2" actix-rt = "2"

View File

@ -9,7 +9,7 @@ use actix_web::{
use futures_util::future::{self, Ready}; use futures_util::future::{self, Ready};
use log::error; use log::error;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tinyvec::tiny_vec; use smallvec::smallvec;
use crate::{AllOrSome, CorsError, CorsMiddleware, Inner, OriginFn}; use crate::{AllOrSome, CorsError, CorsMiddleware, Inner, OriginFn};
@ -82,7 +82,7 @@ impl Cors {
pub fn permissive() -> Self { pub fn permissive() -> Self {
let inner = Inner { let inner = Inner {
allowed_origins: AllOrSome::All, allowed_origins: AllOrSome::All,
allowed_origins_fns: tiny_vec![], allowed_origins_fns: smallvec![],
allowed_methods: ALL_METHODS_SET.clone(), allowed_methods: ALL_METHODS_SET.clone(),
allowed_methods_baked: None, allowed_methods_baked: None,
@ -458,7 +458,7 @@ impl Default for Cors {
fn default() -> Cors { fn default() -> Cors {
let inner = Inner { let inner = Inner {
allowed_origins: AllOrSome::Some(HashSet::with_capacity(8)), allowed_origins: AllOrSome::Some(HashSet::with_capacity(8)),
allowed_origins_fns: tiny_vec![], allowed_origins_fns: smallvec![],
allowed_methods: HashSet::with_capacity(8), allowed_methods: HashSet::with_capacity(8),
allowed_methods_baked: None, allowed_methods_baked: None,
@ -483,13 +483,12 @@ impl Default for Cors {
} }
} }
impl<S, B> Transform<S, ServiceRequest> for Cors impl<S> Transform<S, ServiceRequest> for Cors
where where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse, Error = Error>,
S::Future: 'static, S::Future: 'static,
B: 'static,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
type Transform = CorsMiddleware<S>; type Transform = CorsMiddleware<S>;

View File

@ -9,7 +9,7 @@ use actix_web::{
}, },
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tinyvec::TinyVec; use smallvec::SmallVec;
use crate::{AllOrSome, CorsError}; use crate::{AllOrSome, CorsError};
@ -42,7 +42,7 @@ fn header_value_try_into_method(hdr: &HeaderValue) -> Option<Method> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Inner { pub(crate) struct Inner {
pub(crate) allowed_origins: AllOrSome<HashSet<HeaderValue>>, pub(crate) allowed_origins: AllOrSome<HashSet<HeaderValue>>,
pub(crate) allowed_origins_fns: TinyVec<[OriginFn; 4]>, pub(crate) allowed_origins_fns: SmallVec<[OriginFn; 4]>,
pub(crate) allowed_methods: HashSet<Method>, pub(crate) allowed_methods: HashSet<Method>,
pub(crate) allowed_methods_baked: Option<HeaderValue>, pub(crate) allowed_methods_baked: Option<HeaderValue>,

View File

@ -1,6 +1,7 @@
use std::{convert::TryInto, rc::Rc}; use std::{convert::TryInto, error::Error as StdError, rc::Rc};
use actix_web::{ use actix_web::{
body::{AnyBody, MessageBody},
dev::{Service, ServiceRequest, ServiceResponse}, dev::{Service, ServiceRequest, ServiceResponse},
error::{Error, Result}, error::{Error, Result},
http::{ http::{
@ -9,7 +10,9 @@ use actix_web::{
}, },
HttpResponse, HttpResponse,
}; };
use futures_util::future::{ok, Either, FutureExt as _, LocalBoxFuture, Ready}; use futures_util::future::{
ok, Either, FutureExt as _, LocalBoxFuture, Ready, TryFutureExt as _,
};
use log::debug; use log::debug;
use crate::Inner; use crate::Inner;
@ -26,7 +29,7 @@ pub struct CorsMiddleware<S> {
} }
impl<S> CorsMiddleware<S> { impl<S> CorsMiddleware<S> {
fn handle_preflight<B>(inner: &Inner, req: ServiceRequest) -> ServiceResponse<B> { fn handle_preflight(inner: &Inner, req: ServiceRequest) -> ServiceResponse {
if let Err(err) = inner if let Err(err) = inner
.validate_origin(req.head()) .validate_origin(req.head())
.and_then(|_| inner.validate_allowed_method(req.head())) .and_then(|_| inner.validate_allowed_method(req.head()))
@ -69,7 +72,6 @@ impl<S> CorsMiddleware<S> {
} }
let res = res.finish(); let res = res.finish();
let res = res.into_body();
req.into_response(res) req.into_response(res)
} }
@ -112,20 +114,21 @@ impl<S> CorsMiddleware<S> {
} }
} }
type CorsMiddlewareServiceFuture<B> = Either< type CorsMiddlewareServiceFuture = Either<
Ready<Result<ServiceResponse<B>, Error>>, Ready<Result<ServiceResponse, Error>>,
LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>, LocalBoxFuture<'static, Result<ServiceResponse, Error>>,
>; >;
impl<S, B> Service<ServiceRequest> for CorsMiddleware<S> impl<S, B> Service<ServiceRequest> for CorsMiddleware<S>
where where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static, S::Future: 'static,
B: 'static, B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type Future = CorsMiddlewareServiceFuture<B>; type Future = CorsMiddlewareServiceFuture;
actix_service::forward_ready!(service); actix_service::forward_ready!(service);
@ -158,6 +161,7 @@ where
res res
} }
} }
.map_ok(|res| res.map_body(|_, body| AnyBody::from_message(body)))
.boxed_local(); .boxed_local();
Either::Right(res) Either::Right(res)

View File

@ -3,10 +3,9 @@ name = "actix-identity"
version = "0.4.0-beta.1" version = "0.4.0-beta.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Identity service for Actix web" description = "Identity service for Actix web"
readme = "README.md"
keywords = ["actix", "auth", "identity", "web", "security"] keywords = ["actix", "auth", "identity", "web", "security"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras.git" repository = "https://github.com/actix/actix-extras"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2018" edition = "2018"
@ -15,8 +14,8 @@ name = "actix_identity"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-service = "2.0.0-beta.5" actix-service = "2.0.0"
actix-web = { version = "4.0.0-beta.5", default-features = false, features = ["cookies", "secure-cookies"] } actix-web = { version = "4.0.0-beta.8", default-features = false, features = ["cookies", "secure-cookies"] }
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"

View File

@ -69,16 +69,17 @@ impl CookieIdentityInner {
value: Option<CookieValue>, value: Option<CookieValue>,
) -> Result<()> { ) -> Result<()> {
let add_cookie = value.is_some(); let add_cookie = value.is_some();
let val = value.map(|val| { let val = value
if !self.legacy_supported() { .map(|val| {
serde_json::to_string(&val) if !self.legacy_supported() {
} else { serde_json::to_string(&val)
Ok(val.identity) } else {
} Ok(val.identity)
}); }
})
.transpose()?;
let mut cookie = let mut cookie = Cookie::new(self.name.clone(), val.unwrap_or_default());
Cookie::new(self.name.clone(), val.unwrap_or_else(|| Ok(String::new()))?);
cookie.set_path(self.path.clone()); cookie.set_path(self.path.clone());
cookie.set_secure(self.secure); cookie.set_secure(self.secure);
cookie.set_http_only(true); cookie.set_http_only(true);
@ -108,10 +109,10 @@ impl CookieIdentityInner {
}; };
if add_cookie { if add_cookie {
jar.private(&key).add(cookie); jar.private_mut(&key).add(cookie);
} else { } else {
jar.add_original(cookie.clone()); jar.add_original(cookie.clone());
jar.private(&key).remove(cookie); jar.private_mut(&key).remove(cookie);
} }
for cookie in jar.delta() { for cookie in jar.delta() {
@ -128,17 +129,19 @@ impl CookieIdentityInner {
jar.add_original(cookie.clone()); jar.add_original(cookie.clone());
let res = if self.legacy_supported() { let res = if self.legacy_supported() {
jar.private(&self.key).get(&self.name).map(|n| CookieValue { jar.private_mut(&self.key)
identity: n.value().to_string(), .get(&self.name)
login_timestamp: None, .map(|n| CookieValue {
visit_timestamp: None, identity: n.value().to_string(),
}) login_timestamp: None,
visit_timestamp: None,
})
} else { } else {
None None
}; };
res.or_else(|| { res.or_else(|| {
jar.private(&self.key_v2) jar.private_mut(&self.key_v2)
.get(&self.name) .get(&self.name)
.and_then(|c| self.parse(c)) .and_then(|c| self.parse(c))
}) })
@ -391,7 +394,7 @@ mod tests {
.copied() .copied()
.collect(); .collect();
jar.private(&Key::derive_from(&key)).add(Cookie::new( jar.private_mut(&Key::derive_from(&key)).add(Cookie::new(
COOKIE_NAME, COOKIE_NAME,
serde_json::to_string(&CookieValue { serde_json::to_string(&CookieValue {
identity: identity.to_string(), identity: identity.to_string(),
@ -575,7 +578,7 @@ mod tests {
fn legacy_login_cookie(identity: &'static str) -> Cookie<'static> { fn legacy_login_cookie(identity: &'static str) -> Cookie<'static> {
let mut jar = CookieJar::new(); let mut jar = CookieJar::new();
jar.private(&Key::derive_from(&COOKIE_KEY_MASTER)) jar.private_mut(&Key::derive_from(&COOKIE_KEY_MASTER))
.add(Cookie::new(COOKIE_NAME, identity)); .add(Cookie::new(COOKIE_NAME, identity));
jar.get(COOKIE_NAME).unwrap().clone() jar.get(COOKIE_NAME).unwrap().clone()
} }
@ -592,7 +595,7 @@ mod tests {
cookies.add(Cookie::parse(cookie.to_str().unwrap().to_string()).unwrap()); cookies.add(Cookie::parse(cookie.to_str().unwrap().to_string()).unwrap());
} }
let cookie = cookies let cookie = cookies
.private(&Key::derive_from(&COOKIE_KEY_MASTER)) .private_mut(&Key::derive_from(&COOKIE_KEY_MASTER))
.get(COOKIE_NAME) .get(COOKIE_NAME)
.unwrap(); .unwrap();
assert_eq!(cookie.value(), identity); assert_eq!(cookie.value(), identity);

View File

@ -1,10 +1,13 @@
use std::rc::Rc; use std::{error::Error as StdError, rc::Rc};
use actix_web::{ use actix_web::{
body::{AnyBody, MessageBody},
dev::{Service, ServiceRequest, ServiceResponse, Transform}, dev::{Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpMessage, Result, Error, HttpMessage, Result,
}; };
use futures_util::future::{ready, FutureExt, LocalBoxFuture, Ready}; use futures_util::future::{
ready, FutureExt as _, LocalBoxFuture, Ready, TryFutureExt as _,
};
use crate::{identity::IdentityItem, IdentityPolicy}; use crate::{identity::IdentityItem, IdentityPolicy};
@ -41,9 +44,10 @@ where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static, S::Future: 'static,
T: IdentityPolicy, T: IdentityPolicy,
B: 'static, B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type InitError = (); type InitError = ();
type Transform = IdentityServiceMiddleware<S, T>; type Transform = IdentityServiceMiddleware<S, T>;
@ -73,12 +77,13 @@ impl<S, T> Clone for IdentityServiceMiddleware<S, T> {
impl<S, T, B> Service<ServiceRequest> for IdentityServiceMiddleware<S, T> impl<S, T, B> Service<ServiceRequest> for IdentityServiceMiddleware<S, T>
where where
B: 'static,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static, S::Future: 'static,
T: IdentityPolicy, T: IdentityPolicy,
B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
@ -100,16 +105,19 @@ where
if let Some(id) = id { if let Some(id) = id {
match backend.to_response(id.id, id.changed, &mut res).await { match backend.to_response(id.id, id.changed, &mut res).await {
Ok(_) => Ok(res), Ok(_) => {
Ok(res.map_body(|_, body| AnyBody::from_message(body)))
}
Err(e) => Ok(res.error_response(e)), Err(e) => Ok(res.error_response(e)),
} }
} else { } else {
Ok(res) Ok(res.map_body(|_, body| AnyBody::from_message(body)))
} }
} }
Err(err) => Ok(req.error_response(err)), Err(err) => Ok(req.error_response(err)),
} }
} }
.map_ok(|res| res.map_body(|_, body| AnyBody::from_message(body)))
.boxed_local() .boxed_local()
} }
} }

View File

@ -7,10 +7,9 @@ authors = [
"Yuki Okushi <huyuumi.dev@gmail.com>" "Yuki Okushi <huyuumi.dev@gmail.com>"
] ]
description = "Protobuf support for Actix web" description = "Protobuf support for Actix web"
readme = "README.md"
keywords = ["actix", "protobuf", "protocol", "rpc"] keywords = ["actix", "protobuf", "protocol", "rpc"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras.git" repository = "https://github.com/actix/actix-extras"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
exclude = [".cargo/config", "/examples/**"] exclude = [".cargo/config", "/examples/**"]
@ -20,7 +19,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
actix-rt = "2" actix-rt = "2"
actix-web = { version = "4.0.0-beta.5", default_features = false } actix-web = { version = "4.0.0-beta.8", default_features = false }
derive_more = "0.99.5" derive_more = "0.99.5"
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }
prost = "0.7" prost = "0.7"

View File

@ -8,7 +8,7 @@ authors = [
] ]
[dependencies] [dependencies]
actix-web = "4.0.0-beta.5" actix-web = "4.0.0-beta.8"
actix-protobuf = { path = "../../" } actix-protobuf = { path = "../../" }
env_logger = "0.8" env_logger = "0.8"

View File

@ -1,39 +1,49 @@
#![deny(rust_2018_idioms)] #![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style)]
use std::{
fmt,
future::Future,
ops::{Deref, DerefMut},
pin::Pin,
task::{self, Poll},
};
use actix_web::{
dev::Payload,
error::PayloadError,
http::header::{CONTENT_LENGTH, CONTENT_TYPE},
web::BytesMut,
Error, FromRequest, HttpMessage, HttpRequest, HttpResponse, HttpResponseBuilder,
Responder, ResponseError,
};
use derive_more::Display; use derive_more::Display;
use std::fmt; use futures_util::{
use std::future::Future; future::{FutureExt as _, LocalBoxFuture},
use std::ops::{Deref, DerefMut}; stream::StreamExt as _,
use std::pin::Pin; };
use std::task; use prost::{
use std::task::Poll; DecodeError as ProtoBufDecodeError, EncodeError as ProtoBufEncodeError, Message,
};
use prost::DecodeError as ProtoBufDecodeError;
use prost::EncodeError as ProtoBufEncodeError;
use prost::Message;
use actix_web::dev::{HttpResponseBuilder, Payload};
use actix_web::error::{Error, PayloadError, ResponseError};
use actix_web::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
use actix_web::web::BytesMut;
use actix_web::{FromRequest, HttpMessage, HttpRequest, HttpResponse, Responder};
use futures_util::future::{FutureExt, LocalBoxFuture};
use futures_util::StreamExt;
#[derive(Debug, Display)] #[derive(Debug, Display)]
pub enum ProtoBufPayloadError { pub enum ProtoBufPayloadError {
/// Payload size is bigger than 256k /// Payload size is bigger than 256k
#[display(fmt = "Payload size is bigger than 256k")] #[display(fmt = "Payload size is bigger than 256k")]
Overflow, Overflow,
/// Content type error /// Content type error
#[display(fmt = "Content type error")] #[display(fmt = "Content type error")]
ContentType, ContentType,
/// Serialize error /// Serialize error
#[display(fmt = "ProtoBuf serialize error: {}", _0)] #[display(fmt = "ProtoBuf serialize error: {}", _0)]
Serialize(ProtoBufEncodeError), Serialize(ProtoBufEncodeError),
/// Deserialize error /// Deserialize error
#[display(fmt = "ProtoBuf deserialize error: {}", _0)] #[display(fmt = "ProtoBuf deserialize error: {}", _0)]
Deserialize(ProtoBufDecodeError), Deserialize(ProtoBufDecodeError),
/// Payload error /// Payload error
#[display(fmt = "Error that occur during reading payload: {}", _0)] #[display(fmt = "Error that occur during reading payload: {}", _0)]
Payload(PayloadError), Payload(PayloadError),

View File

@ -4,11 +4,9 @@ version = "0.10.0-beta.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Redis integration for Actix and session store for Actix Web" description = "Redis integration for Actix and session store for Actix Web"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
readme = "README.md"
keywords = ["actix", "redis", "async", "session"] keywords = ["actix", "redis", "async", "session"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras.git" repository = "https://github.com/actix/actix-extras"
documentation = "https://docs.rs/actix-redis/"
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
exclude = [".cargo/config"] exclude = [".cargo/config"]
edition = "2018" edition = "2018"
@ -31,9 +29,9 @@ web = [
] ]
[dependencies] [dependencies]
actix = { version = "0.11.0", default-features = false } actix = { version = "0.12.0", default-features = false }
actix-rt = { version = "2.1", default-features = false } actix-rt = { version = "2.1", default-features = false }
actix-service = "2.0.0-beta.5" actix-service = "2.0.0"
actix-tls = { version = "3.0.0-beta.5", default-features = false, features = ["connect"] } actix-tls = { version = "3.0.0-beta.5", default-features = false, features = ["connect"] }
log = "0.4.6" log = "0.4.6"
@ -47,15 +45,23 @@ tokio = { version = "1", features = ["sync"] }
tokio-util = "0.6.1" tokio-util = "0.6.1"
# actix-session # actix-session
actix-web = { version = "4.0.0-beta.5", default_features = false, optional = true } actix-web = { version = "4.0.0-beta.8", default_features = false, optional = true }
actix-session = { version = "0.5.0-beta.1", optional = true } actix-session = { version = "0.5.0-beta.1", optional = true }
rand = { version = "0.8.0", optional = true } rand = { version = "0.8.0", optional = true }
serde = { version = "1.0.101", optional = true } serde = { version = "1.0.101", optional = true }
serde_json = { version = "1.0.40", optional = true } serde_json = { version = "1.0.40", optional = true }
[dev-dependencies] [dev-dependencies]
actix-test = "0.1.0-beta.1" actix-test = "0.1.0-beta.3"
actix-http = "3.0.0-beta.5" actix-http = "3.0.0-beta.5"
actix-rt = "2.1" actix-rt = "2.1"
env_logger = "0.7" env_logger = "0.8"
serde_derive = "1.0" serde = { version = "1.0.101", features = ["derive"] }
[[example]]
name = "basic"
required-features = ["web"]
[[example]]
name = "authentication"
required-features = ["web"]

View File

@ -1,7 +1,8 @@
use actix_redis::RedisSession; use actix_redis::RedisSession;
use actix_session::Session; use actix_session::Session;
use actix_web::{ use actix_web::{
cookie, middleware, web, App, Error, HttpResponse, HttpServer, Responder, cookie, error::InternalError, middleware, web, App, Error, HttpResponse, HttpServer,
Responder,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -49,12 +50,12 @@ pub fn validate_session(session: &Session) -> Result<i64, HttpResponse> {
async fn login( async fn login(
credentials: web::Json<Credentials>, credentials: web::Json<Credentials>,
session: Session, session: Session,
) -> Result<impl Responder, HttpResponse> { ) -> Result<impl Responder, Error> {
let credentials = credentials.into_inner(); let credentials = credentials.into_inner();
match User::authenticate(credentials) { match User::authenticate(credentials) {
Ok(user) => session.insert("user_id", user.id).unwrap(), Ok(user) => session.insert("user_id", user.id).unwrap(),
Err(_) => return Err(HttpResponse::Unauthorized().json("Unauthorized")), Err(err) => return Err(InternalError::from_response("", err).into()),
}; };
Ok("Welcome!") Ok("Welcome!")
@ -63,7 +64,7 @@ async fn login(
/// some protected resource /// some protected resource
async fn secret(session: Session) -> Result<impl Responder, Error> { async fn secret(session: Session) -> Result<impl Responder, Error> {
// only allow access to this resource if the user has an active session // only allow access to this resource if the user has an active session
validate_session(&session)?; validate_session(&session).map_err(|err| InternalError::from_response("", err))?;
Ok("secret revealed") Ok("secret revealed")
} }

View File

@ -3,14 +3,16 @@ use std::{collections::HashMap, iter, rc::Rc};
use actix::prelude::*; use actix::prelude::*;
use actix_service::{Service, Transform}; use actix_service::{Service, Transform};
use actix_session::{Session, SessionStatus}; use actix_session::{Session, SessionStatus};
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; use actix_web::{
use actix_web::dev::{ServiceRequest, ServiceResponse}; cookie::{Cookie, CookieJar, Key, SameSite},
use actix_web::http::header::{self, HeaderValue}; dev::{ServiceRequest, ServiceResponse},
use actix_web::{error, Error, HttpMessage}; error,
http::header::{self, HeaderValue},
Error,
};
use futures_core::future::LocalBoxFuture; use futures_core::future::LocalBoxFuture;
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
use redis_async::resp::RespValue; use redis_async::{resp::RespValue, resp_array};
use redis_async::resp_array;
use time::{self, Duration, OffsetDateTime}; use time::{self, Duration, OffsetDateTime};
use crate::redis::{Command, RedisActor}; use crate::redis::{Command, RedisActor};
@ -311,7 +313,7 @@ impl Inner {
// set cookie // set cookie
let mut jar = CookieJar::new(); let mut jar = CookieJar::new();
jar.signed(&self.key).add(cookie); jar.signed_mut(&self.key).add(cookie);
(value, Some(jar)) (value, Some(jar))
}; };
@ -321,7 +323,7 @@ impl Inner {
let state: HashMap<_, _> = state.collect(); let state: HashMap<_, _> = state.collect();
let body = match serde_json::to_string(&state) { let body = match serde_json::to_string(&state) {
Err(e) => return Err(e.into()), Err(err) => return Err(err.into()),
Ok(body) => body, Ok(body) => body,
}; };
@ -442,12 +444,15 @@ mod test {
async fn logout(session: Session) -> Result<HttpResponse> { async fn logout(session: Session) -> Result<HttpResponse> {
let id: Option<String> = session.get("user_id")?; let id: Option<String> = session.get("user_id")?;
if let Some(x) = id {
let body = if let Some(x) = id {
session.purge(); session.purge();
Ok(format!("Logged out: {}", x).into()) format!("Logged out: {}", x)
} else { } else {
Ok("Could not log out anonymous user".into()) "Could not log out anonymous user".to_owned()
} };
Ok(HttpResponse::Ok().body(body))
} }
#[actix_rt::test] #[actix_rt::test]
@ -648,7 +653,10 @@ mod test {
.unwrap(); .unwrap();
assert_ne!( assert_ne!(
OffsetDateTime::now_utc().year(), OffsetDateTime::now_utc().year(),
cookie_4.expires().map(|t| t.year()).unwrap() cookie_4
.expires()
.map(|t| t.datetime().expect("Expiration is a datetime").year())
.unwrap()
); );
// Step 10: GET index, including session cookie #2 in request // Step 10: GET index, including session cookie #2 in request

View File

@ -3,11 +3,9 @@ name = "actix-session"
version = "0.5.0-beta.1" version = "0.5.0-beta.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Sessions for Actix web" description = "Sessions for Actix web"
readme = "README.md"
keywords = ["http", "web", "framework", "async", "session"] keywords = ["http", "web", "framework", "async", "session"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras" repository = "https://github.com/actix/actix-extras"
documentation = "https://docs.rs/actix-session/"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2018" edition = "2018"
@ -20,8 +18,8 @@ default = ["cookie-session"]
cookie-session = ["actix-web/secure-cookies"] cookie-session = ["actix-web/secure-cookies"]
[dependencies] [dependencies]
actix-web = { version = "4.0.0-beta.5", default_features = false, features = ["cookies"] } actix-web = { version = "4.0.0-beta.8", default_features = false, features = ["cookies"] }
actix-service = "2.0.0-beta.5" actix-service = "2.0.0"
derive_more = "0.99.5" derive_more = "0.99.5"
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }

View File

@ -1,14 +1,16 @@
//! Cookie based sessions. See docs for [`CookieSession`]. //! Cookie based sessions. See docs for [`CookieSession`].
use std::{collections::HashMap, rc::Rc}; use std::{collections::HashMap, error::Error as StdError, rc::Rc};
use actix_service::{Service, Transform}; use actix_web::{
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; body::{AnyBody, MessageBody},
use actix_web::dev::{ServiceRequest, ServiceResponse}; cookie::{Cookie, CookieJar, Key, SameSite},
use actix_web::http::{header::SET_COOKIE, HeaderValue}; dev::{Service, ServiceRequest, ServiceResponse, Transform},
use actix_web::{Error, HttpMessage, ResponseError}; http::{header::SET_COOKIE, HeaderValue},
Error, ResponseError,
};
use derive_more::Display; use derive_more::Display;
use futures_util::future::{ok, LocalBoxFuture, Ready}; use futures_util::future::{ok, FutureExt as _, LocalBoxFuture, Ready};
use serde_json::error::Error as JsonError; use serde_json::error::Error as JsonError;
use time::{Duration, OffsetDateTime}; use time::{Duration, OffsetDateTime};
@ -106,8 +108,8 @@ impl CookieSessionInner {
let mut jar = CookieJar::new(); let mut jar = CookieJar::new();
match self.security { match self.security {
CookieSecurity::Signed => jar.signed(&self.key).add(cookie), CookieSecurity::Signed => jar.signed_mut(&self.key).add(cookie),
CookieSecurity::Private => jar.private(&self.key).add(cookie), CookieSecurity::Private => jar.private_mut(&self.key).add(cookie),
} }
for cookie in jar.delta() { for cookie in jar.delta() {
@ -292,13 +294,15 @@ impl CookieSession {
} }
} }
impl<S, B: 'static> Transform<S, ServiceRequest> for CookieSession impl<S, B> Transform<S, ServiceRequest> for CookieSession
where where
S: Service<ServiceRequest, Response = ServiceResponse<B>>, S: Service<ServiceRequest, Response = ServiceResponse<B>>,
S::Future: 'static, S::Future: 'static,
S::Error: 'static, S::Error: 'static,
B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = S::Error; type Error = S::Error;
type InitError = (); type InitError = ();
type Transform = CookieSessionMiddleware<S>; type Transform = CookieSessionMiddleware<S>;
@ -318,13 +322,15 @@ pub struct CookieSessionMiddleware<S> {
inner: Rc<CookieSessionInner>, inner: Rc<CookieSessionInner>,
} }
impl<S, B: 'static> Service<ServiceRequest> for CookieSessionMiddleware<S> impl<S, B> Service<ServiceRequest> for CookieSessionMiddleware<S>
where where
S: Service<ServiceRequest, Response = ServiceResponse<B>>, S: Service<ServiceRequest, Response = ServiceResponse<B>>,
S::Future: 'static, S::Future: 'static,
S::Error: 'static, S::Error: 'static,
B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = S::Error; type Error = S::Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
@ -343,36 +349,40 @@ where
let fut = self.service.call(req); let fut = self.service.call(req);
Box::pin(async move { async move {
let mut res = fut.await?; let mut res = fut.await?;
let res = match Session::get_changes(&mut res) { let result = match Session::get_changes(&mut res) {
(SessionStatus::Changed, state) | (SessionStatus::Renewed, state) => { (SessionStatus::Changed, state) | (SessionStatus::Renewed, state) => {
res.checked_expr(|res| inner.set_cookie(res, state)) inner.set_cookie(&mut res, state)
} }
(SessionStatus::Unchanged, state) if prolong_expiration => { (SessionStatus::Unchanged, state) if prolong_expiration => {
res.checked_expr(|res| inner.set_cookie(res, state)) inner.set_cookie(&mut res, state)
} }
// set a new session cookie upon first request (new client) // set a new session cookie upon first request (new client)
(SessionStatus::Unchanged, _) => { (SessionStatus::Unchanged, _) => {
if is_new { if is_new {
let state: HashMap<String, String> = HashMap::new(); let state: HashMap<String, String> = HashMap::new();
res.checked_expr(|res| inner.set_cookie(res, state.into_iter())) inner.set_cookie(&mut res, state.into_iter())
} else { } else {
res Ok(())
} }
} }
(SessionStatus::Purged, _) => { (SessionStatus::Purged, _) => {
let _ = inner.remove_cookie(&mut res); let _ = inner.remove_cookie(&mut res);
res Ok(())
} }
}; };
Ok(res) match result {
}) Ok(()) => Ok(res.map_body(|_, body| AnyBody::from_message(body))),
Err(error) => Ok(res.error_response(error)),
}
}
.boxed_local()
} }
} }
@ -533,7 +543,9 @@ mod tests {
.find(|c| c.name() == "actix-session") .find(|c| c.name() == "actix-session")
.expect("Cookie is set") .expect("Cookie is set")
.expires() .expires()
.expect("Expiration is set"); .expect("Expiration is set")
.datetime()
.expect("Expiration is a datetime");
actix_rt::time::sleep(std::time::Duration::from_secs(1)).await; actix_rt::time::sleep(std::time::Duration::from_secs(1)).await;
@ -545,7 +557,9 @@ mod tests {
.find(|c| c.name() == "actix-session") .find(|c| c.name() == "actix-session")
.expect("Cookie is set") .expect("Cookie is set")
.expires() .expires()
.expect("Expiration is set"); .expect("Expiration is set")
.datetime()
.expect("Expiration is a datetime");
assert!(expires_2 - expires_1 >= Duration::seconds(1)); assert!(expires_2 - expires_1 >= Duration::seconds(1));
} }

View File

@ -6,11 +6,9 @@ authors = [
"Yuki Okushi <huyuumi.dev@gmail.com>", "Yuki Okushi <huyuumi.dev@gmail.com>",
] ]
description = "HTTP authentication schemes for Actix web" description = "HTTP authentication schemes for Actix web"
readme = "README.md"
keywords = ["http", "web", "framework", "authentication", "security"] keywords = ["http", "web", "framework", "authentication", "security"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-extras.git" repository = "https://github.com/actix/actix-extras"
documentation = "https://docs.rs/actix-web-httpauth/"
categories = ["web-programming::http-server"] categories = ["web-programming::http-server"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2018" edition = "2018"
@ -20,8 +18,8 @@ name = "actix_web_httpauth"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-web = { version = "4.0.0-beta.5", default_features = false } actix-web = { version = "4.0.0-beta.8", default_features = false }
actix-service = "2.0.0-beta.5" actix-service = "2.0.0"
base64 = "0.13" base64 = "0.13"
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }

View File

@ -81,7 +81,7 @@ impl AuthExtractorConfig for Config {
/// ///
/// fn main() { /// fn main() {
/// let app = App::new() /// let app = App::new()
/// .data(Config::default().realm("Restricted area")) /// .app_data(Config::default().realm("Restricted area"))
/// .service(web::resource("/index.html").route(web::get().to(index))); /// .service(web::resource("/index.html").route(web::get().to(index)));
/// } /// }
/// ``` /// ```

View File

@ -84,7 +84,7 @@ impl AuthExtractorConfig for Config {
/// ///
/// fn main() { /// fn main() {
/// let app = App::new() /// let app = App::new()
/// .data( /// .app_data(
/// Config::default() /// Config::default()
/// .realm("Restricted area") /// .realm("Restricted area")
/// .scope("email photo"), /// .scope("email photo"),

View File

@ -1,8 +1,12 @@
//! HTTP Authentication middleware. //! HTTP Authentication middleware.
use std::{future::Future, marker::PhantomData, pin::Pin, rc::Rc, sync::Arc}; use std::{
error::Error as StdError, future::Future, marker::PhantomData, pin::Pin, rc::Rc,
sync::Arc,
};
use actix_web::{ use actix_web::{
body::{AnyBody, MessageBody},
dev::{Service, ServiceRequest, ServiceResponse, Transform}, dev::{Service, ServiceRequest, ServiceResponse, Transform},
Error, Error,
}; };
@ -120,8 +124,10 @@ where
F: Fn(ServiceRequest, T) -> O + 'static, F: Fn(ServiceRequest, T) -> O + 'static,
O: Future<Output = Result<ServiceRequest, Error>> + 'static, O: Future<Output = Result<ServiceRequest, Error>> + 'static,
T: AuthExtractor + 'static, T: AuthExtractor + 'static,
B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = Error; type Error = Error;
type Transform = AuthenticationMiddleware<S, F, T>; type Transform = AuthenticationMiddleware<S, F, T>;
type InitError = (); type InitError = ();
@ -153,10 +159,12 @@ where
F: Fn(ServiceRequest, T) -> O + 'static, F: Fn(ServiceRequest, T) -> O + 'static,
O: Future<Output = Result<ServiceRequest, Error>> + 'static, O: Future<Output = Result<ServiceRequest, Error>> + 'static,
T: AuthExtractor + 'static, T: AuthExtractor + 'static,
B: MessageBody + 'static,
B::Error: StdError,
{ {
type Response = ServiceResponse<B>; type Response = ServiceResponse;
type Error = S::Error; type Error = S::Error;
type Future = LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>; type Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
actix_service::forward_ready!(service); actix_service::forward_ready!(service);
@ -177,7 +185,10 @@ where
// middleware to do their thing (eg. cors adding headers) // middleware to do their thing (eg. cors adding headers)
let req = process_fn(req, credentials).await?; let req = process_fn(req, credentials).await?;
service.call(req).await service
.call(req)
.await
.map(|res| res.map_body(|_, body| AnyBody::from_message(body)))
} }
.boxed_local() .boxed_local()
} }