|
|
|
|
@@ -250,12 +250,26 @@ fn production_allowed_headers() -> [axum::http::HeaderName; 5] {
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Production CORS allowed methods.
|
|
|
|
|
///
|
|
|
|
|
/// Keep this list explicit because tower-http rejects
|
|
|
|
|
/// `allow_credentials(true)` together with `allow_methods(Any)`.
|
|
|
|
|
fn production_allowed_methods() -> [axum::http::Method; 5] {
|
|
|
|
|
[
|
|
|
|
|
axum::http::Method::GET,
|
|
|
|
|
axum::http::Method::POST,
|
|
|
|
|
axum::http::Method::PATCH,
|
|
|
|
|
axum::http::Method::DELETE,
|
|
|
|
|
axum::http::Method::OPTIONS,
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build the CORS layer for the application.
|
|
|
|
|
///
|
|
|
|
|
/// In production mode the origin is restricted to the BASE_URL origin
|
|
|
|
|
/// (scheme://host:port, path stripped) and credentials are allowed.
|
|
|
|
|
/// `allow_headers` uses an explicit whitelist to avoid the tower-http
|
|
|
|
|
/// restriction on `allow_credentials(true)` + `allow_headers(Any)`.
|
|
|
|
|
/// `allow_headers` and `allow_methods` use explicit whitelists to avoid the
|
|
|
|
|
/// tower-http restriction on `allow_credentials(true)` + wildcards.
|
|
|
|
|
///
|
|
|
|
|
/// In development mode all origins, methods and headers are allowed.
|
|
|
|
|
fn build_cors_layer(base_url: &str, is_production: bool) -> CorsLayer {
|
|
|
|
|
@@ -272,7 +286,7 @@ fn build_cors_layer(base_url: &str, is_production: bool) -> CorsLayer {
|
|
|
|
|
};
|
|
|
|
|
CorsLayer::new()
|
|
|
|
|
.allow_origin(allowed_origin)
|
|
|
|
|
.allow_methods(Any)
|
|
|
|
|
.allow_methods(production_allowed_methods())
|
|
|
|
|
.allow_headers(production_allowed_headers())
|
|
|
|
|
.allow_credentials(true)
|
|
|
|
|
} else {
|
|
|
|
|
@@ -304,6 +318,16 @@ mod tests {
|
|
|
|
|
assert!(names.contains(&"x-mcp-session"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn production_cors_methods_include_all_required() {
|
|
|
|
|
let methods = production_allowed_methods();
|
|
|
|
|
assert!(methods.contains(&axum::http::Method::GET));
|
|
|
|
|
assert!(methods.contains(&axum::http::Method::POST));
|
|
|
|
|
assert!(methods.contains(&axum::http::Method::PATCH));
|
|
|
|
|
assert!(methods.contains(&axum::http::Method::DELETE));
|
|
|
|
|
assert!(methods.contains(&axum::http::Method::OPTIONS));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn production_cors_normalizes_base_url_with_path() {
|
|
|
|
|
let url = url::Url::parse("https://secrets.example.com/secrets/app").unwrap();
|
|
|
|
|
|