|
| 1 | +use header::{Header, HeaderFormat, EntityTag}; |
| 2 | +use header::parsing::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; |
| 3 | +use std::fmt::{self}; |
| 4 | + |
| 5 | +/// The `If-None-Match` header defined by HTTP/1.1. |
| 6 | +/// |
| 7 | +/// The "If-None-Match" header field makes the request method conditional |
| 8 | +/// on a recipient cache or origin server either not having any current |
| 9 | +/// representation of the target resource, when the field-value is "*", |
| 10 | +/// or having a selected representation with an entity-tag that does not |
| 11 | +/// match any of those listed in the field-value. |
| 12 | +/// |
| 13 | +/// A recipient MUST use the weak comparison function when comparing |
| 14 | +/// entity-tags for If-None-Match (Section 2.3.2), since weak entity-tags |
| 15 | +/// can be used for cache validation even if there have been changes to |
| 16 | +/// the representation data. |
| 17 | +/// |
| 18 | +/// Spec: https://tools.ietf.org/html/rfc7232#section-3.2 |
| 19 | +
|
| 20 | +/// The `If-None-Match` header field. |
| 21 | +#[derive(Clone, PartialEq, Debug)] |
| 22 | +pub enum IfNoneMatch { |
| 23 | + /// This corresponds to '*'. |
| 24 | + Any, |
| 25 | + /// The header field names which will influence the response representation. |
| 26 | + EntityTags(Vec<EntityTag>) |
| 27 | +} |
| 28 | + |
| 29 | +impl Header for IfNoneMatch { |
| 30 | + fn header_name() -> &'static str { |
| 31 | + "If-None-Match" |
| 32 | + } |
| 33 | + |
| 34 | + fn parse_header(raw: &[Vec<u8>]) -> Option<IfNoneMatch> { |
| 35 | + from_one_raw_str(raw).and_then(|s: String| { |
| 36 | + let slice = &s[]; |
| 37 | + match slice { |
| 38 | + "" => None, |
| 39 | + "*" => Some(IfNoneMatch::Any), |
| 40 | + _ => from_comma_delimited(raw).map(|vec| IfNoneMatch::EntityTags(vec)), |
| 41 | + } |
| 42 | + }) |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +impl HeaderFormat for IfNoneMatch { |
| 47 | + fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 48 | + match *self { |
| 49 | + IfNoneMatch::Any => { write!(fmt, "*") } |
| 50 | + IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[]) } |
| 51 | + } |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +#[cfg(test)] |
| 56 | +mod tests { |
| 57 | + use super::IfNoneMatch; |
| 58 | + use header::Header; |
| 59 | + use header::EntityTag; |
| 60 | + |
| 61 | + #[test] |
| 62 | + fn test_if_none_match() { |
| 63 | + let mut if_none_match: Option<IfNoneMatch>; |
| 64 | + |
| 65 | + if_none_match = Header::parse_header([b"*".to_vec()].as_slice()); |
| 66 | + assert_eq!(if_none_match, Some(IfNoneMatch::Any)); |
| 67 | + |
| 68 | + if_none_match = Header::parse_header([b"\"foobar\", W/\"weak-etag\"".to_vec()].as_slice()); |
| 69 | + let mut entities: Vec<EntityTag> = Vec::new(); |
| 70 | + let foobar_etag = EntityTag { |
| 71 | + weak: false, |
| 72 | + tag: "foobar".to_string() |
| 73 | + }; |
| 74 | + let weak_etag = EntityTag { |
| 75 | + weak: true, |
| 76 | + tag: "weak-etag".to_string() |
| 77 | + }; |
| 78 | + entities.push(foobar_etag); |
| 79 | + entities.push(weak_etag); |
| 80 | + assert_eq!(if_none_match, Some(IfNoneMatch::EntityTags(entities))); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +bench_header!(bench, IfNoneMatch, { vec![b"W/\"nonemptytag\"".to_vec()] }); |
0 commit comments