fastify 4.9.2 → 4.10.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.
@@ -44,3 +44,82 @@ test('bodyLimit', t => {
44
44
  })
45
45
  })
46
46
  })
47
+
48
+ test('default request.routeOptions.bodyLimit should be 1048576', t => {
49
+ t.plan(4)
50
+ const fastify = Fastify()
51
+ fastify.post('/default-bodylimit', {
52
+ handler (request, reply) {
53
+ t.equal(1048576, request.routeOptions.bodyLimit)
54
+ reply.send({ })
55
+ }
56
+ })
57
+ fastify.listen({ port: 0 }, function (err) {
58
+ t.error(err)
59
+ t.teardown(() => { fastify.close() })
60
+
61
+ sget({
62
+ method: 'POST',
63
+ url: 'http://localhost:' + fastify.server.address().port + '/default-bodylimit',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: [],
66
+ json: true
67
+ }, (err, response, body) => {
68
+ t.error(err)
69
+ t.equal(response.statusCode, 200)
70
+ })
71
+ })
72
+ })
73
+
74
+ test('request.routeOptions.bodyLimit should be equal to route limit', t => {
75
+ t.plan(4)
76
+ const fastify = Fastify({ bodyLimit: 1 })
77
+ fastify.post('/route-limit', {
78
+ bodyLimit: 1000,
79
+ handler (request, reply) {
80
+ t.equal(1000, request.routeOptions.bodyLimit)
81
+ reply.send({})
82
+ }
83
+ })
84
+ fastify.listen({ port: 0 }, function (err) {
85
+ t.error(err)
86
+ t.teardown(() => { fastify.close() })
87
+
88
+ sget({
89
+ method: 'POST',
90
+ url: 'http://localhost:' + fastify.server.address().port + '/route-limit',
91
+ headers: { 'Content-Type': 'application/json' },
92
+ body: [],
93
+ json: true
94
+ }, (err, response, body) => {
95
+ t.error(err)
96
+ t.equal(response.statusCode, 200)
97
+ })
98
+ })
99
+ })
100
+
101
+ test('request.routeOptions.bodyLimit should be equal to server limit', t => {
102
+ t.plan(4)
103
+ const fastify = Fastify({ bodyLimit: 100 })
104
+ fastify.post('/server-limit', {
105
+ handler (request, reply) {
106
+ t.equal(100, request.routeOptions.bodyLimit)
107
+ reply.send({})
108
+ }
109
+ })
110
+ fastify.listen({ port: 0 }, function (err) {
111
+ t.error(err)
112
+ t.teardown(() => { fastify.close() })
113
+
114
+ sget({
115
+ method: 'POST',
116
+ url: 'http://localhost:' + fastify.server.address().port + '/server-limit',
117
+ headers: { 'Content-Type': 'application/json' },
118
+ body: [],
119
+ json: true
120
+ }, (err, response, body) => {
121
+ t.error(err)
122
+ t.equal(response.statusCode, 200)
123
+ })
124
+ })
125
+ })
@@ -4,42 +4,72 @@ const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
6
  const { Client } = require('undici')
7
+ const semver = require('semver')
7
8
 
