mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-25 13:36:50 +00:00
fix: restore default CORS fallback and STS object ACL ownership (#2053)
Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
@@ -641,13 +641,23 @@ pub(crate) fn needs_cors_processing(headers: &HeaderMap) -> bool {
|
||||
/// 2. Retrieves the bucket's CORS configuration
|
||||
/// 3. Matches the origin against CORS rules
|
||||
/// 4. Validates AllowedHeaders if request headers are present
|
||||
/// 5. Returns headers to add to the response if a match is found
|
||||
/// 5. Returns one of:
|
||||
/// - `None`: bucket has no CORS config (or request has no valid `Origin`)
|
||||
/// - `Some(empty headers)`: bucket CORS exists but request is denied / no rule matched
|
||||
/// - `Some(non-empty headers)`: bucket CORS exists and request matched
|
||||
///
|
||||
/// Note: This function should only be called if `needs_cors_processing()` returns true
|
||||
/// to avoid unnecessary overhead for non-CORS requests.
|
||||
pub(crate) async fn apply_cors_headers(bucket: &str, method: &http::Method, headers: &HeaderMap) -> Option<HeaderMap> {
|
||||
use http::HeaderValue;
|
||||
|
||||
fn is_credentialed_request(headers: &HeaderMap) -> bool {
|
||||
headers.contains_key(http::header::AUTHORIZATION)
|
||||
|| headers.contains_key(http::header::COOKIE)
|
||||
|| headers.contains_key("x-amz-security-token")
|
||||
|| headers.contains_key("x-amz-content-sha256")
|
||||
}
|
||||
|
||||
// Get Origin header from request
|
||||
let origin = headers.get(cors::standard::ORIGIN)?.to_str().ok()?;
|
||||
|
||||
@@ -659,14 +669,14 @@ pub(crate) async fn apply_cors_headers(bucket: &str, method: &http::Method, head
|
||||
|
||||
// Early return if no CORS rules configured
|
||||
if cors_config.cors_rules.is_empty() {
|
||||
return None;
|
||||
return Some(HeaderMap::new());
|
||||
}
|
||||
|
||||
// Check if method is supported and get its string representation
|
||||
const SUPPORTED_METHODS: &[&str] = &["GET", "PUT", "POST", "DELETE", "HEAD", "OPTIONS"];
|
||||
let method_str = method.as_str();
|
||||
if !SUPPORTED_METHODS.contains(&method_str) {
|
||||
return None;
|
||||
return Some(HeaderMap::new());
|
||||
}
|
||||
|
||||
// Use Access-Control-Request-Method if present (for preflight and non-preflight requests),
|
||||
@@ -740,19 +750,37 @@ pub(crate) async fn apply_cors_headers(bucket: &str, method: &http::Method, head
|
||||
let mut response_headers = HeaderMap::new();
|
||||
|
||||
// Access-Control-Allow-Origin
|
||||
// If origin is "*", use "*", otherwise echo back the origin
|
||||
// Credentials mode + wildcard allow list requires echoing the request origin.
|
||||
// Browsers reject `Access-Control-Allow-Origin: *` with `credentials: include`.
|
||||
let has_wildcard_origin = rule.allowed_origins.iter().any(|o| o == "*");
|
||||
let credentialed_request = is_credentialed_request(headers);
|
||||
let mut origin_reflected = false;
|
||||
|
||||
if has_wildcard_origin {
|
||||
response_headers.insert(cors::response::ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
|
||||
if credentialed_request {
|
||||
if let Ok(origin_value) = HeaderValue::from_str(origin) {
|
||||
response_headers.insert(cors::response::ACCESS_CONTROL_ALLOW_ORIGIN, origin_value);
|
||||
origin_reflected = true;
|
||||
}
|
||||
} else {
|
||||
response_headers.insert(cors::response::ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
|
||||
}
|
||||
} else if let Ok(origin_value) = HeaderValue::from_str(origin) {
|
||||
response_headers.insert(cors::response::ACCESS_CONTROL_ALLOW_ORIGIN, origin_value);
|
||||
origin_reflected = true;
|
||||
}
|
||||
|
||||
// Vary: Origin (required for caching, except when using wildcard)
|
||||
if !has_wildcard_origin {
|
||||
// Vary: Origin whenever origin is reflected (non-"*" allow-origin).
|
||||
// This prevents proxy/browser caches from reusing CORS headers across different origins.
|
||||
if origin_reflected {
|
||||
response_headers.insert(cors::standard::VARY, HeaderValue::from_static("Origin"));
|
||||
}
|
||||
|
||||
// Credentials mode requires explicit allow-credentials.
|
||||
if credentialed_request {
|
||||
response_headers.insert(cors::response::ACCESS_CONTROL_ALLOW_CREDENTIALS, HeaderValue::from_static("true"));
|
||||
}
|
||||
|
||||
// Access-Control-Allow-Methods (required for preflight)
|
||||
if is_preflight || !rule.allowed_methods.is_empty() {
|
||||
let methods_str = rule.allowed_methods.iter().map(|m| m.as_str()).collect::<Vec<_>>().join(", ");
|
||||
@@ -788,7 +816,7 @@ pub(crate) async fn apply_cors_headers(bucket: &str, method: &http::Method, head
|
||||
return Some(response_headers);
|
||||
}
|
||||
|
||||
None // No matching rule found
|
||||
Some(HeaderMap::new()) // No matching rule found
|
||||
}
|
||||
/// Check if an origin matches a pattern (supports wildcards like https://*.example.com)
|
||||
pub(crate) fn matches_origin_pattern(pattern: &str, origin: &str) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user