fastify 4.23.2 → 4.24.1

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.
Files changed (91) hide show
  1. package/README.md +1 -1
  2. package/docs/Guides/Ecosystem.md +6 -0
  3. package/docs/Reference/Hooks.md +1 -0
  4. package/docs/Reference/Plugins.md +1 -1
  5. package/docs/Reference/Reply.md +4 -3
  6. package/docs/Reference/Request.md +3 -2
  7. package/docs/Reference/Server.md +31 -3
  8. package/docs/Reference/Type-Providers.md +2 -2
  9. package/docs/Reference/TypeScript.md +21 -7
  10. package/fastify.d.ts +2 -2
  11. package/fastify.js +8 -1
  12. package/lib/contentTypeParser.js +1 -1
  13. package/lib/reply.js +20 -3
  14. package/lib/reqIdGenFactory.js +15 -9
  15. package/lib/request.js +1 -1
  16. package/lib/route.js +28 -7
  17. package/lib/schemas.js +3 -3
  18. package/lib/warnings.js +3 -1
  19. package/package.json +33 -33
  20. package/test/404s.test.js +31 -39
  21. package/test/async-await.test.js +1 -1
  22. package/test/async-dispose.test.js +21 -0
  23. package/test/build-certificate.js +90 -1
  24. package/test/close-pipelining.test.js +5 -5
  25. package/test/close.test.js +1 -5
  26. package/test/constrained-routes.test.js +127 -3
  27. package/test/custom-http-server.test.js +94 -91
  28. package/test/custom-parser.0.test.js +21 -47
  29. package/test/custom-parser.1.test.js +10 -732
  30. package/test/custom-parser.2.test.js +102 -0
  31. package/test/custom-parser.3.test.js +245 -0
  32. package/test/custom-parser.4.test.js +239 -0
  33. package/test/custom-parser.5.test.js +149 -0
  34. package/test/head.test.js +204 -0
  35. package/test/helper.js +30 -8
  36. package/test/hooks-async.test.js +163 -13
  37. package/test/hooks.on-listen.test.js +7 -6
  38. package/test/hooks.test.js +4 -15
  39. package/test/http2/closing.test.js +7 -15
  40. package/test/https/custom-https-server.test.js +43 -40
  41. package/test/input-validation.js +3 -3
  42. package/test/internals/reply.test.js +33 -4
  43. package/test/listen.1.test.js +101 -0
  44. package/test/listen.2.test.js +103 -0
  45. package/test/listen.3.test.js +87 -0
  46. package/test/listen.4.test.js +164 -0
  47. package/test/listen.deprecated.test.js +3 -9
  48. package/test/logger/instantiation.test.js +347 -0
  49. package/test/logger/logger-test-utils.js +47 -0
  50. package/test/logger/logging.test.js +406 -0
  51. package/test/logger/options.test.js +500 -0
  52. package/test/logger/request.test.js +292 -0
  53. package/test/logger/response.test.js +184 -0
  54. package/test/plugin.1.test.js +249 -0
  55. package/test/plugin.2.test.js +328 -0
  56. package/test/plugin.3.test.js +311 -0
  57. package/test/plugin.4.test.js +416 -0
  58. package/test/reply-code.test.js +64 -0
  59. package/test/reply-trailers.test.js +1 -2
  60. package/test/route.1.test.js +309 -0
  61. package/test/route.2.test.js +99 -0
  62. package/test/route.3.test.js +205 -0
  63. package/test/route.4.test.js +131 -0
  64. package/test/route.5.test.js +230 -0
  65. package/test/route.6.test.js +306 -0
  66. package/test/route.7.test.js +370 -0
  67. package/test/route.8.test.js +142 -0
  68. package/test/stream.1.test.js +108 -0
  69. package/test/stream.2.test.js +119 -0
  70. package/test/stream.3.test.js +192 -0
  71. package/test/stream.4.test.js +223 -0
  72. package/test/stream.5.test.js +194 -0
  73. package/test/trust-proxy.test.js +2 -4
  74. package/test/types/reply.test-d.ts +3 -3
  75. package/test/types/request.test-d.ts +9 -9
  76. package/test/types/type-provider.test-d.ts +89 -0
  77. package/test/types/using.test-d.ts +14 -0
  78. package/test/upgrade.test.js +3 -3
  79. package/types/context.d.ts +9 -2
  80. package/types/instance.d.ts +4 -1
  81. package/types/plugin.d.ts +2 -1
  82. package/types/reply.d.ts +2 -2
  83. package/types/request.d.ts +3 -3
  84. package/types/route.d.ts +5 -5
  85. package/test/listen.test.js +0 -427
  86. package/test/plugin.test.js +0 -1275
  87. package/test/route.test.js +0 -1762
  88. package/test/serial/logger.0.test.js +0 -866
  89. package/test/serial/logger.1.test.js +0 -862
  90. package/test/stream.test.js +0 -816
  91. /package/test/{serial → logger}/tap-parallel-not-ok +0 -0
