barehttp/gzip/mod.rs
1//! Gzip, zlib, and raw DEFLATE decompression (RFC 1950–1952).
2
3mod bit;
4mod crc32;
5mod fixed_tables;
6#[allow(clippy::module_inception)] // RFC 1952 member parser lives in `gzip.rs` by design
7mod gzip;
8mod huffman;
9mod inflate;
10mod zlib;
11
12#[cfg(test)]
13mod tests;
14
15use alloc::vec::Vec;
16
17/// Same type as [`crate::DecompressError`] (always at the crate root; this module is
18/// feature-gated behind `gzip`).
19pub use crate::error::DecompressError;
20
21/// RFC 1952 gzip member → uncompressed bytes. Enforces `max_out`.
22///
23/// # Errors
24/// [`DecompressError`] when the member is invalid or output would exceed `max_out`.
25///
26/// # Examples
27///
28/// ```
29/// use barehttp::gzip::decompress_gzip;
30///
31/// // gzip member for payload "hi"
32/// let gz: &[u8] = &[
33/// 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcb, 0xc8, 0x04, 0x00, 0xac, 0x2a, 0x93,
34/// 0xd8, 0x02, 0x00, 0x00, 0x00,
35/// ];
36/// assert_eq!(decompress_gzip(gz, 64)?, b"hi");
37/// # Ok::<(), barehttp::gzip::DecompressError>(())
38/// ```
39pub fn decompress_gzip(
40 data: &[u8],
41 max_out: usize,
42) -> Result<Vec<u8>, DecompressError> {
43 gzip::decompress_member_owned(data, max_out)
44}
45
46/// Like [`decompress_gzip`], writing into `out` (cleared first; capacity reused).
47///
48/// Crate-internal: response parse / pooled buffers can adopt without a public API change.
49pub(crate) fn decompress_gzip_into(
50 data: &[u8],
51 max_out: usize,
52 out: &mut Vec<u8>,
53) -> Result<(), DecompressError> {
54 gzip::decompress_member(data, max_out, out)
55}
56
57/// HTTP `Content-Encoding: deflate`: try zlib (RFC 1950), then raw RFC 1951.
58///
59/// # Errors
60/// [`DecompressError`] when both wrappers fail or output would exceed `max_out`.
61///
62/// # Examples
63///
64/// ```
65/// use barehttp::gzip::decompress_http_deflate;
66///
67/// // zlib-wrapped DEFLATE for payload "hi" (CMF/FLG + deflate + Adler-32)
68/// let z: &[u8] = &[0x78, 0xda, 0xcb, 0xc8, 0x04, 0x00, 0x01, 0x3b, 0x00, 0xd2];
69/// assert_eq!(decompress_http_deflate(z, 64)?, b"hi");
70/// # Ok::<(), barehttp::gzip::DecompressError>(())
71/// ```
72pub fn decompress_http_deflate(
73 data: &[u8],
74 max_out: usize,
75) -> Result<Vec<u8>, DecompressError> {
76 match zlib::decompress_owned(data, max_out) {
77 Ok(out) => Ok(out),
78 Err(DecompressError::LimitExceeded) => Err(DecompressError::LimitExceeded),
79 Err(DecompressError::InvalidInput) => decompress_raw_deflate(data, max_out),
80 }
81}
82
83/// Like [`decompress_http_deflate`], writing into `out` (cleared; capacity reused).
84pub(crate) fn decompress_http_deflate_into(
85 data: &[u8],
86 max_out: usize,
87 out: &mut Vec<u8>,
88) -> Result<(), DecompressError> {
89 match zlib::decompress(data, max_out, out) {
90 Ok(()) => Ok(()),
91 Err(DecompressError::LimitExceeded) => Err(DecompressError::LimitExceeded),
92 // zlib may have filled `out` before rejecting the trailer / stream; clear for raw retry.
93 Err(DecompressError::InvalidInput) => {
94 out.clear();
95 decompress_raw_deflate_into(data, max_out, out)
96 },
97 }
98}
99
100/// Raw DEFLATE bitstream (RFC 1951) only.
101///
102/// # Errors
103/// [`DecompressError`] when the stream is invalid or output would exceed `max_out`.
104///
105/// # Examples
106///
107/// ```
108/// use barehttp::gzip::decompress_raw_deflate;
109///
110/// // raw DEFLATE for payload "hi" (no zlib wrapper)
111/// let raw: &[u8] = &[0xcb, 0xc8, 0x04, 0x00];
112/// assert_eq!(decompress_raw_deflate(raw, 64)?, b"hi");
113/// # Ok::<(), barehttp::gzip::DecompressError>(())
114/// ```
115pub fn decompress_raw_deflate(
116 data: &[u8],
117 max_out: usize,
118) -> Result<Vec<u8>, DecompressError> {
119 let mut none = inflate::RunningChecksum::None;
120 let (out, _) = inflate::inflate_owned(data, max_out, &mut none)?;
121 Ok(out)
122}
123
124/// Like [`decompress_raw_deflate`], writing into `out` (cleared; capacity reused).
125pub(crate) fn decompress_raw_deflate_into(
126 data: &[u8],
127 max_out: usize,
128 out: &mut Vec<u8>,
129) -> Result<(), DecompressError> {
130 let mut none = inflate::RunningChecksum::None;
131 let _ = inflate::inflate(data, max_out, &mut none, out)?;
132 Ok(())
133}