Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/node_zlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ class ZlibContext final : public MemoryRetainer {
void SetFlush(int flush);
void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
CompressionError GetErrorInfo() const;
inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
inline void SetMode(node_zlib_mode mode) {
mode_ = mode;
initial_mode_ = mode;
}
CompressionError ResetStream();

// Zlib-specific:
Expand All @@ -212,6 +215,7 @@ class ZlibContext final : public MemoryRetainer {

private:
CompressionError ErrorForMessage(const char* message) const;
CompressionError ResetStream(node_zlib_mode target_mode);
CompressionError SetDictionary();
bool InitZlib();

Expand All @@ -222,6 +226,7 @@ class ZlibContext final : public MemoryRetainer {
int level_ = 0;
int mem_level_ = 0;
node_zlib_mode mode_ = NONE;
node_zlib_mode initial_mode_ = NONE;
int strategy_ = 0;
int window_bits_ = 0;
bool reject_garbage_after_end_ = false;
Expand Down Expand Up @@ -1144,7 +1149,7 @@ void ZlibContext::DoThreadPoolWork() {
// Trailing zero bytes are okay, though, since they are frequently
// used for padding.

ResetStream();
ResetStream(mode_);
err_ = inflate(&strm_, flush_);
}
break;
Expand Down Expand Up @@ -1209,6 +1214,10 @@ CompressionError ZlibContext::GetErrorInfo() const {


CompressionError ZlibContext::ResetStream() {
return ResetStream(initial_mode_);
}

CompressionError ZlibContext::ResetStream(node_zlib_mode target_mode) {
bool first_init_call = InitZlib();
if (first_init_call && err_ != Z_OK) {
return ErrorForMessage("Failed to init stream before reset");
Expand All @@ -1225,6 +1234,7 @@ CompressionError ZlibContext::ResetStream() {
case INFLATE:
case INFLATERAW:
case GUNZIP:
case UNZIP:
err_ = inflateReset(&strm_);
break;
default:
Expand All @@ -1234,6 +1244,9 @@ CompressionError ZlibContext::ResetStream() {
if (err_ != Z_OK)
return ErrorForMessage("Failed to reset stream");

mode_ = target_mode;
if (mode_ == UNZIP) gzip_id_bytes_read_ = 0;

return SetDictionary();
}

Expand Down
39 changes: 39 additions & 0 deletions test/parallel/test-zlib-unzip-reset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

const common = require('../common');
const assert = require('node:assert');
const zlib = require('node:zlib');

function testReset(prefix, input, expected) {
const output = [];
const unzip = zlib.createUnzip()
.on('error', common.mustNotCall())
.on('data', (chunk) => output.push(chunk))
.on('end', common.mustCall(() => {
assert.strictEqual(Buffer.concat(output).toString(), expected);
}));

unzip.write(prefix, common.mustCall(() => {
unzip.reset();
unzip.end(input);
}));
}

// Reset while gzip auto-detection is halfway through.
testReset(
Buffer.from([0x1f]),
zlib.gzipSync('hello'),
'hello',
);

// Reset after auto-detection selected INFLATE. The new input must be detected
// as GUNZIP so that every concatenated gzip member is processed.
testReset(
zlib.deflateSync('discarded').subarray(0, 2),
Buffer.concat([
zlib.gzipSync('abc'),
zlib.gzipSync('def'),
zlib.gzipSync('ghi'),
]),
'abcdefghi',
);
Loading