cookie_monster/cookie/expires/
dep_chrono.rs1use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, NaiveTime, Utc};
2
3use crate::{Cookie, Error, cookie::expires::ExpVal};
4
5use super::Expires;
6
7static FMT: &str = "%a, %d %b %Y %T GMT";
9
10static MAX_EXPIRES: DateTime<Utc> = NaiveDateTime::new(
11 NaiveDate::from_ymd_opt(9999, 12, 31).unwrap(),
12 NaiveTime::from_hms_micro_opt(23, 59, 59, 59).unwrap(),
13)
14.and_utc();
15
16impl From<DateTime<Utc>> for Expires {
17 fn from(value: DateTime<Utc>) -> Self {
18 Self::Exp(ExpVal {
19 chrono: Some(std::cmp::min(value, MAX_EXPIRES)),
20 ..Default::default()
21 })
22 }
23}
24
25impl Cookie {
26 pub fn expires_chrono(&self) -> Option<DateTime<Utc>> {
28 match &self.expires {
29 Expires::Exp(ExpVal { chrono, .. }) => *chrono,
30 _ => None,
31 }
32 }
33
34 pub fn max_age_chrono(&self) -> Option<Duration> {
36 self.max_age_secs()
37 .map(|max_age| Duration::seconds(max_age as i64))
38 }
39}
40
41impl Expires {
42 pub fn remove_chrono() -> Self {
44 Self::from(Utc::now() - Duration::days(365))
45 }
46}
47
48pub(super) fn ser_expires(expires: &DateTime<Utc>, buf: &mut String) -> crate::Result<()> {
49 buf.push_str("; Expires=");
50
51 expires
52 .format(FMT)
53 .write_to(buf)
54 .map_err(|_| Error::ExpiresFmt)
55}
56
57#[cfg(test)]
58mod test_chrono {
59 use crate::{Cookie, cookie::expires::dep_chrono::MAX_EXPIRES};
60 use chrono::{Duration, TimeZone, Utc};
61
62 #[test]
63 fn parse() {
64 let expires = Utc.with_ymd_and_hms(2015, 10, 21, 7, 28, 0).unwrap();
65
66 let expected = Cookie::build("foo", "bar").expires(expires).build();
67
68 assert_eq!(
69 expected.serialize().as_deref(),
70 Ok("foo=bar; Expires=Wed, 21 Oct 2015 07:28:00 GMT")
71 )
72 }
73
74 #[test]
75 fn large_date() {
76 assert_eq!(
77 Cookie::build("foo", "bar")
78 .expires(MAX_EXPIRES + Duration::weeks(1))
79 .build()
80 .serialize()
81 .as_deref(),
82 Ok("foo=bar; Expires=Fri, 31 Dec 9999 23:59:59 GMT")
83 );
84 }
85}