1 use std::cell::RefCell;
2 use std::fmt::{self, Write};
3 use std::str;
4 use std::time::{Duration, SystemTime};
5
6 #[cfg(feature = "http2")]
7 use http::header::HeaderValue;
8 use httpdate::HttpDate;
9
10 // "Sun, 06 Nov 1994 08:49:37 GMT".len()
11 pub(crate) const DATE_VALUE_LENGTH: usize = 29;
12
13 #[cfg(feature = "http1")]
extend(dst: &mut Vec<u8>)14 pub(crate) fn extend(dst: &mut Vec<u8>) {
15 CACHED.with(|cache| {
16 dst.extend_from_slice(cache.borrow().buffer());
17 })
18 }
19
20 #[cfg(feature = "http1")]
update()21 pub(crate) fn update() {
22 CACHED.with(|cache| {
23 cache.borrow_mut().check();
24 })
25 }
26
27 #[cfg(feature = "http2")]
update_and_header_value() -> HeaderValue28 pub(crate) fn update_and_header_value() -> HeaderValue {
29 CACHED.with(|cache| {
30 let mut cache = cache.borrow_mut();
31 cache.check();
32 HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
33 })
34 }
35
36 struct CachedDate {
37 bytes: [u8; DATE_VALUE_LENGTH],
38 pos: usize,
39 next_update: SystemTime,
40 }
41
42 thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));
43
44 impl CachedDate {
new() -> Self45 fn new() -> Self {
46 let mut cache = CachedDate {
47 bytes: [0; DATE_VALUE_LENGTH],
48 pos: 0,
49 next_update: SystemTime::now(),
50 };
51 cache.update(cache.next_update);
52 cache
53 }
54
buffer(&self) -> &[u8]55 fn buffer(&self) -> &[u8] {
56 &self.bytes[..]
57 }
58
check(&mut self)59 fn check(&mut self) {
60 let now = SystemTime::now();
61 if now > self.next_update {
62 self.update(now);
63 }
64 }
65
update(&mut self, now: SystemTime)66 fn update(&mut self, now: SystemTime) {
67 self.render(now);
68 self.next_update = now + Duration::new(1, 0);
69 }
70
render(&mut self, now: SystemTime)71 fn render(&mut self, now: SystemTime) {
72 self.pos = 0;
73 let _ = write!(self, "{}", HttpDate::from(now));
74 debug_assert!(self.pos == DATE_VALUE_LENGTH);
75 }
76 }
77
78 impl fmt::Write for CachedDate {
write_str(&mut self, s: &str) -> fmt::Result79 fn write_str(&mut self, s: &str) -> fmt::Result {
80 let len = s.len();
81 self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
82 self.pos += len;
83 Ok(())
84 }
85 }
86
87 #[cfg(test)]
88 mod tests {
89 use super::*;
90
91 #[cfg(feature = "nightly")]
92 use test::Bencher;
93
94 #[test]
test_date_len()95 fn test_date_len() {
96 assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
97 }
98
99 #[cfg(feature = "nightly")]
100 #[bench]
bench_date_check(b: &mut Bencher)101 fn bench_date_check(b: &mut Bencher) {
102 let mut date = CachedDate::new();
103 // cache the first update
104 date.check();
105
106 b.iter(|| {
107 date.check();
108 });
109 }
110
111 #[cfg(feature = "nightly")]
112 #[bench]
bench_date_render(b: &mut Bencher)113 fn bench_date_render(b: &mut Bencher) {
114 let mut date = CachedDate::new();
115 let now = SystemTime::now();
116 date.render(now);
117 b.bytes = date.buffer().len() as u64;
118
119 b.iter(|| {
120 date.render(now);
121 test::black_box(&date);
122 });
123 }
124 }
125