mco_http/header/common/
if_range.rs

1use std::fmt::{self, Display};
2use crate::header::{self, Header, HeaderFormat, EntityTag, HttpDate};
3
4/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
5///
6/// If a client has a partial copy of a representation and wishes to have
7/// an up-to-date copy of the entire representation, it could use the
8/// Range header field with a conditional GET (using either or both of
9/// If-Unmodified-Since and If-Match.)  However, if the precondition
10/// fails because the representation has been modified, the client would
11/// then have to make a second request to obtain the entire current
12/// representation.
13///
14/// The `If-Range` header field allows a client to \"short-circuit\" the
15/// second request.  Informally, its meaning is as follows: if the
16/// representation is unchanged, send me the part(s) that I am requesting
17/// in Range; otherwise, send me the entire representation.
18///
19/// # ABNF
20/// ```plain
21/// If-Range = entity-tag / HTTP-date
22/// ```
23///
24/// # Example values
25/// * `Sat, 29 Oct 1994 19:43:31 GMT`
26/// * `\"xyzzy\"`
27///
28/// # Examples
29/// ```
30/// use mco_http::header::{Headers, IfRange, EntityTag};
31///
32/// let mut headers = Headers::new();
33/// headers.set(IfRange::EntityTag(EntityTag::new(false, "xyzzy".to_owned())));
34/// ```
35/// ```
36/// # extern crate mco_http;
37/// # extern crate time;
38/// # fn main() {
39/// // extern crate time;
40///
41/// use mco_http::header::{Headers, IfRange, HttpDate};
42/// use time::{self, Duration};
43///
44/// let mut headers = Headers::new();
45/// headers.set(IfRange::Date(HttpDate(time::now() - Duration::days(1))));
46/// # }
47/// ```
48#[derive(Clone, Debug, PartialEq)]
49pub enum IfRange {
50    /// The entity-tag the client has of the resource
51    EntityTag(EntityTag),
52    /// The date when the client retrieved the resource
53    Date(HttpDate),
54}
55
56impl Header for IfRange {
57    fn header_name() -> &'static str {
58        "If-Range"
59    }
60    fn parse_header(raw: &[Vec<u8>]) -> crate::Result<IfRange> {
61        let etag: crate::Result<EntityTag> = header::parsing::from_one_raw_str(raw);
62        if etag.is_ok() {
63            return Ok(IfRange::EntityTag(etag.unwrap()));
64        }
65        let date: crate::Result<HttpDate> = header::parsing::from_one_raw_str(raw);
66        if date.is_ok() {
67            return Ok(IfRange::Date(date.unwrap()));
68        }
69        Err(crate::Error::Header)
70    }
71}
72
73impl HeaderFormat for IfRange {
74    fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
75        match *self {
76            IfRange::EntityTag(ref x) => Display::fmt(x, f),
77            IfRange::Date(ref x) => Display::fmt(x, f),
78        }
79    }
80}
81
82impl Display for IfRange {
83    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84        self.fmt_header(f)
85    }
86}
87
88#[cfg(test)]
89mod test_if_range {
90    use std::str;
91    use crate::header::*;
92    use super::IfRange as HeaderField;
93    test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);
94    test_header!(test2, vec![b"\"xyzzy\""]);
95    test_header!(test3, vec![b"this-is-invalid"], None::<IfRange>);
96}