8
- test('Should return 503 while closing - pipelining', t => {
9
+ test('Should return 503 while closing - pipelining', async t => {
9
10
  const fastify = Fastify({
10
11
  return503OnClosing: true,
11
12
  forceCloseConnections: false
12
13
  })
13
14
 
15
+ fastify.get('/', async (req, reply) => {
16
+ fastify.close()
17
+ return { hello: 'world' }
18
+ })
19
+
20
+ await fastify.listen({ port: 0 })
21
+
22
+ const instance = new Client('http://localhost:' + fastify.server.address().port, {
23
+ pipelining: 2
24
+ })
25
+
26
+ const codes = [200, 200, 503]
27
+ const responses = await Promise.all([
28
+ instance.request({ path: '/', method: 'GET' }),
29
+ instance.request({ path: '/', method: 'GET' }),
30
+ instance.request({ path: '/', method: 'GET' })
31
+ ])
32
+ const actual = responses.map(r => r.statusCode)
33
+
34
+ t.same(actual, codes)
35
+
36
+ await instance.close()
37
+ })
38
+
39
+ const isV19plus = semver.satisfies(process.version, '>= v19.0.0')
40
+ test('Should not return 503 while closing - pipelining - return503OnClosing: false, skip Node >= v19.x', { skip: isV19plus }, async t => {
41
+ const fastify = Fastify({
42
+ return503OnClosing: false,
43
+ forceCloseConnections: false
44
+ })
45
+
14
46
  fastify.get('/', (req, reply) => {
15
47
  fastify.close()
16
48
  reply.send({ hello: 'world' })
17
49
  })
18
50
 
19
- fastify.listen({ port: 0 }, async err => {
20
- t.error(err)
21
-
22
- const instance = new Client('http://localhost:' + fastify.server.address().port, {
23
- pipelining: 1
24
- })
25
-
26
- const codes = [200, 503]
27
- for (const code of codes) {
28
- instance.request(
29
- { path: '/', method: 'GET' }
30
- ).then(data => {
31
- t.equal(data.statusCode, code)
32
- }).catch((e) => {
33
- t.fail(e)
34
- })
35
- }
36
- instance.close(() => {
37
- t.end('Done')
38
- })
51
+ await fastify.listen({ port: 0 })
52
+
53
+ const instance = new Client('http://localhost:' + fastify.server.address().port, {
54
+ pipelining: 2
39
55
  })
56
+
57
+ const codes = [200, 200, 200]
58
+ const responses = await Promise.all([
59
+ instance.request({ path: '/', method: 'GET' }),
60
+ instance.request({ path: '/', method: 'GET' }),
61
+ instance.request({ path: '/', method: 'GET' })
62
+ ])
63
+ const actual = responses.map(r => r.statusCode)
64
+
65
+ t.same(actual, codes)
66
+
67
+ await instance.close()
40
68
  })
41
69
 
42
- test('Should not return 503 while closing - pipelining - return503OnClosing', t => {
70
+ test('Should close the socket abruptly - pipelining - return503OnClosing: false, skip Node < v19.x', { skip: !isV19plus }, async t => {
71
+ // Since Node v19, we will always invoke server.closeIdleConnections()
72
+ // therefore our socket will be closed
43
73
  const fastify = Fastify({
44
74
  return503OnClosing: false,
45
75
  forceCloseConnections: false
@@ -50,25 +80,20 @@ test('Should not return 503 while closing - pipelining - return503OnClosing', t
50
80
  reply.send({ hello: 'world' })
51
81
  })
52
82
 
53
- fastify.listen({ port: 0 }, err => {
54
- t.error(err)
55
-
56
- const instance = new Client('http://localhost:' + fastify.server.address().port, {
57
- pipelining: 1
58
- })
59
-
60
- const codes = [200, 200]
61
- for (const code of codes) {
62
- instance.request(
63
- { path: '/', method: 'GET' }
64
- ).then(data => {
65
- t.equal(data.statusCode, code)
66
- }).catch((e) => {
67
- t.fail(e)
68
- })
69
- }
70
- instance.close(() => {
71
- t.end('Done')
72
- })
83
+ await fastify.listen({ port: 0 })
84
+
85
+ const instance = new Client('http://localhost:' + fastify.server.address().port, {
86
+ pipelining: 2
73
87
  })
88
+
89
+ const responses = await Promise.allSettled([
90
+ instance.request({ path: '/', method: 'GET' }),
91
+ instance.request({ path: '/', method: 'GET' }),
92
+ instance.request({ path: '/', method: 'GET' })
93
+ ])
94
+ t.equal(responses[0].status, 'fulfilled')
95
+ t.equal(responses[1].status, 'rejected')
96
+ t.equal(responses[2].status, 'rejected')
97
+
98
+ await instance.close()
74
99
  })
@@ -6,6 +6,7 @@ const t = require('tap')
6
6
  const test = t.test
7
7
  const Fastify = require('..')
8
8
  const { Client } = require('undici')
9
+ const semver = require('semver')
9
10
 
10
11
  test('close callback', t => {
11
12
  t.plan(4)
@@ -202,7 +203,8 @@ test('Should return error while closing (callback) - injection', t => {
202
203
  })
203
204
  })
204
205
 
205
- t.test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false', t => {
206
+ const isV19plus = semver.satisfies(process.version, '>= v19.0.0')
207
+ t.test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node >= v19.x', { skip: isV19plus }, t => {
206
208
  const fastify = Fastify({
207
209
  return503OnClosing: false,
208
210
  forceCloseConnections: false
@@ -240,6 +242,45 @@ t.test('Current opened connection should continue to work after closing and retu
240
242
  })
241
243
  })
242
244
 
245
+ t.test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node < v19.x', { skip: !isV19plus }, t => {
246
+ t.plan(4)
247
+ const fastify = Fastify({
248
+ return503OnClosing: false,
249
+ forceCloseConnections: false
250
+ })
251
+
252
+ fastify.get('/', (req, reply) => {
253
+ fastify.close()
254
+ reply.send({ hello: 'world' })
255
+ })
256
+
257
+ fastify.listen({ port: 0 }, err => {
258
+ t.error(err)
259
+
260
+ const port = fastify.server.address().port
261
+ const client = net.createConnection({ port }, () => {
262
+ client.write('GET / HTTP/1.1\r\n\r\n')
263
+
264
+ client.on('error', function () {
265
+ // Dependending on the Operating System
266
+ // the socket could error or not.
267
+ // However, it will always be closed.
268
+ })
269
+
270
+ client.on('close', function () {
271
+ t.pass('close')
272
+ })
273
+
274
+ client.once('data', data => {
275
+ t.match(data.toString(), /Connection:\s*keep-alive/i)
276
+ t.match(data.toString(), /200 OK/i)
277
+
278
+ client.write('GET / HTTP/1.1\r\n\r\n')
279
+ })
280
+ })
281
+ })
282
+ })
283
+
243
284
  t.test('Current opened connection should not accept new incoming connections', t => {
244
285
  t.plan(3)
245
286
  const fastify = Fastify({ forceCloseConnections: false })
@@ -585,33 +585,37 @@ test('preHandler respond with a stream', t => {
585
585
 
586
586
  test('Should log a warning if is an async function with `done`', t => {
587
587
  t.test('3 arguments', t => {
588
- t.plan(1)
588
+ t.plan(2)
589
589
  const fastify = Fastify()
590
590
 
591
591
  try {
592
592
  fastify.addHook('onRequest', async (req, reply, done) => {})
593
593
  } catch (e) {
594
+ t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
594
595
  t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
595
596
  }
596
597
  })
597
598
 
598
599
  t.test('4 arguments', t => {
599
- t.plan(3)
600
+ t.plan(6)
600
601
  const fastify = Fastify()
601
602
 
602
603
  try {
603
604
  fastify.addHook('onSend', async (req, reply, payload, done) => {})
604
605
  } catch (e) {
606
+ t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
605
607
  t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
606
608
  }
607
609
  try {
608
610
  fastify.addHook('preSerialization', async (req, reply, payload, done) => {})
609
611
  } catch (e) {
612
+ t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
610
613
  t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
611
614
  }
612
615
  try {
613
616
  fastify.addHook('onError', async (req, reply, payload, done) => {})
614
617
  } catch (e) {
618
+ t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
615
619
  t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
616
620
  }
617
621
  })
@@ -291,12 +291,13 @@ t.test('onReady cannot add lifecycle hooks', t => {
291
291
  })
292
292
 
293
293
  t.test('onReady throw loading error', t => {
294
- t.plan(1)
294
+ t.plan(2)
295
295
  const fastify = Fastify()
296
296
 
297
297
  try {
298
298
  fastify.addHook('onReady', async function (done) {})
299
299
  } catch (e) {
300
+ t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
300
301
  t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
301
302
  }
302
303
  })
@@ -23,7 +23,7 @@ function getUrl (app) {
23
23
  }
24
24
 
25
25
  test('hooks', t => {
26
- t.plan(43)
26
+ t.plan(49)
27
27
  const fastify = Fastify({ exposeHeadRoutes: false })
28
28
 
29
29
  try {
@@ -41,6 +41,22 @@ test('hooks', t => {
41
41
  t.fail()
42
42
  }
43
43
 
44
+ try {
45
+ fastify.addHook('preHandler', null)
46
+ } catch (e) {
47
+ t.equal(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
48
+ t.equal(e.message, 'preHandler hook should be a function, instead got null')
49
+ t.pass()
50
+ }
51
+
52
+ try {
53
+ fastify.addHook('preParsing')
54
+ } catch (e) {
55
+ t.equal(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
56
+ t.equal(e.message, 'preParsing hook should be a function, instead got undefined')
57
+ t.pass()
58
+ }
59
+
44
60
  try {
45
61
  fastify.addHook('preParsing', function (request, reply, payload, done) {
46
62
  request.preParsing = true
@@ -3316,7 +3332,7 @@ test('registering invalid hooks should throw an error', async t => {
3316
3332
  return 'hello world'
3317
3333
  }
3318
3334
  })
3319
- }, new Error('onRequest hook should be a function, instead got undefined'))
3335
+ }, new Error('onRequest hook should be a function, instead got [object Undefined]'))
3320
3336
 
3321
3337
  t.throws(() => {
3322
3338
  fastify.route({
@@ -3327,7 +3343,7 @@ test('registering invalid hooks should throw an error', async t => {
3327
3343
  return 'hello world'
3328
3344
  }
3329
3345
  })
3330
- }, new Error('onRequest hook should be a function, instead got object'))
3346
+ }, new Error('onRequest hook should be a function, instead got [object Null]'))
3331
3347
 
3332
3348
  // undefined is ok
3333
3349
  fastify.route({
@@ -3347,5 +3363,5 @@ test('registering invalid hooks should throw an error', async t => {
3347
3363
  fastify.get('/', function (request, reply) {
3348
3364
  reply.send('hello world')
3349
3365
  })
3350
- }, new Error('onSend hook should be a function, instead got undefined'))
3366
+ }, new Error('onSend hook should be a function, instead got [object Undefined]'))
3351
3367
  })
@@ -1,4 +1,3 @@
1
-
2
1
  'use strict'
3
2
 
4
3
  const sget = require('simple-get').concat
@@ -78,6 +78,6 @@ test('should throw on wrong parameters', t => {
78
78
  t.fail()
79
79
  } catch (e) {
80
80
  t.equal(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
81
- t.equal(e.message, 'onSend hook should be a function, instead got object')
81
+ t.equal(e.message, 'onSend hook should be a function, instead got [object Null]')
82
82
  }
83
83
  })