Skip to content

fix(res): remove magic from res.set() Content-Type - #7430

Open
vaibhavmashal wants to merge 1 commit into
expressjs:masterfrom
vaibhavmashal:master
Open

fix(res): remove magic from res.set() Content-Type#7430
vaibhavmashal wants to merge 1 commit into
expressjs:masterfrom
vaibhavmashal:master

Conversation

@vaibhavmashal

Copy link
Copy Markdown

Problem

Currently, res.set() contains unexpected magic when setting the Content-Type header. If a given content-type string does not contain a / (e.g., shorthand like 'json' or invalid input), res.set() attempts a MIME type lookup via mime.contentType(). This mutates user input unexpectedly and causes a known bug (Issue #7034), where unrecognized types return false from mime.contentType() and the header gets coercively set to the literal string "false".

Solution

This PR removes the MIME type lookup logic from res.set() completely, keeping res.set() strictly for assigning header values as provided, which resolves unexpected mutations. The intended way to set a content type with MIME type expansion remains res.type() (which already exists for this exact purpose).

By migrating internal dependencies (res.json and res.jsonp) to use res.type() instead of res.set(), we maintain backward compatibility for built-in response types (such as automatically appending charset=utf-8 to JSON responses) while fulfilling the goal of making res.set() predictable.

Changes Made

  • lib/response.js:
    • res.set(): Removed the mime.contentType() assignment block and the associated obsolete JSDoc comments. Kept the validation that prevents Content-Type from being set to an Array.
    • res.json(): Refactored this.set('Content-Type', ...) to this.type('json') to preserve charset=utf-8 expansion.
    • res.jsonp(): Refactored this.set('Content-Type', ...) to this.type('json') and this.type('text/javascript') to maintain expansion behavior for JSON/JSONP responses.
  • test/res.send.js:
    • Updated expectations in tests where res.set('Content-Type', 'text/plain') was used, expecting exactly 'text/plain' rather than 'text/plain; charset=utf-8'.

Testing

  • To reproduce the original bug:
    1. Call res.set('Content-Type', 'some-custom-type');
    2. Observe that the header sent in the response is erroneously set to Content-Type: false.
  • To verify the fix:
    1. Run the same test above, and observe the output correctly maintains Content-Type: some-custom-type.
    2. Verify that res.type('json') and res.json({}) still properly resolve to application/json; charset=utf-8.
    3. Ensure all tests in the Express suite pass via npm test (all 1260 tests passed locally).

Fixes #7145
Fixes #7034

Copilot AI lite review requested due to automatic review settings August 25, 2026 16:49

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

Remove magic from res.set res.set('Content-Type') silently sets header to literal string 'false' for unknown types

2 participants