Skip to main content

headers/common/
vary.rs

1use http::{HeaderName, HeaderValue};
2use std::iter::FromIterator;
3
4use crate::util::FlatCsv;
5
6/// `Vary` header, defined in [RFC7231](https://tools.ietf.org/html/rfc7231#section-7.1.4)
7///
8/// The "Vary" header field in a response describes what parts of a
9/// request message, aside from the method, Host header field, and
10/// request target, might influence the origin server's process for
11/// selecting and representing this response.  The value consists of
12/// either a single asterisk ("*") or a list of header field names
13/// (case-insensitive).
14///
15/// # ABNF
16///
17/// ```text
18/// Vary = "*" / 1#field-name
19/// ```
20///
21/// # Example values
22///
23/// * `accept-encoding, accept-language`
24///
25/// # Example
26///
27/// ```
28/// use headers::Vary;
29///
30/// let vary = Vary::any();
31/// ```
32#[derive(Debug, Clone, PartialEq)]
33pub struct Vary(FlatCsv);
34
35derive_header! {
36    Vary(_),
37    name: VARY
38}
39
40impl Vary {
41    /// Create a new `Very: *` header.
42    pub fn any() -> Vary {
43        Vary(HeaderValue::from_static("*").into())
44    }
45
46    /// Check if this includes `*`.
47    pub fn is_any(&self) -> bool {
48        self.0.iter().any(|val| val == "*")
49    }
50
51    /// Iterate the header names of this `Vary`.
52    pub fn iter_strs(&self) -> impl Iterator<Item = &str> {
53        self.0.iter()
54    }
55}
56
57impl From<HeaderName> for Vary {
58    fn from(name: HeaderName) -> Self {
59        Vary(HeaderValue::from(name).into())
60    }
61}
62
63impl FromIterator<HeaderName> for Vary {
64    fn from_iter<I>(iter: I) -> Self
65    where
66        I: IntoIterator<Item = HeaderName>,
67    {
68        Vary(iter.into_iter().map(HeaderValue::from).collect())
69    }
70}
71
72/*
73test_vary {
74    test_header!(test1, vec![b"accept-encoding, accept-language"]);
75
76    #[test]
77    fn test2() {
78        let mut vary: ::Result<Vary>;
79
80        vary = Header::parse_header(&"*".into());
81        assert_eq!(vary.ok(), Some(Vary::Any));
82
83        vary = Header::parse_header(&"etag,cookie,allow".into());
84        assert_eq!(vary.ok(), Some(Vary::Items(vec!["eTag".parse().unwrap(),
85                                                    "cookIE".parse().unwrap(),
86                                                    "AlLOw".parse().unwrap(),])));
87    }
88}
89*/
90
91#[cfg(test)]
92mod tests {
93    use http::header::{ACCEPT_ENCODING, ACCEPT_LANGUAGE};
94
95    use super::*;
96
97    #[test]
98    fn any_is_any() {
99        assert!(Vary::any().is_any());
100    }
101
102    #[test]
103    fn from_header_name() {
104        let vary = Vary::from(ACCEPT_ENCODING);
105
106        assert!(!vary.is_any());
107        assert_eq!(
108            vary.iter_strs().collect::<Vec<_>>(),
109            vec![ACCEPT_ENCODING.as_str()]
110        );
111    }
112
113    #[test]
114    fn from_iter_header_name() {
115        let vary = Vary::from_iter([ACCEPT_ENCODING, ACCEPT_LANGUAGE]);
116
117        assert!(!vary.is_any());
118        assert_eq!(
119            vary.iter_strs().collect::<Vec<_>>(),
120            vec![ACCEPT_ENCODING.as_str(), ACCEPT_LANGUAGE.as_str()]
121        );
122    }
123}