http_types_rs/transfer/
te.rs1use crate::headers::{self, Header, HeaderName, HeaderValue, Headers};
2use crate::transfer::{Encoding, EncodingProposal, TransferEncoding};
3use crate::utils::sort_by_weight;
4use crate::{Error, StatusCode};
5
6use std::fmt::{self, Debug, Write};
7
8use std::slice;
9
10pub struct TE {
41 wildcard: bool,
42 entries: Vec<EncodingProposal>,
43}
44
45impl TE {
46 pub fn new() -> Self {
48 Self {
49 entries: vec![],
50 wildcard: false,
51 }
52 }
53
54 pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
56 let mut entries = vec![];
57 let headers = match headers.as_ref().get(headers::TE) {
58 Some(headers) => headers,
59 None => return Ok(None),
60 };
61
62 let mut wildcard = false;
63
64 for value in headers {
65 for part in value.as_str().trim().split(',') {
66 let part = part.trim();
67
68 if part.is_empty() {
70 continue;
71 } else if part == "*" {
72 wildcard = true;
73 continue;
74 }
75
76 if let Some(entry) = EncodingProposal::from_str(part)? {
79 entries.push(entry);
80 }
81 }
82 }
83
84 Ok(Some(Self { wildcard, entries }))
85 }
86
87 pub fn push(&mut self, prop: impl Into<EncodingProposal>) {
89 self.entries.push(prop.into());
90 }
91
92 pub fn wildcard(&self) -> bool {
94 self.wildcard
95 }
96
97 pub fn set_wildcard(&mut self, wildcard: bool) {
99 self.wildcard = wildcard
100 }
101
102 pub fn sort(&mut self) {
108 sort_by_weight(&mut self.entries);
109 }
110
111 pub fn negotiate(&mut self, available: &[Encoding]) -> crate::Result<TransferEncoding> {
117 self.sort();
119
120 for encoding in &self.entries {
122 if available.contains(encoding) {
123 return Ok(encoding.into());
124 }
125 }
126
127 if self.wildcard {
129 if let Some(encoding) = available.iter().next() {
130 return Ok(encoding.into());
131 }
132 }
133
134 let mut err = Error::new_adhoc("No suitable Transfer-Encoding found");
135 err.set_status(StatusCode::NotAcceptable);
136 Err(err)
137 }
138
139 pub fn iter(&self) -> Iter<'_> {
141 Iter { inner: self.entries.iter() }
142 }
143
144 pub fn iter_mut(&mut self) -> IterMut<'_> {
146 IterMut {
147 inner: self.entries.iter_mut(),
148 }
149 }
150}
151
152impl Header for TE {
153 fn header_name(&self) -> HeaderName {
154 headers::TE
155 }
156
157 fn header_value(&self) -> HeaderValue {
158 let mut output = String::new();
159 for (n, directive) in self.entries.iter().enumerate() {
160 let directive: HeaderValue = (*directive).into();
161 match n {
162 0 => write!(output, "{}", directive).unwrap(),
163 _ => write!(output, ", {}", directive).unwrap(),
164 };
165 }
166
167 if self.wildcard {
168 match output.len() {
169 0 => write!(output, "*").unwrap(),
170 _ => write!(output, ", *").unwrap(),
171 }
172 }
173
174 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
176 }
177}
178
179impl IntoIterator for TE {
180 type Item = EncodingProposal;
181 type IntoIter = IntoIter;
182
183 #[inline]
184 fn into_iter(self) -> Self::IntoIter {
185 IntoIter {
186 inner: self.entries.into_iter(),
187 }
188 }
189}
190
191impl<'a> IntoIterator for &'a TE {
192 type Item = &'a EncodingProposal;
193 type IntoIter = Iter<'a>;
194
195 #[inline]
196 fn into_iter(self) -> Self::IntoIter {
197 self.iter()
198 }
199}
200
201impl<'a> IntoIterator for &'a mut TE {
202 type Item = &'a mut EncodingProposal;
203 type IntoIter = IterMut<'a>;
204
205 #[inline]
206 fn into_iter(self) -> Self::IntoIter {
207 self.iter_mut()
208 }
209}
210
211#[derive(Debug)]
213pub struct IntoIter {
214 inner: std::vec::IntoIter<EncodingProposal>,
215}
216
217impl Iterator for IntoIter {
218 type Item = EncodingProposal;
219
220 fn next(&mut self) -> Option<Self::Item> {
221 self.inner.next()
222 }
223
224 #[inline]
225 fn size_hint(&self) -> (usize, Option<usize>) {
226 self.inner.size_hint()
227 }
228}
229
230#[derive(Debug)]
232pub struct Iter<'a> {
233 inner: slice::Iter<'a, EncodingProposal>,
234}
235
236impl<'a> Iterator for Iter<'a> {
237 type Item = &'a EncodingProposal;
238
239 fn next(&mut self) -> Option<Self::Item> {
240 self.inner.next()
241 }
242
243 #[inline]
244 fn size_hint(&self) -> (usize, Option<usize>) {
245 self.inner.size_hint()
246 }
247}
248
249#[derive(Debug)]
251pub struct IterMut<'a> {
252 inner: slice::IterMut<'a, EncodingProposal>,
253}
254
255impl<'a> Iterator for IterMut<'a> {
256 type Item = &'a mut EncodingProposal;
257
258 fn next(&mut self) -> Option<Self::Item> {
259 self.inner.next()
260 }
261
262 #[inline]
263 fn size_hint(&self) -> (usize, Option<usize>) {
264 self.inner.size_hint()
265 }
266}
267
268impl Debug for TE {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 let mut list = f.debug_list();
271 for directive in &self.entries {
272 list.entry(directive);
273 }
274 list.finish()
275 }
276}
277
278#[cfg(test)]
279mod test {
280 use super::*;
281 use crate::transfer::Encoding;
282 use crate::Response;
283
284 #[test]
285 fn smoke() -> crate::Result<()> {
286 let mut accept = TE::new();
287 accept.push(Encoding::Gzip);
288
289 let mut headers = Response::new(200);
290 accept.apply_header(&mut headers);
291
292 let accept = TE::from_headers(headers)?.unwrap();
293 assert_eq!(accept.iter().next().unwrap(), Encoding::Gzip);
294 Ok(())
295 }
296
297 #[test]
298 fn wildcard() -> crate::Result<()> {
299 let mut accept = TE::new();
300 accept.set_wildcard(true);
301
302 let mut headers = Response::new(200);
303 accept.apply_header(&mut headers);
304
305 let accept = TE::from_headers(headers)?.unwrap();
306 assert!(accept.wildcard());
307 Ok(())
308 }
309
310 #[test]
311 fn wildcard_and_header() -> crate::Result<()> {
312 let mut accept = TE::new();
313 accept.push(Encoding::Gzip);
314 accept.set_wildcard(true);
315
316 let mut headers = Response::new(200);
317 accept.apply_header(&mut headers);
318
319 let accept = TE::from_headers(headers)?.unwrap();
320 assert!(accept.wildcard());
321 assert_eq!(accept.iter().next().unwrap(), Encoding::Gzip);
322 Ok(())
323 }
324
325 #[test]
326 fn iter() -> crate::Result<()> {
327 let mut accept = TE::new();
328 accept.push(Encoding::Gzip);
329 accept.push(Encoding::Brotli);
330
331 let mut headers = Response::new(200);
332 accept.apply_header(&mut headers);
333
334 let accept = TE::from_headers(headers)?.unwrap();
335 let mut accept = accept.iter();
336 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
337 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
338 Ok(())
339 }
340
341 #[test]
342 fn reorder_based_on_weight() -> crate::Result<()> {
343 let mut accept = TE::new();
344 accept.push(EncodingProposal::new(Encoding::Gzip, Some(0.4))?);
345 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
346 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
347
348 let mut headers = Response::new(200);
349 accept.apply_header(&mut headers);
350
351 let mut accept = TE::from_headers(headers)?.unwrap();
352 accept.sort();
353 let mut accept = accept.iter();
354 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
355 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
356 assert_eq!(accept.next().unwrap(), Encoding::Identity);
357 Ok(())
358 }
359
360 #[test]
361 fn reorder_based_on_weight_and_location() -> crate::Result<()> {
362 let mut accept = TE::new();
363 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
364 accept.push(EncodingProposal::new(Encoding::Gzip, None)?);
365 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
366
367 let mut res = Response::new(200);
368 accept.apply_header(&mut res);
369
370 let mut accept = TE::from_headers(res)?.unwrap();
371 accept.sort();
372 let mut accept = accept.iter();
373 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
374 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
375 assert_eq!(accept.next().unwrap(), Encoding::Identity);
376 Ok(())
377 }
378
379 #[test]
380 fn negotiate() -> crate::Result<()> {
381 let mut accept = TE::new();
382 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
383 accept.push(EncodingProposal::new(Encoding::Gzip, Some(0.4))?);
384 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
385
386 assert_eq!(accept.negotiate(&[Encoding::Brotli, Encoding::Gzip])?, Encoding::Brotli,);
387 Ok(())
388 }
389
390 #[test]
391 fn negotiate_not_acceptable() -> crate::Result<()> {
392 let mut accept = TE::new();
393 let err = accept.negotiate(&[Encoding::Gzip]).unwrap_err();
394 assert_eq!(err.status(), 406);
395
396 let mut accept = TE::new();
397 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
398 let err = accept.negotiate(&[Encoding::Gzip]).unwrap_err();
399 assert_eq!(err.status(), 406);
400 Ok(())
401 }
402
403 #[test]
404 fn negotiate_wildcard() -> crate::Result<()> {
405 let mut accept = TE::new();
406 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
407 accept.set_wildcard(true);
408
409 assert_eq!(accept.negotiate(&[Encoding::Gzip])?, Encoding::Gzip);
410 Ok(())
411 }
412}