#[derive(Clone, Debug, PartialEq)]
pub enum SameSiteTypes {
Strict,
Lax,
None,
}
#[derive(Clone, Debug, PartialEq)]
pub enum CookieAttributes {
Secure,
HTTPOnly,
Path(String),
Domain(String),
SameSite(SameSiteTypes),
MaxAge(usize),
Expires(String),
}
impl CookieAttributes {
pub fn to_string(&self) -> String {
match self {
CookieAttributes::Secure => String::from("Secure"),
CookieAttributes::HTTPOnly => String::from("HttpOnly"),
CookieAttributes::Path(n) => format!("Path={}", n),
CookieAttributes::Domain(n) => format!("Domain={}", n),
CookieAttributes::SameSite(n) => match n {
SameSiteTypes::Strict => String::from("SameSite=Strict"),
SameSiteTypes::Lax => String::from("SameSite=Lax"),
SameSiteTypes::None => String::from("SameSite=None"),
},
CookieAttributes::MaxAge(n) => format!("Max-Age={}", n),
CookieAttributes::Expires(n) => format!("Expires={}", n),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Cookie {
name: String,
value: String,
attributes: Option<Vec<CookieAttributes>>,
}
impl Cookie {
pub fn new(name: String, value: String, attributes: Option<Vec<CookieAttributes>>) -> Cookie {
Cookie {
name,
value,
attributes,
}
}
pub fn from_string(string: String) -> Option<Cookie> {
let mut parts = string.split('=');
let name: String = match parts.next() {
Some(n) => n.to_string(),
None => {
return None;
}
};
let mut other_parts = string.split("; ");
let left = match other_parts.next() {
Some(n) => n,
None => return None,
};
let value = match left.split('=').nth(1) {
Some(n) => n,
None => return None,
};
let mut attributes: Vec<CookieAttributes> = Vec::new();
for i in string.split("; ").skip(1) {
if i.contains('=') {
let mut parts = i.split('=');
let left = match parts.next() {
Some(n) => n,
None => break,
};
let right = match parts.next() {
Some(n) => n,
None => break,
};
match left {
"Expires" => attributes.push(CookieAttributes::Expires(right.to_string())),
"Max-Age" => {
if let Ok(n) = right.parse::<usize>() {
attributes.push(CookieAttributes::MaxAge(n));
}
}
"Domain" => attributes.push(CookieAttributes::Domain(right.to_string())),
"Path" => attributes.push(CookieAttributes::Path(right.to_string())),
"SameSite" => match right {
"Lax" => attributes.push(CookieAttributes::SameSite(SameSiteTypes::Lax)),
"Strict" => {
attributes.push(CookieAttributes::SameSite(SameSiteTypes::Strict))
}
"None" => attributes.push(CookieAttributes::SameSite(SameSiteTypes::None)),
_ => (),
},
_ => (),
}
} else {
match i {
"Secure" => attributes.push(CookieAttributes::Secure),
"HttpOnly" => attributes.push(CookieAttributes::HTTPOnly),
_ => (),
}
}
}
let out_attributes: Option<Vec<CookieAttributes>> = match attributes.len() {
0 => None,
_ => Some(attributes),
};
Some(Cookie::new(name, value.to_string(), out_attributes))
}
pub fn to_string(&self) -> String {
let mut out: String = format!("{}={}", self.name, self.value);
if let Some(n) = &self.attributes {
for attr in n {
out.push_str(format!("; {}", attr.to_string()).as_str());
}
}
out
}
}