1use rama_utils::macros::match_ignore_ascii_case_str;
4use std::fmt;
5
6mod accept_encoding;
7pub use accept_encoding::AcceptEncoding;
8
9use super::specifier::{Quality, QualityValue};
10
11pub trait SupportedEncodings: Copy {
12 fn gzip(&self) -> bool;
13 fn deflate(&self) -> bool;
14 fn br(&self) -> bool;
15 fn zstd(&self) -> bool;
16}
17
18impl SupportedEncodings for bool {
19 fn gzip(&self) -> bool {
20 *self
21 }
22
23 fn deflate(&self) -> bool {
24 *self
25 }
26
27 fn br(&self) -> bool {
28 *self
29 }
30
31 fn zstd(&self) -> bool {
32 *self
33 }
34}
35
36#[derive(Copy, Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Hash)]
37pub enum Encoding {
39 Identity,
40 Deflate,
41 Gzip,
42 Brotli,
43 Zstd,
44}
45
46impl fmt::Display for Encoding {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(f, "{}", self.as_str())
49 }
50}
51
52impl From<Encoding> for rama_http_types::HeaderValue {
53 #[inline]
54 fn from(encoding: Encoding) -> Self {
55 Self::from_static(encoding.as_str())
56 }
57}
58
59impl Encoding {
60 fn as_str(self) -> &'static str {
61 match self {
62 Self::Identity => "identity",
63 Self::Gzip => "gzip",
64 Self::Deflate => "deflate",
65 Self::Brotli => "br",
66 Self::Zstd => "zstd",
67 }
68 }
69
70 #[must_use]
71 pub fn to_file_extension(self) -> Option<&'static std::ffi::OsStr> {
72 match self {
73 Self::Gzip => Some(std::ffi::OsStr::new(".gz")),
74 Self::Deflate => Some(std::ffi::OsStr::new(".zz")),
75 Self::Brotli => Some(std::ffi::OsStr::new(".br")),
76 Self::Zstd => Some(std::ffi::OsStr::new(".zst")),
77 Self::Identity => None,
78 }
79 }
80
81 fn parse(s: &str, supported_encoding: impl SupportedEncodings) -> Option<Self> {
82 match_ignore_ascii_case_str! {
83 match (s) {
84 "gzip" | "x-gzip" if supported_encoding.gzip() => Some(Self::Gzip),
85 "deflate" if supported_encoding.deflate() => Some(Self::Deflate),
86 "br" if supported_encoding.br() => Some(Self::Brotli),
87 "zstd" if supported_encoding.zstd() => Some(Self::Zstd),
88 "identity" => Some(Self::Identity),
89 _ => None,
90 }
91 }
92 }
93
94 pub fn maybe_from_content_encoding_directive(
95 encoding: &crate::ContentEncodingDirective,
96 supported_encoding: impl SupportedEncodings,
97 ) -> Option<Self> {
98 match encoding {
99 crate::ContentEncodingDirective::Gzip if supported_encoding.gzip() => Some(Self::Gzip),
100 crate::ContentEncodingDirective::Deflate if supported_encoding.deflate() => {
101 Some(Self::Deflate)
102 }
103 crate::ContentEncodingDirective::Brotli if supported_encoding.br() => {
104 Some(Self::Brotli)
105 }
106 crate::ContentEncodingDirective::ZStandard if supported_encoding.zstd() => {
107 Some(Self::Zstd)
108 }
109 _ => None,
110 }
111 }
112
113 pub fn maybe_from_content_encoding_header(
114 headers: &rama_http_types::HeaderMap,
115 supported_encoding: impl SupportedEncodings,
116 ) -> Option<Self> {
117 headers
118 .get(rama_http_types::header::CONTENT_ENCODING)
119 .and_then(|hval| hval.to_str().ok())
120 .and_then(|s| Self::parse(s, supported_encoding))
121 }
122
123 #[inline]
124 pub fn from_content_encoding_header(
125 headers: &rama_http_types::HeaderMap,
126 supported_encoding: impl SupportedEncodings,
127 ) -> Self {
128 Self::maybe_from_content_encoding_header(headers, supported_encoding)
129 .unwrap_or(Self::Identity)
130 }
131
132 pub fn maybe_from_accept_encoding_headers(
133 headers: &rama_http_types::HeaderMap,
134 supported_encoding: impl SupportedEncodings,
135 ) -> Option<Self> {
136 Self::maybe_preferred_encoding(parse_accept_encoding_headers(headers, supported_encoding))
137 }
138
139 #[inline]
140 pub fn from_accept_encoding_headers(
141 headers: &rama_http_types::HeaderMap,
142 supported_encoding: impl SupportedEncodings,
143 ) -> Self {
144 Self::maybe_from_accept_encoding_headers(headers, supported_encoding)
145 .unwrap_or(Self::Identity)
146 }
147
148 pub fn maybe_preferred_encoding(
149 accepted_encodings: impl Iterator<Item = QualityValue<Self>>,
150 ) -> Option<Self> {
151 accepted_encodings
152 .filter(|qval| qval.quality.as_u16() > 0)
153 .max_by_key(|qval| (qval.quality, qval.value))
154 .map(|qval| qval.value)
155 }
156}
157
158pub fn parse_accept_encoding_headers<'a>(
160 headers: &'a rama_http_types::HeaderMap,
161 supported_encoding: impl SupportedEncodings + 'a,
162) -> impl Iterator<Item = QualityValue<Encoding>> + 'a {
163 headers
164 .get_all(rama_http_types::header::ACCEPT_ENCODING)
165 .iter()
166 .filter_map(|hval| hval.to_str().ok())
167 .flat_map(|s| s.split(','))
168 .filter_map(move |v| {
169 let mut v = v.splitn(2, ';');
170
171 let encoding = Encoding::parse(v.next()?.trim(), supported_encoding)?;
173
174 let qval = if let Some(qval) = v.next() {
175 qval.trim().parse::<Quality>().ok()?
176 } else {
177 Quality::one()
178 };
179
180 Some(QualityValue::new(encoding, qval))
181 })
182}
183
184pub fn parse_accept_encoding_wildcard_quality(
189 headers: &rama_http_types::HeaderMap,
190) -> Option<Quality> {
191 headers
192 .get_all(rama_http_types::header::ACCEPT_ENCODING)
193 .iter()
194 .filter_map(|hval| hval.to_str().ok())
195 .flat_map(|s| s.split(','))
196 .find_map(|v| {
197 let mut v = v.splitn(2, ';');
198 if v.next()?.trim() != "*" {
199 return None;
200 }
201 Some(match v.next() {
202 Some(qval) => qval.trim().parse::<Quality>().ok()?,
203 None => Quality::one(),
204 })
205 })
206}
207
208pub fn maybe_preferred_encoding_with_wildcard(
220 accepted: &[QualityValue<Encoding>],
221 wildcard_quality: Option<Quality>,
222 supported: impl SupportedEncodings,
223) -> Option<Encoding> {
224 let Some(wildcard_quality) = wildcard_quality else {
225 let identity_rejected = accepted
228 .iter()
229 .any(|qval| qval.value == Encoding::Identity && qval.quality.as_u16() == 0);
230 return match Encoding::maybe_preferred_encoding(accepted.iter().copied()) {
231 Some(enc) => Some(enc),
232 None if identity_rejected => None,
233 None => Some(Encoding::Identity),
234 };
235 };
236
237 let effective = all_supported_encodings(supported)
240 .into_iter()
241 .flatten()
242 .map(|enc| {
243 let quality = accepted
244 .iter()
245 .find(|qval| qval.value == enc)
246 .map_or(wildcard_quality, |qval| qval.quality);
247 QualityValue::new(enc, quality)
248 });
249 Encoding::maybe_preferred_encoding(effective)
250}
251
252fn all_supported_encodings(supported: impl SupportedEncodings) -> [Option<Encoding>; 5] {
254 [
255 Some(Encoding::Identity),
256 supported.gzip().then_some(Encoding::Gzip),
257 supported.deflate().then_some(Encoding::Deflate),
258 supported.br().then_some(Encoding::Brotli),
259 supported.zstd().then_some(Encoding::Zstd),
260 ]
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[derive(Copy, Clone, Default)]
268 struct SupportedEncodingsAll;
269
270 impl SupportedEncodings for SupportedEncodingsAll {
271 fn gzip(&self) -> bool {
272 true
273 }
274
275 fn deflate(&self) -> bool {
276 true
277 }
278
279 fn br(&self) -> bool {
280 true
281 }
282
283 fn zstd(&self) -> bool {
284 true
285 }
286 }
287
288 #[test]
289 fn no_accept_encoding_header() {
290 let encoding = Encoding::from_accept_encoding_headers(
291 &rama_http_types::HeaderMap::new(),
292 SupportedEncodingsAll,
293 );
294 assert_eq!(Encoding::Identity, encoding);
295 }
296
297 #[test]
298 fn accept_encoding_header_single_encoding() {
299 let mut headers = rama_http_types::HeaderMap::new();
300 headers.append(
301 rama_http_types::header::ACCEPT_ENCODING,
302 rama_http_types::HeaderValue::from_static("gzip"),
303 );
304 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
305 assert_eq!(Encoding::Gzip, encoding);
306 }
307
308 #[test]
309 fn accept_encoding_header_two_encodings() {
310 let mut headers = rama_http_types::HeaderMap::new();
311 headers.append(
312 rama_http_types::header::ACCEPT_ENCODING,
313 rama_http_types::HeaderValue::from_static("gzip,br"),
314 );
315 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
316 assert_eq!(Encoding::Brotli, encoding);
317 }
318
319 #[test]
320 fn accept_encoding_header_gzip_x_gzip() {
321 let mut headers = rama_http_types::HeaderMap::new();
322 headers.append(
323 rama_http_types::header::ACCEPT_ENCODING,
324 rama_http_types::HeaderValue::from_static("gzip,x-gzip"),
325 );
326 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
327 assert_eq!(Encoding::Gzip, encoding);
328 }
329
330 #[test]
331 fn accept_encoding_header_x_gzip_deflate() {
332 let mut headers = rama_http_types::HeaderMap::new();
333 headers.append(
334 rama_http_types::header::ACCEPT_ENCODING,
335 rama_http_types::HeaderValue::from_static("deflate,x-gzip"),
336 );
337 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
338 assert_eq!(Encoding::Gzip, encoding);
339 }
340
341 #[test]
342 fn accept_encoding_header_three_encodings() {
343 let mut headers = rama_http_types::HeaderMap::new();
344 headers.append(
345 rama_http_types::header::ACCEPT_ENCODING,
346 rama_http_types::HeaderValue::from_static("gzip,deflate,br"),
347 );
348 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
349 assert_eq!(Encoding::Brotli, encoding);
350 }
351
352 #[test]
353 fn accept_encoding_header_two_encodings_with_one_qvalue() {
354 let mut headers = rama_http_types::HeaderMap::new();
355 headers.append(
356 rama_http_types::header::ACCEPT_ENCODING,
357 rama_http_types::HeaderValue::from_static("gzip;q=0.5,br"),
358 );
359 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
360 assert_eq!(Encoding::Brotli, encoding);
361 }
362
363 #[test]
364 fn accept_encoding_header_three_encodings_with_one_qvalue() {
365 let mut headers = rama_http_types::HeaderMap::new();
366 headers.append(
367 rama_http_types::header::ACCEPT_ENCODING,
368 rama_http_types::HeaderValue::from_static("gzip;q=0.5,deflate,br"),
369 );
370 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
371 assert_eq!(Encoding::Brotli, encoding);
372 }
373
374 #[test]
375 fn two_accept_encoding_headers_with_one_qvalue() {
376 let mut headers = rama_http_types::HeaderMap::new();
377 headers.append(
378 rama_http_types::header::ACCEPT_ENCODING,
379 rama_http_types::HeaderValue::from_static("gzip;q=0.5"),
380 );
381 headers.append(
382 rama_http_types::header::ACCEPT_ENCODING,
383 rama_http_types::HeaderValue::from_static("br"),
384 );
385 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
386 assert_eq!(Encoding::Brotli, encoding);
387 }
388
389 #[test]
390 fn two_accept_encoding_headers_three_encodings_with_one_qvalue() {
391 let mut headers = rama_http_types::HeaderMap::new();
392 headers.append(
393 rama_http_types::header::ACCEPT_ENCODING,
394 rama_http_types::HeaderValue::from_static("gzip;q=0.5,deflate"),
395 );
396 headers.append(
397 rama_http_types::header::ACCEPT_ENCODING,
398 rama_http_types::HeaderValue::from_static("br"),
399 );
400 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
401 assert_eq!(Encoding::Brotli, encoding);
402 }
403
404 #[test]
405 fn three_accept_encoding_headers_with_one_qvalue() {
406 let mut headers = rama_http_types::HeaderMap::new();
407 headers.append(
408 rama_http_types::header::ACCEPT_ENCODING,
409 rama_http_types::HeaderValue::from_static("gzip;q=0.5"),
410 );
411 headers.append(
412 rama_http_types::header::ACCEPT_ENCODING,
413 rama_http_types::HeaderValue::from_static("deflate"),
414 );
415 headers.append(
416 rama_http_types::header::ACCEPT_ENCODING,
417 rama_http_types::HeaderValue::from_static("br"),
418 );
419 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
420 assert_eq!(Encoding::Brotli, encoding);
421 }
422
423 #[test]
424 fn accept_encoding_header_two_encodings_with_two_qvalues() {
425 let mut headers = rama_http_types::HeaderMap::new();
426 headers.append(
427 rama_http_types::header::ACCEPT_ENCODING,
428 rama_http_types::HeaderValue::from_static("gzip;q=0.5,br;q=0.8"),
429 );
430 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
431 assert_eq!(Encoding::Brotli, encoding);
432
433 let mut headers = rama_http_types::HeaderMap::new();
434 headers.append(
435 rama_http_types::header::ACCEPT_ENCODING,
436 rama_http_types::HeaderValue::from_static("gzip;q=0.8,br;q=0.5"),
437 );
438 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
439 assert_eq!(Encoding::Gzip, encoding);
440
441 let mut headers = rama_http_types::HeaderMap::new();
442 headers.append(
443 rama_http_types::header::ACCEPT_ENCODING,
444 rama_http_types::HeaderValue::from_static("gzip;q=0.995,br;q=0.999"),
445 );
446 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
447 assert_eq!(Encoding::Brotli, encoding);
448 }
449
450 #[test]
451 fn accept_encoding_header_three_encodings_with_three_qvalues() {
452 let mut headers = rama_http_types::HeaderMap::new();
453 headers.append(
454 rama_http_types::header::ACCEPT_ENCODING,
455 rama_http_types::HeaderValue::from_static("gzip;q=0.5,deflate;q=0.6,br;q=0.8"),
456 );
457 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
458 assert_eq!(Encoding::Brotli, encoding);
459
460 let mut headers = rama_http_types::HeaderMap::new();
461 headers.append(
462 rama_http_types::header::ACCEPT_ENCODING,
463 rama_http_types::HeaderValue::from_static("gzip;q=0.8,deflate;q=0.6,br;q=0.5"),
464 );
465 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
466 assert_eq!(Encoding::Gzip, encoding);
467
468 let mut headers = rama_http_types::HeaderMap::new();
469 headers.append(
470 rama_http_types::header::ACCEPT_ENCODING,
471 rama_http_types::HeaderValue::from_static("gzip;q=0.6,deflate;q=0.8,br;q=0.5"),
472 );
473 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
474 assert_eq!(Encoding::Deflate, encoding);
475
476 let mut headers = rama_http_types::HeaderMap::new();
477 headers.append(
478 rama_http_types::header::ACCEPT_ENCODING,
479 rama_http_types::HeaderValue::from_static("gzip;q=0.995,deflate;q=0.997,br;q=0.999"),
480 );
481 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
482 assert_eq!(Encoding::Brotli, encoding);
483 }
484
485 #[test]
486 fn accept_encoding_header_invalid_encdoing() {
487 let mut headers = rama_http_types::HeaderMap::new();
488 headers.append(
489 rama_http_types::header::ACCEPT_ENCODING,
490 rama_http_types::HeaderValue::from_static("invalid,gzip"),
491 );
492 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
493 assert_eq!(Encoding::Gzip, encoding);
494 }
495
496 #[test]
497 fn accept_encoding_header_with_qvalue_zero() {
498 let mut headers = rama_http_types::HeaderMap::new();
499 headers.append(
500 rama_http_types::header::ACCEPT_ENCODING,
501 rama_http_types::HeaderValue::from_static("gzip;q=0"),
502 );
503 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
504 assert_eq!(Encoding::Identity, encoding);
505
506 let mut headers = rama_http_types::HeaderMap::new();
507 headers.append(
508 rama_http_types::header::ACCEPT_ENCODING,
509 rama_http_types::HeaderValue::from_static("gzip;q=0."),
510 );
511 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
512 assert_eq!(Encoding::Identity, encoding);
513
514 let mut headers = rama_http_types::HeaderMap::new();
515 headers.append(
516 rama_http_types::header::ACCEPT_ENCODING,
517 rama_http_types::HeaderValue::from_static("gzip;q=0,br;q=0.5"),
518 );
519 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
520 assert_eq!(Encoding::Brotli, encoding);
521 }
522
523 #[test]
524 fn accept_encoding_header_with_uppercase_letters() {
525 let mut headers = rama_http_types::HeaderMap::new();
526 headers.append(
527 rama_http_types::header::ACCEPT_ENCODING,
528 rama_http_types::HeaderValue::from_static("gZiP"),
529 );
530 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
531 assert_eq!(Encoding::Gzip, encoding);
532
533 let mut headers = rama_http_types::HeaderMap::new();
534 headers.append(
535 rama_http_types::header::ACCEPT_ENCODING,
536 rama_http_types::HeaderValue::from_static("gzip;q=0.5,br;Q=0.8"),
537 );
538 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
539 assert_eq!(Encoding::Brotli, encoding);
540 }
541
542 #[test]
543 fn accept_encoding_header_with_allowed_spaces() {
544 let mut headers = rama_http_types::HeaderMap::new();
545 headers.append(
546 rama_http_types::header::ACCEPT_ENCODING,
547 rama_http_types::HeaderValue::from_static(" gzip\t; q=0.5 ,\tbr ;\tq=0.8\t"),
548 );
549 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
550 assert_eq!(Encoding::Brotli, encoding);
551 }
552
553 #[test]
554 fn accept_encoding_header_with_invalid_spaces() {
555 let mut headers = rama_http_types::HeaderMap::new();
556 headers.append(
557 rama_http_types::header::ACCEPT_ENCODING,
558 rama_http_types::HeaderValue::from_static("gzip;q =0.5"),
559 );
560 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
561 assert_eq!(Encoding::Identity, encoding);
562
563 let mut headers = rama_http_types::HeaderMap::new();
564 headers.append(
565 rama_http_types::header::ACCEPT_ENCODING,
566 rama_http_types::HeaderValue::from_static("gzip;q= 0.5"),
567 );
568 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
569 assert_eq!(Encoding::Identity, encoding);
570 }
571
572 #[test]
573 fn accept_encoding_header_with_invalid_quvalues() {
574 let mut headers = rama_http_types::HeaderMap::new();
575 headers.append(
576 rama_http_types::header::ACCEPT_ENCODING,
577 rama_http_types::HeaderValue::from_static("gzip;q=-0.1"),
578 );
579 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
580 assert_eq!(Encoding::Identity, encoding);
581
582 let mut headers = rama_http_types::HeaderMap::new();
583 headers.append(
584 rama_http_types::header::ACCEPT_ENCODING,
585 rama_http_types::HeaderValue::from_static("gzip;q=00.5"),
586 );
587 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
588 assert_eq!(Encoding::Identity, encoding);
589
590 let mut headers = rama_http_types::HeaderMap::new();
591 headers.append(
592 rama_http_types::header::ACCEPT_ENCODING,
593 rama_http_types::HeaderValue::from_static("gzip;q=0.5000"),
594 );
595 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
596 assert_eq!(Encoding::Identity, encoding);
597
598 let mut headers = rama_http_types::HeaderMap::new();
599 headers.append(
600 rama_http_types::header::ACCEPT_ENCODING,
601 rama_http_types::HeaderValue::from_static("gzip;q=.5"),
602 );
603 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
604 assert_eq!(Encoding::Identity, encoding);
605
606 let mut headers = rama_http_types::HeaderMap::new();
607 headers.append(
608 rama_http_types::header::ACCEPT_ENCODING,
609 rama_http_types::HeaderValue::from_static("gzip;q=1.01"),
610 );
611 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
612 assert_eq!(Encoding::Identity, encoding);
613
614 let mut headers = rama_http_types::HeaderMap::new();
615 headers.append(
616 rama_http_types::header::ACCEPT_ENCODING,
617 rama_http_types::HeaderValue::from_static("gzip;q=1.001"),
618 );
619 let encoding = Encoding::from_accept_encoding_headers(&headers, SupportedEncodingsAll);
620 assert_eq!(Encoding::Identity, encoding);
621 }
622
623 #[derive(Copy, Clone)]
624 struct SupportedGzipOnly;
625
626 impl SupportedEncodings for SupportedGzipOnly {
627 fn gzip(&self) -> bool {
628 true
629 }
630 fn deflate(&self) -> bool {
631 false
632 }
633 fn br(&self) -> bool {
634 false
635 }
636 fn zstd(&self) -> bool {
637 false
638 }
639 }
640
641 fn negotiate(
642 headers: &rama_http_types::HeaderMap,
643 supported: impl SupportedEncodings,
644 ) -> Option<Encoding> {
645 let accepted: Vec<_> = parse_accept_encoding_headers(headers, supported).collect();
646 let wildcard = parse_accept_encoding_wildcard_quality(headers);
647 maybe_preferred_encoding_with_wildcard(&accepted, wildcard, supported)
648 }
649
650 fn accept_encoding(value: &'static str) -> rama_http_types::HeaderMap {
651 let mut headers = rama_http_types::HeaderMap::new();
652 headers.append(
653 rama_http_types::header::ACCEPT_ENCODING,
654 rama_http_types::HeaderValue::from_static(value),
655 );
656 headers
657 }
658
659 #[test]
660 fn wildcard_alone_picks_best_supported() {
661 let headers = accept_encoding("*");
662 assert_eq!(
664 Some(Encoding::Zstd),
665 negotiate(&headers, SupportedEncodingsAll)
666 );
667 }
668
669 #[test]
670 fn wildcard_q_zero_with_nothing_else_returns_not_satisfiable() {
671 let headers = accept_encoding("*;q=0");
673 assert_eq!(None, negotiate(&headers, SupportedEncodingsAll));
674 }
675
676 #[test]
677 fn wildcard_q_zero_with_gzip_picks_gzip() {
678 let headers = accept_encoding("*;q=0,gzip");
679 assert_eq!(
680 Some(Encoding::Gzip),
681 negotiate(&headers, SupportedEncodingsAll)
682 );
683 }
684
685 #[test]
686 fn identity_q_zero_alone_returns_not_satisfiable() {
687 let headers = accept_encoding("identity;q=0");
690 assert_eq!(None, negotiate(&headers, SupportedEncodingsAll));
691 }
692
693 #[test]
694 fn identity_q_zero_with_gzip_picks_gzip() {
695 let headers = accept_encoding("identity;q=0,gzip");
696 assert_eq!(
697 Some(Encoding::Gzip),
698 negotiate(&headers, SupportedEncodingsAll)
699 );
700 }
701
702 #[test]
703 fn wildcard_q_zero_identity_q_zero_no_compression_returns_not_satisfiable() {
704 let headers = accept_encoding("*;q=0,identity;q=0");
706 assert_eq!(None, negotiate(&headers, SupportedEncodingsAll));
707 }
708
709 #[test]
710 fn wildcard_with_low_qvalue() {
711 let headers = accept_encoding("*;q=0.5,gzip;q=1");
713 assert_eq!(
714 Some(Encoding::Gzip),
715 negotiate(&headers, SupportedEncodingsAll)
716 );
717 }
718
719 #[test]
720 fn wildcard_q_zero_with_identity_picks_identity() {
721 let headers = accept_encoding("*;q=0,identity");
723 assert_eq!(
724 Some(Encoding::Identity),
725 negotiate(&headers, SupportedEncodingsAll)
726 );
727 }
728
729 #[test]
730 fn wildcard_with_partial_server_support_picks_best_available() {
731 let headers = accept_encoding("*");
733 assert_eq!(Some(Encoding::Gzip), negotiate(&headers, SupportedGzipOnly));
734 }
735
736 #[test]
737 fn wildcard_q_zero_with_unsupported_encoding_returns_not_satisfiable() {
738 let headers = accept_encoding("*;q=0,br");
741 assert_eq!(None, negotiate(&headers, SupportedGzipOnly));
742 }
743}