use cookie::Cookie;
use crate::Cookies;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Prefix {
Host,
Secure,
}
impl Prefix {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Prefix::Host => "__Host-",
Prefix::Secure => "__Secure-",
}
}
fn apply_name(self, cookie: &mut Cookie<'static>) {
if !cookie.name().starts_with(self.as_str()) {
let name = format!("{}{}", self.as_str(), cookie.name());
cookie.set_name(name);
}
}
fn strip_name(self, cookie: &mut Cookie<'static>) {
if let Some(stripped) = cookie.name().strip_prefix(self.as_str()) {
let stripped = stripped.to_owned();
cookie.set_name(stripped);
}
}
fn conform(self, cookie: &mut Cookie<'static>, mode: Conform) {
let force = matches!(mode, Conform::Override);
if force || cookie.secure().is_none() {
cookie.set_secure(true);
}
if self == Prefix::Host {
if force || cookie.path().is_none() {
cookie.set_path("/");
}
if force {
cookie.unset_domain();
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Conform {
Default,
Override,
}
#[derive(Debug, Clone, Copy)]
pub struct Prefixed<J> {
inner: J,
prefix: Prefix,
conform: Conform,
}
impl<J> Prefixed<J> {
pub(crate) fn new(inner: J, prefix: Prefix, conform: Conform) -> Self {
Self {
inner,
prefix,
conform,
}
}
fn prepare(&self, cookie: impl Into<Cookie<'static>>, mode: Conform) -> Cookie<'static> {
let mut cookie = cookie.into();
self.prefix.apply_name(&mut cookie);
self.prefix.conform(&mut cookie, mode);
cookie
}
}
impl<J: Cookies> Cookies for Prefixed<J> {
fn get(&self, name: &str) -> Option<Cookie<'static>> {
let prefixed = format!("{}{}", self.prefix.as_str(), name);
let mut cookie = self.inner.get(&prefixed)?;
self.prefix.strip_name(&mut cookie);
Some(cookie)
}
fn add<C: Into<Cookie<'static>>>(&self, cookie: C) {
self.inner.add(self.prepare(cookie, self.conform));
}
fn remove<C: Into<Cookie<'static>>>(&self, cookie: C) {
self.inner.remove(self.prepare(cookie, Conform::Override));
}
}