fastify 5.3.1 → 5.3.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.
- package/.vscode/settings.json +15 -15
- package/docs/Guides/Benchmarking.md +1 -1
- package/docs/Guides/Ecosystem.md +7 -2
- package/docs/Guides/Serverless.md +28 -69
- package/docs/Reference/Errors.md +0 -2
- package/docs/Reference/Server.md +17 -1
- package/eslint.config.js +17 -9
- package/fastify.js +7 -3
- package/lib/decorate.js +2 -2
- package/lib/errors.js +0 -8
- package/lib/logger-factory.js +1 -1
- package/lib/logger-pino.js +2 -2
- package/lib/reply.js +2 -2
- package/lib/request.js +1 -1
- package/lib/server.js +30 -51
- package/lib/validation.js +1 -1
- package/package.json +4 -4
- package/test/close-pipelining.test.js +5 -4
- package/test/decorator.test.js +422 -341
- package/test/helper.js +107 -69
- package/test/hooks.on-listen.test.js +255 -239
- package/test/hooks.on-ready.test.js +110 -92
- package/test/inject.test.js +114 -97
- package/test/input-validation.js +63 -53
- package/test/internals/errors.test.js +1 -11
- package/test/internals/hooks.test.js +17 -0
- package/test/issue-4959.test.js +2 -2
- package/test/logger/response.test.js +19 -20
- package/test/options.error-handler.test.js +1 -1
- package/test/options.test.js +1 -1
- package/test/output-validation.test.js +49 -70
- package/test/patch.error-handler.test.js +1 -1
- package/test/patch.test.js +1 -1
- package/test/plugin.1.test.js +71 -60
- package/test/promises.test.js +36 -30
- package/test/put.error-handler.test.js +1 -1
- package/test/put.test.js +1 -1
- package/test/reply-error.test.js +169 -148
- package/test/reply-trailers.test.js +119 -108
- package/test/schema-feature.test.js +309 -238
- package/test/schema-validation.test.js +74 -16
- package/test/stream.1.test.js +30 -27
- package/test/stream.2.test.js +20 -10
- package/test/stream.3.test.js +37 -31
- package/test/types/errors.test-d.ts +0 -1
- package/test/types/plugin.test-d.ts +1 -1
- package/test/types/register.test-d.ts +1 -1
- package/test/use-semicolon-delimiter.test.js +1 -1
- package/types/errors.d.ts +0 -1
- package/test/http2/missing-http2-module.test.js +0 -17
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
4
|
const Fastify = require('..')
|
|
5
|
+
const { request } = require('undici')
|
|
5
6
|
|
|
6
7
|
const AJV = require('ajv')
|
|
7
8
|
const Schema = require('fluent-json-schema')
|
|
@@ -1342,8 +1343,6 @@ test('Schema validation when no content type is provided', async t => {
|
|
|
1342
1343
|
})
|
|
1343
1344
|
|
|
1344
1345
|
test('Schema validation will not be bypass by different content type', async t => {
|
|
1345
|
-
t.plan(8)
|
|
1346
|
-
|
|
1347
1346
|
const fastify = Fastify()
|
|
1348
1347
|
|
|
1349
1348
|
fastify.post('/', {
|
|
@@ -1365,58 +1364,117 @@ test('Schema validation will not be bypass by different content type', async t =
|
|
|
1365
1364
|
}
|
|
1366
1365
|
}, async () => 'ok')
|
|
1367
1366
|
|
|
1368
|
-
await fastify.
|
|
1367
|
+
await fastify.listen({ port: 0 })
|
|
1368
|
+
t.teardown(() => fastify.close())
|
|
1369
|
+
const address = fastify.listeningOrigin
|
|
1369
1370
|
|
|
1370
|
-
const correct1 = await
|
|
1371
|
+
const correct1 = await request(address, {
|
|
1371
1372
|
method: 'POST',
|
|
1372
1373
|
url: '/',
|
|
1373
1374
|
headers: {
|
|
1374
1375
|
'content-type': 'application/json'
|
|
1375
1376
|
},
|
|
1376
|
-
body: { foo: 'string' }
|
|
1377
|
+
body: JSON.stringify({ foo: 'string' })
|
|
1377
1378
|
})
|
|
1378
1379
|
t.equal(correct1.statusCode, 200)
|
|
1380
|
+
await correct1.body.dump()
|
|
1379
1381
|
|
|
1380
|
-
const correct2 = await
|
|
1382
|
+
const correct2 = await request(address, {
|
|
1381
1383
|
method: 'POST',
|
|
1382
1384
|
url: '/',
|
|
1383
1385
|
headers: {
|
|
1384
1386
|
'content-type': 'application/json; charset=utf-8'
|
|
1385
1387
|
},
|
|
1386
|
-
body: { foo: 'string' }
|
|
1388
|
+
body: JSON.stringify({ foo: 'string' })
|
|
1387
1389
|
})
|
|
1388
1390
|
t.equal(correct2.statusCode, 200)
|
|
1391
|
+
await correct2.body.dump()
|
|
1389
1392
|
|
|
1390
|
-
const invalid1 = await
|
|
1393
|
+
const invalid1 = await request(address, {
|
|
1391
1394
|
method: 'POST',
|
|
1392
1395
|
url: '/',
|
|
1393
1396
|
headers: {
|
|
1394
1397
|
'content-type': 'application/json ;'
|
|
1395
1398
|
},
|
|
1396
|
-
body: { invalid: 'string' }
|
|
1399
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1397
1400
|
})
|
|
1398
1401
|
t.equal(invalid1.statusCode, 400)
|
|
1399
|
-
t.equal(invalid1.json().code, 'FST_ERR_VALIDATION')
|
|
1402
|
+
t.equal((await invalid1.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1400
1403
|
|
|
1401
|
-
const invalid2 = await
|
|
1404
|
+
const invalid2 = await request(address, {
|
|
1402
1405
|
method: 'POST',
|
|
1403
1406
|
url: '/',
|
|
1404
1407
|
headers: {
|
|
1405
1408
|
'content-type': 'ApPlIcAtIoN/JsOn;'
|
|
1406
1409
|
},
|
|
1407
|
-
body: { invalid: 'string' }
|
|
1410
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1408
1411
|
})
|
|
1409
1412
|
t.equal(invalid2.statusCode, 400)
|
|
1410
|
-
t.equal(invalid2.json().code, 'FST_ERR_VALIDATION')
|
|
1413
|
+
t.equal((await invalid2.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1411
1414
|
|
|
1412
|
-
const invalid3 = await
|
|
1415
|
+
const invalid3 = await request(address, {
|
|
1413
1416
|
method: 'POST',
|
|
1414
1417
|
url: '/',
|
|
1415
1418
|
headers: {
|
|
1416
1419
|
'content-type': 'ApPlIcAtIoN/JsOn ;'
|
|
1417
1420
|
},
|
|
1418
|
-
body: { invalid: 'string' }
|
|
1421
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1419
1422
|
})
|
|
1420
1423
|
t.equal(invalid3.statusCode, 400)
|
|
1421
|
-
t.equal(invalid3.json().code, 'FST_ERR_VALIDATION')
|
|
1424
|
+
t.equal((await invalid3.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1425
|
+
|
|
1426
|
+
const invalid4 = await request(address, {
|
|
1427
|
+
method: 'POST',
|
|
1428
|
+
url: '/',
|
|
1429
|
+
headers: {
|
|
1430
|
+
'content-type': 'ApPlIcAtIoN/JsOn foo;'
|
|
1431
|
+
},
|
|
1432
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1433
|
+
})
|
|
1434
|
+
t.equal(invalid4.statusCode, 400)
|
|
1435
|
+
t.equal((await invalid4.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1436
|
+
|
|
1437
|
+
const invalid5 = await request(address, {
|
|
1438
|
+
method: 'POST',
|
|
1439
|
+
url: '/',
|
|
1440
|
+
headers: {
|
|
1441
|
+
'content-type': 'ApPlIcAtIoN/JsOn \tfoo;'
|
|
1442
|
+
},
|
|
1443
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1444
|
+
})
|
|
1445
|
+
t.equal(invalid5.statusCode, 400)
|
|
1446
|
+
t.equal((await invalid5.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1447
|
+
|
|
1448
|
+
const invalid6 = await request(address, {
|
|
1449
|
+
method: 'POST',
|
|
1450
|
+
url: '/',
|
|
1451
|
+
headers: {
|
|
1452
|
+
'content-type': 'ApPlIcAtIoN/JsOn\t foo;'
|
|
1453
|
+
},
|
|
1454
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1455
|
+
})
|
|
1456
|
+
t.equal(invalid6.statusCode, 415)
|
|
1457
|
+
t.equal((await invalid6.body.json()).code, 'FST_ERR_CTP_INVALID_MEDIA_TYPE')
|
|
1458
|
+
|
|
1459
|
+
const invalid7 = await request(address, {
|
|
1460
|
+
method: 'POST',
|
|
1461
|
+
url: '/',
|
|
1462
|
+
headers: {
|
|
1463
|
+
'content-type': 'ApPlIcAtIoN/JsOn \t'
|
|
1464
|
+
},
|
|
1465
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1466
|
+
})
|
|
1467
|
+
t.equal(invalid7.statusCode, 400)
|
|
1468
|
+
t.equal((await invalid7.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1469
|
+
|
|
1470
|
+
const invalid8 = await request(address, {
|
|
1471
|
+
method: 'POST',
|
|
1472
|
+
url: '/',
|
|
1473
|
+
headers: {
|
|
1474
|
+
'content-type': 'ApPlIcAtIoN/JsOn\t'
|
|
1475
|
+
},
|
|
1476
|
+
body: JSON.stringify({ invalid: 'string' })
|
|
1477
|
+
})
|
|
1478
|
+
t.equal(invalid8.statusCode, 400)
|
|
1479
|
+
t.equal((await invalid8.body.json()).code, 'FST_ERR_VALIDATION')
|
|
1422
1480
|
})
|
package/test/stream.1.test.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const test = t.test
|
|
3
|
+
const { test } = require('node:test')
|
|
5
4
|
const sget = require('simple-get').concat
|
|
6
5
|
const fs = require('node:fs')
|
|
7
6
|
const Fastify = require('../fastify')
|
|
8
7
|
|
|
9
|
-
test('should respond with a stream', t => {
|
|
8
|
+
test('should respond with a stream', (t, testDone) => {
|
|
10
9
|
t.plan(6)
|
|
11
10
|
const fastify = Fastify()
|
|
12
11
|
|
|
@@ -16,23 +15,24 @@ test('should respond with a stream', t => {
|
|
|
16
15
|
})
|
|
17
16
|
|
|
18
17
|
fastify.listen({ port: 0 }, err => {
|
|
19
|
-
t.
|
|
20
|
-
t.
|
|
18
|
+
t.assert.ifError(err)
|
|
19
|
+
t.after(() => { fastify.close() })
|
|
21
20
|
|
|
22
21
|
sget(`http://localhost:${fastify.server.address().port}`, function (err, response, data) {
|
|
23
|
-
t.
|
|
24
|
-
t.
|
|
25
|
-
t.
|
|
22
|
+
t.assert.ifError(err)
|
|
23
|
+
t.assert.strictEqual(response.headers['content-type'], undefined)
|
|
24
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
26
25
|
|
|
27
26
|
fs.readFile(__filename, (err, expected) => {
|
|
28
|
-
t.
|
|
29
|
-
t.
|
|
27
|
+
t.assert.ifError(err)
|
|
28
|
+
t.assert.strictEqual(expected.toString(), data.toString())
|
|
29
|
+
testDone()
|
|
30
30
|
})
|
|
31
31
|
})
|
|
32
32
|
})
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
test('should respond with a stream (error)', t => {
|
|
35
|
+
test('should respond with a stream (error)', (t, testDone) => {
|
|
36
36
|
t.plan(3)
|
|
37
37
|
const fastify = Fastify()
|
|
38
38
|
|
|
@@ -42,17 +42,18 @@ test('should respond with a stream (error)', t => {
|
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
fastify.listen({ port: 0 }, err => {
|
|
45
|
-
t.
|
|
46
|
-
t.
|
|
45
|
+
t.assert.ifError(err)
|
|
46
|
+
t.after(() => { fastify.close() })
|
|
47
47
|
|
|
48
48
|
sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
|
|
49
|
-
t.
|
|
50
|
-
t.
|
|
49
|
+
t.assert.ifError(err)
|
|
50
|
+
t.assert.strictEqual(response.statusCode, 500)
|
|
51
|
+
testDone()
|
|
51
52
|
})
|
|
52
53
|
})
|
|
53
54
|
})
|
|
54
55
|
|
|
55
|
-
test('should trigger the onSend hook', t => {
|
|
56
|
+
test('should trigger the onSend hook', (t, testDone) => {
|
|
56
57
|
t.plan(4)
|
|
57
58
|
const fastify = Fastify()
|
|
58
59
|
|
|
@@ -61,7 +62,7 @@ test('should trigger the onSend hook', t => {
|
|
|
61
62
|
})
|
|
62
63
|
|
|
63
64
|
fastify.addHook('onSend', (req, reply, payload, done) => {
|
|
64
|
-
t.ok(payload._readableState)
|
|
65
|
+
t.assert.ok(payload._readableState)
|
|
65
66
|
reply.header('Content-Type', 'application/javascript')
|
|
66
67
|
done()
|
|
67
68
|
})
|
|
@@ -69,14 +70,15 @@ test('should trigger the onSend hook', t => {
|
|
|
69
70
|
fastify.inject({
|
|
70
71
|
url: '/'
|
|
71
72
|
}, (err, res) => {
|
|
72
|
-
t.
|
|
73
|
-
t.
|
|
74
|
-
t.
|
|
73
|
+
t.assert.ifError(err)
|
|
74
|
+
t.assert.strictEqual(res.headers['content-type'], 'application/javascript')
|
|
75
|
+
t.assert.strictEqual(res.payload, fs.readFileSync(__filename, 'utf8'))
|
|
75
76
|
fastify.close()
|
|
77
|
+
testDone()
|
|
76
78
|
})
|
|
77
79
|
})
|
|
78
80
|
|
|
79
|
-
test('should trigger the onSend hook only twice if pumping the stream fails, first with the stream, second with the serialized error', t => {
|
|
81
|
+
test('should trigger the onSend hook only twice if pumping the stream fails, first with the stream, second with the serialized error', (t, testDone) => {
|
|
80
82
|
t.plan(5)
|
|
81
83
|
const fastify = Fastify()
|
|
82
84
|
|
|
@@ -87,22 +89,23 @@ test('should trigger the onSend hook only twice if pumping the stream fails, fir
|
|
|
87
89
|
let counter = 0
|
|
88
90
|
fastify.addHook('onSend', (req, reply, payload, done) => {
|
|
89
91
|
if (counter === 0) {
|
|
90
|
-
t.ok(payload._readableState)
|
|
92
|
+
t.assert.ok(payload._readableState)
|
|
91
93
|
} else if (counter === 1) {
|
|
92
94
|
const error = JSON.parse(payload)
|
|
93
|
-
t.
|
|
95
|
+
t.assert.strictEqual(error.statusCode, 500)
|
|
94
96
|
}
|
|
95
97
|
counter++
|
|
96
98
|
done()
|
|
97
99
|
})
|
|
98
100
|
|
|
99
101
|
fastify.listen({ port: 0 }, err => {
|
|
100
|
-
t.
|
|
101
|
-
t.
|
|
102
|
+
t.assert.ifError(err)
|
|
103
|
+
t.after(() => { fastify.close() })
|
|
102
104
|
|
|
103
105
|
sget(`http://localhost:${fastify.server.address().port}`, function (err, response) {
|
|
104
|
-
t.
|
|
105
|
-
t.
|
|
106
|
+
t.assert.ifError(err)
|
|
107
|
+
t.assert.strictEqual(response.statusCode, 500)
|
|
108
|
+
testDone()
|
|
106
109
|
})
|
|
107
110
|
})
|
|
108
111
|
})
|
package/test/stream.2.test.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const test = t.test
|
|
3
|
+
const { test } = require('node:test')
|
|
5
4
|
const proxyquire = require('proxyquire')
|
|
6
5
|
const fs = require('node:fs')
|
|
7
6
|
const resolve = require('node:path').resolve
|
|
8
7
|
const zlib = require('node:zlib')
|
|
9
8
|
const pipeline = require('node:stream').pipeline
|
|
10
9
|
const Fastify = require('..')
|
|
10
|
+
const { waitForCb } = require('./toolkit')
|
|
11
11
|
|
|
12
12
|
test('onSend hook stream', t => {
|
|
13
13
|
t.plan(4)
|
|
@@ -17,6 +17,8 @@ test('onSend hook stream', t => {
|
|
|
17
17
|
reply.send({ hello: 'world' })
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
+
const { stepIn, patience } = waitForCb({ steps: 2 })
|
|
21
|
+
|
|
20
22
|
fastify.addHook('onSend', (req, reply, payload, done) => {
|
|
21
23
|
const gzStream = zlib.createGzip()
|
|
22
24
|
|
|
@@ -24,7 +26,10 @@ test('onSend hook stream', t => {
|
|
|
24
26
|
pipeline(
|
|
25
27
|
fs.createReadStream(resolve(__filename), 'utf8'),
|
|
26
28
|
gzStream,
|
|
27
|
-
|
|
29
|
+
(err) => {
|
|
30
|
+
t.assert.ifError(err)
|
|
31
|
+
stepIn()
|
|
32
|
+
}
|
|
28
33
|
)
|
|
29
34
|
done(null, gzStream)
|
|
30
35
|
})
|
|
@@ -33,16 +38,19 @@ test('onSend hook stream', t => {
|
|
|
33
38
|
url: '/',
|
|
34
39
|
method: 'GET'
|
|
35
40
|
}, (err, res) => {
|
|
36
|
-
t.
|
|
37
|
-
t.
|
|
41
|
+
t.assert.ifError(err)
|
|
42
|
+
t.assert.strictEqual(res.headers['content-encoding'], 'gzip')
|
|
38
43
|
const file = fs.readFileSync(resolve(__filename), 'utf8')
|
|
39
44
|
const payload = zlib.gunzipSync(res.rawPayload)
|
|
40
|
-
t.
|
|
45
|
+
t.assert.strictEqual(payload.toString('utf-8'), file)
|
|
41
46
|
fastify.close()
|
|
47
|
+
stepIn()
|
|
42
48
|
})
|
|
49
|
+
|
|
50
|
+
return patience
|
|
43
51
|
})
|
|
44
52
|
|
|
45
|
-
test('onSend hook stream should work even if payload is not a proper stream', t => {
|
|
53
|
+
test('onSend hook stream should work even if payload is not a proper stream', (t, testDone) => {
|
|
46
54
|
t.plan(1)
|
|
47
55
|
|
|
48
56
|
const reply = proxyquire('../lib/reply', {
|
|
@@ -59,8 +67,9 @@ test('onSend hook stream should work even if payload is not a proper stream', t
|
|
|
59
67
|
fatal: () => { },
|
|
60
68
|
error: () => { },
|
|
61
69
|
warn: (message) => {
|
|
62
|
-
t.
|
|
70
|
+
t.assert.strictEqual(message, 'stream payload does not end properly')
|
|
63
71
|
fastify.close()
|
|
72
|
+
testDone()
|
|
64
73
|
},
|
|
65
74
|
info: () => { },
|
|
66
75
|
debug: () => { },
|
|
@@ -83,7 +92,7 @@ test('onSend hook stream should work even if payload is not a proper stream', t
|
|
|
83
92
|
})
|
|
84
93
|
})
|
|
85
94
|
|
|
86
|
-
test('onSend hook stream should work on payload with "close" ending function', t => {
|
|
95
|
+
test('onSend hook stream should work on payload with "close" ending function', (t, testDone) => {
|
|
87
96
|
t.plan(1)
|
|
88
97
|
|
|
89
98
|
const reply = proxyquire('../lib/reply', {
|
|
@@ -106,7 +115,8 @@ test('onSend hook stream should work on payload with "close" ending function', t
|
|
|
106
115
|
pipe: () => { },
|
|
107
116
|
close: (cb) => {
|
|
108
117
|
cb()
|
|
109
|
-
t.
|
|
118
|
+
t.assert.ok('close callback called')
|
|
119
|
+
testDone()
|
|
110
120
|
}
|
|
111
121
|
}
|
|
112
122
|
done(null, fakeStream)
|
package/test/stream.3.test.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const test = t.test
|
|
3
|
+
const { test } = require('node:test')
|
|
5
4
|
const split = require('split2')
|
|
6
5
|
const Fastify = require('..')
|
|
7
6
|
|
|
8
|
-
test('Destroying streams prematurely', t => {
|
|
7
|
+
test('Destroying streams prematurely', (t, testDone) => {
|
|
9
8
|
t.plan(6)
|
|
10
9
|
|
|
11
10
|
let fastify = null
|
|
@@ -18,7 +17,7 @@ test('Destroying streams prematurely', t => {
|
|
|
18
17
|
}
|
|
19
18
|
})
|
|
20
19
|
} catch (e) {
|
|
21
|
-
t.fail()
|
|
20
|
+
t.assert.fail()
|
|
22
21
|
}
|
|
23
22
|
const stream = require('node:stream')
|
|
24
23
|
const http = require('node:http')
|
|
@@ -26,13 +25,14 @@ test('Destroying streams prematurely', t => {
|
|
|
26
25
|
// Test that "premature close" errors are logged with level warn
|
|
27
26
|
logStream.on('data', line => {
|
|
28
27
|
if (line.res) {
|
|
29
|
-
t.
|
|
30
|
-
t.
|
|
28
|
+
t.assert.strictEqual(line.msg, 'stream closed prematurely')
|
|
29
|
+
t.assert.strictEqual(line.level, 30)
|
|
30
|
+
testDone()
|
|
31
31
|
}
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
fastify.get('/', function (request, reply) {
|
|
35
|
-
t.
|
|
35
|
+
t.assert.ok('Received request')
|
|
36
36
|
|
|
37
37
|
let sent = false
|
|
38
38
|
const reallyLongStream = new stream.Readable({
|
|
@@ -48,26 +48,26 @@ test('Destroying streams prematurely', t => {
|
|
|
48
48
|
})
|
|
49
49
|
|
|
50
50
|
fastify.listen({ port: 0 }, err => {
|
|
51
|
-
t.
|
|
52
|
-
t.
|
|
51
|
+
t.assert.ifError(err)
|
|
52
|
+
t.after(() => fastify.close())
|
|
53
53
|
|
|
54
54
|
const port = fastify.server.address().port
|
|
55
55
|
|
|
56
56
|
http.get(`http://localhost:${port}`, function (response) {
|
|
57
|
-
t.
|
|
57
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
58
58
|
response.on('readable', function () {
|
|
59
59
|
response.destroy()
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
// Node bug? Node never emits 'close' here.
|
|
63
63
|
response.on('aborted', function () {
|
|
64
|
-
t.
|
|
64
|
+
t.assert.ok('Response closed')
|
|
65
65
|
})
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
test('Destroying streams prematurely should call close method', t => {
|
|
70
|
+
test('Destroying streams prematurely should call close method', (t, testDone) => {
|
|
71
71
|
t.plan(7)
|
|
72
72
|
|
|
73
73
|
let fastify = null
|
|
@@ -80,7 +80,7 @@ test('Destroying streams prematurely should call close method', t => {
|
|
|
80
80
|
}
|
|
81
81
|
})
|
|
82
82
|
} catch (e) {
|
|
83
|
-
t.fail()
|
|
83
|
+
t.assert.fail()
|
|
84
84
|
}
|
|
85
85
|
const stream = require('node:stream')
|
|
86
86
|
const http = require('node:http')
|
|
@@ -88,13 +88,13 @@ test('Destroying streams prematurely should call close method', t => {
|
|
|
88
88
|
// Test that "premature close" errors are logged with level warn
|
|
89
89
|
logStream.on('data', line => {
|
|
90
90
|
if (line.res) {
|
|
91
|
-
t.
|
|
92
|
-
t.
|
|
91
|
+
t.assert.strictEqual(line.msg, 'stream closed prematurely')
|
|
92
|
+
t.assert.strictEqual(line.level, 30)
|
|
93
93
|
}
|
|
94
94
|
})
|
|
95
95
|
|
|
96
96
|
fastify.get('/', function (request, reply) {
|
|
97
|
-
t.
|
|
97
|
+
t.assert.ok('Received request')
|
|
98
98
|
|
|
99
99
|
let sent = false
|
|
100
100
|
const reallyLongStream = new stream.Readable({
|
|
@@ -106,30 +106,33 @@ test('Destroying streams prematurely should call close method', t => {
|
|
|
106
106
|
}
|
|
107
107
|
})
|
|
108
108
|
reallyLongStream.destroy = undefined
|
|
109
|
-
reallyLongStream.close = () =>
|
|
109
|
+
reallyLongStream.close = () => {
|
|
110
|
+
t.assert.ok('called')
|
|
111
|
+
testDone()
|
|
112
|
+
}
|
|
110
113
|
reply.send(reallyLongStream)
|
|
111
114
|
})
|
|
112
115
|
|
|
113
116
|
fastify.listen({ port: 0 }, err => {
|
|
114
|
-
t.
|
|
115
|
-
t.
|
|
117
|
+
t.assert.ifError(err)
|
|
118
|
+
t.after(() => { fastify.close() })
|
|
116
119
|
|
|
117
120
|
const port = fastify.server.address().port
|
|
118
121
|
|
|
119
122
|
http.get(`http://localhost:${port}`, function (response) {
|
|
120
|
-
t.
|
|
123
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
121
124
|
response.on('readable', function () {
|
|
122
125
|
response.destroy()
|
|
123
126
|
})
|
|
124
127
|
// Node bug? Node never emits 'close' here.
|
|
125
128
|
response.on('aborted', function () {
|
|
126
|
-
t.
|
|
129
|
+
t.assert.ok('Response closed')
|
|
127
130
|
})
|
|
128
131
|
})
|
|
129
132
|
})
|
|
130
133
|
})
|
|
131
134
|
|
|
132
|
-
test('Destroying streams prematurely should call close method when destroy is not a function', t => {
|
|
135
|
+
test('Destroying streams prematurely should call close method when destroy is not a function', (t, testDone) => {
|
|
133
136
|
t.plan(7)
|
|
134
137
|
|
|
135
138
|
let fastify = null
|
|
@@ -142,7 +145,7 @@ test('Destroying streams prematurely should call close method when destroy is no
|
|
|
142
145
|
}
|
|
143
146
|
})
|
|
144
147
|
} catch (e) {
|
|
145
|
-
t.fail()
|
|
148
|
+
t.assert.fail()
|
|
146
149
|
}
|
|
147
150
|
const stream = require('node:stream')
|
|
148
151
|
const http = require('node:http')
|
|
@@ -150,13 +153,13 @@ test('Destroying streams prematurely should call close method when destroy is no
|
|
|
150
153
|
// Test that "premature close" errors are logged with level warn
|
|
151
154
|
logStream.on('data', line => {
|
|
152
155
|
if (line.res) {
|
|
153
|
-
t.
|
|
154
|
-
t.
|
|
156
|
+
t.assert.strictEqual(line.msg, 'stream closed prematurely')
|
|
157
|
+
t.assert.strictEqual(line.level, 30)
|
|
155
158
|
}
|
|
156
159
|
})
|
|
157
160
|
|
|
158
161
|
fastify.get('/', function (request, reply) {
|
|
159
|
-
t.
|
|
162
|
+
t.assert.ok('Received request')
|
|
160
163
|
|
|
161
164
|
let sent = false
|
|
162
165
|
const reallyLongStream = new stream.Readable({
|
|
@@ -168,24 +171,27 @@ test('Destroying streams prematurely should call close method when destroy is no
|
|
|
168
171
|
}
|
|
169
172
|
})
|
|
170
173
|
reallyLongStream.destroy = true
|
|
171
|
-
reallyLongStream.close = () =>
|
|
174
|
+
reallyLongStream.close = () => {
|
|
175
|
+
t.assert.ok('called')
|
|
176
|
+
testDone()
|
|
177
|
+
}
|
|
172
178
|
reply.send(reallyLongStream)
|
|
173
179
|
})
|
|
174
180
|
|
|
175
181
|
fastify.listen({ port: 0 }, err => {
|
|
176
|
-
t.
|
|
177
|
-
t.
|
|
182
|
+
t.assert.ifError(err)
|
|
183
|
+
t.after(() => { fastify.close() })
|
|
178
184
|
|
|
179
185
|
const port = fastify.server.address().port
|
|
180
186
|
|
|
181
187
|
http.get(`http://localhost:${port}`, function (response) {
|
|
182
|
-
t.
|
|
188
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
183
189
|
response.on('readable', function () {
|
|
184
190
|
response.destroy()
|
|
185
191
|
})
|
|
186
192
|
// Node bug? Node never emits 'close' here.
|
|
187
193
|
response.on('aborted', function () {
|
|
188
|
-
t.
|
|
194
|
+
t.assert.ok('Response closed')
|
|
189
195
|
})
|
|
190
196
|
})
|
|
191
197
|
})
|
|
@@ -52,7 +52,6 @@ expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_SCH_DUPLICATE)
|
|
|
52
52
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_SCH_VALIDATION_BUILD)
|
|
53
53
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_SCH_SERIALIZATION_BUILD)
|
|
54
54
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX)
|
|
55
|
-
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_HTTP2_INVALID_VERSION)
|
|
56
55
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_INIT_OPTS_INVALID)
|
|
57
56
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE)
|
|
58
57
|
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_DUPLICATED_ROUTE)
|
|
@@ -12,7 +12,7 @@ interface TestOptions extends FastifyPluginOptions {
|
|
|
12
12
|
}
|
|
13
13
|
const testOptions: TestOptions = {
|
|
14
14
|
option1: 'a',
|
|
15
|
-
option2: false
|
|
15
|
+
option2: false
|
|
16
16
|
}
|
|
17
17
|
const testPluginOpts: FastifyPluginCallback<TestOptions> = function (instance, opts, done) {
|
|
18
18
|
expectType<TestOptions>(opts)
|
|
@@ -50,7 +50,7 @@ const testPluginWithHttp2WithType = (instance: ServerWithHttp2, opts: FastifyPlu
|
|
|
50
50
|
const testPluginWithHttp2WithTypeAsync = async (instance: ServerWithHttp2, opts: FastifyPluginOptions) => { }
|
|
51
51
|
const testOptions: TestOptions = {
|
|
52
52
|
option1: 'a',
|
|
53
|
-
option2: false
|
|
53
|
+
option2: false
|
|
54
54
|
}
|
|
55
55
|
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginCallback))
|
|
56
56
|
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginAsync))
|
package/types/errors.d.ts
CHANGED
|
@@ -51,7 +51,6 @@ export type FastifyErrorCodes = Record<
|
|
|
51
51
|
'FST_ERR_SCH_VALIDATION_BUILD' |
|
|
52
52
|
'FST_ERR_SCH_SERIALIZATION_BUILD' |
|
|
53
53
|
'FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX' |
|
|
54
|
-
'FST_ERR_HTTP2_INVALID_VERSION' |
|
|
55
54
|
'FST_ERR_INIT_OPTS_INVALID' |
|
|
56
55
|
'FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE' |
|
|
57
56
|
'FST_ERR_DUPLICATED_ROUTE' |
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { test } = require('node:test')
|
|
4
|
-
const proxyquire = require('proxyquire')
|
|
5
|
-
const server = proxyquire('../../lib/server', { 'node:http2': null })
|
|
6
|
-
const Fastify = proxyquire('../..', { './lib/server.js': server })
|
|
7
|
-
|
|
8
|
-
test('should throw when http2 module cannot be found', t => {
|
|
9
|
-
t.plan(2)
|
|
10
|
-
try {
|
|
11
|
-
Fastify({ http2: true })
|
|
12
|
-
t.assert.fail('fastify did not throw expected error')
|
|
13
|
-
} catch (err) {
|
|
14
|
-
t.assert.strictEqual(err.code, 'FST_ERR_HTTP2_INVALID_VERSION')
|
|
15
|
-
t.assert.strictEqual(err.message, 'HTTP2 is available only from node >= 8.8.1')
|
|
16
|
-
}
|
|
17
|
-
})
|