http_types_2/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 {
142 inner: self.entries.iter(),
143 }
144 }
145
146 pub fn iter_mut(&mut self) -> IterMut<'_> {
148 IterMut {
149 inner: self.entries.iter_mut(),
150 }
151 }
152}
153
154impl Header for TE {
155 fn header_name(&self) -> HeaderName {
156 headers::TE
157 }
158
159 fn header_value(&self) -> HeaderValue {
160 let mut output = String::new();
161 for (n, directive) in self.entries.iter().enumerate() {
162 let directive: HeaderValue = (*directive).into();
163 match n {
164 0 => write!(output, "{directive}").unwrap(),
165 _ => write!(output, ", {directive}").unwrap(),
166 };
167 }
168
169 if self.wildcard {
170 match output.len() {
171 0 => write!(output, "*").unwrap(),
172 _ => write!(output, ", *").unwrap(),
173 }
174 }
175
176 unsafe { HeaderValue::from_bytes_unchecked(output.into()) }
178 }
179}
180
181impl IntoIterator for TE {
182 type Item = EncodingProposal;
183 type IntoIter = IntoIter;
184
185 #[inline]
186 fn into_iter(self) -> Self::IntoIter {
187 IntoIter {
188 inner: self.entries.into_iter(),
189 }
190 }
191}
192
193impl<'a> IntoIterator for &'a TE {
194 type Item = &'a EncodingProposal;
195 type IntoIter = Iter<'a>;
196
197 #[inline]
198 fn into_iter(self) -> Self::IntoIter {
199 self.iter()
200 }
201}
202
203impl<'a> IntoIterator for &'a mut TE {
204 type Item = &'a mut EncodingProposal;
205 type IntoIter = IterMut<'a>;
206
207 #[inline]
208 fn into_iter(self) -> Self::IntoIter {
209 self.iter_mut()
210 }
211}
212
213#[derive(Debug)]
215pub struct IntoIter {
216 inner: std::vec::IntoIter<EncodingProposal>,
217}
218
219impl Iterator for IntoIter {
220 type Item = EncodingProposal;
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
232#[derive(Debug)]
234pub struct Iter<'a> {
235 inner: slice::Iter<'a, EncodingProposal>,
236}
237
238impl<'a> Iterator for Iter<'a> {
239 type Item = &'a EncodingProposal;
240
241 fn next(&mut self) -> Option<Self::Item> {
242 self.inner.next()
243 }
244
245 #[inline]
246 fn size_hint(&self) -> (usize, Option<usize>) {
247 self.inner.size_hint()
248 }
249}
250
251#[derive(Debug)]
253pub struct IterMut<'a> {
254 inner: slice::IterMut<'a, EncodingProposal>,
255}
256
257impl<'a> Iterator for IterMut<'a> {
258 type Item = &'a mut EncodingProposal;
259
260 fn next(&mut self) -> Option<Self::Item> {
261 self.inner.next()
262 }
263
264 #[inline]
265 fn size_hint(&self) -> (usize, Option<usize>) {
266 self.inner.size_hint()
267 }
268}
269
270impl Debug for TE {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 let mut list = f.debug_list();
273 for directive in &self.entries {
274 list.entry(directive);
275 }
276 list.finish()
277 }
278}
279
280#[cfg(test)]
281mod test {
282 use super::*;
283 use crate::transfer::Encoding;
284 use crate::Response;
285
286 #[test]
287 fn smoke() -> crate::Result<()> {
288 let mut accept = TE::new();
289 accept.push(Encoding::Gzip);
290
291 let mut headers = Response::new(200);
292 accept.apply_header(&mut headers);
293
294 let accept = TE::from_headers(headers)?.unwrap();
295 assert_eq!(accept.iter().next().unwrap(), Encoding::Gzip);
296 Ok(())
297 }
298
299 #[test]
300 fn wildcard() -> crate::Result<()> {
301 let mut accept = TE::new();
302 accept.set_wildcard(true);
303
304 let mut headers = Response::new(200);
305 accept.apply_header(&mut headers);
306
307 let accept = TE::from_headers(headers)?.unwrap();
308 assert!(accept.wildcard());
309 Ok(())
310 }
311
312 #[test]
313 fn wildcard_and_header() -> crate::Result<()> {
314 let mut accept = TE::new();
315 accept.push(Encoding::Gzip);
316 accept.set_wildcard(true);
317
318 let mut headers = Response::new(200);
319 accept.apply_header(&mut headers);
320
321 let accept = TE::from_headers(headers)?.unwrap();
322 assert!(accept.wildcard());
323 assert_eq!(accept.iter().next().unwrap(), Encoding::Gzip);
324 Ok(())
325 }
326
327 #[test]
328 fn iter() -> crate::Result<()> {
329 let mut accept = TE::new();
330 accept.push(Encoding::Gzip);
331 accept.push(Encoding::Brotli);
332
333 let mut headers = Response::new(200);
334 accept.apply_header(&mut headers);
335
336 let accept = TE::from_headers(headers)?.unwrap();
337 let mut accept = accept.iter();
338 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
339 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
340 Ok(())
341 }
342
343 #[test]
344 fn reorder_based_on_weight() -> crate::Result<()> {
345 let mut accept = TE::new();
346 accept.push(EncodingProposal::new(Encoding::Gzip, Some(0.4))?);
347 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
348 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
349
350 let mut headers = Response::new(200);
351 accept.apply_header(&mut headers);
352
353 let mut accept = TE::from_headers(headers)?.unwrap();
354 accept.sort();
355 let mut accept = accept.iter();
356 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
357 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
358 assert_eq!(accept.next().unwrap(), Encoding::Identity);
359 Ok(())
360 }
361
362 #[test]
363 fn reorder_based_on_weight_and_location() -> crate::Result<()> {
364 let mut accept = TE::new();
365 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
366 accept.push(EncodingProposal::new(Encoding::Gzip, None)?);
367 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
368
369 let mut res = Response::new(200);
370 accept.apply_header(&mut res);
371
372 let mut accept = TE::from_headers(res)?.unwrap();
373 accept.sort();
374 let mut accept = accept.iter();
375 assert_eq!(accept.next().unwrap(), Encoding::Brotli);
376 assert_eq!(accept.next().unwrap(), Encoding::Gzip);
377 assert_eq!(accept.next().unwrap(), Encoding::Identity);
378 Ok(())
379 }
380
381 #[test]
382 fn negotiate() -> crate::Result<()> {
383 let mut accept = TE::new();
384 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
385 accept.push(EncodingProposal::new(Encoding::Gzip, Some(0.4))?);
386 accept.push(EncodingProposal::new(Encoding::Identity, None)?);
387
388 assert_eq!(
389 accept.negotiate(&[Encoding::Brotli, Encoding::Gzip])?,
390 Encoding::Brotli,
391 );
392 Ok(())
393 }
394
395 #[test]
396 fn negotiate_not_acceptable() -> crate::Result<()> {
397 let mut accept = TE::new();
398 let err = accept.negotiate(&[Encoding::Gzip]).unwrap_err();
399 assert_eq!(err.status(), 406);
400
401 let mut accept = TE::new();
402 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
403 let err = accept.negotiate(&[Encoding::Gzip]).unwrap_err();
404 assert_eq!(err.status(), 406);
405 Ok(())
406 }
407
408 #[test]
409 fn negotiate_wildcard() -> crate::Result<()> {
410 let mut accept = TE::new();
411 accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
412 accept.set_wildcard(true);
413
414 assert_eq!(accept.negotiate(&[Encoding::Gzip])?, Encoding::Gzip);
415 Ok(())
416 }
417}