@@ -1,816 +0,0 @@
1
- 'use strict'
2
-
3
- const t = require('tap')
4
- const test = t.test
5
- const proxyquire = require('proxyquire')
6
- const sget = require('simple-get').concat
7
- const fs = require('node:fs')
8
- const resolve = require('node:path').resolve
9
- const zlib = require('node:zlib')
10
- const pipeline = require('node:stream').pipeline
11
- const Fastify = require('..')
12
- const errors = require('http-errors')
13
- const JSONStream = require('JSONStream')
14
- const send = require('send')
15
- const Readable = require('node:stream').Readable
16
- const split = require('split2')
17
- const semver = require('semver')
18
- const { kDisableRequestLogging } = require('../lib/symbols.js')
19
-
20
- function getUrl (app) {
21
- const { address, port } = app.server.address()
22
- if (address === '::1') {
23
- return `http://[${address}]:${port}`
24
- } else {
25
- return `http://${address}:${port}`
26
- }
27
- }
28
-
29
- test('should respond with a stream', t => {
30
- t.plan(6)
31
- const fastify = Fastify()
32
-
33
- fastify.get('/', function (req, reply) {
34
- const stream = fs.createReadStream(__filename, 'utf8')
35
- reply.code(200).send(stream)
36
- })
37
-
38
- fastify.listen({ port: 0 }, err => {
39
- t.error(err)
40
- t.teardown(() => { fastify.close() })
41
-
42
- sget(`http://localhost:${fastify.server.address().port}`, function (err, response, data) {
43
- t.error(err)
44
- t.equal(response.headers['content-type'], undefined)
45
- t.equal(response.statusCode, 200)
46
-
47
- fs.readFile(__filename, (err, expected) => {
48
- t.error(err)
49
- t.equal(expected.toString(), data.toString())
50
- })
51
- })
52
- })
53
- })
54
-
55
- test('should respond with a stream (error)', t => {
56
- t.plan(3)
57
- const fastify = Fastify()
58
-
59
- fastify.get('/error', function (req, reply) {
60
- const stream = fs.createReadStream('not-existing-file', 'utf8')
61
- reply.code(200).send(stream)
62
- })
63
-
64
- fastify.listen({ port: 0 }, err => {
65
- t.error(err)
66
- t.teardown(() => { fastify.close() })
67
-
68
- sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
69
- t.error(err)
70
- t.equal(response.statusCode, 500)
71
- })
72
- })
73
- })
74
-
75
- test('should trigger the onSend hook', t => {
76
- t.plan(4)
77
- const fastify = Fastify()
78
-
79
- fastify.get('/', (req, reply) => {
80
- reply.send(fs.createReadStream(__filename, 'utf8'))
81
- })
82
-
83
- fastify.addHook('onSend', (req, reply, payload, done) => {
84
- t.ok(payload._readableState)
85
- reply.header('Content-Type', 'application/javascript')
86
- done()
87
- })
88
-
89
- fastify.inject({
90
- url: '/'
91
- }, (err, res) => {
92
- t.error(err)
93
- t.equal(res.headers['content-type'], 'application/javascript')
94
- t.equal(res.payload, fs.readFileSync(__filename, 'utf8'))
95
- fastify.close()
96
- })
97
- })
98
-
99
- test('should trigger the onSend hook only twice if pumping the stream fails, first with the stream, second with the serialized error', t => {
100
- t.plan(5)
101
- const fastify = Fastify()
102
-
103
- fastify.get('/', (req, reply) => {
104
- reply.send(fs.createReadStream('not-existing-file', 'utf8'))
105
- })
106
-
107
- let counter = 0
108
- fastify.addHook('onSend', (req, reply, payload, done) => {
109
- if (counter === 0) {
110
- t.ok(payload._readableState)
111
- } else if (counter === 1) {
112
- const error = JSON.parse(payload)
113
- t.equal(error.statusCode, 500)
114
- }
115
- counter++
116
- done()
117
- })
118
-
119
- fastify.listen({ port: 0 }, err => {
120
- t.error(err)
121
- t.teardown(() => { fastify.close() })
122
-
123
- sget(`http://localhost:${fastify.server.address().port}`, function (err, response) {
124
- t.error(err)
125
- t.equal(response.statusCode, 500)
126
- })
127
- })
128
- })
129
-
130
- test('onSend hook stream', t => {
131
- t.plan(4)
132
- const fastify = Fastify()
133
-
134
- fastify.get('/', function (req, reply) {
135
- reply.send({ hello: 'world' })
136
- })
137
-
138
- fastify.addHook('onSend', (req, reply, payload, done) => {
139
- const gzStream = zlib.createGzip()
140
-
141
- reply.header('Content-Encoding', 'gzip')
142
- pipeline(
143
- fs.createReadStream(resolve(process.cwd() + '/test/stream.test.js'), 'utf8'),
144
- gzStream,
145
- t.error
146
- )
147
- done(null, gzStream)
148
- })
149
-
150
- fastify.inject({
151
- url: '/',
152
- method: 'GET'
153
- }, (err, res) => {
154
- t.error(err)
155
- t.equal(res.headers['content-encoding'], 'gzip')
156
- const file = fs.readFileSync(resolve(process.cwd() + '/test/stream.test.js'), 'utf8')
157
- const payload = zlib.gunzipSync(res.rawPayload)
158
- t.equal(payload.toString('utf-8'), file)
159
- fastify.close()
160
- })
161
- })
162
-
163
- test('onSend hook stream should work even if payload is not a proper stream', t => {
164
- t.plan(1)
165
-
166
- const reply = proxyquire('../lib/reply', {
167
- 'node:stream': {
168
- finished: (...args) => {
169
- if (args.length === 2) { args[1](new Error('test-error')) }
170
- }
171
- }
172
- })
173
- const Fastify = proxyquire('..', {
174
- './lib/reply.js': reply
175
- })
176
- const spyLogger = {
177
- fatal: () => { },
178
- error: () => { },
179
- warn: (message) => {
180
- t.equal(message, 'stream payload does not end properly')
181
- fastify.close()
182
- },
183
- info: () => { },
184
- debug: () => { },
185
- trace: () => { },
186
- child: () => { return spyLogger }
187
- }
188
-
189
- const fastify = Fastify({ logger: spyLogger })
190
- fastify.get('/', function (req, reply) {
191
- reply.send({ hello: 'world' })
192
- })
193
- fastify.addHook('onSend', (req, reply, payload, done) => {
194
- const fakeStream = { pipe: () => { } }
195
- done(null, fakeStream)
196
- })
197
-
198
- fastify.inject({
199
- url: '/',
200
- method: 'GET'
201
- })
202
- })
203
-
204
- test('onSend hook stream should work on payload with "close" ending function', t => {
205
- t.plan(1)
206
-
207
- const reply = proxyquire('../lib/reply', {
208
- 'node:stream': {
209
- finished: (...args) => {
210
- if (args.length === 2) { args[1](new Error('test-error')) }
211
- }
212
- }
213
- })
214
- const Fastify = proxyquire('..', {
215
- './lib/reply.js': reply
216
- })
217
-
218
- const fastify = Fastify({ logger: false })
219
- fastify.get('/', function (req, reply) {
220
- reply.send({ hello: 'world' })
221
- })
222
- fastify.addHook('onSend', (req, reply, payload, done) => {
223
- const fakeStream = {
224
- pipe: () => { },
225
- close: (cb) => {
226
- cb()
227
- t.pass()
228
- }
229
- }
230
- done(null, fakeStream)
231
- })
232
-
233
- fastify.inject({
234
- url: '/',
235
- method: 'GET'
236
- })
237
- })
238
-
239
- test('Destroying streams prematurely', t => {
240
- t.plan(6)
241
-
242
- let fastify = null
243
- const logStream = split(JSON.parse)
244
- try {
245
- fastify = Fastify({
246
- logger: {
247
- stream: logStream,
248
- level: 'info'
249
- }
250
- })
251
- } catch (e) {
252
- t.fail()
253
- }
254
- const stream = require('node:stream')
255
- const http = require('node:http')
256
-
257
- // Test that "premature close" errors are logged with level warn
258
- logStream.on('data', line => {
259
- if (line.res) {
260
- t.equal(line.msg, 'stream closed prematurely')
261
- t.equal(line.level, 30)
262
- }
263
- })
264
-
265
- fastify.get('/', function (request, reply) {
266
- t.pass('Received request')
267
-
268
- let sent = false
269
- const reallyLongStream = new stream.Readable({
270
- read: function () {
271
- if (!sent) {
272
- this.push(Buffer.from('hello\n'))
273
- }
274
- sent = true
275
- }
276
- })
277
-
278
- reply.send(reallyLongStream)
279
- })
280
-
281
- fastify.listen({ port: 0 }, err => {
282
- t.error(err)
283
- t.teardown(() => { fastify.close() })
284
-
285
- const port = fastify.server.address().port
286
-
287
- http.get(`http://localhost:${port}`, function (response) {
288
- t.equal(response.statusCode, 200)
289
- response.on('readable', function () {
290
- response.destroy()
291
- })
292
-
293
- // Node bug? Node never emits 'close' here.
294
- response.on('aborted', function () {
295
- t.pass('Response closed')
296
- })
297
- })
298
- })
299
- })
300
-
301
- test('Destroying streams prematurely should call close method', t => {
302
- t.plan(7)
303
-
304
- let fastify = null
305
- const logStream = split(JSON.parse)
306
- try {
307
- fastify = Fastify({
308
- logger: {
309
- stream: logStream,
310
- level: 'info'
311
- }
312
- })
313
- } catch (e) {
314
- t.fail()
315
- }
316
- const stream = require('node:stream')
317
- const http = require('node:http')
318
-
319
- // Test that "premature close" errors are logged with level warn
320
- logStream.on('data', line => {
321
- if (line.res) {
322
- t.equal(line.msg, 'stream closed prematurely')
323
- t.equal(line.level, 30)
324
- }
325
- })
326
-
327
- fastify.get('/', function (request, reply) {
328
- t.pass('Received request')
329
-
330
- let sent = false
331
- const reallyLongStream = new stream.Readable({
332
- read: function () {
333
- if (!sent) {
334
- this.push(Buffer.from('hello\n'))
335
- }
336
- sent = true
337
- }
338
- })
339
- reallyLongStream.destroy = undefined
340
- reallyLongStream.close = () => t.ok('called')
341
- reply.send(reallyLongStream)
342
- })
343
-
344
- fastify.listen({ port: 0 }, err => {
345
- t.error(err)
346
- t.teardown(() => { fastify.close() })
347
-
348
- const port = fastify.server.address().port
349
-
350
- http.get(`http://localhost:${port}`, function (response) {
351
- t.equal(response.statusCode, 200)
352
- response.on('readable', function () {
353
- response.destroy()
354
- })
355
- // Node bug? Node never emits 'close' here.
356
- response.on('aborted', function () {
357
- t.pass('Response closed')
358
- })
359
- })
360
- })
361
- })
362
-
363
- test('Destroying streams prematurely should call close method when destroy is not a function', t => {
364
- t.plan(7)
365
-
366
- let fastify = null
367
- const logStream = split(JSON.parse)
368
- try {
369
- fastify = Fastify({
370
- logger: {
371
- stream: logStream,
372
- level: 'info'
373
- }
374
- })
375
- } catch (e) {
376
- t.fail()
377
- }
378
- const stream = require('node:stream')
379
- const http = require('node:http')
380
-
381
- // Test that "premature close" errors are logged with level warn
382
- logStream.on('data', line => {
383
- if (line.res) {
384
- t.equal(line.msg, 'stream closed prematurely')
385
- t.equal(line.level, 30)
386
- }
387
- })
388
-
389
- fastify.get('/', function (request, reply) {
390
- t.pass('Received request')
391
-
392
- let sent = false
393
- const reallyLongStream = new stream.Readable({
394
- read: function () {
395
- if (!sent) {
396
- this.push(Buffer.from('hello\n'))
397
- }
398
- sent = true
399
- }
400
- })
401
- reallyLongStream.destroy = true
402
- reallyLongStream.close = () => t.ok('called')
403
- reply.send(reallyLongStream)
404
- })
405
-
406
- fastify.listen({ port: 0 }, err => {
407
- t.error(err)
408
- t.teardown(() => { fastify.close() })
409
-
410
- const port = fastify.server.address().port
411
-
412
- http.get(`http://localhost:${port}`, function (response) {
413
- t.equal(response.statusCode, 200)
414
- response.on('readable', function () {
415
- response.destroy()
416
- })
417
- // Node bug? Node never emits 'close' here.
418
- response.on('aborted', function () {
419
- t.pass('Response closed')
420
- })
421
- })
422
- })
423
- })
424
-
425
- test('Destroying streams prematurely should call abort method', t => {
426
- t.plan(7)
427
-
428
- let fastify = null
429
- const logStream = split(JSON.parse)
430
- try {
431
- fastify = Fastify({
432
- logger: {
433
- stream: logStream,
434
- level: 'info'
435
- }
436
- })
437
- } catch (e) {
438
- t.fail()
439
- }
440
- const stream = require('node:stream')
441
- const http = require('node:http')
442
-
443
- // Test that "premature close" errors are logged with level warn
444
- logStream.on('data', line => {
445
- if (line.res) {
446
- t.equal(line.msg, 'stream closed prematurely')
447
- t.equal(line.level, 30)
448
- }
449
- })
450
-
451
- fastify.get('/', function (request, reply) {
452
- t.pass('Received request')
453
-
454
- let sent = false
455
- const reallyLongStream = new stream.Readable({
456
- read: function () {
457
- if (!sent) {
458
- this.push(Buffer.from('hello\n'))
459
- }
460
- sent = true
461
- }
462
- })
463
- reallyLongStream.destroy = undefined
464
- reallyLongStream.close = undefined
465
- reallyLongStream.abort = () => t.ok('called')
466
- reply.send(reallyLongStream)
467
- })
468
-
469
- fastify.listen({ port: 0 }, err => {
470
- t.error(err)
471
- t.teardown(() => { fastify.close() })
472
-
473
- const port = fastify.server.address().port
474
-
475
- http.get(`http://localhost:${port}`, function (response) {
476
- t.equal(response.statusCode, 200)
477
- response.on('readable', function () {
478
- response.destroy()
479
- })
480
- // Node bug? Node never emits 'close' here.
481
- response.on('aborted', function () {
482
- t.pass('Response closed')
483
- })
484
- })
485
- })
486
- })
487
-
488
- test('Destroying streams prematurely, log is disabled', t => {
489
- t.plan(4)
490
-
491
- let fastify = null
492
- try {
493
- fastify = Fastify({
494
- logger: false
495
- })
496
- } catch (e) {
497
- t.fail()
498
- }
499
- const stream = require('node:stream')
500
- const http = require('node:http')
501
-
502
- fastify.get('/', function (request, reply) {
503
- reply.log[kDisableRequestLogging] = true
504
-
505
- let sent = false
506
- const reallyLongStream = new stream.Readable({
507
- read: function () {
508
- if (!sent) {
509
- this.push(Buffer.from('hello\n'))
510
- }
511
- sent = true
512
- }
513
- })
514
- reallyLongStream.destroy = true
515
- reallyLongStream.close = () => t.ok('called')
516
- reply.send(reallyLongStream)
517
- })
518
-
519
- fastify.listen({ port: 0 }, err => {
520
- t.error(err)
521
- t.teardown(() => { fastify.close() })
522
-
523
- const port = fastify.server.address().port
524
-
525
- http.get(`http://localhost:${port}`, function (response) {
526
- t.equal(response.statusCode, 200)
527
- response.on('readable', function () {
528
- response.destroy()
529
- })
530
- // Node bug? Node never emits 'close' here.
531
- response.on('aborted', function () {
532
- t.pass('Response closed')
533
- })
534
- })
535
- })
536
- })
537
-
538
- test('should respond with a stream1', t => {
539
- t.plan(5)
540
- const fastify = Fastify()
541
-
542
- fastify.get('/', function (req, reply) {
543
- const stream = JSONStream.stringify()
544
- reply.code(200).type('application/json').send(stream)
545
- stream.write({ hello: 'world' })
546
- stream.end({ a: 42 })
547
- })
548
-
549
- fastify.listen({ port: 0 }, err => {
550
- t.error(err)
551
- t.teardown(() => { fastify.close() })
552
-
553
- sget(`http://localhost:${fastify.server.address().port}`, function (err, response, body) {
554
- t.error(err)
555
- t.equal(response.headers['content-type'], 'application/json')
556
- t.equal(response.statusCode, 200)
557
- t.same(JSON.parse(body), [{ hello: 'world' }, { a: 42 }])
558
- })
559
- })
560
- })
561
-
562
- test('return a 404 if the stream emits a 404 error', t => {
563
- t.plan(5)
564
-
565
- const fastify = Fastify()
566
-
567
- fastify.get('/', function (request, reply) {
568
- t.pass('Received request')
569
-
570
- const reallyLongStream = new Readable({
571
- read: function () {
572
- setImmediate(() => {
573
- this.emit('error', new errors.NotFound())
574
- })
575
- }
576
- })
577
-
578
- reply.send(reallyLongStream)
579
- })
580
-
581
- fastify.listen({ port: 0 }, err => {
582
- t.error(err)
583
- t.teardown(() => { fastify.close() })
584
-
585
- const port = fastify.server.address().port
586
-
587
- sget(`http://localhost:${port}`, function (err, response) {
588
- t.error(err)
589
- t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
590
- t.equal(response.statusCode, 404)
591
- })
592
- })
593
- })
594
-
595
- test('should support send module 200 and 404', { skip: semver.gte(process.versions.node, '17.0.0') }, t => {
596
- t.plan(8)
597
- const fastify = Fastify()
598
-
599
- fastify.get('/', function (req, reply) {
600
- const stream = send(req.raw, __filename)
601
- reply.code(200).send(stream)
602
- })
603
-
604
- fastify.get('/error', function (req, reply) {
605
- const stream = send(req.raw, 'non-existing-file')
606
- reply.code(200).send(stream)
607
- })
608
-
609
- fastify.listen({ port: 0 }, err => {
610
- t.error(err)
611
- t.teardown(() => { fastify.close() })
612
-
613
- const url = getUrl(fastify)
614
-
615
- sget(url, function (err, response, data) {
616
- t.error(err)
617
- t.equal(response.headers['content-type'], 'application/javascript; charset=UTF-8')
618
- t.equal(response.statusCode, 200)
619
-
620
- fs.readFile(__filename, (err, expected) => {
621
- t.error(err)
622
- t.equal(expected.toString(), data.toString())
623
- })
624
- })
625
-
626
- sget(url + '/error', function (err, response) {
627
- t.error(err)
628
- t.equal(response.statusCode, 404)
629
- })
630
- })
631
- })
632
-
633
- test('should destroy stream when response is ended', t => {
634
- t.plan(4)
635
- const stream = require('node:stream')
636
- const fastify = Fastify()
637
-
638
- fastify.get('/error', function (req, reply) {
639
- const reallyLongStream = new stream.Readable({
640
- read: function () { },
641
- destroy: function (err, callback) {
642
- t.ok('called')
643
- callback(err)
644
- }
645
- })
646
- reply.code(200).send(reallyLongStream)
647
- reply.raw.end(Buffer.from('hello\n'))
648
- })
649
-
650
- fastify.listen({ port: 0 }, err => {
651
- t.error(err)
652
- t.teardown(() => { fastify.close() })
653
-
654
- sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
655
- t.error(err)
656
- t.equal(response.statusCode, 200)
657
- })
658
- })
659
- })
660
-
661
- test('should mark reply as sent before pumping the payload stream into response for async route handler', t => {
662
- t.plan(3)
663
-
664
- const handleRequest = proxyquire('../lib/handleRequest', {
665
- './wrapThenable': (thenable, reply) => {
666
- thenable.then(function (payload) {
667
- t.equal(reply.sent, true)
668
- })
669
- }
670
- })
671
-
672
- const route = proxyquire('../lib/route', {
673
- './handleRequest': handleRequest
674
- })
675
-
676
- const Fastify = proxyquire('..', {
677
- './lib/route': route
678
- })
679
-
680
- const fastify = Fastify()
681
-
682
- fastify.get('/', async function (req, reply) {
683
- const stream = fs.createReadStream(__filename, 'utf8')
684
- return reply.code(200).send(stream)
685
- })
686
-
687
- fastify.inject({
688
- url: '/',
689
- method: 'GET'
690
- }, (err, res) => {
691
- t.error(err)
692
- t.equal(res.payload, fs.readFileSync(__filename, 'utf8'))
693
- fastify.close()
694
- })
695
- })
696
-
697
- test('reply.send handles aborted requests', t => {
698
- t.plan(2)
699
-
700
- const spyLogger = {
701
- level: 'error',
702
- fatal: () => { },
703
- error: () => {
704
- t.fail('should not log an error')
705
- },
706
- warn: () => { },
707
- info: () => { },
708
- debug: () => { },
709
- trace: () => { },
710
- child: () => { return spyLogger }
711
- }
712
- const fastify = Fastify({
713
- logger: spyLogger
714
- })
715
-
716
- fastify.get('/', (req, reply) => {
717
- setTimeout(() => {
718
- const stream = new Readable({
719
- read: function () {
720
- this.push(null)
721
- }
722
- })
723
- reply.send(stream)
724
- }, 6)
725
- })
726
-
727
- fastify.listen({ port: 0 }, err => {
728
- t.error(err)
729
- t.teardown(() => { fastify.close() })
730
-
731
- const port = fastify.server.address().port
732
- const http = require('node:http')
733
- const req = http.get(`http://localhost:${port}`)
734
- .on('error', (err) => {
735
- t.equal(err.code, 'ECONNRESET')
736
- fastify.close()
737
- })
738
-
739
- setTimeout(() => {
740
- req.abort()
741
- }, 1)
742
- })
743
- })
744
-
745
- test('request terminated should not crash fastify', t => {
746
- t.plan(10)
747
-
748
- const spyLogger = {
749
- level: 'error',
750
- fatal: () => { },
751
- error: () => {
752
- t.fail('should not log an error')
753
- },
754
- warn: () => { },
755
- info: () => { },
756
- debug: () => { },
757
- trace: () => { },
758
- child: () => { return spyLogger }
759
- }
760
- const fastify = Fastify({
761
- logger: spyLogger
762
- })
763
-
764
- fastify.get('/', async (req, reply) => {
765
- const stream = new Readable()
766
- stream._read = () => { }
767
- reply.header('content-type', 'text/html; charset=utf-8')
768
- reply.header('transfer-encoding', 'chunked')
769
- stream.push('<h1>HTML</h1>')
770
-
771
- reply.send(stream)
772
-
773
- await new Promise((resolve) => { setTimeout(resolve, 100).unref() })
774
-
775
- stream.push('<h1>should disply on second stream</h1>')
776
- stream.push(null)
777
- return reply
778
- })
779
-
780
- fastify.listen({ port: 0 }, err => {
781
- t.error(err)
782
- t.teardown(() => { fastify.close() })
783
-
784
- const port = fastify.server.address().port
785
- const http = require('node:http')
786
- const req = http.get(`http://localhost:${port}`, function (res) {
787
- const { statusCode, headers } = res
788
- t.equal(statusCode, 200)
789
- t.equal(headers['content-type'], 'text/html; charset=utf-8')
790
- t.equal(headers['transfer-encoding'], 'chunked')
791
- res.on('data', function (chunk) {
792
- t.equal(chunk.toString(), '<h1>HTML</h1>')
793
- })
794
-
795
- setTimeout(() => {
796
- req.destroy()
797
-
798
- // the server is not crash, we can connect it
799
- http.get(`http://localhost:${port}`, function (res) {
800
- const { statusCode, headers } = res
801
- t.equal(statusCode, 200)
802
- t.equal(headers['content-type'], 'text/html; charset=utf-8')
803
- t.equal(headers['transfer-encoding'], 'chunked')
804
- let payload = ''
805
- res.on('data', function (chunk) {
806
- payload += chunk.toString()
807
- })
808
- res.on('end', function () {
809
- t.equal(payload, '<h1>HTML</h1><h1>should disply on second stream</h1>')
810
- t.pass('should end properly')
811
- })
812
- })
813
- }, 1)
814
- })
815
- })
816
- })