hyper_sync/header/common/
if_range.rs

1use std::fmt::{self, Display};
2
3use header::{self, Header, Raw, EntityTag, HttpDate};
4
5/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
6///
7/// If a client has a partial copy of a representation and wishes to have
8/// an up-to-date copy of the entire representation, it could use the
9/// Range header field with a conditional GET (using either or both of
10/// If-Unmodified-Since and If-Match.)  However, if the precondition
11/// fails because the representation has been modified, the client would
12/// then have to make a second request to obtain the entire current
13/// representation.
14///
15/// The `If-Range` header field allows a client to \"short-circuit\" the
16/// second request.  Informally, its meaning is as follows: if the
17/// representation is unchanged, send me the part(s) that I am requesting
18/// in Range; otherwise, send me the entire representation.
19///
20/// # ABNF
21///
22/// ```text
23/// If-Range = entity-tag / HTTP-date
24/// ```
25///
26/// # Example values
27///
28/// * `Sat, 29 Oct 1994 19:43:31 GMT`
29/// * `\"xyzzy\"`
30///
31/// # Examples
32///
33/// ```
34/// use hyper_sync::header::{Headers, IfRange, EntityTag};
35///
36/// let mut headers = Headers::new();
37/// headers.set(IfRange::EntityTag(EntityTag::new(false, "xyzzy".to_owned())));
38/// ```
39///
40/// ```
41/// use hyper_sync::header::{Headers, IfRange};
42/// use std::time::{SystemTime, Duration};
43///
44/// let mut headers = Headers::new();
45/// let fetched = SystemTime::now() - Duration::from_secs(60 * 60 * 24);
46/// headers.set(IfRange::Date(fetched.into()));
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        static NAME: &'static str = "If-Range";
59        NAME
60    }
61
62    fn parse_header(raw: &Raw) -> ::Result<IfRange> {
63        let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw);
64        if let Ok(etag) = etag {
65            return Ok(IfRange::EntityTag(etag));
66        }
67        let date: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw);
68        if let Ok(date) = date {
69            return Ok(IfRange::Date(date));
70        }
71        Err(::Error::Header)
72    }
73
74    fn fmt_header(&self, f: &mut ::header::Formatter) -> ::std::fmt::Result {
75        f.fmt_line(self)
76    }
77}
78
79impl Display for IfRange {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        match *self {
82            IfRange::EntityTag(ref x) => Display::fmt(x, f),
83            IfRange::Date(ref x) => Display::fmt(x, f),
84        }
85    }
86}
87
88#[cfg(test)]
89mod test_if_range {
90    use std::str;
91    use 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}