soma_http_server/middleware/
cors.rs1use axum::http::{HeaderName, HeaderValue, Method};
9pub use tower_http::cors::CorsLayer;
10
11pub fn cors_layer(
15 origins: Vec<HeaderValue>,
16 methods: Vec<Method>,
17 headers: Vec<HeaderName>,
18) -> CorsLayer {
19 CorsLayer::new()
20 .allow_origin(origins)
21 .allow_methods(methods)
22 .allow_headers(headers)
23}
24
25#[cfg(test)]
26mod tests {
27 use super::*;
28 use axum::{
29 body::Body,
30 http::{Request, StatusCode},
31 routing::get,
32 Router,
33 };
34 use tower::ServiceExt;
35
36 #[tokio::test]
37 async fn preflight_from_an_allowed_origin_succeeds() {
38 let origin: HeaderValue = "https://example.test".parse().unwrap();
39 let layer = cors_layer(
40 vec![origin.clone()],
41 vec![Method::GET],
42 vec![axum::http::header::CONTENT_TYPE],
43 );
44 let app = Router::new()
45 .route("/", get(|| async { "ok" }))
46 .layer(layer);
47
48 let request = Request::builder()
49 .method(Method::OPTIONS)
50 .uri("/")
51 .header(axum::http::header::ORIGIN, origin.clone())
52 .header(axum::http::header::ACCESS_CONTROL_REQUEST_METHOD, "GET")
53 .body(Body::empty())
54 .unwrap();
55 let response = app.oneshot(request).await.unwrap();
56 assert_eq!(response.status(), StatusCode::OK);
57 assert_eq!(
58 response
59 .headers()
60 .get(axum::http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
61 .unwrap(),
62 &origin
63 );
64 }
65
66 #[tokio::test]
67 async fn preflight_from_a_disallowed_origin_omits_the_allow_origin_header() {
68 let allowed: HeaderValue = "https://example.test".parse().unwrap();
73 let disallowed: HeaderValue = "https://not-allowed.test".parse().unwrap();
74 let layer = cors_layer(
75 vec![allowed],
76 vec![Method::GET],
77 vec![axum::http::header::CONTENT_TYPE],
78 );
79 let app = Router::new()
80 .route("/", get(|| async { "ok" }))
81 .layer(layer);
82
83 let request = Request::builder()
84 .method(Method::OPTIONS)
85 .uri("/")
86 .header(axum::http::header::ORIGIN, disallowed)
87 .header(axum::http::header::ACCESS_CONTROL_REQUEST_METHOD, "GET")
88 .body(Body::empty())
89 .unwrap();
90 let response = app.oneshot(request).await.unwrap();
91 assert!(
92 response
93 .headers()
94 .get(axum::http::header::ACCESS_CONTROL_ALLOW_ORIGIN)
95 .is_none(),
96 "a disallowed origin must not receive an Access-Control-Allow-Origin header"
97 );
98 }
99}