use crate::http::headers::Header;
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<Header> {
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(Header::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 Header {
fn from(cookie: SetCookie) -> Self {
let mut value = format!("{}={}", cookie.name, cookie.value);
if let Some(expires) = cookie.expires {
value = format!("{}; Expires={}", value, 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!("{}; Domain={}", value, domain);
}
if let Some(path) = cookie.path {
value = format!("{}; Path={}", value, 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!("{}; Secure", value);
}
if cookie.http_only {
value = format!("{}; HttpOnly", value);
}
Header::new("Set-Cookie", value)
}
}