cookie_monster/cookie/expires/
dep_chrono.rs

1use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, NaiveTime, Utc};
2
3use crate::{Cookie, Error, cookie::expires::ExpVal};
4
5use super::Expires;
6
7// Sun, 06 Nov 1994 08:49:37 GMT (RFC)
8static 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    /// Returns the Expires attribute using [`chrono::DateTime`].
27    pub fn expires_chrono(&self) -> Option<DateTime<Utc>> {
28        match &self.expires {
29            Expires::Exp(ExpVal { chrono, .. }) => *chrono,
30            _ => None,
31        }
32    }
33
34    /// Returns the Max-Age attribute using [`chrono::Duration`].
35    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    /// Creates an [`Expires`] with a [`chrono::DateTime`] one year in the past.
43    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}