pub(crate) type CookiePairs = Box<[(Box<str>, Box<str>)]>;
use super::strip_quotes;
pub(crate) fn parse_cookies(header_value: &str) -> CookiePairs {
header_value
.split(';')
.filter_map(|pair| parse_one_cookie(pair.trim()))
.collect()
}
pub(crate) fn sanitize_cookie(field: &str) -> String {
field.replace(';', "")
}
fn parse_one_cookie(trimmed: &str) -> Option<(Box<str>, Box<str>)> {
let (name, value) = match trimmed.split_once('=') {
Some((n, v)) => (n.trim(), strip_quotes(v.trim())),
None => (trimmed, ""),
};
match name.is_empty() {
true => None,
false => Some((Box::from(name), Box::from(value))),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SameSite {
Strict,
Lax,
None,
}
impl SameSite {
fn as_str(self) -> &'static str {
match self {
Self::Strict => "Strict",
Self::Lax => "Lax",
Self::None => "None",
}
}
}
#[derive(Debug, Clone)]
pub struct CookieOptions {
path: Option<Box<str>>,
domain: Option<Box<str>>,
max_age: Option<u64>,
same_site: Option<SameSite>,
is_secure: bool,
is_http_only: bool,
}
impl Default for CookieOptions {
fn default() -> Self {
Self::new()
}
}
impl CookieOptions {
pub fn new() -> Self {
Self {
path: None,
domain: None,
max_age: None,
same_site: None,
is_secure: false,
is_http_only: false,
}
}
pub fn path(mut self, path: &str) -> Self {
self.path = Some(path.into());
self
}
pub fn domain(mut self, domain: &str) -> Self {
self.domain = Some(domain.into());
self
}
pub fn max_age(mut self, seconds: u64) -> Self {
self.max_age = Some(seconds);
self
}
pub fn same_site(mut self, value: SameSite) -> Self {
self.same_site = Some(value);
self
}
pub fn secure(mut self) -> Self {
self.is_secure = true;
self
}
pub fn http_only(mut self) -> Self {
self.is_http_only = true;
self
}
pub(crate) fn format_header(&self, name: &str, value: &str) -> String {
let mut header = format!("{}={}", sanitize_cookie(name), sanitize_cookie(value));
if let Some(ref path) = self.path {
header.push_str("; Path=");
header.push_str(&sanitize_cookie(path));
}
if let Some(ref domain) = self.domain {
header.push_str("; Domain=");
header.push_str(&sanitize_cookie(domain));
}
if let Some(seconds) = self.max_age {
header.push_str("; Max-Age=");
header.push_str(&seconds.to_string());
}
if self.is_secure {
header.push_str("; Secure");
}
if self.is_http_only {
header.push_str("; HttpOnly");
}
if let Some(same_site) = self.same_site {
header.push_str("; SameSite=");
header.push_str(same_site.as_str());
}
header
}
}