Skip to content

Skip compression for partial content responses - #277

Open
vibhor-aggr wants to merge 3 commits into
expressjs:masterfrom
vibhor-aggr:fix/skip-compression-partial-content
Open

Skip compression for partial content responses#277
vibhor-aggr wants to merge 3 commits into
expressjs:masterfrom
vibhor-aggr:fix/skip-compression-partial-content

Conversation

@vibhor-aggr

Copy link
Copy Markdown

Fixes #185.

This skips response compression when the response status is 206 Partial Content. Compressing a partial response can leave Content-Range describing the original unencoded bytes while the payload has been transformed, which makes the response metadata inconsistent.

Verification:

  • ./node_modules/.bin/mocha --check-leaks --reporter spec --grep 'partial content responses'
  • npm test
  • npm run lint
  • git diff --check

@bhamiltoncx

Copy link
Copy Markdown

I just ran into this issue myself, I'm glad to see this potential fix.

@kilisamemarisaaa kilisamemarisaaa 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.

Verified independently at 2418be3 on Windows with Node 24: npm test passed (57 passing, 1 pending) and npm run lint passed. The 206 regression test preserves Content-Range and Content-Length while suppressing Content-Encoding; the early status check also prevents the existing compression path from removing the range response's length. I found no blocking issue.

@UlisesGascon
UlisesGascon force-pushed the fix/skip-compression-partial-content branch from 2418be3 to 63d9224 Compare September 9, 2026 09:48
@UlisesGascon UlisesGascon self-assigned this Sep 9, 2026

@UlisesGascon UlisesGascon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @vibhor-aggr! I rebased the changes, added some changes (docs and tests) and I think we can ship this in next minor release as it is 👍

@krzysdz

krzysdz commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Is there any reason to prefer skipping compression instead of ignoring the Range? I'm pretty sure that's what was requested in #185:

Express should ignore Range: requests header when gzip compression is in place

Since by default compression tries to compress only compressible data (generally text, which compresses very well - see the database), I think it may be more beneficial to send everything as one compressed response, instead of potentially many more responses with selected ranges. On the other hand, no range = no resumption of broken downloads. In my experience, large text files that could be hard to re-download if the connection is broken often are stored on servers as compressed archives in the first place. This is not always the case, but for such uses (#185 (comment)), I would suggest using range requests with Transfer-Encoding: gzip if it hadn't been removed from HTTP/2.

RFC 9110 allows both ignoring the Range and skipping encoding:

A server MAY ignore the Range header field. However, origin servers and intermediate caches ought to support byte ranges when possible, since they support efficient recovery from partially failed transfers and partial retrieval of large representations.
source

If a non-empty Accept-Encoding header field is present in a request and none of the available representations for the response have a content coding that is listed as acceptable, the origin server SHOULD send a response without any content coding unless the identity coding is indicated as unacceptable.
source

Here's a small comparison of other server software:

Name Range + compression Details
NGINX ignore range src
Apache skip compression src, commit, discussion
Caddy ignore range src
Pingora (a lib from CF) ignore range seems to mostly follow NGINX, src
IIS skips compression by default, but can compress range requests noCompressionForRange docs
Akamai supports both tested manually using curl, compression not recommended for streaming content

@UlisesGascon
UlisesGascon force-pushed the master branch 2 times, most recently from 7f83fdb to 151f63e Compare September 11, 2026 10:53
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.

Express returns a non-compliant HTTP/206 response when gzip is enabled

5 participants