Skip to main content

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}