Skip to content

fix(util): handle compressed responses in downloadWithProgress (#803) - #945

Open
ousamabenyounes wants to merge 1 commit into
ffmpegwasm:mainfrom
ousamabenyounes:fix/issue-803
Open

ousamabenyounes wants to merge 1 commit into
ffmpegwasm:mainfrom
ousamabenyounes:fix/issue-803

Conversation

@ousamabenyounes

Copy link
Copy Markdown

Summary

Fixes #803.

downloadWithProgress (in @ffmpeg/util) tracks download progress from the
Content-Length header. When the server returns a compressed response
(Content-Encoding: gzip/br/…), Content-Length is the compressed size,
while fetch's body reader yields the decompressed bytes. The old code
compared that compressed total against the decompressed received count, so:

This is exactly the root cause described in the issue.

Fix

Detect the encoding and, when the response carries a Content-Encoding other
than identity, treat the total as unknown (-1) — the same behaviour already
used when no Content-Length is present. Comma-separated encodings are handled,
and identity (which means no transformation) keeps the accurate total so
progress still works.

const compressed = (resp.headers.get(HeaderContentEncoding) || "")
  .split(",")
  .map((encoding) => encoding.trim().toLowerCase())
  .some((encoding) => encoding !== "" && encoding !== "identity");
const total = compressed
  ? -1
  : parseInt(resp.headers.get(HeaderContentLength) || "-1");

Test verification (RED → GREEN)

Added tests/util-download-progress.test.js, a Node/mocha test that stubs
fetch to return a response whose Content-Length (compressed) differs from
the decompressed body the reader delivers. Run it with:

npm run build --workspace=packages/util
npx mocha tests/util-download-progress.test.js

RED — on the unmodified branch (compressed Content-Length: 100, body of 300 decompressed bytes):

  1) downloadWithProgress content-encoding handling
       never reports received > total for compressed responses and returns the full payload:
      AssertionError [ERR_ASSERTION]: progress reported received > total (over 100%): [
        { "url": "http://localhost/core.wasm", "total": 100, "received": 200, ... },
        { "url": "http://localhost/core.wasm", "total": 100, "received": 300, ... }
      ]
      + expected - actual
      -[ { ...received:300, total:100... } ]
      +[]
  0 passing / 1 failing

GREEN — with the fix:

  downloadWithProgress content-encoding handling
    ✔ never reports received > total for compressed responses and returns the full payload
    ✔ still reports an accurate total for uncompressed responses
    ✔ keeps the accurate total for Content-Encoding: identity
  3 passing

The suite covers the compressed case (the bug), an uncompressed regression
guard, and Content-Encoding: identity (total preserved).

Scope

Behaviour change is limited to downloadWithProgress; the public signature of
downloadWithProgress/toBlobURL is unchanged. Uncompressed responses keep
their existing accurate progress.

…thProgress

For compressed responses (Content-Encoding present) the Content-Length
header is the compressed size while the response body reader yields the
decompressed bytes. downloadWithProgress compared that compressed total
against the decompressed received count, which reported progress above
100% and then threw a bogus "failed to complete download" error before
falling back to a plain arrayBuffer read.

Detect Content-Encoding and treat the total as unknown (-1) in that case,
matching the existing behaviour for responses without a Content-Length.

Fixes ffmpegwasm#803
@netlify

netlify Bot commented Sep 8, 2026

Copy link
Copy Markdown

Deploy Preview for ffmpegwasm canceled.

Name Link
🔨 Latest commit 8dd7dcf
🔍 Latest deploy log https://app.netlify.com/projects/ffmpegwasm/deploys/6aa0382073dd7b00086185a9

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

toBlobURL / downloadWithProgress method don't handle compressed files

1 participant