fastify 5.11.3 → 5.12.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.
- package/.pi/self-learning-memory/README.md +8 -0
- package/.pi/self-learning-memory/core/CORE.md +33 -0
- package/.pi/self-learning-memory/core/index.json +735 -0
- package/.pi/self-learning-memory/daily/2026-07-06.md +22 -0
- package/.pi/self-learning-memory/daily/2026-07-29.md +50 -0
- package/.pi/self-learning-memory/daily/2026-08-04.md +41 -0
- package/.pi/self-learning-memory/daily/2026-08-18.md +40 -0
- package/.pi/self-learning-memory/long-term-memory.md +89 -0
- package/AGENTS.md +290 -0
- package/SPONSORS.md +1 -0
- package/docs/Guides/Serverless.md +34 -2
- package/docs/Reference/Reply.md +14 -0
- package/docs/Reference/Server.md +8 -3
- package/fastify.d.ts +1 -1
- package/fastify.js +2 -2
- package/lib/content-type.js +4 -1
- package/lib/reply.js +11 -1
- package/lib/request.js +3 -2
- package/lib/route.js +2 -1
- package/lib/validation.js +10 -1
- package/package.json +2 -3
- package/test/close.test.js +34 -0
- package/test/content-parser.test.js +16 -18
- package/test/content-type.test.js +4 -0
- package/test/fix-root-primitive-coercion.test.js +35 -0
- package/test/helper.js +73 -1
- package/test/hooks-async.test.js +1 -2
- package/test/hooks.test.js +1 -2
- package/test/internals/reply.test.js +76 -1
- package/test/listen.1.test.js +17 -52
- package/test/listen.5.test.js +6 -9
- package/test/logger/instantiation.test.js +1 -1
- package/test/logger/logging.test.js +1 -1
- package/test/logger/request.test.js +1 -1
- package/test/logger/response.test.js +1 -1
- package/test/plugin.4.test.js +5 -4
- package/test/reply-media-type.test.js +131 -0
- package/test/route-prefix.test.js +33 -1
- package/test/route.6.test.js +4 -11
- package/test/schema-feature.test.js +36 -65
- package/test/schema-serialization.test.js +1 -1
- package/test/schema-special-usage.test.js +1 -1
- package/test/schema-validation.test.js +1 -1
- package/test/stream.2.test.js +1 -1
- package/test/trust-proxy.test.js +27 -21
- package/test/types/fastify.tst.ts +2 -0
- package/test/toolkit.js +0 -63
package/fastify.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ declare namespace fastify {
|
|
|
149
149
|
requestIdLogLabel?: string;
|
|
150
150
|
useSemicolonDelimiter?: boolean,
|
|
151
151
|
genReqId?: (req: RawRequestDefaultExpression<RawServer>) => string,
|
|
152
|
-
trustProxy?: boolean | string | string[] |
|
|
152
|
+
trustProxy?: boolean | string | string[] | TrustProxyFunction,
|
|
153
153
|
querystringParser?: (str: string) => { [key: string]: unknown },
|
|
154
154
|
constraints?: {
|
|
155
155
|
[name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>,
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '5.
|
|
3
|
+
const VERSION = '5.12.1'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -601,7 +601,7 @@ function fastify (serverOptions) {
|
|
|
601
601
|
|
|
602
602
|
if (name === 'onClose') {
|
|
603
603
|
this.onClose(fn.bind(this))
|
|
604
|
-
} else if (name === 'onReady' || name === 'onListen' || name === 'onRoute') {
|
|
604
|
+
} else if (name === 'onReady' || name === 'onListen' || name === 'onRoute' || name === 'preClose') {
|
|
605
605
|
this[kHooks].add(name, fn)
|
|
606
606
|
} else {
|
|
607
607
|
this.after((err, done) => {
|
package/lib/content-type.js
CHANGED
|
@@ -183,7 +183,10 @@ class ContentType {
|
|
|
183
183
|
|
|
184
184
|
get isValid () { return this.#valid }
|
|
185
185
|
|
|
186
|
-
get mediaType () {
|
|
186
|
+
get mediaType () {
|
|
187
|
+
if (this.#valid === false) return undefined
|
|
188
|
+
return `${this.#type}/${this.#subtype}`
|
|
189
|
+
}
|
|
187
190
|
|
|
188
191
|
get type () { return this.#type }
|
|
189
192
|
|
package/lib/reply.js
CHANGED
|
@@ -93,6 +93,12 @@ Object.defineProperties(Reply.prototype, {
|
|
|
93
93
|
return (this[kReplyEndTime] || now()) - this[kReplyStartTime]
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
|
+
mediaType: {
|
|
97
|
+
get () {
|
|
98
|
+
const contentTypeHeader = this[kReplyHeaders]['content-type']
|
|
99
|
+
return ContentType.from(contentTypeHeader).mediaType
|
|
100
|
+
}
|
|
101
|
+
},
|
|
96
102
|
server: {
|
|
97
103
|
get () {
|
|
98
104
|
return this.request[kRouteContext].server
|
|
@@ -254,9 +260,13 @@ Reply.prototype.hasHeader = function (key) {
|
|
|
254
260
|
}
|
|
255
261
|
|
|
256
262
|
Reply.prototype.removeHeader = function (key) {
|
|
263
|
+
key = key.toLowerCase()
|
|
257
264
|
// Node.js does not like headers with keys set to undefined,
|
|
258
265
|
// so we have to delete the key.
|
|
259
|
-
delete this[kReplyHeaders][key
|
|
266
|
+
delete this[kReplyHeaders][key]
|
|
267
|
+
if (!this.raw.headersSent) {
|
|
268
|
+
this.raw.removeHeader(key)
|
|
269
|
+
}
|
|
260
270
|
return this
|
|
261
271
|
}
|
|
262
272
|
|
package/lib/request.js
CHANGED
|
@@ -49,8 +49,9 @@ function getTrustProxyFn (tp) {
|
|
|
49
49
|
return function () { return true }
|
|
50
50
|
}
|
|
51
51
|
if (typeof tp === 'number') {
|
|
52
|
-
//
|
|
53
|
-
|
|
52
|
+
// Hop-count-only trust cannot validate the immediate peer. Fail closed so
|
|
53
|
+
// direct clients cannot spoof X-Forwarded-* values by supplying enough hops.
|
|
54
|
+
return function () { return false }
|
|
54
55
|
}
|
|
55
56
|
if (typeof tp === 'string') {
|
|
56
57
|
// Support comma-separated tps
|
package/lib/route.js
CHANGED
|
@@ -290,6 +290,7 @@ function buildRouting (options) {
|
|
|
290
290
|
opts.attachValidation = false
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
const routeConfigUrl = prefixing ? prefix : url
|
|
293
294
|
if (prefixing === false) {
|
|
294
295
|
// run 'onRoute' hooks
|
|
295
296
|
for (const hook of this[kHooks].onRoute) {
|
|
@@ -328,7 +329,7 @@ function buildRouting (options) {
|
|
|
328
329
|
const constraints = opts.constraints || {}
|
|
329
330
|
const config = {
|
|
330
331
|
...opts.config,
|
|
331
|
-
url,
|
|
332
|
+
url: routeConfigUrl,
|
|
332
333
|
method: opts.method
|
|
333
334
|
}
|
|
334
335
|
|
package/lib/validation.js
CHANGED
|
@@ -120,7 +120,16 @@ function validateParam (validatorFunction, request, paramName) {
|
|
|
120
120
|
let ret
|
|
121
121
|
|
|
122
122
|
try {
|
|
123
|
-
|
|
123
|
+
const data = isUndefined ? null : request[paramName]
|
|
124
|
+
// Ajv can only mutate a root value when its parent is provided.
|
|
125
|
+
if (validatorFunction?.schemaEnv) {
|
|
126
|
+
ret = validatorFunction(data, {
|
|
127
|
+
parentData: request,
|
|
128
|
+
parentDataProperty: paramName
|
|
129
|
+
})
|
|
130
|
+
} else {
|
|
131
|
+
ret = validatorFunction?.(data)
|
|
132
|
+
}
|
|
124
133
|
} catch (err) {
|
|
125
134
|
// If validator throws synchronously, ensure it propagates as an internal error
|
|
126
135
|
err.statusCode = 500
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.12.1",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -167,7 +167,6 @@
|
|
|
167
167
|
],
|
|
168
168
|
"devDependencies": {
|
|
169
169
|
"@jsumners/line-reporter": "^1.0.1",
|
|
170
|
-
"@sinonjs/fake-timers": "^11.2.2",
|
|
171
170
|
"@stylistic/eslint-plugin": "^5.1.0",
|
|
172
171
|
"@stylistic/eslint-plugin-js": "^4.1.0",
|
|
173
172
|
"@types/node": "^26.0.1",
|
|
@@ -214,7 +213,7 @@
|
|
|
214
213
|
"find-my-way": "^9.6.0",
|
|
215
214
|
"light-my-request": "^6.0.0",
|
|
216
215
|
"pino": "^9.14.0 || ^10.1.0",
|
|
217
|
-
"process-warning": "^5.
|
|
216
|
+
"process-warning": "^5.1.0",
|
|
218
217
|
"rfdc": "^1.3.1",
|
|
219
218
|
"secure-json-parse": "^4.0.0",
|
|
220
219
|
"semver": "^7.6.0",
|
package/test/close.test.js
CHANGED
|
@@ -665,6 +665,40 @@ test('preClose async', async t => {
|
|
|
665
665
|
await fastify.close()
|
|
666
666
|
})
|
|
667
667
|
|
|
668
|
+
test('preClose runs exactly once with a child plugin', async t => {
|
|
669
|
+
t.plan(1)
|
|
670
|
+
const fastify = Fastify()
|
|
671
|
+
let count = 0
|
|
672
|
+
|
|
673
|
+
fastify.register(async (child) => {
|
|
674
|
+
child.get('/x', async () => 'ok')
|
|
675
|
+
})
|
|
676
|
+
fastify.addHook('preClose', async () => { count++ })
|
|
677
|
+
|
|
678
|
+
await fastify.ready()
|
|
679
|
+
await fastify.close()
|
|
680
|
+
|
|
681
|
+
t.assert.strictEqual(count, 1)
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
test('preClose runs exactly once with nested child plugins', async t => {
|
|
685
|
+
t.plan(1)
|
|
686
|
+
const fastify = Fastify()
|
|
687
|
+
let count = 0
|
|
688
|
+
|
|
689
|
+
fastify.register(async (child) => {
|
|
690
|
+
child.register(async (grandchild) => {
|
|
691
|
+
grandchild.get('/y', async () => 'ok')
|
|
692
|
+
})
|
|
693
|
+
})
|
|
694
|
+
fastify.addHook('preClose', async () => { count++ })
|
|
695
|
+
|
|
696
|
+
await fastify.ready()
|
|
697
|
+
await fastify.close()
|
|
698
|
+
|
|
699
|
+
t.assert.strictEqual(count, 1)
|
|
700
|
+
})
|
|
701
|
+
|
|
668
702
|
test('preClose execution order', (t, done) => {
|
|
669
703
|
t.plan(4)
|
|
670
704
|
const fastify = Fastify()
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { test } = require('node:test')
|
|
4
|
+
const { spyWarning } = require('process-warning')
|
|
4
5
|
const Fastify = require('..')
|
|
5
6
|
const keys = require('../lib/symbols')
|
|
6
7
|
const { FST_ERR_CTP_ALREADY_PRESENT, FST_ERR_CTP_INVALID_TYPE, FST_ERR_CTP_INVALID_MEDIA_TYPE } = require('../lib/errors')
|
|
8
|
+
const { FSTSEC001 } = require('../lib/warnings')
|
|
7
9
|
|
|
8
10
|
const first = function (req, payload, done) {}
|
|
9
11
|
const second = function (req, payload, done) {}
|
|
@@ -488,41 +490,37 @@ test('Safeguard against content-type spoofing - string', async t => {
|
|
|
488
490
|
})
|
|
489
491
|
|
|
490
492
|
test('Warning against improper content-type - regexp', async t => {
|
|
491
|
-
await t.test('improper regex - text plain', (t
|
|
493
|
+
await t.test('improper regex - text plain', async (t) => {
|
|
492
494
|
t.plan(2)
|
|
493
|
-
const
|
|
495
|
+
const spyData = spyWarning(FSTSEC001)
|
|
496
|
+
t.after(spyData.restore)
|
|
494
497
|
|
|
495
|
-
|
|
496
|
-
function onWarning (warning) {
|
|
497
|
-
t.assert.strictEqual(warning.name, 'FastifySecurity')
|
|
498
|
-
t.assert.strictEqual(warning.code, 'FSTSEC001')
|
|
499
|
-
done()
|
|
500
|
-
}
|
|
501
|
-
t.after(() => process.removeListener('warning', onWarning))
|
|
498
|
+
const fastify = Fastify()
|
|
502
499
|
|
|
503
500
|
fastify.removeAllContentTypeParsers()
|
|
504
501
|
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
|
|
505
502
|
done(null, body)
|
|
506
503
|
})
|
|
504
|
+
|
|
505
|
+
await fastify.ready()
|
|
506
|
+
t.assert.deepStrictEqual(spyData.calls, [{ arguments: ['text\\/plain'], result: true }])
|
|
507
|
+
t.assert.strictEqual(spyData.callCount(), 1)
|
|
507
508
|
})
|
|
508
509
|
|
|
509
|
-
await t.test('improper regex - application json', (t
|
|
510
|
+
await t.test('improper regex - application json', async (t) => {
|
|
510
511
|
t.plan(2)
|
|
512
|
+
const spyData = spyWarning(FSTSEC001)
|
|
513
|
+
t.after(spyData.restore)
|
|
511
514
|
const fastify = Fastify()
|
|
512
515
|
|
|
513
|
-
process.on('warning', onWarning)
|
|
514
|
-
function onWarning (warning) {
|
|
515
|
-
t.assert.strictEqual(warning.name, 'FastifySecurity')
|
|
516
|
-
t.assert.strictEqual(warning.code, 'FSTSEC001')
|
|
517
|
-
done()
|
|
518
|
-
}
|
|
519
|
-
t.after(() => process.removeListener('warning', onWarning))
|
|
520
|
-
|
|
521
516
|
fastify.removeAllContentTypeParsers()
|
|
522
517
|
|
|
523
518
|
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
|
|
524
519
|
done(null, body)
|
|
525
520
|
})
|
|
521
|
+
|
|
522
|
+
t.assert.deepStrictEqual(spyData.calls, [{ arguments: ['application\\/json'], result: true }])
|
|
523
|
+
t.assert.deepEqual(spyData.callCount(), 1)
|
|
526
524
|
})
|
|
527
525
|
})
|
|
528
526
|
|
|
@@ -46,18 +46,22 @@ describe('ContentType class', () => {
|
|
|
46
46
|
test('returns empty instance for empty value', (t) => {
|
|
47
47
|
let found = new ContentType('')
|
|
48
48
|
t.assert.equal(found.isEmpty, true)
|
|
49
|
+
t.assert.equal(found.mediaType, undefined)
|
|
49
50
|
|
|
50
51
|
found = new ContentType('undefined')
|
|
51
52
|
t.assert.equal(found.isEmpty, true)
|
|
53
|
+
t.assert.equal(found.mediaType, undefined)
|
|
52
54
|
|
|
53
55
|
found = new ContentType()
|
|
54
56
|
t.assert.equal(found.isEmpty, true)
|
|
57
|
+
t.assert.equal(found.mediaType, undefined)
|
|
55
58
|
})
|
|
56
59
|
|
|
57
60
|
test('indicates media type is not correct format', (t) => {
|
|
58
61
|
let found = new ContentType('foo')
|
|
59
62
|
t.assert.equal(found.isEmpty, true)
|
|
60
63
|
t.assert.equal(found.isValid, false)
|
|
64
|
+
t.assert.equal(found.mediaType, undefined)
|
|
61
65
|
|
|
62
66
|
found = new ContentType('foo /bar')
|
|
63
67
|
t.assert.equal(found.isEmpty, true)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test')
|
|
4
|
+
const Fastify = require('..')
|
|
5
|
+
|
|
6
|
+
test('root primitive values coerced by Ajv are assigned to the request', async (t) => {
|
|
7
|
+
const fastify = Fastify()
|
|
8
|
+
|
|
9
|
+
fastify.post('/', {
|
|
10
|
+
schema: {
|
|
11
|
+
body: {
|
|
12
|
+
type: 'integer',
|
|
13
|
+
minimum: 1,
|
|
14
|
+
maximum: 10
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}, (request, reply) => {
|
|
18
|
+
reply.send({ body: request.body, type: typeof request.body })
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const response = await fastify.inject({
|
|
22
|
+
method: 'POST',
|
|
23
|
+
url: '/',
|
|
24
|
+
payload: '"10"',
|
|
25
|
+
headers: { 'content-type': 'application/json' }
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
29
|
+
t.assert.deepStrictEqual(JSON.parse(response.payload), {
|
|
30
|
+
body: 10,
|
|
31
|
+
type: 'number'
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
await fastify.close()
|
|
35
|
+
})
|
package/test/helper.js
CHANGED
|
@@ -4,11 +4,42 @@ const dns = require('node:dns').promises
|
|
|
4
4
|
const stream = require('node:stream')
|
|
5
5
|
const { promisify } = require('node:util')
|
|
6
6
|
const symbols = require('../lib/symbols')
|
|
7
|
-
const { waitForCb } = require('./toolkit')
|
|
8
7
|
const assert = require('node:assert')
|
|
9
8
|
|
|
10
9
|
module.exports.sleep = promisify(setTimeout)
|
|
11
10
|
|
|
11
|
+
function waitForCb (options) {
|
|
12
|
+
let count = null
|
|
13
|
+
let done = false
|
|
14
|
+
let iResolve
|
|
15
|
+
let iReject
|
|
16
|
+
|
|
17
|
+
function stepIn () {
|
|
18
|
+
if (done) {
|
|
19
|
+
iReject(new Error('Unexpected done call'))
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (--count) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
done = true
|
|
28
|
+
iResolve()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const patience = new Promise((resolve, reject) => {
|
|
32
|
+
iResolve = resolve
|
|
33
|
+
iReject = reject
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
count = options.steps || 1
|
|
37
|
+
done = false
|
|
38
|
+
|
|
39
|
+
return { stepIn, patience }
|
|
40
|
+
}
|
|
41
|
+
module.exports.waitForCb = waitForCb
|
|
42
|
+
|
|
12
43
|
/**
|
|
13
44
|
* @param method HTTP request method
|
|
14
45
|
* @param t node:test instance
|
|
@@ -494,3 +525,44 @@ module.exports.getServerUrl = function (app) {
|
|
|
494
525
|
? `http://[${address}]:${port}`
|
|
495
526
|
: `http://${address}:${port}`
|
|
496
527
|
}
|
|
528
|
+
|
|
529
|
+
module.exports.partialDeepStrictEqual = function partialDeepStrictEqual (actual, expected) {
|
|
530
|
+
if (typeof expected !== 'object' || expected === null) {
|
|
531
|
+
return actual === expected
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (typeof actual !== 'object' || actual === null) {
|
|
535
|
+
return false
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (Array.isArray(expected)) {
|
|
539
|
+
if (!Array.isArray(actual)) return false
|
|
540
|
+
if (expected.length > actual.length) return false
|
|
541
|
+
|
|
542
|
+
for (let i = 0; i < expected.length; i++) {
|
|
543
|
+
if (!partialDeepStrictEqual(actual[i], expected[i])) {
|
|
544
|
+
return false
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return true
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
for (const key of Object.keys(expected)) {
|
|
551
|
+
if (!(key in actual)) return false
|
|
552
|
+
if (!partialDeepStrictEqual(actual[key], expected[key])) {
|
|
553
|
+
return false
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return true
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
module.exports.assertNoWarning = function (t) {
|
|
561
|
+
function doNotWarn () {
|
|
562
|
+
t.assert.fail('no warning')
|
|
563
|
+
}
|
|
564
|
+
process.on('warning', doNotWarn)
|
|
565
|
+
t.after(() => {
|
|
566
|
+
process.off('warning', doNotWarn)
|
|
567
|
+
})
|
|
568
|
+
}
|
package/test/hooks-async.test.js
CHANGED
|
@@ -4,8 +4,7 @@ const { Readable } = require('node:stream')
|
|
|
4
4
|
const { test, describe } = require('node:test')
|
|
5
5
|
const Fastify = require('../fastify')
|
|
6
6
|
const fs = require('node:fs')
|
|
7
|
-
const { sleep } = require('./helper')
|
|
8
|
-
const { waitForCb } = require('./toolkit')
|
|
7
|
+
const { sleep, waitForCb } = require('./helper')
|
|
9
8
|
|
|
10
9
|
process.removeAllListeners('warning')
|
|
11
10
|
|
package/test/hooks.test.js
CHANGED
|
@@ -10,8 +10,7 @@ const symbols = require('../lib/symbols.js')
|
|
|
10
10
|
const payload = { hello: 'world' }
|
|
11
11
|
const proxyquire = require('proxyquire')
|
|
12
12
|
const { connect } = require('node:net')
|
|
13
|
-
const { sleep } = require('./helper')
|
|
14
|
-
const { waitForCb } = require('./toolkit.js')
|
|
13
|
+
const { sleep, waitForCb } = require('./helper')
|
|
15
14
|
const { fetch } = require('undici')
|
|
16
15
|
|
|
17
16
|
process.removeAllListeners('warning')
|
|
@@ -34,7 +34,7 @@ const doGet = async function (url) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
test('Once called, Reply should return an object with methods', t => {
|
|
37
|
-
t.plan(
|
|
37
|
+
t.plan(16)
|
|
38
38
|
const response = { res: 'res' }
|
|
39
39
|
const context = {
|
|
40
40
|
config: { onSend: [] },
|
|
@@ -49,6 +49,7 @@ test('Once called, Reply should return an object with methods', t => {
|
|
|
49
49
|
t.assert.strictEqual(typeof reply[kReplyErrorHandlerCalled], 'boolean')
|
|
50
50
|
t.assert.strictEqual(typeof reply.send, 'function')
|
|
51
51
|
t.assert.strictEqual(typeof reply.code, 'function')
|
|
52
|
+
t.assert.strictEqual(typeof reply.mediaType, 'undefined')
|
|
52
53
|
t.assert.strictEqual(typeof reply.status, 'function')
|
|
53
54
|
t.assert.strictEqual(typeof reply.header, 'function')
|
|
54
55
|
t.assert.strictEqual(typeof reply.serialize, 'function')
|
|
@@ -1114,6 +1115,80 @@ test('reply.removeHeader can remove the value', async t => {
|
|
|
1114
1115
|
await fetch(`${fastifyServer}/headers`)
|
|
1115
1116
|
})
|
|
1116
1117
|
|
|
1118
|
+
test('reply.removeHeader removes raw headers', async t => {
|
|
1119
|
+
t.plan(9)
|
|
1120
|
+
|
|
1121
|
+
const fastify = require('../../')()
|
|
1122
|
+
|
|
1123
|
+
t.after(() => fastify.close())
|
|
1124
|
+
|
|
1125
|
+
fastify.get('/headers', function (req, reply) {
|
|
1126
|
+
reply.raw.setHeader('X-Foo', 'raw')
|
|
1127
|
+
t.assert.strictEqual(reply.getHeader('x-foo'), 'raw')
|
|
1128
|
+
t.assert.strictEqual(reply.getHeaders()['x-foo'], 'raw')
|
|
1129
|
+
t.assert.strictEqual(reply.hasHeader('x-foo'), true)
|
|
1130
|
+
|
|
1131
|
+
t.assert.strictEqual(reply.removeHeader('x-FoO'), reply)
|
|
1132
|
+
t.assert.strictEqual(reply.getHeader('x-foo'), undefined)
|
|
1133
|
+
t.assert.strictEqual(Object.hasOwn(reply.getHeaders(), 'x-foo'), false)
|
|
1134
|
+
t.assert.strictEqual(reply.hasHeader('x-foo'), false)
|
|
1135
|
+
t.assert.strictEqual(reply.removeHeader('X-FOO'), reply)
|
|
1136
|
+
|
|
1137
|
+
reply.send()
|
|
1138
|
+
})
|
|
1139
|
+
|
|
1140
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
1141
|
+
const response = await fetch(`${fastifyServer}/headers`)
|
|
1142
|
+
t.assert.strictEqual(response.headers.get('x-foo'), null)
|
|
1143
|
+
})
|
|
1144
|
+
|
|
1145
|
+
test('reply.removeHeader removes layered headers', async t => {
|
|
1146
|
+
t.plan(7)
|
|
1147
|
+
|
|
1148
|
+
const fastify = require('../../')()
|
|
1149
|
+
|
|
1150
|
+
t.after(() => fastify.close())
|
|
1151
|
+
|
|
1152
|
+
fastify.get('/headers', function (req, reply) {
|
|
1153
|
+
reply.raw.setHeader('x-foo', 'raw')
|
|
1154
|
+
reply.header('x-foo', 'fastify')
|
|
1155
|
+
t.assert.strictEqual(reply.getHeader('x-foo'), 'fastify')
|
|
1156
|
+
t.assert.strictEqual(reply.getHeaders()['x-foo'], 'fastify')
|
|
1157
|
+
|
|
1158
|
+
t.assert.strictEqual(reply.removeHeader('x-foo'), reply)
|
|
1159
|
+
t.assert.strictEqual(reply.getHeader('x-foo'), undefined)
|
|
1160
|
+
t.assert.strictEqual(Object.hasOwn(reply.getHeaders(), 'x-foo'), false)
|
|
1161
|
+
t.assert.strictEqual(reply.hasHeader('x-foo'), false)
|
|
1162
|
+
|
|
1163
|
+
reply.send()
|
|
1164
|
+
})
|
|
1165
|
+
|
|
1166
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
1167
|
+
const response = await fetch(`${fastifyServer}/headers`)
|
|
1168
|
+
t.assert.strictEqual(response.headers.get('x-foo'), null)
|
|
1169
|
+
})
|
|
1170
|
+
|
|
1171
|
+
test('reply.removeHeader does not throw after headers are sent', async t => {
|
|
1172
|
+
t.plan(3)
|
|
1173
|
+
|
|
1174
|
+
const fastify = require('../../')()
|
|
1175
|
+
|
|
1176
|
+
t.after(() => fastify.close())
|
|
1177
|
+
|
|
1178
|
+
fastify.get('/headers', function (req, reply) {
|
|
1179
|
+
reply.hijack()
|
|
1180
|
+
reply.raw.setHeader('x-foo', 'raw')
|
|
1181
|
+
reply.raw.flushHeaders()
|
|
1182
|
+
t.assert.strictEqual(reply.raw.headersSent, true)
|
|
1183
|
+
t.assert.doesNotThrow(() => reply.removeHeader('x-foo'))
|
|
1184
|
+
reply.raw.end()
|
|
1185
|
+
})
|
|
1186
|
+
|
|
1187
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
1188
|
+
const response = await fetch(`${fastifyServer}/headers`)
|
|
1189
|
+
t.assert.strictEqual(response.headers.get('x-foo'), 'raw')
|
|
1190
|
+
})
|
|
1191
|
+
|
|
1117
1192
|
test('reply.header can reset the value', async t => {
|
|
1118
1193
|
t.plan(1)
|
|
1119
1194
|
|
package/test/listen.1.test.js
CHANGED
|
@@ -4,6 +4,7 @@ const { networkInterfaces } = require('node:os')
|
|
|
4
4
|
const { test, before } = require('node:test')
|
|
5
5
|
const Fastify = require('..')
|
|
6
6
|
const helper = require('./helper')
|
|
7
|
+
const { assertNoWarning } = require('./helper')
|
|
7
8
|
|
|
8
9
|
let localhost
|
|
9
10
|
let localhostForURL
|
|
@@ -13,33 +14,22 @@ before(async function () {
|
|
|
13
14
|
})
|
|
14
15
|
|
|
15
16
|
test('listen works without arguments', async t => {
|
|
16
|
-
|
|
17
|
-
t.assert.fail('should not be deprecated')
|
|
18
|
-
}
|
|
19
|
-
process.on('warning', doNotWarn)
|
|
17
|
+
assertNoWarning(t)
|
|
20
18
|
|
|
21
19
|
const fastify = Fastify()
|
|
22
|
-
|
|
23
|
-
fastify.close()
|
|
24
|
-
process.removeListener('warning', doNotWarn)
|
|
25
|
-
})
|
|
20
|
+
|
|
26
21
|
await fastify.listen()
|
|
27
22
|
const address = fastify.server.address()
|
|
28
23
|
t.assert.strictEqual(address.address, localhost)
|
|
29
24
|
t.assert.ok(address.port > 0)
|
|
25
|
+
await fastify.close()
|
|
30
26
|
})
|
|
31
27
|
|
|
32
28
|
test('Async/await listen with arguments', async t => {
|
|
33
|
-
|
|
34
|
-
t.assert.fail('should not be deprecated')
|
|
35
|
-
}
|
|
36
|
-
process.on('warning', doNotWarn)
|
|
29
|
+
assertNoWarning(t)
|
|
37
30
|
|
|
38
31
|
const fastify = Fastify()
|
|
39
|
-
|
|
40
|
-
fastify.close()
|
|
41
|
-
process.removeListener('warning', doNotWarn)
|
|
42
|
-
})
|
|
32
|
+
|
|
43
33
|
const addr = await fastify.listen({ port: 0, host: '0.0.0.0' })
|
|
44
34
|
const address = fastify.server.address()
|
|
45
35
|
const { protocol, hostname, port, pathname } = new URL(addr)
|
|
@@ -55,39 +45,27 @@ test('Async/await listen with arguments', async t => {
|
|
|
55
45
|
family: 'IPv4',
|
|
56
46
|
port: address.port
|
|
57
47
|
})
|
|
48
|
+
await fastify.close()
|
|
58
49
|
})
|
|
59
50
|
|
|
60
51
|
test('listen accepts a callback', (t, done) => {
|
|
61
52
|
t.plan(2)
|
|
62
|
-
|
|
63
|
-
t.assert.fail('should not be deprecated')
|
|
64
|
-
}
|
|
65
|
-
process.on('warning', doNotWarn)
|
|
53
|
+
assertNoWarning(t)
|
|
66
54
|
|
|
67
55
|
const fastify = Fastify()
|
|
68
|
-
|
|
69
|
-
fastify.close()
|
|
70
|
-
process.removeListener('warning', doNotWarn)
|
|
71
|
-
})
|
|
56
|
+
|
|
72
57
|
fastify.listen({ port: 0 }, (err) => {
|
|
73
58
|
t.assert.ifError(err)
|
|
74
59
|
t.assert.strictEqual(fastify.server.address().address, localhost)
|
|
75
|
-
done
|
|
60
|
+
fastify.close(done)
|
|
76
61
|
})
|
|
77
62
|
})
|
|
78
63
|
|
|
79
64
|
test('listen accepts options and a callback', (t, done) => {
|
|
80
65
|
t.plan(1)
|
|
81
|
-
|
|
82
|
-
t.assert.fail('should not be deprecated')
|
|
83
|
-
}
|
|
84
|
-
process.on('warning', doNotWarn)
|
|
66
|
+
assertNoWarning(t)
|
|
85
67
|
|
|
86
68
|
const fastify = Fastify()
|
|
87
|
-
t.after(() => {
|
|
88
|
-
fastify.close()
|
|
89
|
-
process.removeListener('warning', doNotWarn)
|
|
90
|
-
})
|
|
91
69
|
fastify.listen({
|
|
92
70
|
port: 0,
|
|
93
71
|
host: 'localhost',
|
|
@@ -98,7 +76,7 @@ test('listen accepts options and a callback', (t, done) => {
|
|
|
98
76
|
ipv6Only: false
|
|
99
77
|
}, (err) => {
|
|
100
78
|
t.assert.ifError(err)
|
|
101
|
-
done
|
|
79
|
+
fastify.close(done)
|
|
102
80
|
})
|
|
103
81
|
})
|
|
104
82
|
|
|
@@ -118,37 +96,24 @@ test('listen after Promise.resolve()', (t, done) => {
|
|
|
118
96
|
})
|
|
119
97
|
|
|
120
98
|
test('listen works with undefined host', async t => {
|
|
121
|
-
|
|
122
|
-
t.assert.fail('should not be deprecated')
|
|
123
|
-
}
|
|
124
|
-
process.on('warning', doNotWarn)
|
|
99
|
+
assertNoWarning(t)
|
|
125
100
|
|
|
126
101
|
const fastify = Fastify()
|
|
127
|
-
t.after(() => fastify.close())
|
|
128
|
-
t.after(() => {
|
|
129
|
-
fastify.close()
|
|
130
|
-
process.removeListener('warning', doNotWarn)
|
|
131
|
-
})
|
|
132
102
|
await fastify.listen({ host: undefined, port: 0 })
|
|
133
103
|
const address = fastify.server.address()
|
|
134
104
|
t.assert.strictEqual(address.address, localhost)
|
|
135
105
|
t.assert.ok(address.port > 0)
|
|
106
|
+
await fastify.close()
|
|
136
107
|
})
|
|
137
108
|
|
|
138
109
|
test('listen works with null host', async t => {
|
|
139
|
-
|
|
140
|
-
t.fail('should not be deprecated')
|
|
141
|
-
}
|
|
142
|
-
process.on('warning', doNotWarn)
|
|
110
|
+
assertNoWarning(t)
|
|
143
111
|
|
|
144
112
|
const fastify = Fastify()
|
|
145
|
-
|
|
146
|
-
t.after(() => {
|
|
147
|
-
fastify.close()
|
|
148
|
-
process.removeListener('warning', doNotWarn)
|
|
149
|
-
})
|
|
113
|
+
|
|
150
114
|
await fastify.listen({ host: null, port: 0 })
|
|
151
115
|
const address = fastify.server.address()
|
|
152
116
|
t.assert.strictEqual(address.address, localhost)
|
|
153
117
|
t.assert.ok(address.port > 0)
|
|
118
|
+
await fastify.close()
|
|
154
119
|
})
|