headers/common/
if_match.rs

1use super::ETag;
2use util::EntityTagRange;
3use HeaderValue;
4
5/// `If-Match` header, defined in
6/// [RFC7232](https://tools.ietf.org/html/rfc7232#section-3.1)
7///
8/// The `If-Match` header field makes the request method conditional on
9/// the recipient origin server either having at least one current
10/// representation of the target resource, when the field-value is "*",
11/// or having a current representation of the target resource that has an
12/// entity-tag matching a member of the list of entity-tags provided in
13/// the field-value.
14///
15/// An origin server MUST use the strong comparison function when
16/// comparing entity-tags for `If-Match`, since the client
17/// intends this precondition to prevent the method from being applied if
18/// there have been any changes to the representation data.
19///
20/// # ABNF
21///
22/// ```text
23/// If-Match = "*" / 1#entity-tag
24/// ```
25///
26/// # Example values
27///
28/// * `"xyzzy"`
29/// * "xyzzy", "r2d2xxxx", "c3piozzzz"
30///
31/// # Examples
32///
33/// ```
34/// # extern crate headers;
35/// use headers::IfMatch;
36///
37/// let if_match = IfMatch::any();
38/// ```
39#[derive(Clone, Debug, PartialEq)]
40pub struct IfMatch(EntityTagRange);
41
42derive_header! {
43    IfMatch(_),
44    name: IF_MATCH
45}
46
47impl IfMatch {
48    /// Create a new `If-Match: *` header.
49    pub fn any() -> IfMatch {
50        IfMatch(EntityTagRange::Any)
51    }
52
53    /// Returns whether this is `If-Match: *`, matching any entity tag.
54    pub fn is_any(&self) -> bool {
55        match self.0 {
56            EntityTagRange::Any => true,
57            EntityTagRange::Tags(..) => false,
58        }
59    }
60
61    /// Checks whether the `ETag` strongly matches.
62    pub fn precondition_passes(&self, etag: &ETag) -> bool {
63        self.0.matches_strong(&etag.0)
64    }
65}
66
67impl From<ETag> for IfMatch {
68    fn from(etag: ETag) -> IfMatch {
69        IfMatch(EntityTagRange::Tags(HeaderValue::from(etag.0).into()))
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn is_any() {
79        assert!(IfMatch::any().is_any());
80        assert!(!IfMatch::from(ETag::from_static("\"yolo\"")).is_any());
81    }
82
83    #[test]
84    fn precondition_fails() {
85        let if_match = IfMatch::from(ETag::from_static("\"foo\""));
86
87        let bar = ETag::from_static("\"bar\"");
88        let weak_foo = ETag::from_static("W/\"foo\"");
89
90        assert!(!if_match.precondition_passes(&bar));
91        assert!(!if_match.precondition_passes(&weak_foo));
92    }
93
94    #[test]
95    fn precondition_passes() {
96        let foo = ETag::from_static("\"foo\"");
97
98        let if_match = IfMatch::from(foo.clone());
99
100        assert!(if_match.precondition_passes(&foo));
101    }
102
103    #[test]
104    fn precondition_any() {
105        let foo = ETag::from_static("\"foo\"");
106
107        let if_match = IfMatch::any();
108
109        assert!(if_match.precondition_passes(&foo));
110    }
111}