Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
3325d43f14 Fix HTTP response header handling for Express compatibility
- Strip Content-Length and other content-related headers for 204, 304, and 1xx responses per RFC 2616
- Added test coverage for Express HTTP edge cases

This partially fixes Express test suite compatibility, addressing header stripping requirements for responses that must not include a message body.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-17 00:05:41 +00:00
2 changed files with 115 additions and 0 deletions

View File

@@ -1104,6 +1104,19 @@ function _writeHead(statusCode, reason, obj, response) {
}
updateHasBody(response, statusCode);
// RFC 2616: 204, 304, and 1xx responses MUST NOT include a message-body
// and therefore must not include content-related headers
if (!response._hasBody) {
response.removeHeader("content-length");
response.removeHeader("content-encoding");
response.removeHeader("content-language");
response.removeHeader("content-location");
response.removeHeader("content-md5");
response.removeHeader("content-range");
response.removeHeader("content-type");
response.removeHeader("transfer-encoding");
}
}
Object.defineProperty(NodeHTTPServerSocket, "name", { value: "Socket" });
@@ -1540,6 +1553,22 @@ ServerResponse.prototype.flushHeaders = function () {
if (this[headerStateSymbol] === NodeHTTPHeaderState.assigned) {
this[headerStateSymbol] = NodeHTTPHeaderState.sent;
// Remove content-related headers for responses that must not have a body
const statusCode = this.statusCode;
if (statusCode === 204 || statusCode === 304 || (statusCode >= 100 && statusCode <= 199)) {
const headers = this[headersSymbol];
if (headers) {
headers.delete("content-length");
headers.delete("content-encoding");
headers.delete("content-language");
headers.delete("content-location");
headers.delete("content-md5");
headers.delete("content-range");
headers.delete("content-type");
headers.delete("transfer-encoding");
}
}
handle.writeHead(this.statusCode, this.statusMessage, this[headersSymbol]);
}
handle.flushHeaders();

View File

@@ -0,0 +1,86 @@
import { test, expect } from "bun:test";
import express from "express";
import request from "supertest";
test("res.set() should coerce array values to comma-separated string", async () => {
const app = express();
app.get("/", (req, res) => {
res.set("X-Foo", ["123", "456"] as any);
res.send(JSON.stringify(res.get("X-Foo")));
});
const response = await request(app).get("/");
// Express expects arrays to be joined with ", "
expect(response.text).toBe('"123, 456"');
expect(response.headers["x-foo"]).toBe("123, 456");
});
test("status 204 should strip Content-Length header", async () => {
const app = express();
app.get("/", (req, res) => {
res.status(204).send("test body");
});
const response = await request(app).get("/");
expect(response.status).toBe(204);
expect(response.headers["content-length"]).toBeUndefined();
expect(response.text).toBe("");
});
test("status 304 should strip Content-Length header", async () => {
const app = express();
app.get("/", (req, res) => {
res.status(304).send("test body");
});
const response = await request(app).get("/");
expect(response.status).toBe(304);
expect(response.headers["content-length"]).toBeUndefined();
expect(response.text).toBe("");
});
test("should accept If-Modified-Since header with special characters", async () => {
const app = express();
app.get("/", (req, res) => {
res.set("Last-Modified", "Mon, 01 Jan 2024 00:00:00 GMT");
res.send("ok");
});
// This date format has a comma which was causing the validation error
const response = await request(app)
.get("/")
.set("If-Modified-Since", "Sun, 31 Dec 2023 23:59:59 GMT")
.set("If-None-Match", '"etag"');
expect(response.status).toBe(200);
expect(response.text).toBe("ok");
});
// Additional test for array handling in setHeader
test("setHeader should handle array values correctly", async () => {
const app = express();
app.get("/", (req, res) => {
// Test the underlying setHeader method
res.setHeader("X-Array", ["foo", "bar"]);
res.setHeader("X-Single", "baz");
res.json({
array: res.getHeader("X-Array"),
single: res.getHeader("X-Single")
});
});
const response = await request(app).get("/");
expect(response.headers["x-array"]).toBe("foo, bar");
expect(response.headers["x-single"]).toBe("baz");
expect(response.body.array).toBe("foo, bar");
expect(response.body.single).toBe("baz");
});