use std::{fmt, sync::Arc};
use salvo_core::http::header::{self, HeaderName, HeaderValue};
use salvo_core::{Depot, Request};
#[derive(Clone, Default)]
#[must_use]
pub struct AllowCredentials(AllowCredentialsInner);
type JudgeFn = Arc<dyn for<'a> Fn(&'a HeaderValue, &'a Request, &'a Depot) -> bool + Send + Sync + 'static>;
impl AllowCredentials {
pub fn yes() -> Self {
Self(AllowCredentialsInner::Yes)
}
pub fn judge<F>(f: F) -> Self
where
F: Fn(&HeaderValue, &Request, &Depot) -> bool + Send + Sync + 'static,
{
Self(AllowCredentialsInner::Judge(Arc::new(f)))
}
pub(super) fn is_true(&self) -> bool {
matches!(&self.0, AllowCredentialsInner::Yes)
}
pub(super) fn to_header(
&self,
origin: Option<&HeaderValue>,
req: &Request,
depot: &Depot,
) -> Option<(HeaderName, HeaderValue)> {
let allow_creds = match &self.0 {
AllowCredentialsInner::Yes => true,
AllowCredentialsInner::No => false,
AllowCredentialsInner::Judge(c) => c(origin?, req, depot),
};
allow_creds.then_some((
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
HeaderValue::from_static("true"),
))
}
}
impl From<bool> for AllowCredentials {
fn from(v: bool) -> Self {
match v {
true => Self(AllowCredentialsInner::Yes),
false => Self(AllowCredentialsInner::No),
}
}
}
impl fmt::Debug for AllowCredentials {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
AllowCredentialsInner::Yes => f.debug_tuple("Yes").finish(),
AllowCredentialsInner::No => f.debug_tuple("No").finish(),
AllowCredentialsInner::Judge(_) => f.debug_tuple("Judge").finish(),
}
}
}
#[derive(Default, Clone)]
enum AllowCredentialsInner {
Yes,
#[default]
No,
Judge(JudgeFn),
}