use bun_core::MutableString;
use bun_http_types::Encoding::Encoding;
use bun_brotli::BrotliReaderArrayList;
use bun_zlib::ZlibReaderArrayList;
use bun_zstd::ZstdReaderArrayList;
#[derive(Default)]
pub enum Decompressor {
Zlib(Box<ZlibReaderArrayList<'static>>),
Brotli(Box<BrotliReaderArrayList<'static>>),
Zstd(Box<ZstdReaderArrayList<'static>>),
#[default]
None,
}
#[inline(always)]
unsafe fn seat<'a>(input: &'a [u8], out: &'a mut Vec<u8>) -> (&'static [u8], &'static mut Vec<u8>) {
unsafe {
(
bun_ptr::Interned::assume(input).as_bytes(),
bun_ptr::detach_lifetime_mut(out),
)
}
}
const MAX_DECOMPRESSED_BODY_SIZE: usize = 1024 * 1024 * 1024;
impl Decompressor {
pub fn update_buffers(
&mut self,
encoding: Encoding,
buffer: &[u8],
body_out_str: &mut MutableString,
) -> Result<(), bun_core::Error> {
if !encoding.is_compressed() {
return Ok(());
}
if matches!(self, Decompressor::None) {
let (input, out) = unsafe { seat(buffer, &mut body_out_str.list) };
match encoding {
Encoding::Gzip | Encoding::Deflate => {
let mut reader = ZlibReaderArrayList::init_with_options_and_list_allocator(
input,
out,
bun_zlib::Options {
window_bits: if encoding == Encoding::Gzip {
bun_zlib::MAX_WBITS | 16
} else if buffer.len() > 1 && buffer[0] == 120 {
0
} else {
-bun_zlib::MAX_WBITS
},
..Default::default()
},
)?;
reader.max_output_size = MAX_DECOMPRESSED_BODY_SIZE;
*self = Decompressor::Zlib(reader);
return Ok(());
}
Encoding::Brotli => {
let mut reader = BrotliReaderArrayList::new_with_options(
input,
out,
&Default::default(),
)?;
reader.max_output_size = MAX_DECOMPRESSED_BODY_SIZE;
*self = Decompressor::Brotli(reader);
return Ok(());
}
Encoding::Zstd => {
let mut reader = ZstdReaderArrayList::init_with_list_allocator(
input,
out,
)?;
reader.max_output_size = MAX_DECOMPRESSED_BODY_SIZE;
*self = Decompressor::Zstd(reader);
return Ok(());
}
_ => unreachable!("Invalid encoding. This code should not be reachable"),
}
}
match self {
Decompressor::Zlib(reader) => {
let (input, out) = unsafe { seat(buffer, &mut body_out_str.list) };
reader.input = input;
reader.list_ptr = out;
}
Decompressor::Brotli(reader) => {
let initial = body_out_str.list.len();
let (input, out) = unsafe { seat(buffer, &mut body_out_str.list) };
reader.input = input;
reader.total_in = 0;
reader.list_ptr = out;
reader.total_out = initial;
}
Decompressor::Zstd(reader) => {
let initial = body_out_str.list.len();
let (input, out) = unsafe { seat(buffer, &mut body_out_str.list) };
reader.input = input;
reader.total_in = 0;
reader.list_ptr = out;
reader.total_out = initial;
}
Decompressor::None => {
unreachable!("Invalid encoding. This code should not be reachable")
}
}
Ok(())
}
pub fn read_all(&mut self, is_done: bool) -> Result<(), bun_core::Error> {
match self {
Decompressor::Zlib(zlib) => zlib.read_all(is_done)?,
Decompressor::Brotli(brotli) => brotli.read_all(is_done)?,
Decompressor::Zstd(reader) => reader.read_all(is_done)?,
Decompressor::None => {}
}
Ok(())
}
}