rustls/
compression.rs

1//! Compression related operations
2
3use 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/// A certificate compression algorithm described
13/// as a pair of compression and decompression
14/// functions used to compress and decompress a certificate\
15#[derive(Debug)]
16pub struct CertificateCompression {
17    /// compression algorithm
18    pub alg: CertificateCompressionAlgorithm,
19
20    /// compression provider
21    pub provider: &'static dyn CompressionProvider,
22}
23
24/// todo
25pub trait CompressionProvider: Send + Sync + Debug {
26    /// todo
27    fn compress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>>;
28    /// todo
29    fn decompress(&self, writer: Vec<u8>, input: &[u8]) -> Result<Vec<u8>>;
30}
31
32/// todo
33#[derive(Debug)]
34pub struct BrotliParams {
35    /// todo
36    pub buffer_size: usize,
37    /// todo
38    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
59/// todo
60mod 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
127/// todo
128pub 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)]
137/// todo
138pub struct ZlibParams {
139    /// Must between 0-9 (inclusive)
140    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
159/// todo
160pub 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)]
168/// todo
169pub struct ZstdParams {
170    /// todo
171    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
189/// todo
190pub static ZSTD_DEFAULT: &CertificateCompression = &CertificateCompression {
191    alg: CertificateCompressionAlgorithm::Zstd,
192    provider: &ZstdParams {
193        compression_level: zstd::DEFAULT_COMPRESSION_LEVEL as u32,
194    },
195};