Skip to content

fix: remove stale Content-Length when body is set to ReadableStream or Response#1939

Draft
fengmk2 wants to merge 1 commit into
koajs:masterfrom
fengmk2:fix/readablestream-response-content-length
Draft

fix: remove stale Content-Length when body is set to ReadableStream or Response#1939
fengmk2 wants to merge 1 commit into
koajs:masterfrom
fengmk2:fix/readablestream-response-content-length

Conversation

@fengmk2

@fengmk2 fengmk2 commented Mar 12, 2026

Copy link
Copy Markdown
Member

Problem

When ctx.body is replaced with a ReadableStream or Response after being set to a string/buffer, the previously-set Content-Length header is not removed. This causes a Content-Length mismatch between the header and the actual body, which can lead to:

  • Body truncation or padding
  • Keep-alive connection corruption
  • HTTP desync issues in proxy deployments

The existing Stream handler already correctly removes Content-Length when replacing a body, but the ReadableStream and Response handlers were missing this logic.

Fix

  • ReadableStream handler: Add this.remove('Content-Length') when original != null (consistent with Stream handler)
  • Response handler: Add this.remove('Content-Length') when original != null before copying headers from the Response object. This ensures any stale Content-Length from a previous body is cleared; if the Response itself has a Content-Length, it will be set correctly when its headers are copied.

Tests

Added two test cases in __tests__/response/body.test.js:

  • Verify stale Content-Length is removed when body changes from string to ReadableStream
  • Verify stale Content-Length is removed when body changes from string to Response

All 431 existing tests pass.

…r Response

When ctx.body is replaced with a ReadableStream or Response after being
set to a string/buffer, the previously-set Content-Length header was not
removed. This could cause Content-Length mismatches, leading to body
truncation or keep-alive connection corruption.

The fix adds `this.remove('Content-Length')` to the ReadableStream and
Response handlers, consistent with the existing Stream handler behavior.
@codecov

codecov Bot commented Mar 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.90%. Comparing base (d3ea8bf) to head (01eb671).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1939   +/-   ##
=======================================
  Coverage   99.90%   99.90%           
=======================================
  Files           9        9           
  Lines        2094     2096    +2     
=======================================
+ Hits         2092     2094    +2     
  Misses          2        2           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fengmk2 fengmk2 requested a review from Copilot March 12, 2026 00:56
@fengmk2 fengmk2 marked this pull request as draft March 12, 2026 00:56

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

This PR fixes an HTTP response header correctness issue where Content-Length could become stale when replacing an already-sized body (e.g., a string) with a ReadableStream or a Response, and adds regression tests to prevent reintroduction.

Changes:

  • Remove Content-Length when switching res.body to a ReadableStream (when there was a previous body).
  • Remove Content-Length when switching res.body to a Response (when there was a previous body).
  • Add tests asserting Content-Length is cleared in both replacement scenarios.

Reviewed changes

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

File Description
lib/response.js Clears stale Content-Length when body is replaced with ReadableStream or Response.
__tests__/response/body.test.js Adds regression tests ensuring Content-Length is removed on those body replacements.

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

@guoyangzhen guoyangzhen left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good catch. The Blob handler already sets this.length = val.size which implicitly overwrites Content-Length, but ReadableStream and Response handlers were silently keeping the stale value.

One thing to consider: the Blob handler at line 209 doesn't have this issue because it always sets this.length. But if you wanted to be extra consistent, you could also add if (original != null) this.remove('Content-Length') before this.length = val.size in the Blob handler — though functionally it's equivalent since the setter overwrites it anyway.

LGTM!

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.

4 participants