use crate::http::headers::HttpHeader;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Cookie {
pub name: String,
pub value: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SetCookie {
pub name: String,
pub value: String,
pub expires: Option<String>,
pub max_age: Option<Duration>,
pub domain: Option<String>,
pub path: Option<String>,
pub secure: bool,
pub http_only: bool,
pub same_site: Option<SameSite>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SameSite {
Strict,
Lax,
None,
}
impl Cookie {
pub fn new(name: impl AsRef<str>, value: impl AsRef<str>) -> Self {
Self { name: name.as_ref().to_string(), value: value.as_ref().to_string() }
}
pub fn to_header(cookies: impl AsRef<[Cookie]>) -> Option<HttpHeader> {
let cookies = cookies.as_ref();
if cookies.is_empty() {
return None;
}
let mut value = String::with_capacity(cookies.len() * 32);
for cookie in cookies {
value.push_str(&cookie.name);
value.push('=');
value.push_str(&cookie.value);
value.push_str("; ");
}
Some(HttpHeader::new("Cookie", &value[..value.len() - 2]))
}
}
impl SetCookie {
pub fn new(name: impl AsRef<str>, value: impl AsRef<str>) -> Self {
Self {
name: name.as_ref().to_string(),
value: value.as_ref().to_string(),
expires: None,
max_age: None,
domain: None,
path: None,
secure: false,
http_only: false,
same_site: None,
}
}
pub fn with_expires(mut self, expires: impl AsRef<str>) -> Self {
self.expires = Some(expires.as_ref().to_string());
self
}
pub fn with_max_age(mut self, max_age: Duration) -> Self {
self.max_age = Some(max_age);
self
}
pub fn with_domain(mut self, domain: impl AsRef<str>) -> Self {
self.domain = Some(domain.as_ref().to_string());
self
}
pub fn with_path(mut self, path: impl AsRef<str>) -> Self {
self.path = Some(path.as_ref().to_string());
self
}
pub fn with_secure(mut self, secure: bool) -> Self {
self.secure = secure;
self
}
pub fn with_http_only(mut self, http_only: bool) -> Self {
self.http_only = http_only;
self
}
pub fn with_same_site(mut self, same_site: SameSite) -> Self {
self.same_site = Some(same_site);
self
}
}
impl From<SetCookie> for HttpHeader {
fn from(cookie: SetCookie) -> Self {
let mut value = format!("{}={}", cookie.name, cookie.value);
if let Some(expires) = cookie.expires {
value = format!("{value}; Expires={expires}");
}
if let Some(max_age) = cookie.max_age {
value = format!("{}; Max-Age={}", value, max_age.as_secs());
}
if let Some(domain) = cookie.domain {
value = format!("{value}; Domain={domain}");
}
if let Some(path) = cookie.path {
value = format!("{value}; Path={path}");
}
if let Some(same_site) = cookie.same_site {
value = format!(
"{}; SameSite={}",
value,
match same_site {
SameSite::Strict => "Strict",
SameSite::Lax => "Lax",
SameSite::None => "None",
}
);
}
if cookie.secure {
value = format!("{value}; Secure");
}
if cookie.http_only {
value = format!("{value}; HttpOnly");
}
HttpHeader::new("Set-Cookie", value)
}
}