mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-07 21:33:13 +00:00
fix(cors): return single matching origin instead of multiple values in Access-Control-Allow-Origin (#1419)
## Title fix(cors): return single matching origin instead of multiple values in `Access-Control-Allow-Origin` ## Summary This PR fixes bucket CORS responses when a single CORS rule contains multiple `AllowedOrigins`. Previously, Garage returned the configured origins as a comma-separated list in `Access-Control-Allow-Origin`, for example: ```http Access-Control-Allow-Origin: https://app.example.test, https://admin.example.test ``` This is not the expected browser-facing behavior. When a request origin matches a configured rule, the response should reflect **only the matching request origin**, unless the rule contains `*`. ## What changed - `Access-Control-Allow-Origin` now behaves as follows: - returns `*` when the matched rule contains a wildcard origin - otherwise returns the request `Origin` as a **single value** - added `Vary: Origin` when ACAO reflects the request origin - added preflight-specific `Vary` handling in the preflight path for: - `Origin` - `Access-Control-Request-Method` - `Access-Control-Request-Headers` ## Scope This change applies to shared bucket CORS handling paths, including: - S3 API responses - K2V API responses - S3 POST object responses - web bucket responses - preflight (`OPTIONS`) bucket CORS responses This does **not** change admin API fixed CORS behavior. ## Reproduction A direct repro script is included: ```bash ./script/test-cors-multi-origin.sh ``` It exercises two cases against a direct single-node Garage instance: 1. **single-origin control** 2. **multi-origin repro** Before this fix, the multi-origin case returned a comma-separated ACAO value. After this fix, both cases reflect only the request origin. ## Example behavior ### Before ```http Access-Control-Allow-Origin: https://app.example.test, https://admin.example.test ``` ### After ```http Access-Control-Allow-Origin: https://app.example.test ``` ## Tests Added/updated tests in `src/api/common/cors.rs` for: - single-origin control - multiple allowed origins reflecting the request origin - wildcard origin preserving `*` - preserving existing `Vary` values while appending `Origin` ## Validation Used for validation: ```bash cargo test -p garage_api_common cors::tests -- --nocapture cargo build -p garage --bin garage ./script/test-cors-multi-origin.sh ``` ## Reproducibility For reviewers who want to validate behavior by commit: - Before fix: `aa368e4b` - includes the direct repro script and the regression test setup - multi-origin ACAO is reproduced as a comma-separated value - After fix: `f630eb92` - reflects only the matching request origin - preserves wildcard behavior - adds `Vary: Origin` and preflight-specific `Vary` handling Branch: - `fix/cors-multiple-allow-origin` Base used during validation: - `74ad3bf8` (`main-v2`) Closes Deuxfleurs/garage#1149 Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1419
This commit is contained in:
@@ -111,7 +111,7 @@ impl ApiHandler for K2VApiServer {
|
||||
Method::GET | Method::HEAD | Method::POST => {
|
||||
find_matching_cors_rule(&bucket_params, &req)
|
||||
.ok_or_internal_error("Error looking up CORS rule")?
|
||||
.cloned()
|
||||
.map(|(rule, origin)| (rule.clone(), origin.to_string()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
@@ -164,8 +164,8 @@ impl ApiHandler for K2VApiServer {
|
||||
// If request was a success and we have a CORS rule that applies to it,
|
||||
// add the corresponding CORS headers to the response
|
||||
let mut resp_ok = resp?;
|
||||
if let Some(rule) = matching_cors_rule {
|
||||
add_cors_headers(&mut resp_ok, &rule)
|
||||
if let Some((rule, origin)) = matching_cors_rule {
|
||||
add_cors_headers(&mut resp_ok, &rule, &origin)
|
||||
.ok_or_internal_error("Invalid bucket CORS configuration")?;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user