http_types/conditional/
vary.rs1use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, VARY};
4
5use std::fmt::{self, Debug, Write};
6use std::iter::Iterator;
7use std::option;
8use std::slice;
9use std::str::FromStr;
10
11pub struct Vary {
40 entries: Vec<HeaderName>,
41 wildcard: bool,
42}
43
44impl Vary {
45 pub fn new() -> Self {
47 Self {
48 entries: vec![],
49 wildcard: false,
50 }
51 }
52
53 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
55 let mut entries = vec![];
56 let headers = match headers.as_ref().get(VARY) {
57 Some(headers) => headers,
58 None => return Ok(None),
59 };
60
61 let mut wildcard = false;
62 for value in headers {
63 for part in value.as_str().trim().split(',') {
64 let part = part.trim();
65 if part == "*" {
66 wildcard = true;
67 continue;
68 }
69 let entry = HeaderName::from_str(part.trim())?;
70 entries.push(entry);
71 }
72 }
73
74 Ok(Some(Self { entries, wildcard }))
75 }
76
77 pub fn apply(&self, mut headers: impl AsMut<Headers>) {
79 headers.as_mut().insert(VARY, self.value());
80 }
81
82 pub fn name(&self) -> HeaderName {
84 VARY
85 }
86
87 pub fn wildcard(&self) -> bool {
89 self.wildcard
90 }
91
92 pub fn set_wildcard(&mut self, wildcard: bool) {
94 self.wildcard = wildcard
95 }
96
97 pub fn value(&self) -> HeaderValue {
99 let mut output = String::new();
100 for (n, name) in self.entries.iter().enumerate() {
101 let directive: HeaderValue = name
102 .as_str()
103 .parse()
104 .expect("Could not convert a HeaderName into a HeaderValue");
105 match n {
106 0 => write!(output, "{}", directive).unwrap(),
107 _ => write!(output, ", {}", directive).unwrap(),
108 };
109 }
110
111 if self.wildcard {
112 match output.len() {
113 0 => write!(output, "*").unwrap(),
114 _ => write!(output, ", *").unwrap(),
115 };
116 }
117
118 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
120 }
121
122 pub fn push(&mut self, directive: impl Into<HeaderName>) -> crate::Result<()> {
124 self.entries.push(directive.into());
125 Ok(())
126 }
127
128 pub fn iter(&self) -> Iter<'_> {
130 Iter {
131 inner: self.entries.iter(),
132 }
133 }
134
135 pub fn iter_mut(&mut self) -> IterMut<'_> {
137 IterMut {
138 inner: self.entries.iter_mut(),
139 }
140 }
141}
142
143impl IntoIterator for Vary {
144 type Item = HeaderName;
145 type IntoIter = IntoIter;
146
147 #[inline]
148 fn into_iter(self) -> Self::IntoIter {
149 IntoIter {
150 inner: self.entries.into_iter(),
151 }
152 }
153}
154
155impl<'a> IntoIterator for &'a Vary {
156 type Item = &'a HeaderName;
157 type IntoIter = Iter<'a>;
158
159 #[inline]
160 fn into_iter(self) -> Self::IntoIter {
161 self.iter()
162 }
163}
164
165impl<'a> IntoIterator for &'a mut Vary {
166 type Item = &'a mut HeaderName;
167 type IntoIter = IterMut<'a>;
168
169 #[inline]
170 fn into_iter(self) -> Self::IntoIter {
171 self.iter_mut()
172 }
173}
174
175#[derive(Debug)]
177pub struct IntoIter {
178 inner: std::vec::IntoIter<HeaderName>,
179}
180
181impl Iterator for IntoIter {
182 type Item = HeaderName;
183
184 fn next(&mut self) -> Option<Self::Item> {
185 self.inner.next()
186 }
187
188 #[inline]
189 fn size_hint(&self) -> (usize, Option<usize>) {
190 self.inner.size_hint()
191 }
192}
193
194#[derive(Debug)]
196pub struct Iter<'a> {
197 inner: slice::Iter<'a, HeaderName>,
198}
199
200impl<'a> Iterator for Iter<'a> {
201 type Item = &'a HeaderName;
202
203 fn next(&mut self) -> Option<Self::Item> {
204 self.inner.next()
205 }
206
207 #[inline]
208 fn size_hint(&self) -> (usize, Option<usize>) {
209 self.inner.size_hint()
210 }
211}
212
213#[derive(Debug)]
215pub struct IterMut<'a> {
216 inner: slice::IterMut<'a, HeaderName>,
217}
218
219impl<'a> Iterator for IterMut<'a> {
220 type Item = &'a mut HeaderName;
221
222 fn next(&mut self) -> Option<Self::Item> {
223 self.inner.next()
224 }
225
226 #[inline]
227 fn size_hint(&self) -> (usize, Option<usize>) {
228 self.inner.size_hint()
229 }
230}
231
232impl ToHeaderValues for Vary {
233 type Iter = option::IntoIter<HeaderValue>;
234 fn to_header_values(&self) -> crate::Result<Self::Iter> {
235 Ok(self.value().to_header_values().unwrap())
237 }
238}
239
240impl Debug for Vary {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 let mut list = f.debug_list();
243 for directive in &self.entries {
244 list.entry(directive);
245 }
246 list.finish()
247 }
248}
249
250#[cfg(test)]
251mod test {
252 use crate::conditional::Vary;
253 use crate::Response;
254
255 #[test]
256 fn smoke() -> crate::Result<()> {
257 let mut entries = Vary::new();
258 entries.push("User-Agent")?;
259 entries.push("Accept-Encoding")?;
260
261 let mut res = Response::new(200);
262 entries.apply(&mut res);
263
264 let entries = Vary::from_headers(res)?.unwrap();
265 let mut entries = entries.iter();
266 assert_eq!(entries.next().unwrap(), "User-Agent");
267 assert_eq!(entries.next().unwrap(), "Accept-Encoding");
268 Ok(())
269 }
270
271 #[test]
272 fn wildcard() -> crate::Result<()> {
273 let mut entries = Vary::new();
274 entries.push("User-Agent")?;
275 entries.set_wildcard(true);
276
277 let mut res = Response::new(200);
278 entries.apply(&mut res);
279
280 let entries = Vary::from_headers(res)?.unwrap();
281 assert!(entries.wildcard());
282 let mut entries = entries.iter();
283 assert_eq!(entries.next().unwrap(), "User-Agent");
284 Ok(())
285 }
286}