diff options
Diffstat (limited to 'third_party/rust/headers/src/common/if_range.rs')
-rw-r--r-- | third_party/rust/headers/src/common/if_range.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/third_party/rust/headers/src/common/if_range.rs b/third_party/rust/headers/src/common/if_range.rs new file mode 100644 index 0000000000..38480bbea5 --- /dev/null +++ b/third_party/rust/headers/src/common/if_range.rs @@ -0,0 +1,134 @@ +use std::time::SystemTime; + +use super::{ETag, LastModified}; +use util::{EntityTag, HttpDate}; +use HeaderValue; + +/// `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 +/// +/// ```text +/// If-Range = entity-tag / HTTP-date +/// ``` +/// +/// # Example values +/// +/// * `Sat, 29 Oct 1994 19:43:31 GMT` +/// * `\"xyzzy\"` +/// +/// # Examples +/// +/// ``` +/// # extern crate headers; +/// use headers::IfRange; +/// use std::time::{SystemTime, Duration}; +/// +/// let fetched = SystemTime::now() - Duration::from_secs(60 * 60 * 24); +/// let if_range = IfRange::date(fetched); +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct IfRange(IfRange_); + +derive_header! { + IfRange(_), + name: IF_RANGE +} + +impl IfRange { + /// Create an `IfRange` header with an entity tag. + pub fn etag(tag: ETag) -> IfRange { + IfRange(IfRange_::EntityTag(tag.0)) + } + + /// Create an `IfRange` header with a date value. + pub fn date(time: SystemTime) -> IfRange { + IfRange(IfRange_::Date(time.into())) + } + + /// Checks if the resource has been modified, or if the range request + /// can be served. + pub fn is_modified(&self, etag: Option<&ETag>, last_modified: Option<&LastModified>) -> bool { + match self.0 { + IfRange_::Date(since) => last_modified.map(|time| since < time.0).unwrap_or(true), + IfRange_::EntityTag(ref entity) => etag.map(|etag| !etag.0.strong_eq(entity)).unwrap_or(true), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +enum IfRange_ { + /// The entity-tag the client has of the resource + EntityTag(EntityTag), + /// The date when the client retrieved the resource + Date(HttpDate), +} + +impl ::util::TryFromValues for IfRange_ { + fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error> + where + I: Iterator<Item = &'i HeaderValue>, + { + values + .next() + .and_then(|val| { + if let Some(tag) = EntityTag::from_val(val) { + return Some(IfRange_::EntityTag(tag)); + } + + let date = HttpDate::from_val(val)?; + Some(IfRange_::Date(date)) + }) + .ok_or_else(::Error::invalid) + } +} + +impl<'a> From<&'a IfRange_> for HeaderValue { + fn from(if_range: &'a IfRange_) -> HeaderValue { + match *if_range { + IfRange_::EntityTag(ref tag) => tag.into(), + IfRange_::Date(ref date) => date.into(), + } + } +} + +/* +#[cfg(test)] +mod tests { + use std::str; + use *; + use super::IfRange as HeaderField; + test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); + test_header!(test2, vec![b"\"xyzzy\""]); + test_header!(test3, vec![b"this-is-invalid"], None::<IfRange>); +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_is_modified_etag() { + let etag = ETag::from_static("\"xyzzy\""); + let if_range = IfRange::etag(etag.clone()); + + assert!(!if_range.is_modified(Some(&etag), None)); + + let etag = ETag::from_static("W/\"xyzzy\""); + assert!(if_range.is_modified(Some(&etag), None)); + } +} |