Skip to content

Commit 4ab315e

Browse files
authored
feat(fetch): add zstandard decompression support (#4238)
* feat(fetch): add zstandard decompression support * test(fetch): add a test case for zstandard decompression support
1 parent 674ae24 commit 4ab315e

2 files changed

Lines changed: 38 additions & 5 deletions

File tree

lib/web/fetch/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,6 +2155,12 @@ async function httpNetworkFetch (
21552155
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
21562156
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
21572157
}))
2158+
} else if (coding === 'zstd' && typeof zlib.createZstdDecompress === 'function') {
2159+
// Node.js v23.8.0+ and v22.15.0+ supports Zstandard
2160+
decoders.push(zlib.createZstdDecompress({
2161+
flush: zlib.constants.ZSTD_e_continue,
2162+
finishFlush: zlib.constants.ZSTD_e_end
2163+
}))
21582164
} else {
21592165
decoders.length = 0
21602166
break

test/fetch/encoding.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ const assert = require('node:assert')
55
const { createServer } = require('node:http')
66
const { once } = require('node:events')
77
const { fetch } = require('../..')
8-
const { createBrotliCompress, createGzip, createDeflate } = require('node:zlib')
8+
const zlib = require('node:zlib')
99
const { closeServerAsPromise } = require('../utils/node-http')
1010

1111
test('content-encoding header is case-iNsENsITIve', async (t) => {
1212
const contentCodings = 'GZiP, bR'
1313
const text = 'Hello, World!'
1414

1515
const server = createServer({ joinDuplicateHeaders: true }, (req, res) => {
16-
const gzip = createGzip()
17-
const brotli = createBrotliCompress()
16+
const gzip = zlib.createGzip()
17+
const brotli = zlib.createBrotliCompress()
1818

1919
res.setHeader('Content-Encoding', contentCodings)
2020
res.setHeader('Content-Type', 'text/plain')
@@ -39,8 +39,8 @@ test('response decompression according to content-encoding should be handled in
3939
const text = 'Hello, World!'
4040

4141
const server = createServer({ joinDuplicateHeaders: true }, (req, res) => {
42-
const gzip = createGzip()
43-
const deflate = createDeflate()
42+
const gzip = zlib.createGzip()
43+
const deflate = zlib.createDeflate()
4444

4545
res.setHeader('Content-Encoding', contentCodings)
4646
res.setHeader('Content-Type', 'text/plain')
@@ -58,3 +58,30 @@ test('response decompression according to content-encoding should be handled in
5858

5959
assert.strictEqual(await response.text(), text)
6060
})
61+
62+
test('should decompress zstandard response',
63+
{ skip: typeof zlib.createZstdDecompress !== 'function' },
64+
async (t) => {
65+
const contentCodings = 'zstd'
66+
const text = 'Hello, World!'
67+
const server = createServer({ joinDuplicateHeaders: true }, (req, res) => {
68+
const zstd = zlib.createZstdCompress()
69+
70+
res.setHeader('Content-Encoding', contentCodings)
71+
res.setHeader('Content-Type', 'text/plain')
72+
73+
zstd.pipe(res)
74+
zstd.write(text)
75+
zstd.end()
76+
}
77+
).listen(0)
78+
t.after(closeServerAsPromise(server))
79+
80+
await once(server, 'listening')
81+
const url = `http://localhost:${server.address().port}`
82+
83+
const response = await fetch(url)
84+
assert.strictEqual(await response.text(), text)
85+
assert.strictEqual(response.headers.get('content-encoding'), contentCodings)
86+
assert.strictEqual(response.headers.get('content-type'), 'text/plain')
87+
})

0 commit comments

Comments
 (0)