pingora_core/protocols/http/
date.rs1use chrono::DateTime;
16use http::header::HeaderValue;
17use std::cell::RefCell;
18use std::time::{Duration, SystemTime};
19
20fn to_date_string(epoch_sec: i64) -> String {
21 let dt = DateTime::from_timestamp(epoch_sec, 0).unwrap();
22 dt.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
23}
24
25struct CacheableDate {
26 h1_date: HeaderValue,
27 epoch: Duration,
28}
29
30impl CacheableDate {
31 pub fn new() -> Self {
32 let d = SystemTime::now()
33 .duration_since(SystemTime::UNIX_EPOCH)
34 .unwrap();
35 CacheableDate {
36 h1_date: HeaderValue::from_str(&to_date_string(d.as_secs() as i64)).unwrap(),
37 epoch: d,
38 }
39 }
40
41 pub fn update(&mut self, d_now: Duration) {
42 if d_now.as_secs() != self.epoch.as_secs() {
43 self.epoch = d_now;
44 self.h1_date = HeaderValue::from_str(&to_date_string(d_now.as_secs() as i64)).unwrap();
45 }
46 }
47
48 pub fn get_date(&mut self) -> HeaderValue {
49 let d = SystemTime::now()
50 .duration_since(SystemTime::UNIX_EPOCH)
51 .unwrap();
52 self.update(d);
53 self.h1_date.clone()
54 }
55}
56
57thread_local! {
58 static CACHED_DATE: RefCell<CacheableDate>
59 = RefCell::new(CacheableDate::new());
60}
61
62pub fn get_cached_date() -> HeaderValue {
63 CACHED_DATE.with(|cache_date| (*cache_date.borrow_mut()).get_date())
64}
65
66#[cfg(test)]
67mod test {
68 use super::*;
69
70 fn now_date_header() -> HeaderValue {
71 HeaderValue::from_str(&to_date_string(
72 SystemTime::now()
73 .duration_since(SystemTime::UNIX_EPOCH)
74 .unwrap()
75 .as_secs() as i64,
76 ))
77 .unwrap()
78 }
79
80 #[test]
81 fn test_date_string() {
82 let date_str = to_date_string(1);
83 assert_eq!("Thu, 01 Jan 1970 00:00:01 GMT", date_str);
84 }
85
86 #[test]
87 fn test_date_cached() {
88 assert_eq!(get_cached_date(), now_date_header());
89 }
90}