-
Notifications
You must be signed in to change notification settings - Fork 879
fix(responseInterceptor): remove disallowed headers when response headers contains trailer #830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,23 @@ type Interceptor<TReq = http.IncomingMessage, TRes = http.ServerResponse> = ( | |
| res: TRes, | ||
| ) => Promise<Buffer | string>; | ||
|
|
||
| /** | ||
| * Disallow headers when response contains trailer | ||
| * source: https://developer.mozilla.org/docs/Web/HTTP/Headers/Trailer | ||
| */ | ||
| const TrailerDisallowHeaders: string[] = [ | ||
| 'content-length', | ||
| 'host', | ||
| 'content-type', | ||
| 'authorization', | ||
| 'cache-control', | ||
| 'max-forwards', | ||
| 'te', | ||
| 'set-cookie', | ||
| 'content-encoding', | ||
| 'content-range', | ||
| ]; | ||
|
Comment on lines
+16
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: The Trailer header indicates which HTTP fields (headers) the sender plans to include in the trailer section at the end of a chunked message body. It is sent in the header section (initial headers block) of the HTTP message. Disallowed headers in trailers: Certain headers cannot be used as trailer fields because they must be processed before the body (e.g., for routing, framing, authentication). MDN lists: Content-Encoding, Content-Type, Content-Range, Trailer; authentication headers (e.g., Authorization, Set-Cookie); message framing (Transfer-Encoding, Content-Length); routing (Host); request modifiers (Cache-Control, Max-Forwards, TE). This matches RFC 9110 §6.5.1 limitations on trailers. "Declared as trailer" means listed in the Trailer header (e.g., Trailer: Server-Timing), signaling those fields will appear in the trailers section, not the initial response headers. Trailer fields are processed/stored separately from header fields (RFC 9110 §6.5). They cannot override or duplicate critical headers needed pre-body. Example: HTTP/1.1 200 OK Transfer-Encoding: chunked Trailer: Server-Timing [body] Server-Timing: custom-metric;dur=123.4 Server-Timing is declared via Trailer header and appears only in trailers, not response headers. Citations:
🏁 Script executed: cat -n src/handlers/response-interceptor.ts | head -50Repository: chimurai/http-proxy-middleware Length of output: 1872 🏁 Script executed: cat -n src/handlers/response-interceptor.ts | sed -n '40,150p'Repository: chimurai/http-proxy-middleware Length of output: 4550 The Per MDN and RFC 9110, the disallowed headers list specifies which header names cannot appear in the trailer section at the end of a chunked response. The current code incorrectly strips these headers from the response itself whenever an upstream trailer is present (lines 73–75). This breaks legitimate responses: The actual issue is that Suggested fix- // some headers are disallowed when response headers contains trailer
- if (proxyRes.headers.trailer === undefined) {
- res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8'));
- } else {
- TrailerDisallowHeaders.forEach((value) => {
- res.removeHeader(value);
- });
- }
+ // content-length is incompatible with trailers (which require chunked
+ // transfer encoding), so only set it when no trailer is declared.
+ if (proxyRes.headers.trailer === undefined) {
+ res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8'));
+ } else {
+ res.removeHeader('content-length');
+ }Remove the 🤖 Prompt for AI Agents |
||
|
|
||
| /** | ||
| * Intercept responses from upstream. | ||
| * Automatically decompress (deflate, gzip, brotli). | ||
|
|
@@ -49,8 +66,14 @@ export function responseInterceptor< | |
|
|
||
| // set correct content-length (with double byte character support) | ||
| debug('set content-length: %s', Buffer.byteLength(interceptedBuffer, 'utf8')); | ||
| res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8')); | ||
|
|
||
| // some headers are disallowed when response headers contains trailer | ||
| if (proxyRes.headers.trailer === undefined) { | ||
| res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8')); | ||
| } else { | ||
| TrailerDisallowHeaders.forEach((value) => { | ||
| res.removeHeader(value); | ||
| }); | ||
| } | ||
|
Comment on lines
+69
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also note: the interceptor mutates the response buffer, so the upstream In the trailer branch, neither 🤖 Prompt for AI Agents |
||
| debug('write intercepted response'); | ||
| res.write(interceptedBuffer); | ||
| res.end(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a link to verify the completeness of these headers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://developer.mozilla.org/docs/Web/HTTP/Headers/Trailer