http_types/conditional/
if_unmodified_since.rs1use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, IF_UNMODIFIED_SINCE};
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)]
39pub struct IfUnmodifiedSince {
40 instant: SystemTime,
41}
42
43impl IfUnmodifiedSince {
44 pub fn new(instant: SystemTime) -> Self {
46 Self { instant }
47 }
48
49 pub fn modified(&self) -> SystemTime {
51 self.instant
52 }
53
54 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
56 let headers = match headers.as_ref().get(IF_UNMODIFIED_SINCE) {
57 Some(headers) => headers,
58 None => return Ok(None),
59 };
60
61 let header = headers.iter().last().unwrap();
64
65 let instant = parse_http_date(header.as_str())?;
66 Ok(Some(Self { instant }))
67 }
68
69 pub fn apply(&self, mut headers: impl AsMut<Headers>) {
71 headers.as_mut().insert(IF_UNMODIFIED_SINCE, self.value());
72 }
73
74 pub fn name(&self) -> HeaderName {
76 IF_UNMODIFIED_SINCE
77 }
78
79 pub fn value(&self) -> HeaderValue {
81 let output = fmt_http_date(self.instant);
82
83 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
85 }
86}
87
88impl ToHeaderValues for IfUnmodifiedSince {
89 type Iter = option::IntoIter<HeaderValue>;
90 fn to_header_values(&self) -> crate::Result<Self::Iter> {
91 Ok(self.value().to_header_values().unwrap())
93 }
94}
95
96#[cfg(test)]
97mod test {
98 use super::*;
99 use crate::headers::Headers;
100 use std::time::Duration;
101
102 #[test]
103 fn smoke() -> crate::Result<()> {
104 let time = SystemTime::now() + Duration::from_secs(5 * 60);
105 let expires = IfUnmodifiedSince::new(time);
106
107 let mut headers = Headers::new();
108 expires.apply(&mut headers);
109
110 let expires = IfUnmodifiedSince::from_headers(headers)?.unwrap();
111
112 let elapsed = time.duration_since(expires.modified())?;
114 assert_eq!(elapsed.as_secs(), 0);
115 Ok(())
116 }
117
118 #[test]
119 fn bad_request_on_parse_error() {
120 let mut headers = Headers::new();
121 headers.insert(IF_UNMODIFIED_SINCE, "<nori ate the tag. yum.>");
122 let err = IfUnmodifiedSince::from_headers(headers).unwrap_err();
123 assert_eq!(err.status(), 400);
124 }
125}