@fastify/compress 7.0.1 → 7.0.3

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,62 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const Fastify = require('fastify')
5
+ const fastifyCompress = require('../..')
6
+ const { request } = require('node:http')
7
+
8
+ function fetch (url) {
9
+ return new Promise(function (resolve, reject) {
10
+ request(url, function (response) {
11
+ // we need to use Buffer.concat to prevent wrong utf8 handling
12
+ let body = Buffer.from('')
13
+ response.on('data', function (chunk) {
14
+ body = Buffer.concat([body, Buffer.from(chunk, 'utf-8')])
15
+ })
16
+ response.once('error', reject)
17
+ response.once('end', function () {
18
+ resolve(body.toString())
19
+ })
20
+ })
21
+ .once('error', reject)
22
+ .end()
23
+ })
24
+ }
25
+
26
+ test('should not corrupt the file content', async (t) => {
27
+ t.plan(2)
28
+
29
+ // provide 2 byte unicode content
30
+ const twoByteUnicodeContent = new Array(5_000)
31
+ .fill('0')
32
+ .map(() => {
33
+ const random = new Array(10).fill('A').join('🍃')
34
+ return random + '- FASTIFY COMPRESS,🍃 FASTIFY COMPRESS'
35
+ })
36
+ .join('\n')
37
+ const fastify = new Fastify()
38
+ t.teardown(() => fastify.close())
39
+
40
+ fastify.register(async (instance, opts) => {
41
+ await fastify.register(fastifyCompress)
42
+ // compression
43
+ instance.get('/compress', async (req, reply) => {
44
+ return twoByteUnicodeContent
45
+ })
46
+ })
47
+
48
+ // no compression
49
+ fastify.get('/no-compress', async (req, reply) => {
50
+ return twoByteUnicodeContent
51
+ })
52
+
53
+ const address = await fastify.listen({ port: 0, host: '127.0.0.1' })
54
+
55
+ const [body1, body2] = await Promise.all([
56
+ fetch(`${address}/compress`),
57
+ fetch(`${address}/no-compress`)
58
+ ])
59
+
60
+ t.equal(body1, body2)
61
+ t.equal(body1, twoByteUnicodeContent)
62
+ })
@@ -8,7 +8,7 @@ const compressPlugin = require('../index')
8
8
 
