1use crate::msgs::enums::CertificateCompressionAlgorithm;
4use alloc::vec::Vec;
5use brotli::DecompressorWriter;
6use brotli::{enc::BrotliEncoderParams, CompressorWriter};
7use core::fmt::Debug;
8use flate2::read::ZlibDecoder;
9use flate2::write::ZlibEncoder;
10use std::io::{Read, Result, Write};
11
12#[derive(Debug)]
16pub struct CertificateCompression {
17 pub alg: CertificateCompressionAlgorithm,
19
20 pub provider: &'static dyn CompressionProvider,
22}
23
24pub trait CompressionProvider: Send + Sync + Debug {
26 fn compress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>>;
28 fn decompress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>>;
30}
31
32#[derive(Debug)]
34pub struct BrotliParams {
35 pub buffer_size: usize,
37 pub params: BrotliEncoderParams,
39}
40
41impl CompressionProvider for BrotliParams {
42 fn compress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
43 let mut compressor = CompressorWriter::with_params(writer, self.buffer_size, &self.params);
44 compressor.write_all(input)?;
45 compressor.flush()?;
46 Ok(compressor.into_inner())
47 }
48
49 fn decompress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
50 let mut decompressor = DecompressorWriter::new(writer, self.buffer_size);
51 decompressor.write_all(input)?;
52 decompressor.flush()?;
53 decompressor
54 .into_inner()
55 .map_err(|_| std::io::ErrorKind::InvalidData.into())
56 }
57}
58
59mod compression_params {
61 use brotli::enc::BrotliEncoderParams;
62
63 #[allow(non_snake_case)]
64 const fn BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX: u32, NDIRECT: u32, MAXNBITS: u32) -> u32 {
65 brotli::enc::encode::BROTLI_NUM_DISTANCE_SHORT_CODES
66 + (NDIRECT)
67 + ((MAXNBITS) << ((NPOSTFIX) + 1))
68 }
69
70 pub(crate) const BROTLI_ENCODER_DEFAULT: BrotliEncoderParams = BrotliEncoderParams {
71 dist: brotli::enc::command::BrotliDistanceParams {
72 distance_postfix_bits: 0,
73 num_direct_distance_codes: 0,
74 alphabet_size: BROTLI_DISTANCE_ALPHABET_SIZE(
75 0,
76 0,
77 brotli::enc::encode::BROTLI_MAX_DISTANCE_BITS,
78 ),
79 max_distance: brotli::enc::encode::BROTLI_MAX_DISTANCE,
80 },
81 mode: brotli::enc::backward_references::BrotliEncoderMode::BROTLI_MODE_GENERIC,
82 log_meta_block: false,
83 large_window: false,
84 avoid_distance_prefix_search: false,
85 quality: 11,
86 q9_5: false,
87 lgwin: 22i32,
88 lgblock: 0i32,
89 size_hint: 0usize,
90 disable_literal_context_modeling: 0i32,
91 stride_detection_quality: 0,
92 high_entropy_detection_quality: 0,
93 cdf_adaptation_detection: 0,
94 prior_bitmask_detection: 0,
95 literal_adaptation: [(0, 0); 4],
96 catable: false,
97 use_dictionary: true,
98 appendable: false,
99 magic_number: false,
100 favor_cpu_efficiency: false,
101 hasher: brotli::enc::backward_references::BrotliHasherParams {
102 type_: 6,
103 block_bits: 9 - 1,
104 bucket_bits: 15,
105 hash_len: 5,
106 num_last_distances_to_check: 16,
107 literal_byte_score: 0,
108 },
109 };
110
111 pub(crate) const ZLIB_ENCODER_DEFAULT: flate2::Compression = flate2::Compression::new(6);
112
113 #[test]
114 fn param_eq() {
115 assert_eq!(
116 format!("{BROTLI_ENCODER_DEFAULT:?}"),
117 format!("{:?}", BrotliEncoderParams::default())
118 );
119
120 assert_eq!(
121 format!("{ZLIB_ENCODER_DEFAULT:?}"),
122 format!("{:?}", flate2::Compression::default())
123 );
124 }
125}
126
127pub static BROTLI_DEFAULT: &CertificateCompression = &CertificateCompression {
129 alg: CertificateCompressionAlgorithm::Brotli,
130 provider: &BrotliParams {
131 buffer_size: 4096,
132 params: compression_params::BROTLI_ENCODER_DEFAULT,
133 },
134};
135
136#[derive(Debug)]
137pub struct ZlibParams {
139 pub compression_level: flate2::Compression,
141}
142
143impl CompressionProvider for ZlibParams {
144 fn compress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
145 let mut compressor = ZlibEncoder::new(writer, self.compression_level);
146 compressor.write_all(input)?;
147 compressor.flush()?;
148 compressor.finish()
149 }
150
151 fn decompress(&self, mut writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
152 let mut decompressor = ZlibDecoder::new(input);
153
154 decompressor.read_to_end(&mut writer)?;
155 Ok(writer)
156 }
157}
158
159pub static ZLIB_DEFAULT: &CertificateCompression = &CertificateCompression {
161 alg: CertificateCompressionAlgorithm::Zlib,
162 provider: &ZlibParams {
163 compression_level: compression_params::ZLIB_ENCODER_DEFAULT,
164 },
165};
166
167#[derive(Debug)]
168pub struct ZstdParams {
170 pub compression_level: u32,
172}
173
174impl CompressionProvider for ZstdParams {
175 fn compress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
176 let mut compressor = zstd::Encoder::new(writer, self.compression_level as i32)?;
177 compressor.write_all(input)?;
178 compressor.flush()?;
179 compressor.finish()
180 }
181
182 fn decompress(&self, mut writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>> {
183 let mut decompressor = zstd::Decoder::new(input)?;
184 decompressor.read_to_end(&mut writer)?;
185 Ok(writer)
186 }
187}
188
189pub static ZSTD_DEFAULT: &CertificateCompression = &CertificateCompression {
191 alg: CertificateCompressionAlgorithm::Zstd,
192 provider: &ZstdParams {
193 compression_level: zstd::DEFAULT_COMPRESSION_LEVEL as u32,
194 },
195};