use crate::headers::Headers;
pub const DEFAULT_ALLOWED_HEADERS: [&str; 5] = [
"Content-Type",
"Accept",
"Authorization",
"If-Match",
"If-None-Match",
];
pub const DEFAULT_EXPOSED_HEADERS: [&str; 4] = ["ETag", "Link", "Location", "Allow"];
pub const DEFAULT_METHODS: [&str; 7] = ["GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CorsPolicy {
pub origins: Vec<String>,
pub methods: Vec<String>,
pub allowed_headers: Vec<String>,
pub exposed_headers: Vec<String>,
pub credentials: bool,
pub max_age: u32,
}
impl Default for CorsPolicy {
fn default() -> Self {
Self::permissive()
}
}
impl CorsPolicy {
pub fn permissive() -> Self {
Self {
origins: vec!["*".to_string()],
methods: DEFAULT_METHODS.iter().map(|m| m.to_string()).collect(),
allowed_headers: DEFAULT_ALLOWED_HEADERS
.iter()
.map(|h| h.to_string())
.collect(),
exposed_headers: DEFAULT_EXPOSED_HEADERS
.iter()
.map(|h| h.to_string())
.collect(),
credentials: false,
max_age: 600,
}
}
pub fn with_origins<I, S>(mut self, origins: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.origins = origins.into_iter().map(Into::into).collect();
self
}
pub fn with_credentials(mut self, credentials: bool) -> Self {
self.credentials = credentials;
self
}
pub fn with_max_age(mut self, max_age: u32) -> Self {
self.max_age = max_age;
self
}
}
pub fn cors_headers(policy: &CorsPolicy, request_origin: Option<&str>) -> Headers {
let wildcard = policy.origins.iter().any(|origin| origin == "*");
let allow_origin = if wildcard {
match (policy.credentials, request_origin) {
(true, Some(origin)) => Some(origin.to_string()),
_ => Some("*".to_string()),
}
} else {
request_origin
.filter(|origin| policy.origins.iter().any(|allowed| allowed == origin))
.map(str::to_string)
};
let Some(allow_origin) = allow_origin else {
return Headers::new();
};
let mut headers = Headers::from_pairs([
("Access-Control-Allow-Origin", allow_origin),
("Access-Control-Allow-Methods", policy.methods.join(", ")),
(
"Access-Control-Allow-Headers",
policy.allowed_headers.join(", "),
),
(
"Access-Control-Expose-Headers",
policy.exposed_headers.join(", "),
),
("Access-Control-Max-Age", policy.max_age.to_string()),
]);
if policy.credentials {
headers.insert("Access-Control-Allow-Credentials", "true");
}
headers
}