summaryrefslogtreecommitdiffstats
path: root/third_party/rust/hyper/src/common/date.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/hyper/src/common/date.rs')
-rw-r--r--third_party/rust/hyper/src/common/date.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/third_party/rust/hyper/src/common/date.rs b/third_party/rust/hyper/src/common/date.rs
new file mode 100644
index 0000000000..a436fc07c0
--- /dev/null
+++ b/third_party/rust/hyper/src/common/date.rs
@@ -0,0 +1,124 @@
+use std::cell::RefCell;
+use std::fmt::{self, Write};
+use std::str;
+use std::time::{Duration, SystemTime};
+
+#[cfg(feature = "http2")]
+use http::header::HeaderValue;
+use httpdate::HttpDate;
+
+// "Sun, 06 Nov 1994 08:49:37 GMT".len()
+pub(crate) const DATE_VALUE_LENGTH: usize = 29;
+
+#[cfg(feature = "http1")]
+pub(crate) fn extend(dst: &mut Vec<u8>) {
+ CACHED.with(|cache| {
+ dst.extend_from_slice(cache.borrow().buffer());
+ })
+}
+
+#[cfg(feature = "http1")]
+pub(crate) fn update() {
+ CACHED.with(|cache| {
+ cache.borrow_mut().check();
+ })
+}
+
+#[cfg(feature = "http2")]
+pub(crate) fn update_and_header_value() -> HeaderValue {
+ CACHED.with(|cache| {
+ let mut cache = cache.borrow_mut();
+ cache.check();
+ HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
+ })
+}
+
+struct CachedDate {
+ bytes: [u8; DATE_VALUE_LENGTH],
+ pos: usize,
+ next_update: SystemTime,
+}
+
+thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));
+
+impl CachedDate {
+ fn new() -> Self {
+ let mut cache = CachedDate {
+ bytes: [0; DATE_VALUE_LENGTH],
+ pos: 0,
+ next_update: SystemTime::now(),
+ };
+ cache.update(cache.next_update);
+ cache
+ }
+
+ fn buffer(&self) -> &[u8] {
+ &self.bytes[..]
+ }
+
+ fn check(&mut self) {
+ let now = SystemTime::now();
+ if now > self.next_update {
+ self.update(now);
+ }
+ }
+
+ fn update(&mut self, now: SystemTime) {
+ self.render(now);
+ self.next_update = now + Duration::new(1, 0);
+ }
+
+ fn render(&mut self, now: SystemTime) {
+ self.pos = 0;
+ let _ = write!(self, "{}", HttpDate::from(now));
+ debug_assert!(self.pos == DATE_VALUE_LENGTH);
+ }
+}
+
+impl fmt::Write for CachedDate {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ let len = s.len();
+ self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
+ self.pos += len;
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[cfg(feature = "nightly")]
+ use test::Bencher;
+
+ #[test]
+ fn test_date_len() {
+ assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
+ }
+
+ #[cfg(feature = "nightly")]
+ #[bench]
+ fn bench_date_check(b: &mut Bencher) {
+ let mut date = CachedDate::new();
+ // cache the first update
+ date.check();
+
+ b.iter(|| {
+ date.check();
+ });
+ }
+
+ #[cfg(feature = "nightly")]
+ #[bench]
+ fn bench_date_render(b: &mut Bencher) {
+ let mut date = CachedDate::new();
+ let now = SystemTime::now();
+ date.render(now);
+ b.bytes = date.buffer().len() as u64;
+
+ b.iter(|| {
+ date.render(now);
+ test::black_box(&date);
+ });
+ }
+}