cookie_monster/cookie/builder.rs
1use std::{
2 borrow::{Borrow, Cow},
3 fmt,
4 time::Duration,
5};
6
7use crate::Cookie;
8
9use super::{expires::Expires, same_site::SameSite};
10
11/// A builder struct for building a [`Cookie`].
12#[derive(PartialEq, Clone)]
13pub struct CookieBuilder(Cookie);
14
15impl CookieBuilder {
16 /// Build a new cookie. This returns a `CookieBuilder` that can be used to set other attribute
17 /// values.
18 ///
19 /// # Example
20 /// ```rust
21 /// use cookie_monster::CookieBuilder;
22 ///
23 /// let cookie = CookieBuilder::new("foo", "bar")
24 /// .secure()
25 /// .http_only()
26 /// .build();
27 ///
28 /// assert!(cookie.is_secure());
29 /// assert!(cookie.is_http_only());
30 /// ```
31 #[inline]
32 pub fn new<N, V>(name: N, value: V) -> CookieBuilder
33 where
34 N: Into<Cow<'static, str>>,
35 V: Into<Cow<'static, str>>,
36 {
37 CookieBuilder(Cookie::new(name, value))
38 }
39
40 /// Sets the name of the cookie.
41 #[inline]
42 pub fn name<N: Into<Cow<'static, str>>>(mut self, name: N) -> Self {
43 self.0.set_name(name);
44 self
45 }
46
47 /// Returns the name of the cookie.
48 pub fn get_name(&self) -> &str {
49 self.0.name()
50 }
51
52 /// Sets the name of the cookie.
53 #[inline]
54 pub fn set_name<N: Into<Cow<'static, str>>>(&mut self, name: N) {
55 self.0.set_name(name);
56 }
57
58 /// Stores the cookie name prefix flavour. Used by [`Cookie::host`] / [`Cookie::secure`].
59 #[inline]
60 pub(crate) fn with_prefix(mut self, prefix: super::prefix::CookiePrefix) -> Self {
61 self.0.prefix = Some(prefix);
62 self
63 }
64
65 /// Sets the value of the cookie.
66 #[inline]
67 pub fn value<V: Into<Cow<'static, str>>>(mut self, value: V) -> Self {
68 self.0.set_value(value);
69 self
70 }
71
72 /// Returns the value of the cookie.
73 pub fn get_value(&self) -> &str {
74 self.0.value()
75 }
76
77 /// Sets the value of the cookie.
78 pub fn set_value<V>(&mut self, value: V)
79 where
80 V: Into<Cow<'static, str>>,
81 {
82 self.0.value = value.into().into();
83 }
84
85 /// Sets the Expires attribute of the cookie.
86 ///
87 /// The argument can be a few different types, based on what features are enabled.
88 ///
89 /// # No features needed
90 ///
91 /// ```rust
92 /// use cookie_monster::{Cookie, Expires};
93 ///
94 /// let cookie = Cookie::build("foo", "bar")
95 /// .expires(Expires::remove())
96 /// .build();
97 ///
98 /// assert!(cookie.expires_is_set());
99 /// ```
100 ///
101 /// # Jiff
102 /// ```rust
103 /// # #[cfg(feature="jiff")]
104 /// # {
105 /// # use cookie_monster::Cookie;
106 /// use jiff::Zoned;
107 ///
108 /// let cookie = Cookie::build("foo", "bar")
109 /// .expires(Zoned::now())
110 /// .build();
111 ///
112 /// # assert!(cookie.expires_is_set());
113 /// # }
114 /// ```
115 ///
116 /// # Chrono
117 /// ```rust
118 /// # #[cfg(feature="chrono")]
119 /// # {
120 /// # use cookie_monster::Cookie;
121 /// use chrono::Utc;
122 ///
123 /// let cookie = Cookie::build("foo", "bar")
124 /// .expires(Utc::now())
125 /// .build();
126 ///
127 /// # assert!(cookie.expires_is_set());
128 /// # }
129 /// ```
130 ///
131 /// # Time
132 /// ```rust
133 /// # #[cfg(feature="time")]
134 /// # {
135 /// # use cookie_monster::Cookie;
136 /// use time::OffsetDateTime;
137 ///
138 /// let cookie = Cookie::build("foo", "bar")
139 /// .expires(OffsetDateTime::now_utc())
140 /// .build();
141 ///
142 /// # assert!(cookie.expires_is_set());
143 /// # }
144 /// ```
145 #[inline]
146 pub fn expires(mut self, expiration: impl Into<Expires>) -> Self {
147 self.0.set_expires(expiration.into());
148 self
149 }
150
151 /// Sets the Expires attribute of the cookie.
152 pub fn set_expires(&mut self, expiration: impl Into<Expires>) {
153 self.0.set_expires(expiration.into());
154 }
155
156 /// Sets the Max-Age attribute of the cookie.
157 ///
158 /// # Example
159 /// ```rust
160 /// use cookie_monster::Cookie;
161 ///
162 /// let cookie = Cookie::build("foo", "bar")
163 /// .max_age_secs(100)
164 /// .build();
165 ///
166 /// assert_eq!(cookie.max_age_secs(), Some(100));
167 /// ```
168 #[inline]
169 pub fn max_age_secs(mut self, max_age_secs: u64) -> Self {
170 self.0.set_max_age_secs(max_age_secs);
171 self
172 }
173
174 /// Sets the Max-Age attribute in seconds.
175 pub fn set_max_age_secs(&mut self, max_age_secs: u64) {
176 self.0.set_max_age_secs(max_age_secs);
177 }
178
179 /// Sets the Max-Age attribute of the cookie.
180 ///
181 /// # Example
182 /// ```rust
183 /// use cookie_monster::Cookie;
184 /// use std::time::Duration;
185 ///
186 /// let cookie = Cookie::build("foo", "bar")
187 /// .max_age(Duration::from_secs(100))
188 /// .build();
189 ///
190 /// assert_eq!(cookie.max_age(), Some(Duration::from_secs(100)));
191 /// ```
192 #[inline]
193 pub fn max_age(mut self, max_age: Duration) -> Self {
194 self.0.set_max_age(max_age);
195 self
196 }
197
198 /// Returns the Max-Age attribute of the cookie.
199 pub fn get_max_age(&self) -> Option<Duration> {
200 self.0.max_age()
201 }
202
203 /// Sets the Max-Age attribute of the cookie.
204 #[inline]
205 pub fn set_max_age(&mut self, max_age: Duration) {
206 self.0.set_max_age(max_age);
207 }
208
209 /// Sets the Domain attribute of the cookie.
210 ///
211 /// # Note
212 /// If the domain attribute is set to an empty string or the string contains an invalid cookie
213 /// character, the attribute is ignored.
214 ///
215 /// # Example
216 /// ```rust
217 /// use cookie_monster::Cookie;
218 ///
219 /// let cookie = Cookie::build("foo", "bar")
220 /// .domain("rust-lang.com")
221 /// .build();
222 ///
223 /// assert_eq!(cookie.domain(), Some("rust-lang.com"));
224 /// ```
225 #[inline]
226 pub fn domain<D: Into<Cow<'static, str>>>(mut self, domain: D) -> Self {
227 self.0.set_domain(domain);
228 self
229 }
230
231 /// Sets the Domain attribute of the cookie.
232 #[inline]
233 pub fn set_domain<D: Into<Cow<'static, str>>>(&mut self, domain: D) {
234 self.0.set_domain(domain);
235 }
236
237 /// Sets the Path attribute of the cookie.
238 ///
239 /// # Note
240 /// Not all path value's are allowed by the standard:
241 /// * The path can't be set to and empty string.
242 /// * The path must start with a leading `/`.
243 /// * The path can't contain invalid cookie characters.
244 ///
245 /// If any of these conditions are not met, serializing this cookie returns an error.
246 ///
247 /// # Example
248 /// ```rust
249 /// use cookie_monster::Cookie;
250 ///
251 /// let cookie = Cookie::build("foo", "bar")
252 /// .path("/api/login")
253 /// .build();
254 ///
255 /// assert_eq!(cookie.path(), Some("/api/login"));
256 /// ```
257 #[inline]
258 pub fn path<D: Into<Cow<'static, str>>>(mut self, path: D) -> Self {
259 self.0.set_path(path);
260 self
261 }
262
263 /// Returns the Path attribute of the cookie.
264 pub fn get_path(&self) -> Option<&str> {
265 self.0.path()
266 }
267
268 /// Sets the Path attribute of the cookie.
269 #[inline]
270 pub fn set_path<D: Into<Cow<'static, str>>>(&mut self, path: D) {
271 self.0.set_path(path);
272 }
273
274 /// Sets the Secure attribute of the cookie.
275 ///
276 /// # Example
277 /// ```rust
278 /// use cookie_monster::Cookie;
279 ///
280 /// let cookie = Cookie::build("foo", "bar")
281 /// .secure()
282 /// .build();
283 ///
284 /// assert!(cookie.is_secure());
285 /// ```
286 #[inline]
287 pub fn secure(mut self) -> Self {
288 self.0.set_secure(true);
289 self
290 }
291
292 /// Sets the Secure attribute.
293 #[inline]
294 pub fn set_secure(mut self, secure: bool) -> Self {
295 self.0.set_secure(secure);
296 self
297 }
298
299 /// Sets the HttpOnly attribute of the cookie.
300 ///
301 /// # Example
302 /// ```rust
303 /// use cookie_monster::Cookie;
304 ///
305 /// let cookie = Cookie::build("foo", "bar")
306 /// .http_only()
307 /// .build();
308 ///
309 /// assert!(cookie.is_http_only());
310 /// ```
311 #[inline]
312 pub fn http_only(mut self) -> Self {
313 self.0.set_http_only(true);
314 self
315 }
316
317 /// Sets the HttpOnly attribute of the cookie.
318 #[inline]
319 pub fn set_http_only(mut self, http_only: bool) -> Self {
320 self.0.set_http_only(http_only);
321 self
322 }
323
324 /// Sets the Partitioned attribute of the cookie. When the partitioned attribute is enabled, the
325 /// secure flag is also enabled while serializing.
326 ///
327 /// <https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies>
328 ///
329 /// # Example
330 /// ```rust
331 /// use cookie_monster::Cookie;
332 ///
333 /// let cookie = Cookie::build("foo", "bar")
334 /// .partitioned()
335 /// .build();
336 ///
337 /// assert!(cookie.is_partitioned());
338 /// ```
339 #[inline]
340 pub fn partitioned(self) -> Self {
341 self.set_partitioned(true)
342 }
343
344 /// Set the Partitioned flag, enabling the Partitioned attribute also enables the Secure Attribute.
345 #[inline]
346 pub fn set_partitioned(mut self, partitioned: bool) -> Self {
347 self.0.set_partitioned(partitioned);
348 self
349 }
350
351 /// Sets the SameSite attribute value of the cookie.
352 ///
353 /// # Example
354 /// ```rust
355 /// use cookie_monster::{Cookie, SameSite};
356 ///
357 /// let cookie = Cookie::build("foo", "bar")
358 /// .same_site(SameSite::Strict)
359 /// .build();
360 ///
361 /// assert_eq!(cookie.same_site(), Some(SameSite::Strict));
362 /// ```
363 #[inline]
364 pub fn same_site<S: Into<Option<SameSite>>>(mut self, same_site: S) -> Self {
365 self.0.set_same_site(same_site);
366 self
367 }
368
369 /// Builds and returns the cookie
370 #[inline]
371 pub fn build(self) -> Cookie {
372 self.0
373 }
374}
375
376impl fmt::Debug for CookieBuilder {
377 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378 fmt::Debug::fmt(&self.0, f)
379 }
380}
381
382impl fmt::Display for CookieBuilder {
383 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384 fmt::Display::fmt(&self.0, f)
385 }
386}
387
388impl Borrow<Cookie> for CookieBuilder {
389 fn borrow(&self) -> &Cookie {
390 &self.0
391 }
392}
393
394impl From<CookieBuilder> for Cookie {
395 fn from(value: CookieBuilder) -> Self {
396 value.build()
397 }
398}