zlib: Brotli reset() drops quality and dictionary

Đang mở
#66,156 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
76/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
cpp, javascript, node.js
Lĩnh vực
api, backend

Hướng nghiên cứu

Start in src/node_zlib.cc at BrotliEncoderContext::ResetStream, BrotliDecoderContext::ResetStream, and Init(), then run the JavaScript reproduction from the issue. Verify that reset preserves Brotli quality parameters and dictionaries for compression and decompression, and add regression coverage showing the configured behavior remains after reset.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Version

v27.0.0-pre (built from main at a2a051cd42; src/node_zlib.cc is unchanged on current main)

Platform
Linux x86_64 (Ubuntu 22.04, built with clang 20)
Subsystem

zlib

What steps will reproduce the bug?

Create a Brotli compressor with a custom quality or a dictionary, call .reset() before writing anything, then compress as usual.

The quality/dictionary you passed in is gone. Nothing throws.

import * as zlib from 'node:zlib';

const input = Buffer.from('the quick brown fox jumps over the lazy dog '.repeat(100));
const dict = Buffer.from('the quick brown fox jumps over the lazy dog '.repeat(40));

function compress(options, reset) {
  return new Promise((resolve, reject) => {
    const s = zlib.createBrotliCompress(options);
    const chunks = [];
    s.on('data', (d) => chunks.push(d));
    s.on('error', reject);
    if (reset) s.reset();
    s.end(input);
    s.on('end', () => resolve(Buffer.concat(chunks).length));
  });
}

const q0 = { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 0 } };
console.log('quality 0, no reset:', await compress(q0, false));  // 109
console.log('quality 0, then reset:', await compress(q0, true)); // 55  (same as default quality 11)
console.log('with dictionary, no reset:', await compress({ dictionary: dict }, false));  // 18
console.log('with dictionary, then reset:', await compress({ dictionary: dict }, true)); // 55 (same as no dictionary)

const compressed = zlib.brotliCompressSync(input, { dictionary: dict });
const dec = zlib.createBrotliDecompress({ dictionary: dict });
dec.reset();
dec.end(compressed);
dec.on('error', (err) => console.log('decompress after reset:', err.code));
// ERR__ERROR_FORMAT_DICTIONARY
How often does it reproduce? Is there a required condition?

Always. You do not need to write any data first. Just construct the stream with options and call reset().

What is the expected behavior? Why is that the expected behavior?

reset() should start a new Brotli session on the same stream, keeping the quality/params and dictionary you already set.

That is what the same API already documents for Zstd (zlib.reset(): "start a new session while preserving the configured parameters and dictionary"), and it is what test/parallel/test-zlib-zstd-reset.js asserts. Brotli goes through the same JS reset() method.

If the dictionary is dropped, a decoder cannot read a dictionary-compressed frame at all.

What do you see instead?
  • Quality 0 after reset() compresses as if you had used the default quality 11 (109 bytes become 55).
  • A dictionary after reset() compresses as if you had used no dictionary (18 bytes become 55).
  • createBrotliDecompress({ dictionary }) then reset() fails with ERR__ERROR_FORMAT_DICTIONARY on a frame that was compressed with that dictionary.

The compressor never reports an error. The settings just disappear.

Additional information

C++: BrotliEncoderContext::ResetStream / BrotliDecoderContext::ResetStream both do return Init(); with no arguments. Init() immediately does dictionary_.clear() and creates a brand-new Brotli instance. It never replays SetParams.

This is not #66087 / #66088. Those are about flush() then reset() leaving a broken frame. Here there is no write at all — only the configuration is thrown away.

LLDB on src/node_zlib.cc at a2a051cd42 (same ResetStream/Init as current main):

  1. Stopped in BrotliEncoderContext::ResetStream at line 1514. Watch: this->dictionary_ still has size 1760. Next statement is return Init(); with no dictionary argument.
ResetStream at line 1514: dictionary still size 1760, about to call empty Init()
  1. That call lands in Init at line 1474, on dictionary_.clear();. Watch: the member this->dictionary_ is still 1760 (clear has not run yet), but the dictionary parameter is already size 0, because ResetStream did not pass it in.
Init at line 1474: member dictionary still 1760, parameter dictionary already 0
  1. Continue to line 1483, if (!dictionary.empty()). Watch: both this->dictionary_ and the dictionary parameter are now size 0, so the attach-dictionary branch is skipped.
Init at line 1483: both dictionaries size 0, attach branch skipped
Ngôn ngữ chính
JavaScript
Star
122k
Fork
37.4k
Merge trung bình
4 ngày 3 giờ
Pull request đã merge (30 ngày)
272

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của nodejs/node

Tất cả issue của nodejs/node

Issue tương tự

Thêm issue về JavaScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.