diff --git a/src/header/common/if_range.rs b/src/header/common/if_range.rs new file mode 100644 index 0000000000..7c59bb60fc --- /dev/null +++ b/src/header/common/if_range.rs @@ -0,0 +1,73 @@ +use header::{self, EntityTag, HttpDate}; + +/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2) +/// +/// If a client has a partial copy of a representation and wishes to have +/// an up-to-date copy of the entire representation, it could use the +/// Range header field with a conditional GET (using either or both of +/// If-Unmodified-Since and If-Match.) However, if the precondition +/// fails because the representation has been modified, the client would +/// then have to make a second request to obtain the entire current +/// representation. +/// +/// The `If-Range` header field allows a client to \"short-circuit\" the +/// second request. Informally, its meaning is as follows: if the +/// representation is unchanged, send me the part(s) that I am requesting +/// in Range; otherwise, send me the entire representation. +/// +/// # ABNF +/// ```plain +/// If-Range = entity-tag / HTTP-date +/// ``` +/// +/// # Example values +/// * `Sat, 29 Oct 1994 19:43:31 GMT` +/// * `\"xyzzy\"` +#[derive(Clone, Debug, PartialEq)] +pub enum IfRange { + /// The entity-tag the client has of the resource + EntityTag(EntityTag), + /// The date when the client retrieved the resource + Date(HttpDate), +} + +impl header::Header for IfRange { + fn header_name() -> &'static str { + "If-Range" + } + fn parse_header(raw: &[Vec]) -> Option { + let etag: Option = header::parsing::from_one_raw_str(raw); + if etag != None { + return Some(IfRange::EntityTag(etag.unwrap())); + } + let date: Option = header::parsing::from_one_raw_str(raw); + if date != None { + return Some(IfRange::Date(date.unwrap())); + } + None + } +} + +impl header::HeaderFormat for IfRange { + fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + &IfRange::EntityTag(ref x) => write!(f, "{}", x), + &IfRange::Date(ref x) => write!(f, "{}", x), + } + } +} + +impl ::std::fmt::Display for IfRange { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use header::HeaderFormat; + self.fmt_header(f) + } +} + +#[cfg(test)] +mod test_range { + use header::*; + use super::IfRange as HeaderField; + test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); + test_header!(test2, vec![b"\"xyzzy\""]); +} diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 4dd2db80e6..82ed0fe4bc 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -34,6 +34,7 @@ pub use self::if_match::IfMatch; pub use self::if_modified_since::IfModifiedSince; pub use self::if_none_match::IfNoneMatch; pub use self::if_unmodified_since::IfUnmodifiedSince; +pub use self::if_range::IfRange; pub use self::last_modified::LastModified; pub use self::location::Location; pub use self::pragma::Pragma; @@ -118,8 +119,10 @@ macro_rules! test_header { // Test parsing assert_eq!(val, $typed); // Test formatting - let res: &str = str::from_utf8($raw[0]).unwrap(); - assert_eq!(format!("{}", $typed.unwrap()), res); + if $typed != None { + let res: &str = str::from_utf8($raw[0]).unwrap(); + assert_eq!(format!("{}", $typed.unwrap()), res); + } } } } @@ -313,10 +316,11 @@ mod expect; mod expires; mod host; mod if_match; -mod last_modified; mod if_modified_since; mod if_none_match; +mod if_range; mod if_unmodified_since; +mod last_modified; mod location; mod pragma; mod referer;