cogo_http/header/shared/
httpdate.rs

1use std::str::FromStr;
2use std::fmt::{self, Display};
3
4use time;
5
6/// A `time::Time` with HTTP formatting and parsing
7///
8//   Prior to 1995, there were three different formats commonly used by
9//   servers to communicate timestamps.  For compatibility with old
10//   implementations, all three are defined here.  The preferred format is
11//   a fixed-length and single-zone subset of the date and time
12//   specification used by the Internet Message Format [RFC5322].
13//
14//     HTTP-date    = IMF-fixdate / obs-date
15//
16//   An example of the preferred format is
17//
18//     Sun, 06 Nov 1994 08:49:37 GMT    ; IMF-fixdate
19//
20//   Examples of the two obsolete formats are
21//
22//     Sunday, 06-Nov-94 08:49:37 GMT   ; obsolete RFC 850 format
23//     Sun Nov  6 08:49:37 1994         ; ANSI C's asctime() format
24//
25//   A recipient that parses a timestamp value in an HTTP header field
26//   MUST accept all three HTTP-date formats.  When a sender generates a
27//   header field that contains one or more timestamps defined as
28//   HTTP-date, the sender MUST generate those timestamps in the
29//   IMF-fixdate format.
30#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
31pub struct HttpDate(pub time::Tm);
32
33impl FromStr for HttpDate {
34    type Err = crate::Error;
35    fn from_str(s: &str) -> crate::Result<HttpDate> {
36        match time::strptime(s, "%a, %d %b %Y %T %Z").or_else(|_| {
37            time::strptime(s, "%A, %d-%b-%y %T %Z")
38            }).or_else(|_| {
39                time::strptime(s, "%c")
40                }) {
41                    Ok(t) => Ok(HttpDate(t)),
42                    Err(_) => Err(crate::Error::Header),
43                    }
44    }
45}
46
47impl Display for HttpDate {
48    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49        fmt::Display::fmt(&self.0.to_utc().rfc822(), f)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use time::Tm;
56    use super::HttpDate;
57
58    const NOV_07: HttpDate = HttpDate(Tm {
59        tm_nsec: 0,
60        tm_sec: 37,
61        tm_min: 48,
62        tm_hour: 8,
63        tm_mday: 7,
64        tm_mon: 10,
65        tm_year: 94,
66        tm_wday: 0,
67        tm_isdst: 0,
68        tm_yday: 0,
69        tm_utcoff: 0,
70    });
71
72    #[test]
73    fn test_imf_fixdate() {
74        assert_eq!("Sun, 07 Nov 1994 08:48:37 GMT".parse::<HttpDate>().unwrap(), NOV_07);
75    }
76
77    #[test]
78    fn test_rfc_850() {
79        assert_eq!("Sunday, 07-Nov-94 08:48:37 GMT".parse::<HttpDate>().unwrap(), NOV_07);
80    }
81
82    #[test]
83    fn test_asctime() {
84        assert_eq!("Sun Nov  7 08:48:37 1994".parse::<HttpDate>().unwrap(), NOV_07);
85    }
86
87    #[test]
88    fn test_no_date() {
89        assert!("this-is-no-date".parse::<HttpDate>().is_err());
90    }
91}