feat(headers): Add If-None-Match header field
Add the HTTP/1.1 `If-None-Match` header field makes the request method conditional on a recipient cache or origin server either not having any current representation of the target resource, when the field-value is "*", or having a selected representation with an entity-tag that does not match any of those listed in the field-value. Closes #238
This commit is contained in:
84
src/header/common/if_none_match.rs
Normal file
84
src/header/common/if_none_match.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use header::{Header, HeaderFormat, EntityTag};
|
||||||
|
use header::parsing::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str};
|
||||||
|
use std::fmt::{self};
|
||||||
|
|
||||||
|
/// The `If-None-Match` header defined by HTTP/1.1.
|
||||||
|
///
|
||||||
|
/// The "If-None-Match" header field makes the request method conditional
|
||||||
|
/// on a recipient cache or origin server either not having any current
|
||||||
|
/// representation of the target resource, when the field-value is "*",
|
||||||
|
/// or having a selected representation with an entity-tag that does not
|
||||||
|
/// match any of those listed in the field-value.
|
||||||
|
///
|
||||||
|
/// A recipient MUST use the weak comparison function when comparing
|
||||||
|
/// entity-tags for If-None-Match (Section 2.3.2), since weak entity-tags
|
||||||
|
/// can be used for cache validation even if there have been changes to
|
||||||
|
/// the representation data.
|
||||||
|
///
|
||||||
|
/// Spec: https://tools.ietf.org/html/rfc7232#section-3.2
|
||||||
|
|
||||||
|
/// The `If-None-Match` header field.
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum IfNoneMatch {
|
||||||
|
/// This corresponds to '*'.
|
||||||
|
Any,
|
||||||
|
/// The header field names which will influence the response representation.
|
||||||
|
EntityTags(Vec<EntityTag>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Header for IfNoneMatch {
|
||||||
|
fn header_name() -> &'static str {
|
||||||
|
"If-None-Match"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_header(raw: &[Vec<u8>]) -> Option<IfNoneMatch> {
|
||||||
|
from_one_raw_str(raw).and_then(|s: String| {
|
||||||
|
let slice = &s[];
|
||||||
|
match slice {
|
||||||
|
"" => None,
|
||||||
|
"*" => Some(IfNoneMatch::Any),
|
||||||
|
_ => from_comma_delimited(raw).map(|vec| IfNoneMatch::EntityTags(vec)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeaderFormat for IfNoneMatch {
|
||||||
|
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
IfNoneMatch::Any => { write!(fmt, "*") }
|
||||||
|
IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[]) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::IfNoneMatch;
|
||||||
|
use header::Header;
|
||||||
|
use header::EntityTag;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_if_none_match() {
|
||||||
|
let mut if_none_match: Option<IfNoneMatch>;
|
||||||
|
|
||||||
|
if_none_match = Header::parse_header([b"*".to_vec()].as_slice());
|
||||||
|
assert_eq!(if_none_match, Some(IfNoneMatch::Any));
|
||||||
|
|
||||||
|
if_none_match = Header::parse_header([b"\"foobar\", W/\"weak-etag\"".to_vec()].as_slice());
|
||||||
|
let mut entities: Vec<EntityTag> = Vec::new();
|
||||||
|
let foobar_etag = EntityTag {
|
||||||
|
weak: false,
|
||||||
|
tag: "foobar".to_string()
|
||||||
|
};
|
||||||
|
let weak_etag = EntityTag {
|
||||||
|
weak: true,
|
||||||
|
tag: "weak-etag".to_string()
|
||||||
|
};
|
||||||
|
entities.push(foobar_etag);
|
||||||
|
entities.push(weak_etag);
|
||||||
|
assert_eq!(if_none_match, Some(IfNoneMatch::EntityTags(entities)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bench_header!(bench, IfNoneMatch, { vec![b"W/\"nonemptytag\"".to_vec()] });
|
||||||
@@ -21,6 +21,7 @@ pub use self::etag::Etag;
|
|||||||
pub use self::expires::Expires;
|
pub use self::expires::Expires;
|
||||||
pub use self::host::Host;
|
pub use self::host::Host;
|
||||||
pub use self::if_modified_since::IfModifiedSince;
|
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_unmodified_since::IfUnmodifiedSince;
|
||||||
pub use self::last_modified::LastModified;
|
pub use self::last_modified::LastModified;
|
||||||
pub use self::location::Location;
|
pub use self::location::Location;
|
||||||
@@ -158,6 +159,7 @@ mod expires;
|
|||||||
mod host;
|
mod host;
|
||||||
mod last_modified;
|
mod last_modified;
|
||||||
mod if_modified_since;
|
mod if_modified_since;
|
||||||
|
mod if_none_match;
|
||||||
mod if_unmodified_since;
|
mod if_unmodified_since;
|
||||||
mod location;
|
mod location;
|
||||||
mod pragma;
|
mod pragma;
|
||||||
|
|||||||
Reference in New Issue
Block a user