summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCurran McConnell <curran.mcconnell@protonmail.com>2023-09-07 23:41:33 -0400
committerGitHub <noreply@github.com>2023-09-08 09:11:33 +0530
commita9cc4631ca4b5e2bb64943435d0d8242292b168d (patch)
tree99bc1c8950c141d4c93ff964d2070a41bff5e1de
parent4a11603c76b13ecf92ce3141ec317a42ae9f8d1d (diff)
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.
-rw-r--r--cli/tests/unit_node/zlib_test.ts7
-rw-r--r--ext/node/ops/zlib/brotli.rs36
2 files changed, 13 insertions, 30 deletions
diff --git a/cli/tests/unit_node/zlib_test.ts b/cli/tests/unit_node/zlib_test.ts
index 6b09c50b0..b878b7cc3 100644
--- a/cli/tests/unit_node/zlib_test.ts
+++ b/cli/tests/unit_node/zlib_test.ts
@@ -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(
"zlib create deflate with dictionary",
{ sanitizeResources: false },
diff --git a/ext/node/ops/zlib/brotli.rs b/ext/node/ops/zlib/brotli.rs
index f3b5001aa..b4d970970 100644
--- a/ext/node/ops/zlib/brotli.rs
+++ b/ext/node/ops/zlib/brotli.rs
@@ -4,6 +4,7 @@ use brotli::ffi::compressor::*;
use brotli::ffi::decompressor::ffi::interface::BrotliDecoderResult;
use brotli::ffi::decompressor::ffi::BrotliDecoderState;
use brotli::ffi::decompressor::*;
+use brotli::Decompressor;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::op;
@@ -11,6 +12,7 @@ use deno_core::JsBuffer;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ToJsBuffer;
+use std::io::Read;
fn encoder_mode(mode: u32) -> Result<BrotliEncoderMode, AnyError> {
if mode > 6 {
@@ -214,36 +216,10 @@ pub fn op_brotli_compress_stream_end(
}
fn brotli_decompress(buffer: &[u8]) -> Result<ToJsBuffer, AnyError> {
- let in_buffer = buffer.as_ptr();
- let in_size = buffer.len();
-
- let mut out = vec![0u8; 4096];
- 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")),
- }
- }
+ let mut output = Vec::with_capacity(4096);
+ let mut decompressor = Decompressor::new(buffer, buffer.len());
+ decompressor.read_to_end(&mut output)?;
+ Ok(output.into())
}
#[op]