cookie_store/
cookie_expiration.rs1use std;
2
3#[cfg(feature = "serde")]
4use serde_derive::{Deserialize, Serialize};
5use time::{self, OffsetDateTime};
6
7#[derive(Eq, Clone, Debug)]
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10pub enum CookieExpiration {
11 #[cfg_attr(feature = "serde", serde(with = "crate::rfc3339_fmt"))]
14 AtUtc(OffsetDateTime),
15 SessionEnd,
18}
19
20impl std::cmp::PartialEq for CookieExpiration {
22 fn eq(&self, other: &Self) -> bool {
23 match (self, other) {
24 (CookieExpiration::SessionEnd, CookieExpiration::SessionEnd) => true,
25 (CookieExpiration::AtUtc(this_offset), CookieExpiration::AtUtc(other_offset)) => {
26 this_offset.date() == other_offset.date()
28 && this_offset.time().hour() == other_offset.time().hour()
29 && this_offset.time().minute() == other_offset.time().minute()
30 && this_offset.time().second() == other_offset.time().second()
31 }
32 _ => false,
33 }
34 }
35}
36
37impl CookieExpiration {
38 pub fn is_expired(&self) -> bool {
40 self.expires_by(&time::OffsetDateTime::now_utc())
41 }
42
43 pub fn expires_by(&self, utc_tm: &time::OffsetDateTime) -> bool {
45 match *self {
46 CookieExpiration::AtUtc(ref expire_tm) => *expire_tm <= *utc_tm,
47 CookieExpiration::SessionEnd => false,
48 }
49 }
50}
51
52const MAX_RFC3339: time::OffsetDateTime = time::macros::date!(9999 - 12 - 31)
53 .with_time(time::macros::time!(23:59:59))
54 .assume_utc();
55impl From<u64> for CookieExpiration {
56 fn from(max_age: u64) -> CookieExpiration {
57 CookieExpiration::from(time::Duration::seconds(std::cmp::min(
60 time::Duration::MAX.whole_seconds() as u64,
61 max_age,
62 ) as i64))
63 }
64}
65
66impl From<time::OffsetDateTime> for CookieExpiration {
67 fn from(utc_tm: OffsetDateTime) -> CookieExpiration {
68 CookieExpiration::AtUtc(utc_tm.min(MAX_RFC3339))
69 }
70}
71
72impl From<cookie::Expiration> for CookieExpiration {
73 fn from(expiration: cookie::Expiration) -> CookieExpiration {
74 match expiration {
75 cookie::Expiration::DateTime(offset) => CookieExpiration::AtUtc(offset),
76 cookie::Expiration::Session => CookieExpiration::SessionEnd,
77 }
78 }
79}
80
81impl From<time::Duration> for CookieExpiration {
82 fn from(duration: time::Duration) -> Self {
83 let utc_tm = if duration.is_zero() {
87 time::OffsetDateTime::UNIX_EPOCH
88 } else {
89 let now_utc = time::OffsetDateTime::now_utc();
90 let d = (MAX_RFC3339 - now_utc).min(duration);
91 now_utc + d
92 };
93 CookieExpiration::from(utc_tm)
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::CookieExpiration;
100 use time;
101
102 use crate::utils::test::*;
103
104 #[test]
105 fn max_age_bounds() {
106 match CookieExpiration::from(time::Duration::MAX.whole_seconds() as u64 + 1) {
107 CookieExpiration::AtUtc(_) => assert!(true),
108 _ => assert!(false),
109 }
110 }
111
112 #[test]
113 fn expired() {
114 let ma = CookieExpiration::from(0u64); assert!(ma.is_expired());
116 assert!(ma.expires_by(&in_days(-1)));
117 }
118
119 #[test]
120 fn max_age() {
121 let ma = CookieExpiration::from(60u64);
122 assert!(!ma.is_expired());
123 assert!(ma.expires_by(&in_minutes(2)));
124 }
125
126 #[test]
127 fn session_end() {
128 let se = CookieExpiration::SessionEnd;
130 assert!(!se.is_expired());
131 assert!(!se.expires_by(&in_days(1)));
132 assert!(!se.expires_by(&in_days(-1)));
133 }
134
135 #[test]
136 fn at_utc() {
137 {
138 let expire_tmrw = CookieExpiration::from(in_days(1));
139 assert!(!expire_tmrw.is_expired());
140 assert!(expire_tmrw.expires_by(&in_days(2)));
141 }
142 {
143 let expired_yest = CookieExpiration::from(in_days(-1));
144 assert!(expired_yest.is_expired());
145 assert!(!expired_yest.expires_by(&in_days(-2)));
146 }
147 }
148}