Skip to content

Commit f36ea9c

Browse files
authored
fix(decompress): preserve response trailers (#5572)
Signed-off-by: Ram-blip <ramcruze2000@gmail.com>
1 parent 1760faa commit f36ea9c

2 files changed

Lines changed: 52 additions & 5 deletions

File tree

lib/interceptor/decompress.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ let warningEmitted = /** @type {boolean} */ (false)
3232
class DecompressHandler extends DecoratorHandler {
3333
/** @type {Transform[]} */
3434
#decompressors = []
35+
/** @type {Record<string, string | string[]> | undefined} */
36+
#trailers
3537
/** @type {Readonly<number[]>} */
3638
#skipStatusCodes
3739
/** @type {boolean} */
@@ -123,7 +125,7 @@ class DecompressHandler extends DecoratorHandler {
123125
this.#setupDecompressorEvents(decompressor, controller)
124126

125127
decompressor.on('end', () => {
126-
super.onResponseEnd(controller, {})
128+
super.onResponseEnd(controller, this.#trailers)
127129
})
128130
}
129131

@@ -141,7 +143,7 @@ class DecompressHandler extends DecoratorHandler {
141143
super.onResponseError(controller, err)
142144
return
143145
}
144-
super.onResponseEnd(controller, {})
146+
super.onResponseEnd(controller, this.#trailers)
145147
})
146148
}
147149

@@ -236,6 +238,7 @@ class DecompressHandler extends DecoratorHandler {
236238
*/
237239
onResponseEnd (controller, trailers) {
238240
if (this.#decompressors.length > 0) {
241+
this.#trailers = trailers
239242
this.#decompressors[0].end()
240243
this.#cleanupDecompressors()
241244
return

test/interceptors/decompress.js

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,46 @@ test('should decompress gzip response', async t => {
5151
await t.completed
5252
})
5353

54+
test('should preserve trailers when decompressing response', async t => {
55+
const data = 'Response with trailers'
56+
const compressed = gzipSync(data)
57+
const server = createServer({ joinDuplicateHeaders: true }, (_req, res) => {
58+
res.writeHead(200, {
59+
'Content-Encoding': 'gzip',
60+
Trailer: 'X-Checksum'
61+
})
62+
res.addTrailers({ 'X-Checksum': 'verified' })
63+
res.end(compressed)
64+
})
65+
66+
server.listen(0)
67+
await once(server, 'listening')
68+
69+
const client = new Client(
70+
`http://localhost:${server.address().port}`
71+
).compose(interceptors.decompress())
72+
73+
after(async () => {
74+
await client.close()
75+
server.close()
76+
await once(server, 'close')
77+
})
78+
79+
t = tspl(t, { plan: 2 })
80+
81+
const response = await client.request({
82+
method: 'GET',
83+
path: '/',
84+
headers: { TE: 'trailers' }
85+
})
86+
const body = await response.body.text()
87+
88+
t.equal(body, data)
89+
t.deepEqual(response.trailers, { 'x-checksum': 'verified' })
90+
91+
await t.completed
92+
})
93+
5494
test('should preserve representation headers and empty body for HEAD responses', async t => {
5595
const compressedRepresentation = gzipSync('HEAD response representation')
5696
const server = createServer({ joinDuplicateHeaders: true }, (req, res) => {
@@ -614,7 +654,7 @@ test('should allow custom skipStatusCodes', async t => {
614654
})
615655

616656
test('should decompress multiple encodings in correct order', async t => {
617-
t = tspl(t, { plan: 3 })
657+
t = tspl(t, { plan: 4 })
618658

619659
const server = createServer({ joinDuplicateHeaders: true }, async (req, res) => {
620660
// First compress with gzip, then with deflate (gzip, deflate)
@@ -623,14 +663,16 @@ test('should decompress multiple encodings in correct order', async t => {
623663

624664
res.writeHead(200, {
625665
'Content-Type': 'text/plain',
626-
'Content-Encoding': 'gzip, deflate' // Applied in this order
666+
'Content-Encoding': 'gzip, deflate', // Applied in this order
667+
Trailer: 'X-Checksum'
627668
})
628669

629670
const data = 'Multiple encoding test message'
630671

631672
// Pipe: data → gzip → deflate → response
632673
gzip.pipe(deflate)
633674
deflate.pipe(res)
675+
res.addTrailers({ 'X-Checksum': 'verified' })
634676
gzip.end(data)
635677
})
636678

@@ -649,14 +691,16 @@ test('should decompress multiple encodings in correct order', async t => {
649691

650692
const response = await client.request({
651693
method: 'GET',
652-
path: '/'
694+
path: '/',
695+
headers: { TE: 'trailers' }
653696
})
654697

655698
const body = await response.body.text()
656699

657700
t.equal(response.statusCode, 200)
658701
t.equal(response.headers['content-encoding'], undefined) // Should be removed
659702
t.equal(body, 'Multiple encoding test message') // Should be fully decompressed
703+
t.deepEqual(response.trailers, { 'x-checksum': 'verified' })
660704

661705
await t.completed
662706
})

0 commit comments

Comments
 (0)