Skip to content

fix: preserve writeHead statusText and custom headers (fixes #254)#274

Open
Vansh1811 wants to merge 1 commit intoexpressjs:masterfrom
Vansh1811:fix/preserve-writehead-headers-254
Open

fix: preserve writeHead statusText and custom headers (fixes #254)#274
Vansh1811 wants to merge 1 commit intoexpressjs:masterfrom
Vansh1811:fix/preserve-writehead-headers-254

Conversation

@Vansh1811
Copy link
Copy Markdown

Problem

When a user calls res.writeHead(200, undefined, {'foo': 'bar'}), the compression middleware was silently losing the custom headers. This happens because:

  1. on-headers drops headers when statusText is undefined — it checks typeof arguments[1] === 'string' to determine the header index, treating undefined as "no statusText", but then looks at arguments[1] (which is undefined) instead of arguments[2] for headers
  2. The compression middleware calls this.writeHead(this.statusCode) in res.write and res.end without replaying the original statusText/headers, overwriting whatever the user set

Solution

Intercept res.writeHead in the compression middleware to capture user-supplied arguments. In res.write and res.end, if the user previously called writeHead explicitly, replay those captured arguments instead of calling this.writeHead(this.statusCode) alone.

This approach:

  • Does not rely on the private res._header property (unlike other proposed fixes)
  • Correctly handles all writeHead signatures: (code), (code, message), (code, message, headers), and (code, undefined, headers)
  • Preserves backward compatibility

Testing

To reproduce the bug before this fix:

const express = require('express')
const compression = require('compression')
const app = express()
app.use(compression({ filter: () => false }))
app.get('/', (req, res) => {
  res.writeHead(200, undefined, { 'x-custom': 'value' })
  res.end('hello')
})

Before: x-custom header was missing. After this fix, it is correctly sent.

Fixes #254

…tive

When a user calls res.writeHead(200, undefined, {'foo': 'bar'}), the
compression middleware was overwriting those custom headers because:
1. on-headers drops headers when statusText is undefined (treats args[1]
   as undefined, not looking at args[2])
2. compression calls this.writeHead(this.statusCode) without the
   original statusText/headers, losing them

Fix: intercept res.writeHead to capture user-supplied args and replay
them in res.write/res.end instead of calling writeHead with only the
status code. This avoids relying on private res._header property.

Fixes expressjs#254
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.

Compression middleware changes behavior of undefined statusText in writeHead

1 participant