From 01eb67157b30434b7f97080c8ab7fa74d8c654a2 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 12 Mar 2026 08:53:49 +0800 Subject: [PATCH] fix: remove stale Content-Length when body is set to ReadableStream or 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. --- __tests__/response/body.test.js | 16 ++++++++++++++++ lib/response.js | 2 ++ 2 files changed, 18 insertions(+) diff --git a/__tests__/response/body.test.js b/__tests__/response/body.test.js index c63cb4d75..8f684a328 100644 --- a/__tests__/response/body.test.js +++ b/__tests__/response/body.test.js @@ -288,6 +288,14 @@ describe('res.body=', () => { res.body = new ReadableStream() assert.strictEqual('application/octet-stream', res.header['content-type']) }) + + it('should remove stale Content-Length when replacing a body', () => { + const res = response() + res.body = 'hello' + assert.strictEqual(5, res.length) + res.body = new ReadableStream() + assert.strictEqual(undefined, res.header['content-length']) + }) }) describe('when a Blob is given', () => { @@ -324,5 +332,13 @@ describe('res.body=', () => { assert.strictEqual(301, res.status) assert.strictEqual('https://www.example.com/', res.header.location) }) + + it('should remove stale Content-Length when replacing a body', () => { + const res = response() + res.body = 'hello' + assert.strictEqual(5, res.length) + res.body = new Response('different body') + assert.strictEqual(undefined, res.header['content-length']) + }) }) }) diff --git a/lib/response.js b/lib/response.js index 846a8beed..e1aa2b03e 100644 --- a/lib/response.js +++ b/lib/response.js @@ -201,6 +201,7 @@ module.exports = { // ReadableStream if (val instanceof ReadableStream) { if (setType) this.type = 'bin' + if (original != null) this.remove('Content-Length') cleanupPreviousStream() return } @@ -217,6 +218,7 @@ module.exports = { if (val instanceof Response) { this.status = val.status if (setType) this.type = 'bin' + if (original != null) this.remove('Content-Length') const headers = val.headers for (const key of headers.keys()) { this.set(key, headers.get(key))