Skip to content

Fix range-filtered remote ZIP decoding - #4110

Open
chubes4 wants to merge 8 commits into
WordPress:trunkfrom
chubes4:fix/4109-decode-remote-zip-paths
Open

Fix range-filtered remote ZIP decoding#4110
chubes4 wants to merge 8 commits into
WordPress:trunkfrom
chubes4:fix/4109-decode-remote-zip-paths

Conversation

@chubes4

@chubes4 chubes4 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What?

Make filtered remote ZIP ranges complete and bounded:

  • Compare ZIP entry path bytes by value when filtering range-fetched archive partitions.
  • Use consistent half-open byte ranges when joining central-directory chunks and fetching local entries.
  • Keep the ten-request semaphore slot until each partition body is collected, preventing unbounded live response bodies and partial server responses.

Add a deterministic regression test that creates a ZIP larger than both the range threshold and one central-directory scan window, serves it through a mocked HTTP Range endpoint, selects entries on opposite sides of that window, and verifies their paths and contents.

Why?

The central-directory entry and local-file entry contain distinct Uint8Array path objects. Comparing them with === drops every selected file even when their bytes match.

The Range source uses half-open ends, but central-directory reads supplied inclusive ends, dropping a byte where scan chunks were joined. In addition, request slots were released after response headers instead of body consumption, allowing hundreds of live response bodies and partial results on large archives.

Together these defects caused decodeRemoteZip() to emit empty, truncated, or nondeterministic streams for filtered, range-capable archives.

Fixes #4109.

Testing Instructions

  1. Run npx nx test php-wasm-stream-compression.
  2. Run npx nx lint php-wasm-stream-compression.
  3. Run npx nx build php-wasm-stream-compression.

AI assistance

  • AI assistance: Yes
  • Tool(s): OpenAI GPT-5.6 Sol via OpenCode
  • Used for: Root-cause analysis, implementation, regression test drafting, and verification in collaboration with Chris Huber.

AI assistance: OpenAI gpt-5.6-sol via OpenCode was used to review and implement the follow-up fixes and tests.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes decodeRemoteZip() filtering for range-fetched ZIPs by comparing path bytes by value (not ===) and adds a regression test covering the range-partitioned code path.

Changes:

  • Replace reference equality on ZIP entry path Uint8Arrays with byte-wise equality.
  • Add a deterministic test that forces range fetching and verifies only the selected entry is emitted with correct path/contents.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
packages/php-wasm/stream-compression/src/zip/decode-remote-zip.ts Fixes path matching by switching to byte-wise equality for Uint8Array paths.
packages/php-wasm/stream-compression/src/test/decode-remote-zip.spec.ts Adds a range-response regression test for filtered remote ZIP decoding.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/php-wasm/stream-compression/src/zip/decode-remote-zip.ts Outdated
Comment thread packages/php-wasm/stream-compression/src/zip/decode-remote-zip.ts
Comment thread packages/php-wasm/stream-compression/src/test/decode-remote-zip.spec.ts Outdated
Comment thread packages/php-wasm/stream-compression/src/test/decode-remote-zip.spec.ts Outdated
@chubes4

chubes4 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Production workerd verification now passes with commit 4ea1b5c: the deployed Cloudflare Worker traverses all 4,401 entries in https://wordpress.org/latest.zip, matches one predicate, and emits wordpress/wp-includes/version.php through filtered Range requests. Stacked runtime gate: #4111. Deployed evidence: https://playground-php-wasm-memory-gate.chubes.workers.dev/?probe=remote-zip

@chubes4

chubes4 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Downstream integration evidence from Automattic/wp-codebox#1838 confirms this fix is required for the bounded Cloudflare browser path.

With released @php-wasm/stream-compression 3.1.45, enabling streamWordPressFiles and retaining a selective decodeRemoteZip(url, predicate) call causes the local workerd browser gate to fail because no selected files are emitted; WordPress then cannot read /wordpress/wp-includes/version.php. Removing the predicate makes that gate pass but triggers decodeRemoteZip's explicit full-archive fetch branch, violating Cloudflare's 128 MB isolate limit.

The downstream candidate therefore remains intentionally blocked rather than adding a full-ZIP fallback. This PR's Range-filtered path is the owning-layer prerequisite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

decodeRemoteZip drops range-filtered entries due to path identity comparison

3 participants