Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/middleware/web-outgoing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import { type ProxyOutgoingMiddleware, defineProxyOutgoingMiddleware } from "./_
const redirectRegex = /^201|30([1278])$/;

/**
* Remove chunked transfer-encoding for HTTP/1.0 and HTTP/2 requests
* Remove chunked transfer-encoding for HTTP/1.0, HTTP/2, and bodyless (204/304) responses
*/
export const removeChunked = defineProxyOutgoingMiddleware((req, res, proxyRes) => {
// HTTP/1.0 and HTTP/2 do not have transfer-encoding: chunked
if (req.httpVersion === "1.0" || req.httpVersionMajor >= 2) {
// 204 and 304 responses MUST NOT contain a message body (RFC 9110)
if (
req.httpVersion === "1.0" ||
req.httpVersionMajor >= 2 ||
proxyRes.statusCode === 204 ||
proxyRes.statusCode === 304
) {
delete proxyRes.headers["transfer-encoding"];
}
});
Expand Down
76 changes: 63 additions & 13 deletions test/middleware/web-outgoing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@
const res = {
setHeader(k: string, v: string | string[]) {
// Simulate Node.js ERR_INVALID_CHAR for control characters
if (typeof v === "string" && /[\u0000-\u001F]/.test(v)) {

Check warning on line 654 in test/middleware/web-outgoing.test.ts

View workflow job for this annotation

GitHub Actions / autofix

eslint(no-control-regex)

Unexpected control characters

Check warning on line 654 in test/middleware/web-outgoing.test.ts

View workflow job for this annotation

GitHub Actions / checks

eslint(no-control-regex)

Unexpected control characters

Check warning on line 654 in test/middleware/web-outgoing.test.ts

View workflow job for this annotation

GitHub Actions / checks

eslint(no-control-regex)

Unexpected control characters

Check warning on line 654 in test/middleware/web-outgoing.test.ts

View workflow job for this annotation

GitHub Actions / autofix

eslint(no-control-regex)

Unexpected control characters
throw new TypeError(`Invalid character in header content ["${k}"]`);
}
headers[k.toLowerCase()] = v;
Expand Down Expand Up @@ -692,18 +692,68 @@
});
});

it("#removeChunked", () => {
const proxyRes = {
headers: {
"transfer-encoding": "hello",
},
};
webOutgoing.removeChunked(
stubIncomingMessage({ httpVersion: "1.0" }),
stubServerResponse(),
proxyRes as any,
stubMiddlewareOptions(),
);
expect(proxyRes.headers["transfer-encoding"]).to.eql(undefined);
describe("#removeChunked", () => {
it("removes transfer-encoding on HTTP/1.0", () => {
const proxyRes = {
headers: {
"transfer-encoding": "hello",
},
};
webOutgoing.removeChunked(
stubIncomingMessage({ httpVersion: "1.0" }),
stubServerResponse(),
proxyRes as any,
stubMiddlewareOptions(),
);
expect(proxyRes.headers["transfer-encoding"]).to.eql(undefined);
});

it("removes transfer-encoding on 204 response", () => {
const proxyRes = {
statusCode: 204,
headers: {
"transfer-encoding": "chunked",
},
};
webOutgoing.removeChunked(
stubIncomingMessage({ httpVersion: "1.1" }),
stubServerResponse(),
proxyRes as any,
stubMiddlewareOptions(),
);
expect(proxyRes.headers["transfer-encoding"]).to.eql(undefined);
});

it("removes transfer-encoding on 304 response", () => {
const proxyRes = {
statusCode: 304,
headers: {
"transfer-encoding": "chunked",
},
};
webOutgoing.removeChunked(
stubIncomingMessage({ httpVersion: "1.1" }),
stubServerResponse(),
proxyRes as any,
stubMiddlewareOptions(),
);
expect(proxyRes.headers["transfer-encoding"]).to.eql(undefined);
});

it("preserves transfer-encoding on normal HTTP/1.1 responses", () => {
const proxyRes = {
statusCode: 200,
headers: {
"transfer-encoding": "chunked",
},
};
webOutgoing.removeChunked(
stubIncomingMessage({ httpVersion: "1.1" }),
stubServerResponse(),
proxyRes as any,
stubMiddlewareOptions(),
);
expect(proxyRes.headers["transfer-encoding"]).to.eql("chunked");
});
});
});
Loading