From 6e6f353b01180742ea456d1723b784d24bd1bcee Mon Sep 17 00:00:00 2001 From: JSap0914 Date: Tue, 23 Jun 2026 21:18:14 +0900 Subject: [PATCH] fix: enforce Content-Type singleton guard in response.set() object form When ctx.set(field, val) is called with field as an object, the Content-Type singleton validation introduced in #1899 was bypassed. Setting ctx.set({ 'Content-Type': ['text/html', 'text/plain'] }) silently wrote an array value for Content-Type, violating the HTTP spec and circumventing the existing assert. Apply the same Array.isArray guard in the object-form branch, checking each header key case-insensitively. Closes #1973 --- __tests__/response/set.test.js | 18 ++++++++++++++++++ lib/response.js | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/__tests__/response/set.test.js b/__tests__/response/set.test.js index c8a19c1ef..44b1544d9 100644 --- a/__tests__/response/set.test.js +++ b/__tests__/response/set.test.js @@ -43,3 +43,21 @@ describe('ctx.set(object)', () => { assert.strictEqual(ctx.response.header.bar, '2') }) }) + +describe('ctx.set(object) Content-Type singleton guard', () => { + it('should throw when Content-Type is set to an array via the object form', () => { + const ctx = context() + assert.throws( + () => ctx.set({ 'Content-Type': ['text/html', 'text/plain'] }), + { message: 'Assign multiple Content-Type for response header is not allowed' } + ) + }) + + it('should throw regardless of header name casing in the object form', () => { + const ctx = context() + assert.throws( + () => ctx.set({ 'content-type': ['application/json', 'text/plain'] }), + { message: 'Assign multiple Content-Type for response header is not allowed' } + ) + }) +}) diff --git a/lib/response.js b/lib/response.js index 9b6741476..8534d8a3d 100644 --- a/lib/response.js +++ b/lib/response.js @@ -543,7 +543,12 @@ module.exports = { } this.res.setHeader(field, val) } else { - Object.keys(field).forEach(header => this.res.setHeader(header, field[header])) + Object.keys(field).forEach(header => { + if (header.toLowerCase() === 'content-type') { + assert(!Array.isArray(field[header]), 'Assign multiple Content-Type for response header is not allowed') + } + this.res.setHeader(header, field[header]) + }) } },