1 use std::{convert::Infallible, str::FromStr};
2 
3 use http::header::InvalidHeaderValue;
4 
5 use crate::{
6     error::ParseError,
7     header::{self, from_one_raw_str, Header, HeaderName, HeaderValue, IntoHeaderValue},
8     HttpMessage,
9 };
10 
11 /// Represents a supported content encoding.
12 #[derive(Copy, Clone, PartialEq, Debug)]
13 pub enum ContentEncoding {
14     /// Automatically select encoding based on encoding negotiation.
15     Auto,
16 
17     /// A format using the Brotli algorithm.
18     Br,
19 
20     /// A format using the zlib structure with deflate algorithm.
21     Deflate,
22 
23     /// Gzip algorithm.
24     Gzip,
25 
26     // Zstd algorithm.
27     Zstd,
28 
29     /// Indicates the identity function (i.e. no compression, nor modification).
30     Identity,
31 }
32 
33 impl ContentEncoding {
34     /// Is the content compressed?
35     #[inline]
is_compression(self) -> bool36     pub fn is_compression(self) -> bool {
37         matches!(self, ContentEncoding::Identity | ContentEncoding::Auto)
38     }
39 
40     /// Convert content encoding to string
41     #[inline]
as_str(self) -> &'static str42     pub fn as_str(self) -> &'static str {
43         match self {
44             ContentEncoding::Br => "br",
45             ContentEncoding::Gzip => "gzip",
46             ContentEncoding::Deflate => "deflate",
47             ContentEncoding::Zstd => "zstd",
48             ContentEncoding::Identity | ContentEncoding::Auto => "identity",
49         }
50     }
51 
52     /// Default Q-factor (quality) value.
53     #[inline]
quality(self) -> f6454     pub fn quality(self) -> f64 {
55         match self {
56             ContentEncoding::Br => 1.1,
57             ContentEncoding::Gzip => 1.0,
58             ContentEncoding::Deflate => 0.9,
59             ContentEncoding::Identity | ContentEncoding::Auto => 0.1,
60             ContentEncoding::Zstd => 0.0,
61         }
62     }
63 }
64 
65 impl Default for ContentEncoding {
default() -> Self66     fn default() -> Self {
67         Self::Identity
68     }
69 }
70 
71 impl FromStr for ContentEncoding {
72     type Err = Infallible;
73 
from_str(val: &str) -> Result<Self, Self::Err>74     fn from_str(val: &str) -> Result<Self, Self::Err> {
75         Ok(Self::from(val))
76     }
77 }
78 
79 impl From<&str> for ContentEncoding {
from(val: &str) -> ContentEncoding80     fn from(val: &str) -> ContentEncoding {
81         let val = val.trim();
82 
83         if val.eq_ignore_ascii_case("br") {
84             ContentEncoding::Br
85         } else if val.eq_ignore_ascii_case("gzip") {
86             ContentEncoding::Gzip
87         } else if val.eq_ignore_ascii_case("deflate") {
88             ContentEncoding::Deflate
89         } else if val.eq_ignore_ascii_case("zstd") {
90             ContentEncoding::Zstd
91         } else {
92             ContentEncoding::default()
93         }
94     }
95 }
96 
97 impl IntoHeaderValue for ContentEncoding {
98     type Error = InvalidHeaderValue;
99 
try_into_value(self) -> Result<http::HeaderValue, Self::Error>100     fn try_into_value(self) -> Result<http::HeaderValue, Self::Error> {
101         Ok(HeaderValue::from_static(self.as_str()))
102     }
103 }
104 
105 impl Header for ContentEncoding {
name() -> HeaderName106     fn name() -> HeaderName {
107         header::CONTENT_ENCODING
108     }
109 
parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError>110     fn parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError> {
111         from_one_raw_str(msg.headers().get(Self::name()))
112     }
113 }
114