1 use std::fmt::{self, Display}; 2 use 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 hyper::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 hyper; 37 /// # extern crate time; 38 /// # fn main() { 39 /// // extern crate time; 40 /// 41 /// use hyper::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)] 49 pub 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 56 impl Header for IfRange { header_name() -> &'static str57 fn header_name() -> &'static str { 58 "If-Range" 59 } parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange>60 fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> { 61 let etag: ::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: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw); 66 if date.is_ok() { 67 return Ok(IfRange::Date(date.unwrap())); 68 } 69 Err(::Error::Header) 70 } 71 } 72 73 impl HeaderFormat for IfRange { fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result74 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 82 impl Display for IfRange { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 84 self.fmt_header(f) 85 } 86 } 87 88 #[cfg(test)] 89 mod 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 } 97