pub use crate::HeaderMap;
#[doc(hidden)]
pub use crate::map::{AsName, Either, GetAll, Iter, Value};
pub use crate::value::{HeaderValue, InvalidHeaderValue, ToStrError};
pub use http::header::{
ACCEPT, ACCEPT_CHARSET, ACCEPT_ENCODING, ACCEPT_LANGUAGE, ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS, ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, AGE, ALLOW, ALT_SVC,
AUTHORIZATION, CACHE_CONTROL, CONNECTION, CONTENT_DISPOSITION, CONTENT_ENCODING,
CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_LOCATION, CONTENT_RANGE, CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY, CONTENT_TYPE, COOKIE, DATE, DNT, ETAG, EXPECT, EXPIRES,
FORWARDED, FROM, HOST, IF_MATCH, IF_MODIFIED_SINCE, IF_NONE_MATCH, IF_RANGE,
IF_UNMODIFIED_SINCE, LAST_MODIFIED, LINK, LOCATION, MAX_FORWARDS, ORIGIN, PRAGMA,
PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, PUBLIC_KEY_PINS, PUBLIC_KEY_PINS_REPORT_ONLY, RANGE,
REFERER, REFERRER_POLICY, REFRESH, RETRY_AFTER, SEC_WEBSOCKET_ACCEPT, SEC_WEBSOCKET_EXTENSIONS,
SEC_WEBSOCKET_KEY, SEC_WEBSOCKET_PROTOCOL, SEC_WEBSOCKET_VERSION, SERVER, SET_COOKIE,
STRICT_TRANSPORT_SECURITY, TE, TRAILER, TRANSFER_ENCODING, UPGRADE, UPGRADE_INSECURE_REQUESTS,
USER_AGENT, VARY, VIA, WARNING, WWW_AUTHENTICATE, X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL, X_FRAME_OPTIONS, X_XSS_PROTECTION,
};
pub use http::header::{HeaderName, InvalidHeaderName};
pub use crate::error::InvalidContentEncoding;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ContentEncoding {
Auto,
Br,
Deflate,
Gzip,
Zstd,
Identity,
}
impl ContentEncoding {
#[inline]
pub fn is_compressed(self) -> bool {
!matches!(self, ContentEncoding::Identity | ContentEncoding::Auto)
}
#[inline]
pub fn as_str(self) -> &'static str {
match self {
ContentEncoding::Br => "br",
ContentEncoding::Gzip => "gzip",
ContentEncoding::Deflate => "deflate",
ContentEncoding::Zstd => "zstd",
ContentEncoding::Identity | ContentEncoding::Auto => "identity",
}
}
#[inline]
pub fn quality(self) -> f64 {
match self {
ContentEncoding::Br => 1.1,
ContentEncoding::Zstd => 1.05,
ContentEncoding::Gzip => 1.0,
ContentEncoding::Deflate => 0.9,
ContentEncoding::Identity | ContentEncoding::Auto => 0.1,
}
}
}
impl std::str::FromStr for ContentEncoding {
type Err = InvalidContentEncoding;
fn from_str(s: &str) -> Result<ContentEncoding, InvalidContentEncoding> {
let s = s.trim();
if s.eq_ignore_ascii_case("br") {
Ok(ContentEncoding::Br)
} else if s.eq_ignore_ascii_case("gzip") || s.eq_ignore_ascii_case("x-gzip") {
Ok(ContentEncoding::Gzip)
} else if s.eq_ignore_ascii_case("deflate") {
Ok(ContentEncoding::Deflate)
} else if s.eq_ignore_ascii_case("zstd") {
Ok(ContentEncoding::Zstd)
} else if s.eq_ignore_ascii_case("identity") {
Ok(ContentEncoding::Identity)
} else {
Err(InvalidContentEncoding::new())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encoding() {
assert!(ContentEncoding::Br.is_compressed());
assert!(!ContentEncoding::Identity.is_compressed());
assert!(!ContentEncoding::Auto.is_compressed());
assert_eq!(format!("{:?}", ContentEncoding::Identity), "Identity");
assert!(ContentEncoding::Zstd.is_compressed());
assert_eq!(ContentEncoding::Zstd.as_str(), "zstd");
assert!(ContentEncoding::Br.quality() > ContentEncoding::Zstd.quality());
assert!(ContentEncoding::Zstd.quality() > ContentEncoding::Gzip.quality());
}
#[test]
fn parse() {
for (s, enc) in [
("br", ContentEncoding::Br),
("gzip", ContentEncoding::Gzip),
("X-Gzip", ContentEncoding::Gzip),
("Deflate", ContentEncoding::Deflate),
(" ZStd ", ContentEncoding::Zstd),
("identity", ContentEncoding::Identity),
("IDENTITY", ContentEncoding::Identity),
] {
assert_eq!(s.parse::<ContentEncoding>(), Ok(enc), "{s:?}");
}
for s in ["gizp", "x-zstd", "compress", "auto", "gzip, br", "", " "] {
let err = s.parse::<ContentEncoding>().unwrap_err();
assert_eq!(err.to_string(), "Unsupported content encoding");
assert!(
crate::Error::from(err).is::<InvalidContentEncoding>(),
"{s:?}"
);
}
}
}