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}