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