1use core::net::{Ipv4Addr, Ipv6Addr};
4
5use http::{
6 HeaderName, Method, Uri,
7 header::{ACCEPT, AUTHORIZATION, CONTENT_ENCODING, CONTENT_TYPE},
8};
9use tower_http::cors::{AllowOrigin, CorsLayer};
10
11pub fn cors_layer(
13 additional_allowed_origins: Vec<Uri>,
14 additional_allowed_headers: &[HeaderName],
15 additional_exposed_headers: &[HeaderName],
16) -> CorsLayer {
17 let mut allowed_headers = vec![AUTHORIZATION, ACCEPT, CONTENT_TYPE];
18 allowed_headers.extend_from_slice(additional_allowed_headers);
19
20 let mut exposed_headers = vec![AUTHORIZATION, CONTENT_ENCODING, CONTENT_TYPE];
21 exposed_headers.extend_from_slice(additional_exposed_headers);
22
23 let allowed_methods = [
24 Method::OPTIONS,
25 Method::HEAD,
26 Method::GET,
27 Method::PUT,
28 Method::POST,
29 Method::DELETE,
30 ];
31
32 let allowed_origins = AllowOrigin::predicate(move |header, _| {
33 let Ok(origin) = header.to_str() else {
34 return false;
35 };
36 let Ok(origin) = Uri::try_from(origin) else {
37 return false;
38 };
39 let Some(host) = origin.host() else {
40 return false;
41 };
42
43 if host == "localhost"
45 || host.parse::<Ipv4Addr>() == Ok(Ipv4Addr::LOCALHOST)
46 || host.parse::<Ipv6Addr>() == Ok(Ipv6Addr::LOCALHOST)
47 {
48 return true;
49 }
50
51 additional_allowed_origins.iter().any(|allowed_origin| {
53 allowed_origin.scheme().eq(&origin.scheme())
54 && allowed_origin.host().eq(&origin.host())
55 && allowed_origin.port().eq(&origin.port())
56 })
57 });
58
59 CorsLayer::new()
60 .allow_origin(allowed_origins)
61 .allow_credentials(true)
62 .allow_headers(allowed_headers)
63 .allow_methods(allowed_methods)
64 .expose_headers(exposed_headers)
65}