Skip to content

Commit

Permalink
feat: support Functions for customType option (#262)
Browse files Browse the repository at this point in the history
* Support Functions for customType option

* Apply suggestions from code review

Co-authored-by: Manuel Spigolon <behemoth89@gmail.com>

---------

Co-authored-by: Manuel Spigolon <behemoth89@gmail.com>
  • Loading branch information
Uzlopak and Eomm authored May 14, 2023
1 parent aca375f commit 0c74f85
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 5 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,24 @@ await fastify.register(
)
```
### customTypes
[mime-db](https://github.com/jshttp/mime-db) is used to determine if a `content-type` should be compressed. You can compress additional content types via regular expression.
[mime-db](https://github.com/jshttp/mime-db) is used to determine if a `content-type` should be compressed. You can compress additional content types via regular expression or by providing a function.
```javascript
await fastify.register(
import('@fastify/compress'),
{ customTypes: /x-protobuf$/ }
)
```
or
```javascript
await fastify.register(
import('@fastify/compress'),
{ customTypes: contentType => contentType.endsWith('x-protobuf') }
)
```
### onUnsupportedEncoding
When the encoding is not supported, a custom error response can be sent in place of the uncompressed payload by setting the `onUnsupportedEncoding(encoding, request, reply)` option to be a function that can modify the reply and return a `string | Buffer | Stream | Error` payload.
```javascript
Expand Down
10 changes: 8 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ function fastifyCompress (fastify, opts, next) {
next()
}

const defaultCompressibleTypes = /^text\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/

function processCompressParams (opts) {
/* istanbul ignore next */
if (!opts) {
Expand All @@ -123,7 +125,11 @@ function processCompressParams (opts) {
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\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/
params.compressibleTypes = opts.customTypes instanceof RegExp
? opts.customTypes.test.bind(opts.customTypes)
: typeof opts.customTypes === 'function'
? opts.customTypes
: defaultCompressibleTypes.test.bind(defaultCompressibleTypes)
params.compressStream = {
br: () => ((opts.zlib || zlib).createBrotliCompress || zlib.createBrotliCompress)(params.brotliOptions),
gzip: () => ((opts.zlib || zlib).createGzip || zlib.createGzip)(params.zlibOptions),
Expand Down Expand Up @@ -461,7 +467,7 @@ function getEncodingHeader (encodings, request) {
}

function shouldCompress (type, compressibleTypes) {
if (compressibleTypes.test(type)) return true
if (compressibleTypes(type)) return true
const data = mimedb[type.split(';', 1)[0].trim().toLowerCase()]
if (data === undefined) return false
return data.compressible === true
Expand Down
49 changes: 48 additions & 1 deletion test/global-compress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,29 @@ test('It should not compress :', async (t) => {
t.equal(response.statusCode, 200)
})

t.test('when `customTypes` is a function and returns false on the provided `Content-Type` reply header`', async (t) => {
t.plan(2)

const fastify = Fastify()
await fastify.register(compressPlugin, { customTypes: value => value === 'application/x-user-header' })

fastify.get('/', (request, reply) => {
reply
.type('application/x-other-type')
.compress(createReadStream('./package.json'))
})

const response = await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip'
}
})
t.notOk(response.headers['content-encoding'])
t.equal(response.statusCode, 200)
})

t.test('when `X-No-Compression` request header is `true`', async (t) => {
t.plan(3)

Expand Down Expand Up @@ -2443,7 +2466,31 @@ test('It should compress data if `customTypes` is set and matches `Content-Type`
t.equal(payload.toString('utf-8'), file)
})

test('It should not apply `customTypes` option if the passed value is not a RegExp', async (t) => {
test('It should compress data if `customTypes` is a function and returns true on the provided `Content-Type` reply header value', async (t) => {
t.plan(2)
const fastify = Fastify()
await fastify.register(compressPlugin, { customTypes: value => value === 'application/x-user-header' })

fastify.get('/', (request, reply) => {
reply
.type('application/x-user-header')
.send(createReadStream('./package.json'))
})

const response = await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip'
}
})
const file = readFileSync('./package.json', 'utf8')
const payload = zlib.gunzipSync(response.rawPayload)
t.equal(response.headers['content-encoding'], 'gzip')
t.equal(payload.toString('utf-8'), file)
})

test('It should not apply `customTypes` option if the passed value is not a RegExp or Function', async (t) => {
t.plan(2)

const fastify = Fastify()
Expand Down
4 changes: 3 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ type RouteDecompressOptions = Pick<fastifyCompress.FastifyCompressOptions,

type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';

type CompressibleContentTypeFunction = (contentType: string) => boolean;

declare namespace fastifyCompress {

export interface FastifyCompressOptions {
brotliOptions?: BrotliOptions;
customTypes?: RegExp;
customTypes?: RegExp | CompressibleContentTypeFunction;
encodings?: EncodingToken[];
forceRequestEncoding?: EncodingToken;
global?: boolean;
Expand Down
4 changes: 4 additions & 0 deletions types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const withGlobalOptions: FastifyCompressOptions = {
const app: FastifyInstance = fastify()
app.register(fastifyCompress, withGlobalOptions)

app.register(fastifyCompress, {
customTypes: value => value === 'application/json'
})

app.get('/test-one', async (request, reply) => {
expectType<void>(reply.compress(stream))
})
Expand Down

0 comments on commit 0c74f85

Please sign in to comment.