@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.
- package/.github/dependabot.yml +13 -0
- package/.github/stale.yml +21 -0
- package/.github/workflows/ci.yml +47 -0
- package/.taprc +6 -0
- package/LICENSE +21 -0
- package/README.md +310 -0
- package/index.d.ts +81 -0
- package/index.js +556 -0
- package/lib/utils.js +7 -0
- package/package.json +73 -0
- package/test/global-compress.test.js +3048 -0
- package/test/global-decompress.test.js +423 -0
- package/test/routes-compress.test.js +437 -0
- package/test/routes-decompress.test.js +305 -0
- package/test/types/index.test-d.ts +115 -0
- package/test/utils.test.js +27 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const { createReadStream, readFile, readFileSync } = require('fs')
|
|
5
|
+
const zlib = require('zlib')
|
|
6
|
+
const Fastify = require('fastify')
|
|
7
|
+
const compressPlugin = require('../index')
|
|
8
|
+
|
|
9
|
+
test('When using routes `compress` settings :', async (t) => {
|
|
10
|
+
t.test('it should compress data using the route custom provided `createDeflate` method', async (t) => {
|
|
11
|
+
t.plan(10)
|
|
12
|
+
|
|
13
|
+
let usedCustomGlobal = false
|
|
14
|
+
let usedCustom = false
|
|
15
|
+
const customZlibGlobal = { createDeflate: () => (usedCustomGlobal = true) && zlib.createDeflate() }
|
|
16
|
+
const customZlib = { createDeflate: () => (usedCustom = true) && zlib.createDeflate() }
|
|
17
|
+
|
|
18
|
+
const fastify = Fastify()
|
|
19
|
+
await fastify.register(compressPlugin, { global: true, zlib: customZlibGlobal })
|
|
20
|
+
|
|
21
|
+
fastify.get('/', (request, reply) => {
|
|
22
|
+
reply
|
|
23
|
+
.type('text/plain')
|
|
24
|
+
.compress(createReadStream('./package.json'))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
fastify.get('/custom', {
|
|
28
|
+
compress: { zlib: customZlib }
|
|
29
|
+
}, (request, reply) => {
|
|
30
|
+
reply
|
|
31
|
+
.type('text/plain')
|
|
32
|
+
.compress(createReadStream('./package.json'))
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
await fastify.inject({
|
|
36
|
+
url: '/',
|
|
37
|
+
method: 'GET',
|
|
38
|
+
headers: {
|
|
39
|
+
'accept-encoding': 'deflate'
|
|
40
|
+
}
|
|
41
|
+
}).then((response) => {
|
|
42
|
+
t.equal(usedCustom, false)
|
|
43
|
+
t.equal(usedCustomGlobal, true)
|
|
44
|
+
|
|
45
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
46
|
+
const payload = zlib.inflateSync(response.rawPayload)
|
|
47
|
+
t.equal(response.headers['content-encoding'], 'deflate')
|
|
48
|
+
t.notOk(response.headers['content-length'], 'no content length')
|
|
49
|
+
t.equal(payload.toString('utf-8'), file)
|
|
50
|
+
|
|
51
|
+
usedCustom = false
|
|
52
|
+
usedCustomGlobal = false
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const response = await fastify.inject({
|
|
56
|
+
url: '/custom',
|
|
57
|
+
method: 'GET',
|
|
58
|
+
headers: {
|
|
59
|
+
'accept-encoding': 'deflate'
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
t.equal(usedCustom, true)
|
|
63
|
+
t.equal(usedCustomGlobal, false)
|
|
64
|
+
|
|
65
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
66
|
+
const payload = zlib.inflateSync(response.rawPayload)
|
|
67
|
+
t.equal(response.headers['content-encoding'], 'deflate')
|
|
68
|
+
t.notOk(response.headers['content-length'], 'no content length')
|
|
69
|
+
t.equal(payload.toString('utf-8'), file)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
t.test('it should compress data using the route custom provided `createGzip` method', async (t) => {
|
|
73
|
+
t.plan(8)
|
|
74
|
+
|
|
75
|
+
let usedCustomGlobal = false
|
|
76
|
+
let usedCustom = false
|
|
77
|
+
const customZlibGlobal = { createGzip: () => (usedCustomGlobal = true) && zlib.createGzip() }
|
|
78
|
+
const customZlib = { createGzip: () => (usedCustom = true) && zlib.createGzip() }
|
|
79
|
+
|
|
80
|
+
const fastify = Fastify()
|
|
81
|
+
await fastify.register(compressPlugin, { global: false, zlib: customZlibGlobal })
|
|
82
|
+
|
|
83
|
+
fastify.get('/', (request, reply) => {
|
|
84
|
+
reply
|
|
85
|
+
.type('text/plain')
|
|
86
|
+
.compress(createReadStream('./package.json'))
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
fastify.get('/custom', { compress: { zlib: customZlib } }, (request, reply) => {
|
|
90
|
+
reply
|
|
91
|
+
.type('text/plain')
|
|
92
|
+
.compress(createReadStream('./package.json'))
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
await fastify.inject({
|
|
96
|
+
url: '/',
|
|
97
|
+
method: 'GET',
|
|
98
|
+
headers: {
|
|
99
|
+
'accept-encoding': 'gzip'
|
|
100
|
+
}
|
|
101
|
+
}).then((response) => {
|
|
102
|
+
t.equal(usedCustom, false)
|
|
103
|
+
t.equal(usedCustomGlobal, true)
|
|
104
|
+
|
|
105
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
106
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
107
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
108
|
+
t.equal(payload.toString('utf-8'), file)
|
|
109
|
+
|
|
110
|
+
usedCustom = false
|
|
111
|
+
usedCustomGlobal = false
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const response = await fastify.inject({
|
|
115
|
+
url: '/custom',
|
|
116
|
+
method: 'GET',
|
|
117
|
+
headers: {
|
|
118
|
+
'accept-encoding': 'gzip'
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
t.equal(usedCustom, true)
|
|
122
|
+
t.equal(usedCustomGlobal, false)
|
|
123
|
+
|
|
124
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
125
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
126
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
127
|
+
t.equal(payload.toString('utf-8'), file)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
t.test('it should not compress data when `global` is `false` unless `compress` routes settings have been set up', async (t) => {
|
|
131
|
+
t.plan(9)
|
|
132
|
+
|
|
133
|
+
let usedCustom = false
|
|
134
|
+
const customZlib = { createGzip: () => (usedCustom = true) && zlib.createGzip() }
|
|
135
|
+
|
|
136
|
+
const fastify = Fastify()
|
|
137
|
+
await fastify.register(compressPlugin, { global: false })
|
|
138
|
+
|
|
139
|
+
fastify.get('/', (request, reply) => {
|
|
140
|
+
// compress function should still be available
|
|
141
|
+
t.type(reply.compress, 'function')
|
|
142
|
+
|
|
143
|
+
reply.send({ foo: 1 })
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
fastify.get('/custom', {
|
|
147
|
+
compress: { zlib: customZlib }
|
|
148
|
+
}, (request, reply) => {
|
|
149
|
+
reply
|
|
150
|
+
.type('text/plain')
|
|
151
|
+
.compress(createReadStream('./package.json'))
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
fastify.get('/standard', {
|
|
155
|
+
compress: { threshold: 1 }
|
|
156
|
+
}, (request, reply) => {
|
|
157
|
+
reply.send({ foo: 1 })
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
await fastify.inject({
|
|
161
|
+
url: '/',
|
|
162
|
+
method: 'GET',
|
|
163
|
+
headers: {
|
|
164
|
+
'accept-encoding': 'gzip'
|
|
165
|
+
}
|
|
166
|
+
}).then((response) => {
|
|
167
|
+
t.equal(usedCustom, false)
|
|
168
|
+
|
|
169
|
+
t.equal(response.headers['content-encoding'], undefined)
|
|
170
|
+
t.equal(response.rawPayload.toString('utf-8'), JSON.stringify({ foo: 1 }))
|
|
171
|
+
|
|
172
|
+
usedCustom = false
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
await fastify.inject({
|
|
176
|
+
url: '/custom',
|
|
177
|
+
method: 'GET',
|
|
178
|
+
headers: {
|
|
179
|
+
'accept-encoding': 'gzip'
|
|
180
|
+
}
|
|
181
|
+
}).then((response) => {
|
|
182
|
+
t.equal(usedCustom, true)
|
|
183
|
+
|
|
184
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
185
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
186
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
187
|
+
t.equal(payload.toString('utf-8'), file)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
const response = await fastify.inject({
|
|
191
|
+
url: '/standard',
|
|
192
|
+
method: 'GET',
|
|
193
|
+
headers: {
|
|
194
|
+
'accept-encoding': 'gzip'
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
198
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
199
|
+
t.equal(payload.toString('utf-8'), JSON.stringify({ foo: 1 }))
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
t.test('it should not compress data when route `compress` option is set to `false`', async (t) => {
|
|
203
|
+
t.plan(2)
|
|
204
|
+
|
|
205
|
+
const content = { message: 'Hello World!' }
|
|
206
|
+
|
|
207
|
+
const fastify = Fastify()
|
|
208
|
+
await fastify.register(compressPlugin, { global: false })
|
|
209
|
+
|
|
210
|
+
fastify.get('/', {
|
|
211
|
+
compress: false
|
|
212
|
+
}, (request, reply) => {
|
|
213
|
+
reply.send(content)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
const response = await fastify.inject({
|
|
217
|
+
url: '/',
|
|
218
|
+
method: 'GET',
|
|
219
|
+
headers: {
|
|
220
|
+
'accept-encoding': 'gzip'
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
t.equal(response.headers['content-encoding'], undefined)
|
|
224
|
+
t.equal(response.rawPayload.toString('utf-8'), JSON.stringify(content))
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
t.test('it should throw an error on invalid route `compress` settings', async (t) => {
|
|
228
|
+
t.plan(2)
|
|
229
|
+
|
|
230
|
+
const fastify = Fastify()
|
|
231
|
+
await fastify.register(compressPlugin, { global: false })
|
|
232
|
+
|
|
233
|
+
fastify.get('/', {
|
|
234
|
+
compress: 'bad config'
|
|
235
|
+
}, (request, reply) => {
|
|
236
|
+
reply.send('')
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
await fastify.inject({
|
|
240
|
+
url: '/',
|
|
241
|
+
method: 'GET',
|
|
242
|
+
headers: {
|
|
243
|
+
'accept-encoding': 'gzip'
|
|
244
|
+
}
|
|
245
|
+
}).catch((err) => {
|
|
246
|
+
t.type(err, Error)
|
|
247
|
+
t.equal(err.message, 'Unknown value for route compress configuration')
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
test('When `compress.removeContentLengthHeader` is `false`, it should not remove `Content-Length` header :', async (t) => {
|
|
253
|
+
t.test('using `reply.compress()`', async (t) => {
|
|
254
|
+
t.plan(3)
|
|
255
|
+
|
|
256
|
+
const fastify = Fastify()
|
|
257
|
+
await fastify.register(compressPlugin, { global: true })
|
|
258
|
+
|
|
259
|
+
fastify.get('/', {
|
|
260
|
+
compress: { removeContentLengthHeader: false }
|
|
261
|
+
}, (request, reply) => {
|
|
262
|
+
readFile('./package.json', 'utf8', (err, data) => {
|
|
263
|
+
if (err) {
|
|
264
|
+
return reply.send(err)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
reply
|
|
268
|
+
.type('text/plain')
|
|
269
|
+
.header('content-length', '' + data.length)
|
|
270
|
+
.compress(data)
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
const response = await fastify.inject({
|
|
275
|
+
url: '/',
|
|
276
|
+
method: 'GET',
|
|
277
|
+
headers: {
|
|
278
|
+
'accept-encoding': 'deflate'
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
282
|
+
const payload = zlib.inflateSync(response.rawPayload)
|
|
283
|
+
t.equal(response.headers['content-encoding'], 'deflate')
|
|
284
|
+
t.equal(response.headers['content-length'], payload.length.toString())
|
|
285
|
+
t.equal(payload.toString('utf-8'), file)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
t.test('using `onSend` hook', async (t) => {
|
|
289
|
+
t.plan(3)
|
|
290
|
+
|
|
291
|
+
const fastify = Fastify()
|
|
292
|
+
await fastify.register(compressPlugin, { global: true })
|
|
293
|
+
|
|
294
|
+
fastify.get('/', {
|
|
295
|
+
compress: { removeContentLengthHeader: false }
|
|
296
|
+
}, (request, reply) => {
|
|
297
|
+
readFile('./package.json', 'utf8', (err, data) => {
|
|
298
|
+
if (err) {
|
|
299
|
+
return reply.send(err)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
reply
|
|
303
|
+
.type('text/plain')
|
|
304
|
+
.header('content-length', '' + data.length)
|
|
305
|
+
.send(data)
|
|
306
|
+
})
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
const response = await fastify.inject({
|
|
310
|
+
url: '/',
|
|
311
|
+
method: 'GET',
|
|
312
|
+
headers: {
|
|
313
|
+
'accept-encoding': 'deflate'
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
317
|
+
const payload = zlib.inflateSync(response.rawPayload)
|
|
318
|
+
t.equal(response.headers['content-encoding'], 'deflate')
|
|
319
|
+
t.equal(response.headers['content-length'], payload.length.toString())
|
|
320
|
+
t.equal(payload.toString('utf-8'), file)
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
test('When using the old routes `{ config: compress }` option :', async (t) => {
|
|
325
|
+
t.test('it should compress data using the route custom provided `createGzip` method', async (t) => {
|
|
326
|
+
t.plan(8)
|
|
327
|
+
|
|
328
|
+
let usedCustomGlobal = false
|
|
329
|
+
let usedCustom = false
|
|
330
|
+
const customZlibGlobal = { createGzip: () => (usedCustomGlobal = true) && zlib.createGzip() }
|
|
331
|
+
const customZlib = { createGzip: () => (usedCustom = true) && zlib.createGzip() }
|
|
332
|
+
|
|
333
|
+
const fastify = Fastify()
|
|
334
|
+
await fastify.register(compressPlugin, { global: false, zlib: customZlibGlobal })
|
|
335
|
+
|
|
336
|
+
fastify.get('/', (request, reply) => {
|
|
337
|
+
reply
|
|
338
|
+
.type('text/plain')
|
|
339
|
+
.compress(createReadStream('./package.json'))
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
fastify.get('/custom', {
|
|
343
|
+
config: {
|
|
344
|
+
compress: { zlib: customZlib }
|
|
345
|
+
}
|
|
346
|
+
}, (request, reply) => {
|
|
347
|
+
reply
|
|
348
|
+
.type('text/plain')
|
|
349
|
+
.compress(createReadStream('./package.json'))
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
await fastify.inject({
|
|
353
|
+
url: '/',
|
|
354
|
+
method: 'GET',
|
|
355
|
+
headers: {
|
|
356
|
+
'accept-encoding': 'gzip'
|
|
357
|
+
}
|
|
358
|
+
}).then((response) => {
|
|
359
|
+
t.equal(usedCustom, false)
|
|
360
|
+
t.equal(usedCustomGlobal, true)
|
|
361
|
+
|
|
362
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
363
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
364
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
365
|
+
t.equal(payload.toString('utf-8'), file)
|
|
366
|
+
|
|
367
|
+
usedCustom = false
|
|
368
|
+
usedCustomGlobal = false
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
const response = await fastify.inject({
|
|
372
|
+
url: '/custom',
|
|
373
|
+
method: 'GET',
|
|
374
|
+
headers: {
|
|
375
|
+
'accept-encoding': 'gzip'
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
t.equal(usedCustom, true)
|
|
379
|
+
t.equal(usedCustomGlobal, false)
|
|
380
|
+
|
|
381
|
+
const file = readFileSync('./package.json', 'utf8')
|
|
382
|
+
const payload = zlib.gunzipSync(response.rawPayload)
|
|
383
|
+
t.equal(response.headers['content-encoding'], 'gzip')
|
|
384
|
+
t.equal(payload.toString('utf-8'), file)
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
t.test('it should use the old routes `{ config: compress }` options over routes `compress` options', async (t) => {
|
|
388
|
+
t.plan(2)
|
|
389
|
+
|
|
390
|
+
const fastify = Fastify()
|
|
391
|
+
await fastify.register(compressPlugin, { global: false })
|
|
392
|
+
|
|
393
|
+
fastify.get('/', {
|
|
394
|
+
compress: {
|
|
395
|
+
zlib: { createGzip: () => zlib.createGzip() }
|
|
396
|
+
},
|
|
397
|
+
config: {
|
|
398
|
+
compress: 'bad config'
|
|
399
|
+
}
|
|
400
|
+
}, (request, reply) => {
|
|
401
|
+
reply.send('')
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
await fastify.inject({
|
|
405
|
+
url: '/',
|
|
406
|
+
method: 'GET',
|
|
407
|
+
headers: {
|
|
408
|
+
'accept-encoding': 'gzip'
|
|
409
|
+
}
|
|
410
|
+
}).catch((err) => {
|
|
411
|
+
t.type(err, Error)
|
|
412
|
+
t.equal(err.message, 'Unknown value for route compress configuration')
|
|
413
|
+
})
|
|
414
|
+
})
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
test('It should avoid to trigger `onSend` hook twice', async (t) => {
|
|
418
|
+
t.plan(1)
|
|
419
|
+
|
|
420
|
+
const server = Fastify()
|
|
421
|
+
await server.register(compressPlugin, { threshold: 0 })
|
|
422
|
+
|
|
423
|
+
await server.register(async function (server) {
|
|
424
|
+
server.get('/', async (request, _) => {
|
|
425
|
+
return { hi: true }
|
|
426
|
+
})
|
|
427
|
+
}, { prefix: '/test' })
|
|
428
|
+
|
|
429
|
+
const response = await server.inject({
|
|
430
|
+
url: '/test',
|
|
431
|
+
method: 'GET',
|
|
432
|
+
headers: {
|
|
433
|
+
'accept-encoding': 'br'
|
|
434
|
+
}
|
|
435
|
+
})
|
|
436
|
+
t.same(JSON.parse(zlib.brotliDecompressSync(response.rawPayload)), { hi: true })
|
|
437
|
+
})
|