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