http_types/conditional/
last_modified.rs1use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, LAST_MODIFIED};
2use crate::utils::{fmt_http_date, parse_http_date};
3
4use std::fmt::Debug;
5use std::option;
6use std::time::SystemTime;
7
8#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
38pub struct LastModified {
39 instant: SystemTime,
40}
41
42impl LastModified {
43 pub fn new(instant: SystemTime) -> Self {
45 Self { instant }
46 }
47
48 pub fn modified(&self) -> SystemTime {
50 self.instant
51 }
52
53 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
55 let headers = match headers.as_ref().get(LAST_MODIFIED) {
56 Some(headers) => headers,
57 None => return Ok(None),
58 };
59
60 let header = headers.iter().last().unwrap();
63
64 let instant = parse_http_date(header.as_str())?;
65 Ok(Some(Self { instant }))
66 }
67
68 pub fn apply(&self, mut headers: impl AsMut<Headers>) {
70 headers.as_mut().insert(LAST_MODIFIED, self.value());
71 }
72
73 pub fn name(&self) -> HeaderName {
75 LAST_MODIFIED
76 }
77
78 pub fn value(&self) -> HeaderValue {
80 let output = fmt_http_date(self.instant);
81
82 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
84 }
85}
86
87impl ToHeaderValues for LastModified {
88 type Iter = option::IntoIter<HeaderValue>;
89 fn to_header_values(&self) -> crate::Result<Self::Iter> {
90 Ok(self.value().to_header_values().unwrap())
92 }
93}
94
95#[cfg(test)]
96mod test {
97 use super::*;
98 use crate::headers::Headers;
99 use std::time::Duration;
100
101 #[test]
102 fn smoke() -> crate::Result<()> {
103 let time = SystemTime::now() + Duration::from_secs(5 * 60);
104 let last_modified = LastModified::new(time);
105
106 let mut headers = Headers::new();
107 last_modified.apply(&mut headers);
108
109 let last_modified = LastModified::from_headers(headers)?.unwrap();
110
111 let elapsed = time.duration_since(last_modified.modified())?;
113 assert_eq!(elapsed.as_secs(), 0);
114 Ok(())
115 }
116
117 #[test]
118 fn bad_request_on_parse_error() {
119 let mut headers = Headers::new();
120 headers.insert(LAST_MODIFIED, "<nori ate the tag. yum.>");
121 let err = LastModified::from_headers(headers).unwrap_err();
122 assert_eq!(err.status(), 400);
123 }
124}