1
2use std::fmt::Display;
3
4use crate::util::KVParser;
5
6#[allow(dead_code)]
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum SameSite {
9 Undefined,
10 No,
11 Lax,
12 Strict,
13}
14
15#[derive(Debug, Clone)]
18pub struct Cookie<'buf> {
19 pub name: &'buf str,
20 pub value: String,
21 pub secure: bool,
22 pub http_only: bool,
23 pub same_site: SameSite,
24 pub domain: &'buf str,
25 pub path: &'buf str,
26 pub max_age: i64,
27}
28
29impl<'buf> Default for Cookie<'buf> {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl<'buf> Display for Cookie<'buf> {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 let mut out = format!("{}={}", self.name, self.value);
38 if self.secure {
39 out += "; Secure";
40 }
41 if self.http_only {
42 out += "; HttpOnly";
43 }
44 out += match self.same_site {
45 SameSite::Undefined => "",
46 SameSite::No => "; SameSite=No",
47 SameSite::Lax => "; SameSite=Lax",
48 SameSite::Strict => "; SameSite=Strict",
49 };
50 if !self.domain.is_empty() {
51 out += &format!("; Domain={}", self.domain);
52 }
53 if !self.path.is_empty() {
54 out += &format!("; Path={}", self.path);
55 }
56 if self.max_age > 0 {
57 out += &format!("; Max-Age={}", self.max_age);
58 }
59 write!(f, "{out}")
60 }
61}
62
63impl<'buf> Cookie<'buf> {
64 pub fn new() -> Self {
65 Self {
66 name: "",
67 value: "".to_string(),
68 secure: false,
69 http_only: false,
70 same_site: SameSite::Undefined,
71 domain: "",
72 path: "",
73 max_age: -1i64,
74 }
75 }
76
77 pub fn builder() -> CookieBuilder<'buf> {
79 CookieBuilder::new()
80 }
81}
82
83#[derive(Default)]
84pub struct CookieBuilder<'buf> {
85 cookie: Cookie<'buf>,
86}
87
88#[allow(dead_code)]
89impl<'buf> CookieBuilder<'buf> {
90 pub fn new() -> Self {
91 Self {
92 cookie: Cookie::new(),
93 }
94 }
95
96 pub fn name(mut self, name: &'buf str) -> Self {
97 self.cookie.name = name;
98 self
99 }
100
101 pub fn value(mut self, value: &str) -> Self {
102 self.cookie.value = value.to_string();
103 self
104 }
105
106 pub fn secure(mut self, secure: bool) -> Self {
107 self.cookie.secure = secure;
108 self
109 }
110
111 pub fn http_only(mut self, http_only: bool) -> Self {
112 self.cookie.http_only = http_only;
113 self
114 }
115
116 pub fn same_site(mut self, same_site: SameSite) -> Self {
117 self.cookie.same_site = same_site;
118 self
119 }
120
121 pub fn domain(mut self, domain: &'buf str) -> Self {
122 self.cookie.domain = domain;
123 self
124 }
125
126 pub fn path(mut self, path: &'buf str) -> Self {
127 self.cookie.path = path;
128 self
129 }
130
131 pub fn max_age(mut self, max_age: i64) -> Self {
132 self.cookie.max_age = max_age;
133 self
134 }
135
136 pub fn build(self) -> Cookie<'buf> {
137 self.cookie
138 }
139}
140
141pub fn parse_cookies(raw_cookies: &str) -> Vec<Cookie> {
146 if raw_cookies.is_empty() { return Vec::new() }
147
148 let mut cookies: Vec<Cookie> = Vec::new();
149 let mut cookie = Cookie::new();
150
151 for component in raw_cookies.split(';') {
152 let mut pp = KVParser::new(component.trim());
153 if let Some((key, value)) = pp.cookie_kv_pair() {
154 cookie.name = key;
155 cookie.value = value.to_string();
156 cookies.push(cookie);
157 cookie = Cookie::new();
158 }
159 }
160
161 cookies
162}
163