Skip to content

Commit 0007b90

Browse files
SystemDiscBlake Sager
and
Blake Sager
authored
Support passing zlibOptions and brotliOptions (#113)
* Support passing zlibOptions and brotliOptions #106 * Update tests, types, and docs Co-authored-by: Blake Sager <[email protected]>
1 parent dbc0d16 commit 0007b90

File tree

5 files changed

+132
-7
lines changed

5 files changed

+132
-7
lines changed

README.md

+18
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,24 @@ fastify.register(
144144
)
145145
```
146146

147+
### brotliOptions and zlibOptions
148+
149+
You can tune compression by setting the `brotliOptions` and `zlibOptions` properties. These properties are passed directly to native node `zlib` methods, so they should match the corresponding [class](https://nodejs.org/api/zlib.html#zlib_class_brotlioptions) [definitions](https://nodejs.org/api/zlib.html#zlib_class_options).
150+
151+
```javascript
152+
server.register(fastifyCompress, {
153+
brotliOptions: {
154+
params: {
155+
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, // useful for APIs that primarily return text
156+
[zlib.constants.BROTLI_PARAM_QUALITY]: 4, // default is 11, max is 11, min is 0
157+
},
158+
},
159+
zlibOptions: {
160+
level: 9, // default is 9, max is 9, min is 0
161+
}
162+
});
163+
```
164+
147165
## Usage - Decompress request payloads
148166

149167
This plugin adds a `preParsing` hook that decompress the request payload according to the `content-encoding` request header.

index.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FastifyPlugin, FastifyReply, FastifyRequest, RawServerBase } from 'fastify';
22
import { Input, InputObject } from 'into-stream';
33
import { Stream } from 'stream';
4+
import { BrotliOptions, ZlibOptions } from 'zlib';
45

56
declare module "fastify" {
67
interface FastifyReply {
@@ -15,6 +16,8 @@ export interface FastifyCompressOptions {
1516
threshold?: number
1617
customTypes?: RegExp
1718
zlib?: NodeModule
19+
brotliOptions?: BrotliOptions
20+
zlibOptions?: ZlibOptions
1821
inflateIfDeflated?: boolean
1922
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest<RawServerBase>, reply: FastifyReply<RawServerBase>) => string | Buffer | Stream
2023
encodings?: Array<EncodingToken>

index.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,21 @@ function processCompressParams (opts) {
110110
global: (typeof opts.global === 'boolean') ? opts.global : true
111111
}
112112

113+
params.brotliOptions = opts.brotliOptions
114+
params.zlibOptions = opts.zlibOptions
113115
params.onUnsupportedEncoding = opts.onUnsupportedEncoding
114116
params.inflateIfDeflated = opts.inflateIfDeflated === true
115117
params.threshold = typeof opts.threshold === 'number' ? opts.threshold : 1024
116118
params.compressibleTypes = opts.customTypes instanceof RegExp ? opts.customTypes : /^text\/|\+json$|\+text$|\+xml$|octet-stream$/
117119
params.compressStream = {
118-
br: (opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress,
119-
gzip: (opts.zlib || zlib).createGzip || zlib.createGzip,
120-
deflate: (opts.zlib || zlib).createDeflate || zlib.createDeflate
120+
br: () => ((opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress)(params.brotliOptions),
121+
gzip: () => ((opts.zlib || zlib).createGzip || zlib.createGzip)(params.zlibOptions),
122+
deflate: () => ((opts.zlib || zlib).createDeflate || zlib.createDeflate)(params.zlibOptions)
121123
}
122124
params.uncompressStream = {
123-
br: (opts.zlib || zlib).createBrotliDecompress || zlib.createBrotliDecompress,
124-
gzip: (opts.zlib || zlib).createGunzip || zlib.createGunzip,
125-
deflate: (opts.zlib || zlib).createInflate || zlib.createInflate
125+
br: () => ((opts.zlib || zlib).createBrotliDecompress || zlib.createBrotliDecompress)(params.brotliOptions),
126+
gzip: () => ((opts.zlib || zlib).createGunzip || zlib.createGunzip)(params.zlibOptions),
127+
deflate: () => ((opts.zlib || zlib).createInflate || zlib.createInflate)(params.zlibOptions)
126128
}
127129

128130
const supportedEncodings = ['br', 'gzip', 'deflate', 'identity']

test/index.test-d.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,21 @@ app.register(fastifyCompress, {
1010
global: true,
1111
threshold: 10,
1212
zlib: zlib,
13+
brotliOptions: {
14+
params: {
15+
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
16+
[zlib.constants.BROTLI_PARAM_QUALITY]: 4
17+
}
18+
},
19+
zlibOptions: { level: 1 },
1320
inflateIfDeflated: true,
1421
customTypes: /x-protobuf$/,
1522
encodings: ['gzip', 'br', 'identity', 'deflate'],
1623
requestEncodings: ['gzip', 'br', 'identity', 'deflate'],
1724
forceRequestEncoding: 'gzip'
1825
})
1926

20-
const appWithoutGlobal = fastify();
27+
const appWithoutGlobal = fastify()
2128

2229
appWithoutGlobal.register(fastifyCompress, { global: false })
2330

test/test-global-compress.js

+95
Original file line numberDiff line numberDiff line change
@@ -1597,3 +1597,98 @@ test('Should not compress mime types with undefined compressible values', t => {
15971597
t.strictEqual(res.payload, 'hello')
15981598
})
15991599
})
1600+
1601+
test('Should send data compressed according to brotliOptions', t => {
1602+
t.plan(3)
1603+
const fastify = Fastify()
1604+
const brotliOptions = {
1605+
params: {
1606+
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
1607+
[zlib.constants.BROTLI_PARAM_QUALITY]: 4
1608+
}
1609+
}
1610+
1611+
fastify.register(compressPlugin, {
1612+
global: false,
1613+
brotliOptions
1614+
})
1615+
1616+
fastify.get('/', (req, reply) => {
1617+
reply.type('text/plain').compress(createReadStream('./package.json'))
1618+
})
1619+
1620+
fastify.inject({
1621+
url: '/',
1622+
method: 'GET',
1623+
headers: {
1624+
'accept-encoding': 'br'
1625+
}
1626+
}, (err, res) => {
1627+
t.error(err)
1628+
t.strictEqual(res.headers['content-encoding'], 'br')
1629+
const file = readFileSync('./package.json', 'utf8')
1630+
const payload = zlib.brotliDecompressSync(res.rawPayload, brotliOptions)
1631+
t.strictEqual(payload.toString('utf-8'), file)
1632+
})
1633+
})
1634+
1635+
test('Should send data deflated according to zlibOptions', t => {
1636+
t.plan(3)
1637+
const fastify = Fastify()
1638+
const zlibOptions = {
1639+
level: 1,
1640+
dictionary: Buffer.from('fastifycompress')
1641+
}
1642+
1643+
fastify.register(compressPlugin, {
1644+
global: false,
1645+
zlibOptions
1646+
})
1647+
1648+
fastify.get('/', (req, reply) => {
1649+
reply.type('text/plain').compress(createReadStream('./package.json'))
1650+
})
1651+
1652+
fastify.inject({
1653+
url: '/',
1654+
method: 'GET',
1655+
headers: {
1656+
'accept-encoding': 'deflate'
1657+
}
1658+
}, (err, res) => {
1659+
t.error(err)
1660+
t.strictEqual(res.headers['content-encoding'], 'deflate')
1661+
const fileBuffer = readFileSync('./package.json')
1662+
t.same(res.rawPayload, zlib.deflateSync(fileBuffer, zlibOptions))
1663+
})
1664+
})
1665+
1666+
test('Should send data gzipped according to zlibOptions', t => {
1667+
t.plan(3)
1668+
const fastify = Fastify()
1669+
const zlibOptions = {
1670+
level: 1
1671+
}
1672+
1673+
fastify.register(compressPlugin, {
1674+
global: false,
1675+
zlibOptions
1676+
})
1677+
1678+
fastify.get('/', (req, reply) => {
1679+
reply.type('text/plain').compress(createReadStream('./package.json'))
1680+
})
1681+
1682+
fastify.inject({
1683+
url: '/',
1684+
method: 'GET',
1685+
headers: {
1686+
'accept-encoding': 'gzip'
1687+
}
1688+
}, (err, res) => {
1689+
t.error(err)
1690+
t.strictEqual(res.headers['content-encoding'], 'gzip')
1691+
const fileBuffer = readFileSync('./package.json')
1692+
t.same(res.rawPayload, zlib.gzipSync(fileBuffer, zlibOptions))
1693+
})
1694+
})

0 commit comments

Comments
 (0)