diff --git a/src/handlers/response-interceptor.ts b/src/handlers/response-interceptor.ts index cacadfb0..a12070d9 100644 --- a/src/handlers/response-interceptor.ts +++ b/src/handlers/response-interceptor.ts @@ -13,6 +13,23 @@ type Interceptor = ( res: TRes, ) => Promise; +/** + * 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', +]; + /** * 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); + }); + } debug('write intercepted response'); res.write(interceptedBuffer); res.end(); diff --git a/test/e2e/response-interceptor.spec.ts b/test/e2e/response-interceptor.spec.ts index dc11b6d4..4f675912 100644 --- a/test/e2e/response-interceptor.spec.ts +++ b/test/e2e/response-interceptor.spec.ts @@ -31,6 +31,15 @@ describe('responseInterceptor()', () => { 'content-type': 'image/png', }); + await targetServer + .forGet('/response-headers') + .withExactQuery('?Trailer=X-Stream-Error&Host=localhost') + .thenReply(200, '', { + 'transfer-encoding': 'chunked', + trailer: 'X-Stream-Error', + host: 'localhost', + }); + agent = request( createApp( createProxyMiddleware({ @@ -65,6 +74,13 @@ describe('responseInterceptor()', () => { const response = await agent.get(`/json`).expect(200); expect(response.body.favorite).toEqual('叉燒包'); }); + + it('should not contains disallow headers to trailer in response headers', async () => { + const response = await agent + .get('/response-headers?Trailer=X-Stream-Error&Host=localhost') + .expect(200); + expect(response.header['host']).toBeUndefined(); + }); }); describe('intercept responses with original headers', () => {