1pub(crate) trait ResponseCompression {
12 fn content_encoding<'a>(&'a self) -> Option<&'a str>;
14
15 fn content_type<'a>(&'a self) -> Option<&'a str>;
17
18 #[cfg(feature = "br")]
20 fn can_brotli_compress(&self) -> bool {
21 if self.content_encoding().is_some() {
23 return false;
25 }
26
27 if let Some(header_val) = self.content_type() {
29 let ctype = header_val.trim().to_ascii_lowercase();
30
31 ctype.starts_with("text/")
33 || ctype.starts_with("application/json")
34 || ctype.starts_with("application/xhtml")
35 || ctype.starts_with("application/xml")
36 || ctype.starts_with("application/wasm")
37 || ctype.starts_with("image/svg")
38 } else {
39 false
41 }
42 }
43
44 #[cfg(not(feature = "br"))]
46 fn can_brotli_compress(&self) -> bool {
47 false
48 }
49}
50
51#[cfg(feature = "br")]
53pub(crate) fn compress_response_body<'a>(body: &[u8]) -> String {
54 let cfg = brotli::enc::BrotliEncoderParams {
56 quality: 4,
57 ..Default::default()
58 };
59
60 let mut body_reader = std::io::Cursor::new(body);
62 let mut compressed_base64 = base64::write::EncoderStringWriter::new(base64::STANDARD);
63 let _sz = brotli::BrotliCompress(&mut body_reader, &mut compressed_base64, &cfg);
64
65 compressed_base64.into_inner()
66}
67
68#[cfg(not(feature = "br"))]
70pub(crate) fn compress_response_body<'a>(body: &[u8]) -> String {
71 base64::encode(body)
72}