diff --git a/actix-cors/CHANGES.md b/actix-cors/CHANGES.md index 06674b3e15..f781145f27 100644 --- a/actix-cors/CHANGES.md +++ b/actix-cors/CHANGES.md @@ -1,12 +1,17 @@ # Changes ## Unreleased - 2021-xx-xx + + +## 0.6.0-beta.3 - 2021-10-21 * Make `Cors` middleware generic over body type [#195] +* Fix `expose_any_header` behavior. [#204] * Update `actix-web` dependency to v4.0.0-beta.10. [#203] * Minimum supported Rust version (MSRV) is now 1.52. [#195]: https://github.com/actix/actix-extras/pull/195 [#203]: https://github.com/actix/actix-extras/pull/203 +[#204]: https://github.com/actix/actix-extras/pull/204 ## 0.6.0-beta.2 - 2021-06-27 diff --git a/actix-cors/Cargo.toml b/actix-cors/Cargo.toml index c58301e5ad..dd5de0a4d0 100644 --- a/actix-cors/Cargo.toml +++ b/actix-cors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-cors" -version = "0.6.0-beta.2" +version = "0.6.0-beta.3" authors = [ "Nikolay Kim ", "Rob Ede ", @@ -8,7 +8,7 @@ authors = [ description = "Cross-Origin Resource Sharing (CORS) controls for Actix Web" keywords = ["actix", "cors", "web", "security", "crossorigin"] homepage = "https://actix.rs" -repository = "https://github.com/actix/actix-extras" +repository = "https://github.com/actix/actix-extras.git" license = "MIT OR Apache-2.0" edition = "2018" diff --git a/actix-cors/README.md b/actix-cors/README.md index 05790c544d..f16272f2a1 100644 --- a/actix-cors/README.md +++ b/actix-cors/README.md @@ -3,9 +3,9 @@ > Cross-origin resource sharing (CORS) for Actix Web. [![crates.io](https://img.shields.io/crates/v/actix-cors?label=latest)](https://crates.io/crates/actix-cors) -[![Documentation](https://docs.rs/actix-cors/badge.svg?version=0.6.0-beta.2)](https://docs.rs/actix-cors/0.6.0-beta.2) +[![Documentation](https://docs.rs/actix-cors/badge.svg?version=0.6.0-beta.3)](https://docs.rs/actix-cors/0.6.0-beta.3) ![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-cors) -[![Dependency Status](https://deps.rs/crate/actix-cors/0.6.0-beta.2/status.svg)](https://deps.rs/crate/actix-cors/0.6.0-beta.2) +[![Dependency Status](https://deps.rs/crate/actix-cors/0.6.0-beta.3/status.svg)](https://deps.rs/crate/actix-cors/0.6.0-beta.3) ## Documentation & Resources diff --git a/actix-cors/src/builder.rs b/actix-cors/src/builder.rs index 8aa914daf3..1852a54ad3 100644 --- a/actix-cors/src/builder.rs +++ b/actix-cors/src/builder.rs @@ -95,6 +95,7 @@ impl Cors { expose_headers: AllOrSome::All, expose_headers_baked: None, + max_age: Some(3600), preflight: true, send_wildcard: false, @@ -544,13 +545,18 @@ where } /// Only call when values are guaranteed to be valid header values and set is not empty. -fn intersperse_header_values(val_set: &HashSet) -> HeaderValue +pub(crate) fn intersperse_header_values(val_set: &HashSet) -> HeaderValue where T: AsRef, { + debug_assert!( + !val_set.is_empty(), + "only call `intersperse_header_values` when set is not empty" + ); + val_set .iter() - .fold(String::with_capacity(32), |mut acc, val| { + .fold(String::with_capacity(64), |mut acc, val| { acc.push_str(", "); acc.push_str(val.as_ref()); acc diff --git a/actix-cors/src/middleware.rs b/actix-cors/src/middleware.rs index 4100dcdd26..21cda84411 100644 --- a/actix-cors/src/middleware.rs +++ b/actix-cors/src/middleware.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, error::Error as StdError, rc::Rc}; +use std::{collections::HashSet, convert::TryInto, error::Error as StdError, rc::Rc}; use actix_web::{ body::{AnyBody, MessageBody}, @@ -13,7 +13,7 @@ use actix_web::{ use futures_util::future::{ok, Either, FutureExt as _, LocalBoxFuture, Ready, TryFutureExt as _}; use log::debug; -use crate::Inner; +use crate::{builder::intersperse_header_values, AllOrSome, Inner}; /// Service wrapper for Cross-Origin Resource Sharing support. /// @@ -78,8 +78,34 @@ impl CorsMiddleware { }; if let Some(ref expose) = inner.expose_headers_baked { + log::trace!("exposing selected headers: {:?}", expose); + res.headers_mut() .insert(header::ACCESS_CONTROL_EXPOSE_HEADERS, expose.clone()); + } else if matches!(inner.expose_headers, AllOrSome::All) { + // intersperse_header_values requires that argument is non-empty + if !res.request().headers().is_empty() { + // extract header names from request + let expose_all_request_headers = res + .request() + .headers() + .keys() + .into_iter() + .map(|name| name.as_str()) + .collect::>(); + + // create comma separated string of header names + let expose_headers_value = intersperse_header_values(&expose_all_request_headers); + + log::trace!( + "exposing all headers from request: {:?}", + expose_headers_value + ); + + // add header names to expose response header + res.headers_mut() + .insert(header::ACCESS_CONTROL_EXPOSE_HEADERS, expose_headers_value); + } } if inner.supports_credentials { diff --git a/actix-cors/tests/tests.rs b/actix-cors/tests/tests.rs index 996f8ece91..df0a002a3a 100644 --- a/actix-cors/tests/tests.rs +++ b/actix-cors/tests/tests.rs @@ -416,3 +416,32 @@ async fn test_allow_any_origin_any_method_any_header() { let resp = test::call_service(&cors, req).await; assert_eq!(resp.status(), StatusCode::OK); } + +#[actix_web::test] +async fn expose_all_request_header_values() { + let cors = Cors::permissive() + .new_transform(test::ok_service()) + .await + .unwrap(); + + let req = TestRequest::default() + .insert_header((header::ORIGIN, "https://www.example.com")) + .insert_header((header::ACCESS_CONTROL_REQUEST_METHOD, "POST")) + .insert_header((header::ACCESS_CONTROL_REQUEST_HEADERS, "content-type")) + .insert_header(("X-XSRF-TOKEN", "xsrf-token")) + .to_srv_request(); + + let resp = test::call_service(&cors, req).await; + + assert!(resp + .headers() + .contains_key(header::ACCESS_CONTROL_EXPOSE_HEADERS)); + + assert!(resp + .headers() + .get(header::ACCESS_CONTROL_EXPOSE_HEADERS) + .unwrap() + .to_str() + .unwrap() + .contains("xsrf-token")); +} diff --git a/actix-web-httpauth/Cargo.toml b/actix-web-httpauth/Cargo.toml index b59ae62aa9..8a76081e79 100644 --- a/actix-web-httpauth/Cargo.toml +++ b/actix-web-httpauth/Cargo.toml @@ -24,5 +24,5 @@ base64 = "0.13" futures-util = { version = "0.3.7", default-features = false } [dev-dependencies] -actix-cors = "0.6.0-beta.2" +actix-cors = "0.6.0-beta.3" actix-rt = "2"