Commit c1cbf1f7780 for nodejs

commit c1cbf1f7780cca3c5dfebdd4b0b5a414134817d4
Author: Marco <marco.piraccini@gmail.com>
Date:   Thu Oct 29 09:56:38 2026 +0100

    zlib: restart format detection when resetting Unzip

    Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/66169
    Fixes: https://github.com/nodejs/node/issues/64619
    Reviewed-By: Paolo Insogna <paolo@cowtech.it>

diff --git a/src/node_zlib.cc b/src/node_zlib.cc
index a34905c3e3a..49e2a6e4ddf 100644
--- a/src/node_zlib.cc
+++ b/src/node_zlib.cc
@@ -204,7 +204,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;
+    auto_detect_ = mode == UNZIP;
+  }
   CompressionError ResetStream();

   // Zlib-specific:
@@ -229,6 +232,7 @@ class ZlibContext final : public MemoryRetainer {
  private:
   CompressionError ErrorForMessage(const char* message) const;
   CompressionError SetDictionary();
+  CompressionError ResetZStream();
   bool InitZlib();

   Mutex mutex_;  // Protects zlib_init_done_.
@@ -238,6 +242,7 @@ class ZlibContext final : public MemoryRetainer {
   int level_ = 0;
   int mem_level_ = 0;
   node_zlib_mode mode_ = NONE;
+  bool auto_detect_ = false;
   int strategy_ = 0;
   int window_bits_ = 0;
   bool reject_garbage_after_end_ = false;
@@ -1215,7 +1220,7 @@ void ZlibContext::DoThreadPoolWork() {
         // Trailing zero bytes are okay, though, since they are frequently
         // used for padding.

-        ResetStream();
+        ResetZStream();
         err_ = inflate(&strm_, flush_);
       }
       break;
@@ -1294,6 +1299,14 @@ CompressionError ZlibContext::ResetStream() {
         Z_STREAM_ERROR);
   }

+  if (auto_detect_) {
+    mode_ = UNZIP;
+    gzip_id_bytes_read_ = 0;
+  }
+  return ResetZStream();
+}
+
+CompressionError ZlibContext::ResetZStream() {
   bool first_init_call = InitZlib();
   if (first_init_call && err_ != Z_OK) {
     return ErrorForMessage("Failed to init stream before reset");
@@ -1310,6 +1323,7 @@ CompressionError ZlibContext::ResetStream() {
     case INFLATE:
     case INFLATERAW:
     case GUNZIP:
+    case UNZIP:
       err_ = inflateReset(&strm_);
       break;
     default:
diff --git a/test/parallel/test-zlib-reset-unzip.js b/test/parallel/test-zlib-reset-unzip.js
new file mode 100644
index 00000000000..6e513678262
--- /dev/null
+++ b/test/parallel/test-zlib-reset-unzip.js
@@ -0,0 +1,38 @@
+'use strict';
+
+// Refs: https://github.com/nodejs/node/issues/64619
+
+const common = require('../common');
+const assert = require('assert');
+const zlib = require('zlib');
+
+function resetAfter(prefix, input, expected) {
+  const chunks = [];
+  const unzip = zlib.createUnzip();
+  unzip.on('error', common.mustNotCall());
+  unzip.on('data', (chunk) => chunks.push(chunk));
+  unzip.on('end', common.mustCall(() => {
+    assert.strictEqual(Buffer.concat(chunks).toString(), expected);
+  }));
+  unzip.write(prefix, common.mustCall(() => {
+    unzip.reset();
+    unzip.end(input);
+  }));
+}
+
+// Reset in the middle of the gzip magic number.
+resetAfter(Buffer.from([0x1f]), zlib.gzipSync('hello'), 'hello');
+
+// Reset after deflate was detected.
+resetAfter(
+  zlib.deflateSync('discarded').subarray(0, 2),
+  Buffer.concat([zlib.gzipSync('abc'), zlib.gzipSync('def'), zlib.gzipSync('ghi')]),
+  'abcdefghi',
+);
+
+// Reset after gzip was detected.
+resetAfter(
+  zlib.gzipSync('discarded').subarray(0, 4),
+  zlib.deflateSync('hello'),
+  'hello',
+);