@fastify/compress 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,305 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const { createReadStream } = require('fs')
5
+ const path = require('path')
6
+ const zlib = require('zlib')
7
+ const pump = require('pump')
8
+ const Fastify = require('fastify')
9
+ const compressPlugin = require('../index')
10
+
11
+ function createPayload (compressor) {
12
+ let payload = createReadStream(path.resolve(__dirname, '../package.json'))
13
+
14
+ if (compressor) {
15
+ payload = pump(payload, compressor())
16
+ }
17
+
18
+ return payload
19
+ }
20
+
21
+ test('When using routes `decompress` settings :', async (t) => {
22
+ t.test('it should decompress data using the route custom provided `createInflate` method', async (t) => {
23
+ t.plan(8)
24
+
25
+ let usedCustomGlobal = false
26
+ let usedCustom = false
27
+ const customZlibGlobal = { createInflate: () => (usedCustomGlobal = true) && zlib.createInflate() }
28
+ const customZlib = { createInflate: () => (usedCustom = true) && zlib.createInflate() }
29
+
30
+ const fastify = Fastify()
31
+ await fastify.register(compressPlugin, { zlib: customZlibGlobal })
32
+
33
+ fastify.post('/', (request, reply) => {
34
+ reply.send(request.body.name)
35
+ })
36
+
37
+ fastify.post('/custom', {
38
+ decompress: {
39
+ zlib: customZlib
40
+ }
41
+ }, (request, reply) => {
42
+ reply.send(request.body.name)
43
+ })
44
+
45
+ await fastify.inject({
46
+ url: '/',
47
+ method: 'POST',
48
+ headers: {
49
+ 'content-type': 'application/json',
50
+ 'content-encoding': 'deflate'
51
+ },
52
+ payload: createPayload(zlib.createDeflate)
53
+ }).then((response) => {
54
+ t.equal(usedCustom, false)
55
+ t.equal(usedCustomGlobal, true)
56
+
57
+ t.equal(response.statusCode, 200)
58
+ t.equal(response.body, '@fastify/compress')
59
+
60
+ usedCustom = false
61
+ usedCustomGlobal = false
62
+ })
63
+ const response = await fastify.inject({
64
+ url: '/custom',
65
+ method: 'POST',
66
+ headers: {
67
+ 'content-type': 'application/json',
68
+ 'content-encoding': 'deflate'
69
+ },
70
+ payload: createPayload(zlib.createDeflate)
71
+ })
72
+ t.equal(usedCustom, true)
73
+ t.equal(usedCustomGlobal, false)
74
+
75
+ t.equal(response.statusCode, 200)
76
+ t.equal(response.body, '@fastify/compress')
77
+ })
78
+
79
+ t.test('it should decompress data using the route custom provided `createGunzip` method', async (t) => {
80
+ t.plan(8)
81
+
82
+ let usedCustomGlobal = false
83
+ let usedCustom = false
84
+ const customZlibGlobal = { createGunzip: () => (usedCustomGlobal = true) && zlib.createGunzip() }
85
+ const customZlib = { createGunzip: () => (usedCustom = true) && zlib.createGunzip() }
86
+
87
+ const fastify = Fastify()
88
+ await fastify.register(compressPlugin, { zlib: customZlibGlobal })
89
+
90
+ fastify.post('/', (request, reply) => {
91
+ reply.send(request.body.name)
92
+ })
93
+
94
+ fastify.post('/custom', {
95
+ decompress: {
96
+ zlib: customZlib
97
+ }
98
+ }, (request, reply) => {
99
+ reply.send(request.body.name)
100
+ })
101
+
102
+ await fastify.inject({
103
+ url: '/',
104
+ method: 'POST',
105
+ headers: {
106
+ 'content-type': 'application/json',
107
+ 'content-encoding': 'gzip'
108
+ },
109
+ payload: createPayload(zlib.createGzip)
110
+ }).then((response) => {
111
+ t.equal(usedCustom, false)
112
+ t.equal(usedCustomGlobal, true)
113
+
114
+ t.equal(response.statusCode, 200)
115
+ t.equal(response.body, '@fastify/compress')
116
+
117
+ usedCustom = false
118
+ usedCustomGlobal = false
119
+ })
120
+
121
+ const response = await fastify.inject({
122
+ url: '/custom',
123
+ method: 'POST',
124
+ headers: {
125
+ 'content-type': 'application/json',
126
+ 'content-encoding': 'gzip'
127
+ },
128
+ payload: createPayload(zlib.createGzip)
129
+ })
130
+ t.equal(usedCustom, true)
131
+ t.equal(usedCustomGlobal, false)
132
+
133
+ t.equal(response.statusCode, 200)
134
+ t.equal(response.body, '@fastify/compress')
135
+ })
136
+
137
+ t.test('it should not decompress data when route `decompress` option is set to `false`', async (t) => {
138
+ t.plan(6)
139
+
140
+ let usedCustomGlobal = false
141
+ const customZlibGlobal = { createGunzip: () => (usedCustomGlobal = true) && zlib.createGunzip() }
142
+
143
+ const fastify = Fastify()
144
+ await fastify.register(compressPlugin, { zlib: customZlibGlobal })
145
+
146
+ fastify.post('/', (request, reply) => {
147
+ reply.send(request.body.name)
148
+ })
149
+
150
+ fastify.post('/custom', { decompress: false }, (request, reply) => {
151
+ reply.send(request.body.name)
152
+ })
153
+
154
+ await fastify.inject({
155
+ url: '/',
156
+ method: 'POST',
157
+ headers: {
158
+ 'content-type': 'application/json',
159
+ 'content-encoding': 'gzip'
160
+ },
161
+ payload: createPayload(zlib.createGzip)
162
+ }).then((response) => {
163
+ t.equal(usedCustomGlobal, true)
164
+
165
+ t.equal(response.statusCode, 200)
166
+ t.equal(response.body, '@fastify/compress')
167
+
168
+ usedCustomGlobal = false
169
+ })
170
+
171
+ const response = await fastify.inject({
172
+ url: '/custom',
173
+ method: 'POST',
174
+ headers: {
175
+ 'content-type': 'application/json',
176
+ 'content-encoding': 'gzip'
177
+ },
178
+ payload: createPayload(zlib.createGzip)
179
+ })
180
+ t.equal(usedCustomGlobal, false)
181
+
182
+ t.equal(response.statusCode, 400)
183
+ t.strictSame(response.json(), {
184
+ statusCode: 400,
185
+ code: 'FST_ERR_CTP_INVALID_CONTENT_LENGTH',
186
+ error: 'Bad Request',
187
+ message: 'Request body size did not match Content-Length'
188
+ })
189
+ })
190
+
191
+ t.test('it should throw an error on invalid route `decompress` settings', async (t) => {
192
+ t.plan(2)
193
+
194
+ const fastify = Fastify()
195
+ await fastify.register(compressPlugin, { global: false })
196
+
197
+ fastify.post('/', { decompress: 'bad config' }, (request, reply) => {
198
+ reply.send(request.body.name)
199
+ })
200
+
201
+ await fastify.inject({
202
+ url: '/',
203
+ method: 'POST',
204
+ headers: {
205
+ 'content-encoding': 'gzip'
206
+ },
207
+ payload: ''
208
+ }).catch((err) => {
209
+ t.type(err, Error)
210
+ t.equal(err.message, 'Unknown value for route decompress configuration')
211
+ })
212
+ })
213
+ })
214
+
215
+ test('When using the old routes `{ config: decompress }` option :', async (t) => {
216
+ t.test('it should decompress data using the route custom provided `createGunzip` method', async (t) => {
217
+ t.plan(8)
218
+
219
+ let usedCustomGlobal = false
220
+ let usedCustom = false
221
+ const customZlibGlobal = { createGunzip: () => (usedCustomGlobal = true) && zlib.createGunzip() }
222
+ const customZlib = { createGunzip: () => (usedCustom = true) && zlib.createGunzip() }
223
+
224
+ const fastify = Fastify()
225
+ await fastify.register(compressPlugin, { zlib: customZlibGlobal })
226
+
227
+ fastify.post('/', (request, reply) => {
228
+ reply.send(request.body.name)
229
+ })
230
+
231
+ fastify.post('/custom', {
232
+ config: {
233
+ decompress: {
234
+ zlib: customZlib
235
+ }
236
+ }
237
+ }, (request, reply) => {
238
+ reply.send(request.body.name)
239
+ })
240
+
241
+ await fastify.inject({
242
+ url: '/',
243
+ method: 'POST',
244
+ headers: {
245
+ 'content-type': 'application/json',
246
+ 'content-encoding': 'gzip'
247
+ },
248
+ payload: createPayload(zlib.createGzip)
249
+ }).then((response) => {
250
+ t.equal(usedCustom, false)
251
+ t.equal(usedCustomGlobal, true)
252
+
253
+ t.equal(response.statusCode, 200)
254
+ t.equal(response.body, '@fastify/compress')
255
+
256
+ usedCustom = false
257
+ usedCustomGlobal = false
258
+ })
259
+
260
+ const response = await fastify.inject({
261
+ url: '/custom',
262
+ method: 'POST',
263
+ headers: {
264
+ 'content-type': 'application/json',
265
+ 'content-encoding': 'gzip'
266
+ },
267
+ payload: createPayload(zlib.createGzip)
268
+ })
269
+ t.equal(usedCustom, true)
270
+ t.equal(usedCustomGlobal, false)
271
+
272
+ t.equal(response.statusCode, 200)
273
+ t.equal(response.body, '@fastify/compress')
274
+ })
275
+
276
+ t.test('it should use the old routes `{ config: decompress }` options over routes `decompress` options', async (t) => {
277
+ t.plan(2)
278
+
279
+ const fastify = Fastify()
280
+ await fastify.register(compressPlugin, { global: false })
281
+
282
+ fastify.post('/', {
283
+ decompress: {
284
+ zlib: { createGunzip: () => zlib.createGunzip() }
285
+ },
286
+ config: {
287
+ decompress: 'bad config'
288
+ }
289
+ }, (request, reply) => {
290
+ reply.send(request.body.name)
291
+ })
292
+
293
+ await fastify.inject({
294
+ url: '/',
295
+ method: 'POST',
296
+ headers: {
297
+ 'content-encoding': 'gzip'
298
+ },
299
+ payload: ''
300
+ }).catch((err) => {
301
+ t.type(err, Error)
302
+ t.equal(err.message, 'Unknown value for route decompress configuration')
303
+ })
304
+ })
305
+ })
@@ -0,0 +1,115 @@
1
+ import fastify, { FastifyInstance } from 'fastify'
2
+ import { createReadStream } from 'fs'
3
+ import { expectError, expectType } from 'tsd'
4
+ import * as zlib from 'zlib'
5
+ import fastifyCompress, { FastifyCompressOptions } from '../..'
6
+
7
+ const stream = createReadStream('./package.json')
8
+
9
+ const withGlobalOptions: FastifyCompressOptions = {
10
+ global: true,
11
+ threshold: 10,
12
+ 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 },
20
+ inflateIfDeflated: true,
21
+ customTypes: /x-protobuf$/,
22
+ encodings: ['gzip', 'br', 'identity', 'deflate'],
23
+ requestEncodings: ['gzip', 'br', 'identity', 'deflate'],
24
+ forceRequestEncoding: 'gzip',
25
+ removeContentLengthHeader: true
26
+ }
27
+
28
+ const app: FastifyInstance = fastify()
29
+ app.register(fastifyCompress, withGlobalOptions)
30
+
31
+ app.get('/test-one', async (request, reply) => {
32
+ expectType<void>(reply.compress(stream))
33
+ })
34
+
35
+ app.get('/test-two', async (request, reply) => {
36
+ expectError(reply.compress())
37
+ })
38
+
39
+ // Instanciation of an app without global
40
+ const appWithoutGlobal: FastifyInstance = fastify()
41
+ appWithoutGlobal.register(fastifyCompress, { global: false })
42
+
43
+ appWithoutGlobal.get('/one', {
44
+ compress: {
45
+ zlib: {
46
+ createGzip: () => zlib.createGzip()
47
+ },
48
+ removeContentLengthHeader: false
49
+ },
50
+ decompress: {
51
+ forceRequestEncoding: 'gzip',
52
+ zlib: {
53
+ createGunzip: () => zlib.createGunzip()
54
+ }
55
+ }
56
+ }, (request, reply) => {
57
+ expectType<void>(reply.type('text/plain').compress(stream))
58
+ })
59
+
60
+ appWithoutGlobal.get('/two', {
61
+ config: {
62
+ compress: {
63
+ zlib: {
64
+ createGzip: () => zlib.createGzip()
65
+ }
66
+ },
67
+ decompress: {
68
+ forceRequestEncoding: 'gzip',
69
+ zlib: {
70
+ createGunzip: () => zlib.createGunzip()
71
+ }
72
+ }
73
+ }
74
+ }, (request, reply) => {
75
+ expectType<void>(reply.type('text/plain').compress(stream))
76
+ })
77
+
78
+ expectError(
79
+ appWithoutGlobal.get('/throw-a-ts-arg-error-on-shorthand-route', {
80
+ compress: 'bad compress route option value',
81
+ decompress: 'bad decompress route option value'
82
+ }, (request, reply) => {
83
+ expectType<void>(reply.type('text/plain').compress(stream))
84
+ })
85
+ )
86
+
87
+ expectError(
88
+ appWithoutGlobal.route({
89
+ method: 'GET',
90
+ path: '/throw-a-ts-arg-error',
91
+ compress: 'bad compress route option value',
92
+ decompress: 'bad decompress route option value',
93
+ handler: (request, reply) => { expectType<void>(reply.type('text/plain').compress(stream)) }
94
+ })
95
+ )
96
+
97
+ appWithoutGlobal.inject(
98
+ {
99
+ method: 'GET',
100
+ path: '/throw-a-ts-arg-error',
101
+ headers: {
102
+ 'accept-encoding': 'gzip'
103
+ }
104
+ },
105
+ (err) => {
106
+ expectType<Error>(err)
107
+ }
108
+ )
109
+
110
+ // Instanciation of an app that should trigger a typescript error
111
+ const appThatTriggerAnError = fastify()
112
+ expectError(appThatTriggerAnError.register(fastifyCompress, {
113
+ global: true,
114
+ thisOptionDoesNotExist: 'trigger a typescript error'
115
+ }))
@@ -0,0 +1,27 @@
1
+ 'use strict'
2
+
3
+ const { createReadStream } = require('fs')
4
+ const { Socket } = require('net')
5
+ const { Duplex, PassThrough, Readable, Stream, Transform, Writable } = require('stream')
6
+ const { test } = require('tap')
7
+ const { isStream } = require('../lib/utils')
8
+
9
+ test('isStream() utility should be able to detect Streams', async (t) => {
10
+ t.plan(12)
11
+
12
+ t.equal(isStream(new Stream()), true)
13
+ t.equal(isStream(new Readable()), true)
14
+ t.equal(isStream(new Writable()), true)
15
+ t.equal(isStream(new Duplex()), true)
16
+ t.equal(isStream(new Transform()), true)
17
+ t.equal(isStream(new PassThrough()), true)
18
+
19
+ t.equal(isStream(createReadStream('package.json')), true)
20
+
21
+ t.equal(isStream(new Socket()), true)
22
+
23
+ t.equal(isStream({}), false)
24
+ t.equal(isStream(null), false)
25
+ t.equal(isStream(undefined), false)
26
+ t.equal(isStream(''), false)
27
+ })