1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

fix(ext/node/ops/zlib/brotli): Allow decompressing more than 4096 bytes (#20301)

Fixes https://github.com/denoland/deno/issues/19816

In that issue, I suggest switching over the other brotli functionality
to the Rust API provided by the `brotli` crate. Here, I only do that
with the `brotli_decompress` function to fix the bug with buffers longer
than 4096 bytes.
This commit is contained in:
Curran McConnell 2023-09-07 23:41:33 -04:00 committed by GitHub
parent 4a11603c76
commit a9cc4631ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 13 additions and 30 deletions

View file

@ -62,6 +62,13 @@ Deno.test("brotli compression", async () => {
} }
}); });
Deno.test("brotli end-to-end with 4097 bytes", () => {
const a = "a".repeat(4097);
const compressed = brotliCompressSync(a);
const decompressed = brotliDecompressSync(compressed);
assertEquals(decompressed.toString(), a);
});
Deno.test( Deno.test(
"zlib create deflate with dictionary", "zlib create deflate with dictionary",
{ sanitizeResources: false }, { sanitizeResources: false },

View file

@ -4,6 +4,7 @@ use brotli::ffi::compressor::*;
use brotli::ffi::decompressor::ffi::interface::BrotliDecoderResult; use brotli::ffi::decompressor::ffi::interface::BrotliDecoderResult;
use brotli::ffi::decompressor::ffi::BrotliDecoderState; use brotli::ffi::decompressor::ffi::BrotliDecoderState;
use brotli::ffi::decompressor::*; use brotli::ffi::decompressor::*;
use brotli::Decompressor;
use deno_core::error::type_error; use deno_core::error::type_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::op; use deno_core::op;
@ -11,6 +12,7 @@ use deno_core::JsBuffer;
use deno_core::OpState; use deno_core::OpState;
use deno_core::Resource; use deno_core::Resource;
use deno_core::ToJsBuffer; use deno_core::ToJsBuffer;
use std::io::Read;
fn encoder_mode(mode: u32) -> Result<BrotliEncoderMode, AnyError> { fn encoder_mode(mode: u32) -> Result<BrotliEncoderMode, AnyError> {
if mode > 6 { if mode > 6 {
@ -214,36 +216,10 @@ pub fn op_brotli_compress_stream_end(
} }
fn brotli_decompress(buffer: &[u8]) -> Result<ToJsBuffer, AnyError> { fn brotli_decompress(buffer: &[u8]) -> Result<ToJsBuffer, AnyError> {
let in_buffer = buffer.as_ptr(); let mut output = Vec::with_capacity(4096);
let in_size = buffer.len(); let mut decompressor = Decompressor::new(buffer, buffer.len());
decompressor.read_to_end(&mut output)?;
let mut out = vec![0u8; 4096]; Ok(output.into())
loop {
let out_buffer = out.as_mut_ptr();
let mut out_size = out.len();
// SAFETY: TODO(littledivy)
match unsafe {
CBrotliDecoderDecompress(
in_size,
in_buffer,
&mut out_size as *mut usize,
out_buffer,
)
} {
BrotliDecoderResult::BROTLI_DECODER_RESULT_SUCCESS => {
out.truncate(out_size);
return Ok(out.into());
}
BrotliDecoderResult::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT => {
let new_size = out.len() * 2;
if new_size < out.len() {
return Err(type_error("Failed to decompress"));
}
out.resize(new_size, 0);
}
_ => return Err(type_error("Failed to decompress")),
}
}
} }
#[op] #[op]