Skip to content

Commit

Permalink
Support passing zlibOptions and brotliOptions (#113)
Browse files Browse the repository at this point in the history
* Support passing zlibOptions and brotliOptions

#106

* Update tests, types, and docs

Co-authored-by: Blake Sager <blake.sager@activeprospect.com>
  • Loading branch information
SystemDisc and Blake Sager authored Jun 26, 2020
1 parent dbc0d16 commit 0007b90
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 7 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ fastify.register(
)
```

### brotliOptions and zlibOptions

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).

```javascript
server.register(fastifyCompress, {
brotliOptions: {
params: {
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, // useful for APIs that primarily return text
[zlib.constants.BROTLI_PARAM_QUALITY]: 4, // default is 11, max is 11, min is 0
},
},
zlibOptions: {
level: 9, // default is 9, max is 9, min is 0
}
});
```

## Usage - Decompress request payloads

This plugin adds a `preParsing` hook that decompress the request payload according to the `content-encoding` request header.
Expand Down
3 changes: 3 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FastifyPlugin, FastifyReply, FastifyRequest, RawServerBase } from 'fastify';
import { Input, InputObject } from 'into-stream';
import { Stream } from 'stream';
import { BrotliOptions, ZlibOptions } from 'zlib';

declare module "fastify" {
interface FastifyReply {
Expand All @@ -15,6 +16,8 @@ export interface FastifyCompressOptions {
threshold?: number
customTypes?: RegExp
zlib?: NodeModule
brotliOptions?: BrotliOptions
zlibOptions?: ZlibOptions
inflateIfDeflated?: boolean
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest<RawServerBase>, reply: FastifyReply<RawServerBase>) => string | Buffer | Stream
encodings?: Array<EncodingToken>
Expand Down
14 changes: 8 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,21 @@ function processCompressParams (opts) {
global: (typeof opts.global === 'boolean') ? opts.global : true
}

params.brotliOptions = opts.brotliOptions
params.zlibOptions = opts.zlibOptions
params.onUnsupportedEncoding = opts.onUnsupportedEncoding
params.inflateIfDeflated = opts.inflateIfDeflated === true
params.threshold = typeof opts.threshold === 'number' ? opts.threshold : 1024
params.compressibleTypes = opts.customTypes instanceof RegExp ? opts.customTypes : /^text\/|\+json$|\+text$|\+xml$|octet-stream$/
params.compressStream = {
br: (opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress,
gzip: (opts.zlib || zlib).createGzip || zlib.createGzip,
deflate: (opts.zlib || zlib).createDeflate || zlib.createDeflate
br: () => ((opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress)(params.brotliOptions),
gzip: () => ((opts.zlib || zlib).createGzip || zlib.createGzip)(params.zlibOptions),
deflate: () => ((opts.zlib || zlib).createDeflate || zlib.createDeflate)(params.zlibOptions)
}
params.uncompressStream = {
br: (opts.zlib || zlib).createBrotliDecompress || zlib.createBrotliDecompress,
gzip: (opts.zlib || zlib).createGunzip || zlib.createGunzip,
deflate: (opts.zlib || zlib).createInflate || zlib.createInflate
br: () => ((opts.zlib || zlib).createBrotliDecompress || zlib.createBrotliDecompress)(params.brotliOptions),
gzip: () => ((opts.zlib || zlib).createGunzip || zlib.createGunzip)(params.zlibOptions),
deflate: () => ((opts.zlib || zlib).createInflate || zlib.createInflate)(params.zlibOptions)
}

const supportedEncodings = ['br', 'gzip', 'deflate', 'identity']
Expand Down
9 changes: 8 additions & 1 deletion test/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ app.register(fastifyCompress, {
global: true,
threshold: 10,
zlib: zlib,
brotliOptions: {
params: {
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
[zlib.constants.BROTLI_PARAM_QUALITY]: 4
}
},
zlibOptions: { level: 1 },
inflateIfDeflated: true,
customTypes: /x-protobuf$/,
encodings: ['gzip', 'br', 'identity', 'deflate'],
requestEncodings: ['gzip', 'br', 'identity', 'deflate'],
forceRequestEncoding: 'gzip'
})

const appWithoutGlobal = fastify();
const appWithoutGlobal = fastify()

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

Expand Down
95 changes: 95 additions & 0 deletions test/test-global-compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -1597,3 +1597,98 @@ test('Should not compress mime types with undefined compressible values', t => {
t.strictEqual(res.payload, 'hello')
})
})

test('Should send data compressed according to brotliOptions', t => {
t.plan(3)
const fastify = Fastify()
const brotliOptions = {
params: {
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
[zlib.constants.BROTLI_PARAM_QUALITY]: 4
}
}

fastify.register(compressPlugin, {
global: false,
brotliOptions
})

fastify.get('/', (req, reply) => {
reply.type('text/plain').compress(createReadStream('./package.json'))
})

fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'br'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.headers['content-encoding'], 'br')
const file = readFileSync('./package.json', 'utf8')
const payload = zlib.brotliDecompressSync(res.rawPayload, brotliOptions)
t.strictEqual(payload.toString('utf-8'), file)
})
})

test('Should send data deflated according to zlibOptions', t => {
t.plan(3)
const fastify = Fastify()
const zlibOptions = {
level: 1,
dictionary: Buffer.from('fastifycompress')
}

fastify.register(compressPlugin, {
global: false,
zlibOptions
})

fastify.get('/', (req, reply) => {
reply.type('text/plain').compress(createReadStream('./package.json'))
})

fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'deflate'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.headers['content-encoding'], 'deflate')
const fileBuffer = readFileSync('./package.json')
t.same(res.rawPayload, zlib.deflateSync(fileBuffer, zlibOptions))
})
})

test('Should send data gzipped according to zlibOptions', t => {
t.plan(3)
const fastify = Fastify()
const zlibOptions = {
level: 1
}

fastify.register(compressPlugin, {
global: false,
zlibOptions
})

fastify.get('/', (req, reply) => {
reply.type('text/plain').compress(createReadStream('./package.json'))
})

fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.headers['content-encoding'], 'gzip')
const fileBuffer = readFileSync('./package.json')
t.same(res.rawPayload, zlib.gzipSync(fileBuffer, zlibOptions))
})
})

0 comments on commit 0007b90

Please sign in to comment.