mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-23 15:51:06 +01:00
fix doctest ci (#188)
This commit is contained in:
parent
64eec6e550
commit
20ef05c36e
9
.cargo/config.toml
Normal file
9
.cargo/config.toml
Normal 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"
|
85
.github/workflows/ci.yml
vendored
85
.github/workflows/ci.yml
vendored
@ -31,21 +31,6 @@ jobs:
|
||||
steps:
|
||||
- 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 }}
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -68,21 +53,32 @@ jobs:
|
||||
|
||||
- name: check minimal
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: hack
|
||||
args: --clean-per-run check --workspace --no-default-features --tests
|
||||
with: { command: ci-min }
|
||||
|
||||
- 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
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --workspace --bins --examples --tests
|
||||
with: { command: ci-full }
|
||||
|
||||
- name: tests
|
||||
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:
|
||||
command: test
|
||||
args: -v --workspace --all-features --no-fail-fast -- --nocapture
|
||||
command: ci-doctest
|
||||
args: -- --nocapture
|
||||
|
||||
- name: Generate coverage file
|
||||
if: >
|
||||
@ -101,7 +97,7 @@ jobs:
|
||||
|
||||
- name: Clear the cargo caches
|
||||
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
|
||||
|
||||
build_and_test_other:
|
||||
@ -122,21 +118,6 @@ jobs:
|
||||
steps:
|
||||
- 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 }}
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -159,26 +140,28 @@ jobs:
|
||||
|
||||
- name: check minimal
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: hack
|
||||
args: --clean-per-run check --workspace --no-default-features --tests
|
||||
with: { command: ci-min }
|
||||
|
||||
- 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
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --workspace --bins --examples --tests
|
||||
with: { command: ci-full }
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
timeout-minutes: 40
|
||||
with:
|
||||
command: test
|
||||
args: -v
|
||||
--workspace --all-features --no-fail-fast
|
||||
--exclude=actix-redis
|
||||
-- --nocapture
|
||||
command: ci-test
|
||||
args: --exclude=actix-redis -- --nocapture
|
||||
|
||||
- name: Clear the cargo caches
|
||||
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
|
||||
|
15
Cargo.toml
15
Cargo.toml
@ -1,12 +1,13 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"actix-cors",
|
||||
"actix-identity",
|
||||
"actix-protobuf",
|
||||
"actix-protobuf/examples/prost-example",
|
||||
"actix-redis",
|
||||
"actix-session",
|
||||
"actix-web-httpauth",
|
||||
"actix-cors",
|
||||
"actix-identity",
|
||||
"actix-protobuf",
|
||||
# TODO: move this example to examples repo
|
||||
# "actix-protobuf/examples/prost-example",
|
||||
"actix-redis",
|
||||
"actix-session",
|
||||
"actix-web-httpauth",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
@ -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-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-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. |
|
||||
| [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. |
|
||||
| [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. |
|
||||
|
||||
To add a crate to this list, submit a pull request.
|
||||
|
||||
|
@ -6,11 +6,9 @@ authors = [
|
||||
"Rob Ede <robjtede@icloud.com>",
|
||||
]
|
||||
description = "Cross-Origin Resource Sharing (CORS) controls for Actix Web"
|
||||
readme = "README.md"
|
||||
keywords = ["actix", "cors", "web", "security", "crossorigin"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-extras.git"
|
||||
documentation = "https://docs.rs/actix-cors"
|
||||
repository = "https://github.com/actix/actix-extras"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
@ -19,14 +17,14 @@ name = "actix_cors"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.5", default-features = false }
|
||||
actix-service = "2.0.0-beta.5"
|
||||
actix-web = { version = "4.0.0-beta.8", default-features = false }
|
||||
actix-service = "2.0.0"
|
||||
|
||||
derive_more = "0.99.5"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
log = "0.4"
|
||||
once_cell = "1"
|
||||
tinyvec = { version = "1", features = ["alloc"] }
|
||||
smallvec = "1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2"
|
||||
|
@ -9,7 +9,7 @@ use actix_web::{
|
||||
use futures_util::future::{self, Ready};
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
use tinyvec::tiny_vec;
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::{AllOrSome, CorsError, CorsMiddleware, Inner, OriginFn};
|
||||
|
||||
@ -82,7 +82,7 @@ impl Cors {
|
||||
pub fn permissive() -> Self {
|
||||
let inner = Inner {
|
||||
allowed_origins: AllOrSome::All,
|
||||
allowed_origins_fns: tiny_vec![],
|
||||
allowed_origins_fns: smallvec![],
|
||||
|
||||
allowed_methods: ALL_METHODS_SET.clone(),
|
||||
allowed_methods_baked: None,
|
||||
@ -458,7 +458,7 @@ impl Default for Cors {
|
||||
fn default() -> Cors {
|
||||
let inner = Inner {
|
||||
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_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
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = CorsMiddleware<S>;
|
||||
|
@ -9,7 +9,7 @@ use actix_web::{
|
||||
},
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use tinyvec::TinyVec;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{AllOrSome, CorsError};
|
||||
|
||||
@ -42,7 +42,7 @@ fn header_value_try_into_method(hdr: &HeaderValue) -> Option<Method> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Inner {
|
||||
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_baked: Option<HeaderValue>,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::{convert::TryInto, rc::Rc};
|
||||
use std::{convert::TryInto, error::Error as StdError, rc::Rc};
|
||||
|
||||
use actix_web::{
|
||||
body::{AnyBody, MessageBody},
|
||||
dev::{Service, ServiceRequest, ServiceResponse},
|
||||
error::{Error, Result},
|
||||
http::{
|
||||
@ -9,7 +10,9 @@ use actix_web::{
|
||||
},
|
||||
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 crate::Inner;
|
||||
@ -26,7 +29,7 @@ pub struct 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
|
||||
.validate_origin(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.into_body();
|
||||
req.into_response(res)
|
||||
}
|
||||
|
||||
@ -112,20 +114,21 @@ impl<S> CorsMiddleware<S> {
|
||||
}
|
||||
}
|
||||
|
||||
type CorsMiddlewareServiceFuture<B> = Either<
|
||||
Ready<Result<ServiceResponse<B>, Error>>,
|
||||
LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>,
|
||||
type CorsMiddlewareServiceFuture = Either<
|
||||
Ready<Result<ServiceResponse, Error>>,
|
||||
LocalBoxFuture<'static, Result<ServiceResponse, Error>>,
|
||||
>;
|
||||
|
||||
impl<S, B> Service<ServiceRequest> for CorsMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = CorsMiddlewareServiceFuture<B>;
|
||||
type Future = CorsMiddlewareServiceFuture;
|
||||
|
||||
actix_service::forward_ready!(service);
|
||||
|
||||
@ -158,6 +161,7 @@ where
|
||||
res
|
||||
}
|
||||
}
|
||||
.map_ok(|res| res.map_body(|_, body| AnyBody::from_message(body)))
|
||||
.boxed_local();
|
||||
|
||||
Either::Right(res)
|
||||
|
@ -3,10 +3,9 @@ name = "actix-identity"
|
||||
version = "0.4.0-beta.1"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Identity service for Actix web"
|
||||
readme = "README.md"
|
||||
keywords = ["actix", "auth", "identity", "web", "security"]
|
||||
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"
|
||||
edition = "2018"
|
||||
|
||||
@ -15,8 +14,8 @@ name = "actix_identity"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-service = "2.0.0-beta.5"
|
||||
actix-web = { version = "4.0.0-beta.5", default-features = false, features = ["cookies", "secure-cookies"] }
|
||||
actix-service = "2.0.0"
|
||||
actix-web = { version = "4.0.0-beta.8", default-features = false, features = ["cookies", "secure-cookies"] }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
@ -69,16 +69,17 @@ impl CookieIdentityInner {
|
||||
value: Option<CookieValue>,
|
||||
) -> Result<()> {
|
||||
let add_cookie = value.is_some();
|
||||
let val = value.map(|val| {
|
||||
if !self.legacy_supported() {
|
||||
serde_json::to_string(&val)
|
||||
} else {
|
||||
Ok(val.identity)
|
||||
}
|
||||
});
|
||||
let val = value
|
||||
.map(|val| {
|
||||
if !self.legacy_supported() {
|
||||
serde_json::to_string(&val)
|
||||
} else {
|
||||
Ok(val.identity)
|
||||
}
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let mut cookie =
|
||||
Cookie::new(self.name.clone(), val.unwrap_or_else(|| Ok(String::new()))?);
|
||||
let mut cookie = Cookie::new(self.name.clone(), val.unwrap_or_default());
|
||||
cookie.set_path(self.path.clone());
|
||||
cookie.set_secure(self.secure);
|
||||
cookie.set_http_only(true);
|
||||
@ -108,10 +109,10 @@ impl CookieIdentityInner {
|
||||
};
|
||||
|
||||
if add_cookie {
|
||||
jar.private(&key).add(cookie);
|
||||
jar.private_mut(&key).add(cookie);
|
||||
} else {
|
||||
jar.add_original(cookie.clone());
|
||||
jar.private(&key).remove(cookie);
|
||||
jar.private_mut(&key).remove(cookie);
|
||||
}
|
||||
|
||||
for cookie in jar.delta() {
|
||||
@ -128,17 +129,19 @@ impl CookieIdentityInner {
|
||||
jar.add_original(cookie.clone());
|
||||
|
||||
let res = if self.legacy_supported() {
|
||||
jar.private(&self.key).get(&self.name).map(|n| CookieValue {
|
||||
identity: n.value().to_string(),
|
||||
login_timestamp: None,
|
||||
visit_timestamp: None,
|
||||
})
|
||||
jar.private_mut(&self.key)
|
||||
.get(&self.name)
|
||||
.map(|n| CookieValue {
|
||||
identity: n.value().to_string(),
|
||||
login_timestamp: None,
|
||||
visit_timestamp: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
res.or_else(|| {
|
||||
jar.private(&self.key_v2)
|
||||
jar.private_mut(&self.key_v2)
|
||||
.get(&self.name)
|
||||
.and_then(|c| self.parse(c))
|
||||
})
|
||||
@ -391,7 +394,7 @@ mod tests {
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
jar.private(&Key::derive_from(&key)).add(Cookie::new(
|
||||
jar.private_mut(&Key::derive_from(&key)).add(Cookie::new(
|
||||
COOKIE_NAME,
|
||||
serde_json::to_string(&CookieValue {
|
||||
identity: identity.to_string(),
|
||||
@ -575,7 +578,7 @@ mod tests {
|
||||
|
||||
fn legacy_login_cookie(identity: &'static str) -> Cookie<'static> {
|
||||
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));
|
||||
jar.get(COOKIE_NAME).unwrap().clone()
|
||||
}
|
||||
@ -592,7 +595,7 @@ mod tests {
|
||||
cookies.add(Cookie::parse(cookie.to_str().unwrap().to_string()).unwrap());
|
||||
}
|
||||
let cookie = cookies
|
||||
.private(&Key::derive_from(&COOKIE_KEY_MASTER))
|
||||
.private_mut(&Key::derive_from(&COOKIE_KEY_MASTER))
|
||||
.get(COOKIE_NAME)
|
||||
.unwrap();
|
||||
assert_eq!(cookie.value(), identity);
|
||||
|
@ -1,10 +1,13 @@
|
||||
use std::rc::Rc;
|
||||
use std::{error::Error as StdError, rc::Rc};
|
||||
|
||||
use actix_web::{
|
||||
body::{AnyBody, MessageBody},
|
||||
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||
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};
|
||||
|
||||
@ -41,9 +44,10 @@ where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||
S::Future: 'static,
|
||||
T: IdentityPolicy,
|
||||
B: 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
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>
|
||||
where
|
||||
B: 'static,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||
S::Future: 'static,
|
||||
T: IdentityPolicy,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
@ -100,16 +105,19 @@ where
|
||||
|
||||
if let Some(id) = id {
|
||||
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)),
|
||||
}
|
||||
} else {
|
||||
Ok(res)
|
||||
Ok(res.map_body(|_, body| AnyBody::from_message(body)))
|
||||
}
|
||||
}
|
||||
Err(err) => Ok(req.error_response(err)),
|
||||
}
|
||||
}
|
||||
.map_ok(|res| res.map_body(|_, body| AnyBody::from_message(body)))
|
||||
.boxed_local()
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,9 @@ authors = [
|
||||
"Yuki Okushi <huyuumi.dev@gmail.com>"
|
||||
]
|
||||
description = "Protobuf support for Actix web"
|
||||
readme = "README.md"
|
||||
keywords = ["actix", "protobuf", "protocol", "rpc"]
|
||||
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"
|
||||
exclude = [".cargo/config", "/examples/**"]
|
||||
|
||||
@ -20,7 +19,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
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"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
prost = "0.7"
|
||||
|
@ -8,7 +8,7 @@ authors = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-beta.5"
|
||||
actix-web = "4.0.0-beta.8"
|
||||
actix-protobuf = { path = "../../" }
|
||||
|
||||
env_logger = "0.8"
|
||||
|
@ -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 std::fmt;
|
||||
use std::future::Future;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::pin::Pin;
|
||||
use std::task;
|
||||
use std::task::Poll;
|
||||
|
||||
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;
|
||||
use futures_util::{
|
||||
future::{FutureExt as _, LocalBoxFuture},
|
||||
stream::StreamExt as _,
|
||||
};
|
||||
use prost::{
|
||||
DecodeError as ProtoBufDecodeError, EncodeError as ProtoBufEncodeError, Message,
|
||||
};
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
pub enum ProtoBufPayloadError {
|
||||
/// Payload size is bigger than 256k
|
||||
#[display(fmt = "Payload size is bigger than 256k")]
|
||||
Overflow,
|
||||
|
||||
/// Content type error
|
||||
#[display(fmt = "Content type error")]
|
||||
ContentType,
|
||||
|
||||
/// Serialize error
|
||||
#[display(fmt = "ProtoBuf serialize error: {}", _0)]
|
||||
Serialize(ProtoBufEncodeError),
|
||||
|
||||
/// Deserialize error
|
||||
#[display(fmt = "ProtoBuf deserialize error: {}", _0)]
|
||||
Deserialize(ProtoBufDecodeError),
|
||||
|
||||
/// Payload error
|
||||
#[display(fmt = "Error that occur during reading payload: {}", _0)]
|
||||
Payload(PayloadError),
|
||||
|
@ -4,11 +4,9 @@ version = "0.10.0-beta.1"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Redis integration for Actix and session store for Actix Web"
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "README.md"
|
||||
keywords = ["actix", "redis", "async", "session"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-extras.git"
|
||||
documentation = "https://docs.rs/actix-redis/"
|
||||
repository = "https://github.com/actix/actix-extras"
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
exclude = [".cargo/config"]
|
||||
edition = "2018"
|
||||
@ -31,9 +29,9 @@ web = [
|
||||
]
|
||||
|
||||
[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-service = "2.0.0-beta.5"
|
||||
actix-service = "2.0.0"
|
||||
actix-tls = { version = "3.0.0-beta.5", default-features = false, features = ["connect"] }
|
||||
|
||||
log = "0.4.6"
|
||||
@ -47,15 +45,23 @@ tokio = { version = "1", features = ["sync"] }
|
||||
tokio-util = "0.6.1"
|
||||
|
||||
# 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 }
|
||||
rand = { version = "0.8.0", optional = true }
|
||||
serde = { version = "1.0.101", optional = true }
|
||||
serde_json = { version = "1.0.40", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-test = "0.1.0-beta.1"
|
||||
actix-test = "0.1.0-beta.3"
|
||||
actix-http = "3.0.0-beta.5"
|
||||
actix-rt = "2.1"
|
||||
env_logger = "0.7"
|
||||
serde_derive = "1.0"
|
||||
env_logger = "0.8"
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
|
||||
[[example]]
|
||||
name = "basic"
|
||||
required-features = ["web"]
|
||||
|
||||
[[example]]
|
||||
name = "authentication"
|
||||
required-features = ["web"]
|
||||
|
@ -1,7 +1,8 @@
|
||||
use actix_redis::RedisSession;
|
||||
use actix_session::Session;
|
||||
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};
|
||||
|
||||
@ -49,12 +50,12 @@ pub fn validate_session(session: &Session) -> Result<i64, HttpResponse> {
|
||||
async fn login(
|
||||
credentials: web::Json<Credentials>,
|
||||
session: Session,
|
||||
) -> Result<impl Responder, HttpResponse> {
|
||||
) -> Result<impl Responder, Error> {
|
||||
let credentials = credentials.into_inner();
|
||||
|
||||
match User::authenticate(credentials) {
|
||||
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!")
|
||||
@ -63,7 +64,7 @@ async fn login(
|
||||
/// some protected resource
|
||||
async fn secret(session: Session) -> Result<impl Responder, Error> {
|
||||
// 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")
|
||||
}
|
||||
|
@ -3,14 +3,16 @@ use std::{collections::HashMap, iter, rc::Rc};
|
||||
use actix::prelude::*;
|
||||
use actix_service::{Service, Transform};
|
||||
use actix_session::{Session, SessionStatus};
|
||||
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite};
|
||||
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
||||
use actix_web::http::header::{self, HeaderValue};
|
||||
use actix_web::{error, Error, HttpMessage};
|
||||
use actix_web::{
|
||||
cookie::{Cookie, CookieJar, Key, SameSite},
|
||||
dev::{ServiceRequest, ServiceResponse},
|
||||
error,
|
||||
http::header::{self, HeaderValue},
|
||||
Error,
|
||||
};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
|
||||
use redis_async::resp::RespValue;
|
||||
use redis_async::resp_array;
|
||||
use redis_async::{resp::RespValue, resp_array};
|
||||
use time::{self, Duration, OffsetDateTime};
|
||||
|
||||
use crate::redis::{Command, RedisActor};
|
||||
@ -311,7 +313,7 @@ impl Inner {
|
||||
|
||||
// set cookie
|
||||
let mut jar = CookieJar::new();
|
||||
jar.signed(&self.key).add(cookie);
|
||||
jar.signed_mut(&self.key).add(cookie);
|
||||
|
||||
(value, Some(jar))
|
||||
};
|
||||
@ -321,7 +323,7 @@ impl Inner {
|
||||
let state: HashMap<_, _> = state.collect();
|
||||
|
||||
let body = match serde_json::to_string(&state) {
|
||||
Err(e) => return Err(e.into()),
|
||||
Err(err) => return Err(err.into()),
|
||||
Ok(body) => body,
|
||||
};
|
||||
|
||||
@ -442,12 +444,15 @@ mod test {
|
||||
|
||||
async fn logout(session: Session) -> Result<HttpResponse> {
|
||||
let id: Option<String> = session.get("user_id")?;
|
||||
if let Some(x) = id {
|
||||
|
||||
let body = if let Some(x) = id {
|
||||
session.purge();
|
||||
Ok(format!("Logged out: {}", x).into())
|
||||
format!("Logged out: {}", x)
|
||||
} 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]
|
||||
@ -648,7 +653,10 @@ mod test {
|
||||
.unwrap();
|
||||
assert_ne!(
|
||||
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
|
||||
|
@ -3,11 +3,9 @@ name = "actix-session"
|
||||
version = "0.5.0-beta.1"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Sessions for Actix web"
|
||||
readme = "README.md"
|
||||
keywords = ["http", "web", "framework", "async", "session"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-extras"
|
||||
documentation = "https://docs.rs/actix-session/"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
@ -20,8 +18,8 @@ default = ["cookie-session"]
|
||||
cookie-session = ["actix-web/secure-cookies"]
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.5", default_features = false, features = ["cookies"] }
|
||||
actix-service = "2.0.0-beta.5"
|
||||
actix-web = { version = "4.0.0-beta.8", default_features = false, features = ["cookies"] }
|
||||
actix-service = "2.0.0"
|
||||
|
||||
derive_more = "0.99.5"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
|
@ -1,14 +1,16 @@
|
||||
//! 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::cookie::{Cookie, CookieJar, Key, SameSite};
|
||||
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
||||
use actix_web::http::{header::SET_COOKIE, HeaderValue};
|
||||
use actix_web::{Error, HttpMessage, ResponseError};
|
||||
use actix_web::{
|
||||
body::{AnyBody, MessageBody},
|
||||
cookie::{Cookie, CookieJar, Key, SameSite},
|
||||
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||
http::{header::SET_COOKIE, HeaderValue},
|
||||
Error, ResponseError,
|
||||
};
|
||||
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 time::{Duration, OffsetDateTime};
|
||||
|
||||
@ -106,8 +108,8 @@ impl CookieSessionInner {
|
||||
let mut jar = CookieJar::new();
|
||||
|
||||
match self.security {
|
||||
CookieSecurity::Signed => jar.signed(&self.key).add(cookie),
|
||||
CookieSecurity::Private => jar.private(&self.key).add(cookie),
|
||||
CookieSecurity::Signed => jar.signed_mut(&self.key).add(cookie),
|
||||
CookieSecurity::Private => jar.private_mut(&self.key).add(cookie),
|
||||
}
|
||||
|
||||
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
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>>,
|
||||
S::Future: 'static,
|
||||
S::Error: 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = S::Error;
|
||||
type InitError = ();
|
||||
type Transform = CookieSessionMiddleware<S>;
|
||||
@ -318,13 +322,15 @@ pub struct CookieSessionMiddleware<S> {
|
||||
inner: Rc<CookieSessionInner>,
|
||||
}
|
||||
|
||||
impl<S, B: 'static> Service<ServiceRequest> for CookieSessionMiddleware<S>
|
||||
impl<S, B> Service<ServiceRequest> for CookieSessionMiddleware<S>
|
||||
where
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>>,
|
||||
S::Future: 'static,
|
||||
S::Error: 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = S::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
@ -343,36 +349,40 @@ where
|
||||
|
||||
let fut = self.service.call(req);
|
||||
|
||||
Box::pin(async move {
|
||||
async move {
|
||||
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) => {
|
||||
res.checked_expr(|res| inner.set_cookie(res, state))
|
||||
inner.set_cookie(&mut res, state)
|
||||
}
|
||||
|
||||
(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)
|
||||
(SessionStatus::Unchanged, _) => {
|
||||
if is_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 {
|
||||
res
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
(SessionStatus::Purged, _) => {
|
||||
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")
|
||||
.expect("Cookie is set")
|
||||
.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;
|
||||
|
||||
@ -545,7 +557,9 @@ mod tests {
|
||||
.find(|c| c.name() == "actix-session")
|
||||
.expect("Cookie is set")
|
||||
.expires()
|
||||
.expect("Expiration is set");
|
||||
.expect("Expiration is set")
|
||||
.datetime()
|
||||
.expect("Expiration is a datetime");
|
||||
|
||||
assert!(expires_2 - expires_1 >= Duration::seconds(1));
|
||||
}
|
||||
|
@ -6,11 +6,9 @@ authors = [
|
||||
"Yuki Okushi <huyuumi.dev@gmail.com>",
|
||||
]
|
||||
description = "HTTP authentication schemes for Actix web"
|
||||
readme = "README.md"
|
||||
keywords = ["http", "web", "framework", "authentication", "security"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-extras.git"
|
||||
documentation = "https://docs.rs/actix-web-httpauth/"
|
||||
repository = "https://github.com/actix/actix-extras"
|
||||
categories = ["web-programming::http-server"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -20,8 +18,8 @@ name = "actix_web_httpauth"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.5", default_features = false }
|
||||
actix-service = "2.0.0-beta.5"
|
||||
actix-web = { version = "4.0.0-beta.8", default_features = false }
|
||||
actix-service = "2.0.0"
|
||||
base64 = "0.13"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
|
||||
|
@ -81,7 +81,7 @@ impl AuthExtractorConfig for Config {
|
||||
///
|
||||
/// fn main() {
|
||||
/// 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)));
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -84,7 +84,7 @@ impl AuthExtractorConfig for Config {
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = App::new()
|
||||
/// .data(
|
||||
/// .app_data(
|
||||
/// Config::default()
|
||||
/// .realm("Restricted area")
|
||||
/// .scope("email photo"),
|
||||
|
@ -1,8 +1,12 @@
|
||||
//! 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::{
|
||||
body::{AnyBody, MessageBody},
|
||||
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||
Error,
|
||||
};
|
||||
@ -120,8 +124,10 @@ where
|
||||
F: Fn(ServiceRequest, T) -> O + 'static,
|
||||
O: Future<Output = Result<ServiceRequest, Error>> + 'static,
|
||||
T: AuthExtractor + 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Transform = AuthenticationMiddleware<S, F, T>;
|
||||
type InitError = ();
|
||||
@ -153,10 +159,12 @@ where
|
||||
F: Fn(ServiceRequest, T) -> O + 'static,
|
||||
O: Future<Output = Result<ServiceRequest, Error>> + 'static,
|
||||
T: AuthExtractor + 'static,
|
||||
B: MessageBody + 'static,
|
||||
B::Error: StdError,
|
||||
{
|
||||
type Response = ServiceResponse<B>;
|
||||
type Response = ServiceResponse;
|
||||
type Error = S::Error;
|
||||
type Future = LocalBoxFuture<'static, Result<ServiceResponse<B>, Error>>;
|
||||
type Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
|
||||
|
||||
actix_service::forward_ready!(service);
|
||||
|
||||
@ -177,7 +185,10 @@ where
|
||||
// middleware to do their thing (eg. cors adding headers)
|
||||
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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user