9
9
  test('When using routes `compress` settings :', async (t) => {
10
10
  t.test('it should compress data using the route custom provided `createDeflate` method', async (t) => {
11
- t.plan(10)
11
+ t.plan(12)
12
12
 
13
13
  let usedCustomGlobal = false
14
14
  let usedCustom = false
@@ -44,6 +44,7 @@ test('When using routes `compress` settings :', async (t) => {
44
44
 
45
45
  const file = readFileSync('./package.json', 'utf8')
46
46
  const payload = zlib.inflateSync(response.rawPayload)
47
+ t.equal(response.headers.vary, 'accept-encoding')
47
48
  t.equal(response.headers['content-encoding'], 'deflate')
48
49
  t.notOk(response.headers['content-length'], 'no content length')
49
50
  t.equal(payload.toString('utf-8'), file)
@@ -64,13 +65,14 @@ test('When using routes `compress` settings :', async (t) => {
64
65
 
65
66
  const file = readFileSync('./package.json', 'utf8')
66
67
  const payload = zlib.inflateSync(response.rawPayload)
68
+ t.equal(response.headers.vary, 'accept-encoding')
67
69
  t.equal(response.headers['content-encoding'], 'deflate')
68
70
  t.notOk(response.headers['content-length'], 'no content length')
69
71
  t.equal(payload.toString('utf-8'), file)
70
72
  })
71
73
 
72
74
  t.test('it should compress data using the route custom provided `createGzip` method', async (t) => {
73
- t.plan(8)
75
+ t.plan(10)
74
76
 
75
77
  let usedCustomGlobal = false
76
78
  let usedCustom = false
@@ -104,6 +106,7 @@ test('When using routes `compress` settings :', async (t) => {
104
106
 
105
107
  const file = readFileSync('./package.json', 'utf8')
106
108
  const payload = zlib.gunzipSync(response.rawPayload)
109
+ t.equal(response.headers.vary, 'accept-encoding')
107
110
  t.equal(response.headers['content-encoding'], 'gzip')
108
111
  t.equal(payload.toString('utf-8'), file)
109
112
 
@@ -123,12 +126,13 @@ test('When using routes `compress` settings :', async (t) => {
123
126
 
124
127
  const file = readFileSync('./package.json', 'utf8')
125
128
  const payload = zlib.gunzipSync(response.rawPayload)
129
+ t.equal(response.headers.vary, 'accept-encoding')
126
130
  t.equal(response.headers['content-encoding'], 'gzip')
127
131
  t.equal(payload.toString('utf-8'), file)
128
132
  })
129
133
 
130
134
  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)
135
+ t.plan(12)
132
136
 
133
137
  let usedCustom = false
134
138
  const customZlib = { createGzip: () => (usedCustom = true) && zlib.createGzip() }
@@ -165,8 +169,8 @@ test('When using routes `compress` settings :', async (t) => {
165
169
  }
166
170
  }).then((response) => {
167
171
  t.equal(usedCustom, false)
168
-
169
- t.equal(response.headers['content-encoding'], undefined)
172
+ t.notOk(response.headers.vary)
173
+ t.notOk(response.headers['content-encoding'])
170
174
  t.equal(response.rawPayload.toString('utf-8'), JSON.stringify({ foo: 1 }))
171
175
 
172
176
  usedCustom = false
@@ -183,6 +187,7 @@ test('When using routes `compress` settings :', async (t) => {
183
187
 
184
188
  const file = readFileSync('./package.json', 'utf8')
185
189
  const payload = zlib.gunzipSync(response.rawPayload)
190
+ t.equal(response.headers.vary, 'accept-encoding')
186
191
  t.equal(response.headers['content-encoding'], 'gzip')
187
192
  t.equal(payload.toString('utf-8'), file)
188
193
  })
@@ -195,12 +200,13 @@ test('When using routes `compress` settings :', async (t) => {
195
200
  }
196
201
  })
197
202
  const payload = zlib.gunzipSync(response.rawPayload)
203
+ t.equal(response.headers.vary, 'accept-encoding')
198
204
  t.equal(response.headers['content-encoding'], 'gzip')
199
205
  t.equal(payload.toString('utf-8'), JSON.stringify({ foo: 1 }))
200
206
  })
201
207
 
202
208
  t.test('it should not compress data when route `compress` option is set to `false`', async (t) => {
203
- t.plan(2)
209
+ t.plan(3)
204
210
 
205
211
  const content = { message: 'Hello World!' }
206
212
 
@@ -220,7 +226,8 @@ test('When using routes `compress` settings :', async (t) => {
220
226
  'accept-encoding': 'gzip'
221
227
  }
222
228
  })
223
- t.equal(response.headers['content-encoding'], undefined)
229
+ t.notOk(response.headers.vary)
230
+ t.notOk(response.headers['content-encoding'])
224
231
  t.equal(response.rawPayload.toString('utf-8'), JSON.stringify(content))
225
232
  })
226
233
 
@@ -244,7 +251,7 @@ test('When using routes `compress` settings :', async (t) => {
244
251
 
245
252
  test('When `compress.removeContentLengthHeader` is `false`, it should not remove `Content-Length` header :', async (t) => {
246
253
  t.test('using `reply.compress()`', async (t) => {
247
- t.plan(3)
254
+ t.plan(4)
248
255
 
249
256
  const fastify = Fastify()
250
257
  await fastify.register(compressPlugin, { global: true })
@@ -273,13 +280,14 @@ test('When `compress.removeContentLengthHeader` is `false`, it should not remove
273
280
  })
274
281
  const file = readFileSync('./package.json', 'utf8')
275
282
  const payload = zlib.inflateSync(response.rawPayload)
283
+ t.equal(response.headers.vary, 'accept-encoding')
276
284
  t.equal(response.headers['content-encoding'], 'deflate')
277
285
  t.equal(response.headers['content-length'], payload.length.toString())
278
286
  t.equal(payload.toString('utf-8'), file)
279
287
  })
280
288
 
281
289
  t.test('using `onSend` hook', async (t) => {
282
- t.plan(3)
290
+ t.plan(4)
283
291
 
284
292
  const fastify = Fastify()
285
293
  await fastify.register(compressPlugin, { global: true })
@@ -308,6 +316,7 @@ test('When `compress.removeContentLengthHeader` is `false`, it should not remove
308
316
  })
309
317
  const file = readFileSync('./package.json', 'utf8')
310
318
  const payload = zlib.inflateSync(response.rawPayload)
319
+ t.equal(response.headers.vary, 'accept-encoding')
311
320
  t.equal(response.headers['content-encoding'], 'deflate')
312
321
  t.equal(response.headers['content-length'], payload.length.toString())
313
322
  t.equal(payload.toString('utf-8'), file)
@@ -316,7 +325,7 @@ test('When `compress.removeContentLengthHeader` is `false`, it should not remove
316
325
 
317
326
  test('When using the old routes `{ config: compress }` option :', async (t) => {
318
327
  t.test('it should compress data using the route custom provided `createGzip` method', async (t) => {
319
- t.plan(8)
328
+ t.plan(10)
320
329
 
321
330
  let usedCustomGlobal = false
322
331
  let usedCustom = false
@@ -354,6 +363,7 @@ test('When using the old routes `{ config: compress }` option :', async (t) => {
354
363
 
355
364
  const file = readFileSync('./package.json', 'utf8')
356
365
  const payload = zlib.gunzipSync(response.rawPayload)
366
+ t.equal(response.headers.vary, 'accept-encoding')
357
367
  t.equal(response.headers['content-encoding'], 'gzip')
358
368
  t.equal(payload.toString('utf-8'), file)
359
369
 
@@ -373,6 +383,7 @@ test('When using the old routes `{ config: compress }` option :', async (t) => {
373
383
 
374
384
  const file = readFileSync('./package.json', 'utf8')
375
385
  const payload = zlib.gunzipSync(response.rawPayload)
386
+ t.equal(response.headers.vary, 'accept-encoding')
376
387
  t.equal(response.headers['content-encoding'], 'gzip')
377
388
  t.equal(payload.toString('utf-8'), file)
378
389
  })
@@ -4,7 +4,7 @@ const { createReadStream } = require('node:fs')
4
4
  const { Socket } = require('node:net')
5
5
  const { Duplex, PassThrough, Readable, Stream, Transform, Writable } = require('node:stream')
6
6
  const { test } = require('tap')
7
- const { isStream, isDeflate, isGzip } = require('../lib/utils')
7
+ const { isStream, isDeflate, isGzip, intoAsyncIterator } = require('../lib/utils')
8
8
 
9
9
  test('isStream() utility should be able to detect Streams', async (t) => {
10
10
  t.plan(12)
@@ -61,3 +61,45 @@ test('isGzip() utility should be able to detect gzip compressed Buffer', async (
61
61
  t.equal(isGzip(undefined), false)
62
62
  t.equal(isGzip(''), false)
63
63
  })
64
+
65
+ test('intoAsyncIterator() utility should handle different data', async (t) => {
66
+ t.plan(8)
67
+
68
+ const buf = Buffer.from('foo')
69
+ const str = 'foo'
70
+ const arr = [str, str]
71
+ const arrayBuffer = new ArrayBuffer(8)
72
+ const typedArray = new Int32Array(arrayBuffer)
73
+ const asyncIterator = (async function * () {
74
+ yield str
75
+ })()
76
+ const obj = {}
77
+
78
+ for await (const buffer of intoAsyncIterator(buf)) {
79
+ t.equal(buffer, buf)
80
+ }
81
+
82
+ for await (const string of intoAsyncIterator(str)) {
83
+ t.equal(string, str)
84
+ }
85
+
86
+ for await (const chunk of intoAsyncIterator(arr)) {
87
+ t.equal(chunk, str)
88
+ }
89
+
90
+ for await (const chunk of intoAsyncIterator(arrayBuffer)) {
91
+ t.equal(chunk.toString(), Buffer.from(arrayBuffer).toString())
92
+ }
93
+
94
+ for await (const chunk of intoAsyncIterator(typedArray)) {
95
+ t.equal(chunk.toString(), Buffer.from(typedArray).toString())
96
+ }
97
+
98
+ for await (const chunk of intoAsyncIterator(asyncIterator)) {
99
+ t.equal(chunk, str)
100
+ }
101
+
102
+ for await (const chunk of intoAsyncIterator(obj)) {
103
+ t.equal(chunk, obj)
104
+ }
105
+ })
package/types/index.d.ts CHANGED
@@ -2,13 +2,12 @@ import {
2
2
  FastifyPluginCallback,
3
3
  FastifyReply,
4
4
  FastifyRequest,
5
+ RouteOptions as FastifyRouteOptions,
5
6
  RawServerBase,
6
- RawServerDefault,
7
- RouteOptions as FastifyRouteOptions
8
- } from 'fastify'
9
- import { Input, InputObject } from 'into-stream'
10
- import { Stream } from 'stream'
11
- import { BrotliOptions, ZlibOptions } from 'zlib'
7
+ RawServerDefault
8
+ } from 'fastify';
9
+ import { Stream } from 'stream';
10
+ import { BrotliOptions, ZlibOptions } from 'zlib';
12
11
 
13
12
  declare module 'fastify' {
14
13
  export interface FastifyContextConfig {
@@ -26,7 +25,7 @@ declare module 'fastify' {
26
25
  }
27
26
 
28
27
  interface FastifyReply {
29
- compress(input: Stream | Input | InputObject): void;
28
+ compress(input: Stream | Input): void;
30
29
  }
31
30
 
32
31
  export interface RouteOptions {
@@ -61,6 +60,14 @@ type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';
61
60
 
62
61
  type CompressibleContentTypeFunction = (contentType: string) => boolean;
63
62
 
63
+ type Input =
64
+ | Buffer
65
+ | NodeJS.TypedArray
66
+ | ArrayBuffer
67
+ | string
68
+ | Iterable<Buffer | string>
69
+ | AsyncIterable<Buffer | string>;
70
+
64
71
  declare namespace fastifyCompress {
65
72
 
66
73
  export interface FastifyCompressOptions {