fastify 5.3.2 → 5.4.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.
- package/README.md +2 -0
- package/build/build-validation.js +2 -1
- package/docs/Guides/Delay-Accepting-Requests.md +3 -3
- package/docs/Guides/Ecosystem.md +16 -7
- package/docs/Guides/Serverless.md +28 -69
- package/docs/Reference/ContentTypeParser.md +1 -1
- package/docs/Reference/Errors.md +2 -4
- package/docs/Reference/Hooks.md +14 -14
- package/docs/Reference/Logging.md +3 -3
- package/docs/Reference/Middleware.md +1 -1
- package/docs/Reference/Reply.md +8 -8
- package/docs/Reference/Request.md +1 -1
- package/docs/Reference/Routes.md +3 -3
- package/docs/Reference/Server.md +40 -10
- package/docs/Reference/Validation-and-Serialization.md +1 -1
- package/eslint.config.js +17 -9
- package/fastify.d.ts +2 -1
- package/fastify.js +20 -4
- package/lib/configValidator.js +1 -1
- package/lib/decorate.js +2 -2
- package/lib/errors.js +6 -8
- package/lib/logger-factory.js +1 -1
- package/lib/logger-pino.js +2 -2
- package/lib/pluginOverride.js +3 -1
- package/lib/reply.js +9 -13
- package/lib/request.js +4 -11
- package/lib/server.js +30 -51
- package/lib/symbols.js +1 -0
- package/lib/warnings.js +8 -0
- package/package.json +11 -7
- package/test/404s.test.js +226 -325
- package/test/allow-unsafe-regex.test.js +19 -48
- package/test/als.test.js +28 -40
- package/test/async-await.test.js +11 -2
- package/test/body-limit.test.js +41 -65
- package/test/build-certificate.js +1 -1
- package/test/close-pipelining.test.js +5 -4
- package/test/custom-parser-async.test.js +17 -22
- package/test/decorator-namespace.test._js_ +3 -4
- package/test/decorator.test.js +422 -341
- package/test/diagnostics-channel/async-delay-request.test.js +7 -16
- package/test/diagnostics-channel/sync-delay-request.test.js +7 -16
- package/test/helper.js +108 -70
- package/test/hooks-async.test.js +248 -218
- package/test/hooks.on-listen.test.js +255 -239
- package/test/hooks.on-ready.test.js +110 -92
- package/test/hooks.test.js +910 -769
- package/test/http-methods/lock.test.js +31 -31
- package/test/http-methods/mkcol.test.js +5 -9
- package/test/http-methods/proppatch.test.js +23 -29
- package/test/http-methods/report.test.js +44 -69
- package/test/http-methods/search.test.js +67 -82
- package/test/http2/closing.test.js +38 -20
- package/test/http2/secure-with-fallback.test.js +28 -27
- package/test/https/https.test.js +56 -53
- package/test/inject.test.js +114 -97
- package/test/input-validation.js +63 -53
- package/test/internals/errors.test.js +0 -10
- package/test/internals/handle-request.test.js +49 -66
- package/test/internals/hooks.test.js +17 -0
- package/test/issue-4959.test.js +14 -5
- package/test/listen.4.test.js +31 -43
- package/test/logger/response.test.js +19 -20
- package/test/nullable-validation.test.js +33 -46
- package/test/options.error-handler.test.js +1 -1
- package/test/options.test.js +1 -1
- package/test/output-validation.test.js +49 -72
- 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/plugin.2.test.js +104 -86
- package/test/plugin.3.test.js +56 -35
- package/test/plugin.4.test.js +124 -119
- package/test/promises.test.js +36 -30
- package/test/proto-poisoning.test.js +78 -97
- 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/request-error.test.js +0 -46
- package/test/route-hooks.test.js +112 -92
- package/test/route-prefix.test.js +194 -133
- package/test/schema-feature.test.js +309 -238
- package/test/schema-serialization.test.js +177 -154
- package/test/schema-special-usage.test.js +165 -132
- package/test/schema-validation.test.js +278 -199
- package/test/set-error-handler.test.js +58 -1
- package/test/skip-reply-send.test.js +64 -69
- 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/trust-proxy.test.js +32 -58
- package/test/types/errors.test-d.ts +0 -1
- package/test/types/fastify.test-d.ts +3 -0
- package/test/types/plugin.test-d.ts +1 -1
- package/test/types/register.test-d.ts +1 -1
- package/test/types/request.test-d.ts +1 -0
- package/test/url-rewriting.test.js +45 -62
- package/test/use-semicolon-delimiter.test.js +1 -1
- package/types/errors.d.ts +0 -1
- package/types/request.d.ts +1 -0
- package/.taprc +0 -7
- package/test/http2/missing-http2-module.test.js +0 -17
package/test/input-validation.js
CHANGED
|
@@ -4,6 +4,7 @@ const sget = require('simple-get').concat
|
|
|
4
4
|
const Ajv = require('ajv')
|
|
5
5
|
const Joi = require('joi')
|
|
6
6
|
const yup = require('yup')
|
|
7
|
+
const assert = require('node:assert')
|
|
7
8
|
|
|
8
9
|
module.exports.payloadMethod = function (method, t) {
|
|
9
10
|
const test = t.test
|
|
@@ -127,28 +128,27 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
127
128
|
|
|
128
129
|
done()
|
|
129
130
|
})
|
|
130
|
-
t.
|
|
131
|
+
t.assert.ok(true)
|
|
131
132
|
} catch (e) {
|
|
132
|
-
t.fail()
|
|
133
|
+
t.assert.fail()
|
|
133
134
|
}
|
|
134
135
|
})
|
|
135
136
|
|
|
136
137
|
fastify.listen({ port: 0 }, function (err) {
|
|
137
|
-
|
|
138
|
-
t.error(err)
|
|
139
|
-
}
|
|
138
|
+
assert.ifError(err)
|
|
140
139
|
|
|
141
|
-
t.
|
|
140
|
+
t.after(() => { fastify.close() })
|
|
142
141
|
|
|
143
|
-
test(`${upMethod} - correctly replies`, t => {
|
|
142
|
+
test(`${upMethod} - correctly replies`, (t, testDone) => {
|
|
144
143
|
if (upMethod === 'HEAD') {
|
|
145
144
|
t.plan(2)
|
|
146
145
|
sget({
|
|
147
146
|
method: upMethod,
|
|
148
147
|
url: 'http://localhost:' + fastify.server.address().port
|
|
149
148
|
}, (err, response) => {
|
|
150
|
-
t.
|
|
151
|
-
t.
|
|
149
|
+
t.assert.ifError(err)
|
|
150
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
151
|
+
testDone()
|
|
152
152
|
})
|
|
153
153
|
} else {
|
|
154
154
|
t.plan(3)
|
|
@@ -160,14 +160,15 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
160
160
|
},
|
|
161
161
|
json: true
|
|
162
162
|
}, (err, response, body) => {
|
|
163
|
-
t.
|
|
164
|
-
t.
|
|
165
|
-
t.
|
|
163
|
+
t.assert.ifError(err)
|
|
164
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
165
|
+
t.assert.deepStrictEqual(body, { hello: 42 })
|
|
166
|
+
testDone()
|
|
166
167
|
})
|
|
167
168
|
}
|
|
168
169
|
})
|
|
169
170
|
|
|
170
|
-
test(`${upMethod} - 400 on bad parameters`, t => {
|
|
171
|
+
test(`${upMethod} - 400 on bad parameters`, (t, testDone) => {
|
|
171
172
|
t.plan(3)
|
|
172
173
|
sget({
|
|
173
174
|
method: upMethod,
|
|
@@ -177,18 +178,19 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
177
178
|
},
|
|
178
179
|
json: true
|
|
179
180
|
}, (err, response, body) => {
|
|
180
|
-
t.
|
|
181
|
-
t.
|
|
182
|
-
t.
|
|
181
|
+
t.assert.ifError(err)
|
|
182
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
183
|
+
t.assert.deepStrictEqual(body, {
|
|
183
184
|
error: 'Bad Request',
|
|
184
185
|
message: 'body/hello must be integer',
|
|
185
186
|
statusCode: 400,
|
|
186
187
|
code: 'FST_ERR_VALIDATION'
|
|
187
188
|
})
|
|
189
|
+
testDone()
|
|
188
190
|
})
|
|
189
191
|
})
|
|
190
192
|
|
|
191
|
-
test(`${upMethod} - input-validation coerce`, t => {
|
|
193
|
+
test(`${upMethod} - input-validation coerce`, (t, testDone) => {
|
|
192
194
|
t.plan(3)
|
|
193
195
|
sget({
|
|
194
196
|
method: upMethod,
|
|
@@ -198,13 +200,14 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
198
200
|
},
|
|
199
201
|
json: true
|
|
200
202
|
}, (err, response, body) => {
|
|
201
|
-
t.
|
|
202
|
-
t.
|
|
203
|
-
t.
|
|
203
|
+
t.assert.ifError(err)
|
|
204
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
205
|
+
t.assert.deepStrictEqual(body, { hello: 42 })
|
|
206
|
+
testDone()
|
|
204
207
|
})
|
|
205
208
|
})
|
|
206
209
|
|
|
207
|
-
test(`${upMethod} - input-validation custom schema compiler`, t => {
|
|
210
|
+
test(`${upMethod} - input-validation custom schema compiler`, (t, testDone) => {
|
|
208
211
|
t.plan(3)
|
|
209
212
|
sget({
|
|
210
213
|
method: upMethod,
|
|
@@ -215,13 +218,14 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
215
218
|
},
|
|
216
219
|
json: true
|
|
217
220
|
}, (err, response, body) => {
|
|
218
|
-
t.
|
|
219
|
-
t.
|
|
220
|
-
t.
|
|
221
|
+
t.assert.ifError(err)
|
|
222
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
223
|
+
t.assert.deepStrictEqual(body, { hello: 42 })
|
|
224
|
+
testDone()
|
|
221
225
|
})
|
|
222
226
|
})
|
|
223
227
|
|
|
224
|
-
test(`${upMethod} - input-validation joi schema compiler ok`, t => {
|
|
228
|
+
test(`${upMethod} - input-validation joi schema compiler ok`, (t, testDone) => {
|
|
225
229
|
t.plan(3)
|
|
226
230
|
sget({
|
|
227
231
|
method: upMethod,
|
|
@@ -231,13 +235,14 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
231
235
|
},
|
|
232
236
|
json: true
|
|
233
237
|
}, (err, response, body) => {
|
|
234
|
-
t.
|
|
235
|
-
t.
|
|
236
|
-
t.
|
|
238
|
+
t.assert.ifError(err)
|
|
239
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
240
|
+
t.assert.deepStrictEqual(body, { hello: '42' })
|
|
241
|
+
testDone()
|
|
237
242
|
})
|
|
238
243
|
})
|
|
239
244
|
|
|
240
|
-
test(`${upMethod} - input-validation joi schema compiler ko`, t => {
|
|
245
|
+
test(`${upMethod} - input-validation joi schema compiler ko`, (t, testDone) => {
|
|
241
246
|
t.plan(3)
|
|
242
247
|
sget({
|
|
243
248
|
method: upMethod,
|
|
@@ -247,18 +252,19 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
247
252
|
},
|
|
248
253
|
json: true
|
|
249
254
|
}, (err, response, body) => {
|
|
250
|
-
t.
|
|
251
|
-
t.
|
|
252
|
-
t.
|
|
255
|
+
t.assert.ifError(err)
|
|
256
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
257
|
+
t.assert.deepStrictEqual(body, {
|
|
253
258
|
error: 'Bad Request',
|
|
254
259
|
message: '"hello" must be a string',
|
|
255
260
|
statusCode: 400,
|
|
256
261
|
code: 'FST_ERR_VALIDATION'
|
|
257
262
|
})
|
|
263
|
+
testDone()
|
|
258
264
|
})
|
|
259
265
|
})
|
|
260
266
|
|
|
261
|
-
test(`${upMethod} - input-validation yup schema compiler ok`, t => {
|
|
267
|
+
test(`${upMethod} - input-validation yup schema compiler ok`, (t, testDone) => {
|
|
262
268
|
t.plan(3)
|
|
263
269
|
sget({
|
|
264
270
|
method: upMethod,
|
|
@@ -268,13 +274,14 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
268
274
|
},
|
|
269
275
|
json: true
|
|
270
276
|
}, (err, response, body) => {
|
|
271
|
-
t.
|
|
272
|
-
t.
|
|
273
|
-
t.
|
|
277
|
+
t.assert.ifError(err)
|
|
278
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
279
|
+
t.assert.deepStrictEqual(body, { hello: '42' })
|
|
280
|
+
testDone()
|
|
274
281
|
})
|
|
275
282
|
})
|
|
276
283
|
|
|
277
|
-
test(`${upMethod} - input-validation yup schema compiler ko`, t => {
|
|
284
|
+
test(`${upMethod} - input-validation yup schema compiler ko`, (t, testDone) => {
|
|
278
285
|
t.plan(3)
|
|
279
286
|
sget({
|
|
280
287
|
method: upMethod,
|
|
@@ -284,52 +291,55 @@ module.exports.payloadMethod = function (method, t) {
|
|
|
284
291
|
},
|
|
285
292
|
json: true
|
|
286
293
|
}, (err, response, body) => {
|
|
287
|
-
t.
|
|
288
|
-
t.
|
|
289
|
-
t.
|
|
294
|
+
t.assert.ifError(err)
|
|
295
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
296
|
+
t.assert.deepStrictEqual(body, {
|
|
290
297
|
error: 'Bad Request',
|
|
291
|
-
message:
|
|
298
|
+
message: 'body hello must be a `string` type, but the final value was: `44`.',
|
|
292
299
|
statusCode: 400,
|
|
293
300
|
code: 'FST_ERR_VALIDATION'
|
|
294
301
|
})
|
|
302
|
+
testDone()
|
|
295
303
|
})
|
|
296
304
|
})
|
|
297
305
|
|
|
298
|
-
test(`${upMethod} - input-validation instance custom schema compiler encapsulated`, t => {
|
|
306
|
+
test(`${upMethod} - input-validation instance custom schema compiler encapsulated`, (t, testDone) => {
|
|
299
307
|
t.plan(3)
|
|
300
308
|
sget({
|
|
301
309
|
method: upMethod,
|
|
302
310
|
url: 'http://localhost:' + fastify.server.address().port + '/plugin',
|
|
303
|
-
body: {
|
|
311
|
+
body: {},
|
|
304
312
|
json: true
|
|
305
313
|
}, (err, response, body) => {
|
|
306
|
-
t.
|
|
307
|
-
t.
|
|
308
|
-
t.
|
|
314
|
+
t.assert.ifError(err)
|
|
315
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
316
|
+
t.assert.deepStrictEqual(body, {
|
|
309
317
|
error: 'Bad Request',
|
|
310
318
|
message: 'From custom schema compiler!',
|
|
311
|
-
statusCode:
|
|
319
|
+
statusCode: 400,
|
|
312
320
|
code: 'FST_ERR_VALIDATION'
|
|
313
321
|
})
|
|
322
|
+
testDone()
|
|
314
323
|
})
|
|
315
324
|
})
|
|
316
325
|
|
|
317
|
-
test(`${upMethod} - input-validation custom schema compiler encapsulated`, t => {
|
|
326
|
+
test(`${upMethod} - input-validation custom schema compiler encapsulated`, (t, testDone) => {
|
|
318
327
|
t.plan(3)
|
|
319
328
|
sget({
|
|
320
329
|
method: upMethod,
|
|
321
330
|
url: 'http://localhost:' + fastify.server.address().port + '/plugin/custom',
|
|
322
|
-
body: {
|
|
331
|
+
body: {},
|
|
323
332
|
json: true
|
|
324
333
|
}, (err, response, body) => {
|
|
325
|
-
t.
|
|
326
|
-
t.
|
|
327
|
-
t.
|
|
334
|
+
t.assert.ifError(err)
|
|
335
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
336
|
+
t.assert.deepStrictEqual(body, {
|
|
328
337
|
error: 'Bad Request',
|
|
329
338
|
message: 'Always fail!',
|
|
330
|
-
statusCode:
|
|
339
|
+
statusCode: 400,
|
|
331
340
|
code: 'FST_ERR_VALIDATION'
|
|
332
341
|
})
|
|
342
|
+
testDone()
|
|
333
343
|
})
|
|
334
344
|
})
|
|
335
345
|
})
|
|
@@ -580,16 +580,6 @@ test('FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX', t => {
|
|
|
580
580
|
t.assert.ok(error instanceof Error)
|
|
581
581
|
})
|
|
582
582
|
|
|
583
|
-
test('FST_ERR_HTTP2_INVALID_VERSION', t => {
|
|
584
|
-
t.plan(5)
|
|
585
|
-
const error = new errors.FST_ERR_HTTP2_INVALID_VERSION()
|
|
586
|
-
t.assert.strictEqual(error.name, 'FastifyError')
|
|
587
|
-
t.assert.strictEqual(error.code, 'FST_ERR_HTTP2_INVALID_VERSION')
|
|
588
|
-
t.assert.strictEqual(error.message, 'HTTP2 is available only from node >= 8.8.1')
|
|
589
|
-
t.assert.strictEqual(error.statusCode, 500)
|
|
590
|
-
t.assert.ok(error instanceof Error)
|
|
591
|
-
})
|
|
592
|
-
|
|
593
583
|
test('FST_ERR_INIT_OPTS_INVALID', t => {
|
|
594
584
|
t.plan(5)
|
|
595
585
|
const error = new errors.FST_ERR_INIT_OPTS_INVALID()
|
|
@@ -7,7 +7,6 @@ const Request = require('../../lib/request')
|
|
|
7
7
|
const Reply = require('../../lib/reply')
|
|
8
8
|
const { kRouteContext } = require('../../lib/symbols')
|
|
9
9
|
const buildSchema = require('../../lib/validation').compileSchemasForValidation
|
|
10
|
-
const sget = require('simple-get').concat
|
|
11
10
|
|
|
12
11
|
const Ajv = require('ajv')
|
|
13
12
|
const ajv = new Ajv({ coerceTypes: true })
|
|
@@ -129,8 +128,8 @@ test('handler function - preValidationCallback with finished response', t => {
|
|
|
129
128
|
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context }))
|
|
130
129
|
})
|
|
131
130
|
|
|
132
|
-
test('request should be defined in onSend Hook on post request with content type application/json',
|
|
133
|
-
t.plan(
|
|
131
|
+
test('request should be defined in onSend Hook on post request with content type application/json', async t => {
|
|
132
|
+
t.plan(6)
|
|
134
133
|
const fastify = require('../..')()
|
|
135
134
|
|
|
136
135
|
t.after(() => {
|
|
@@ -149,28 +148,24 @@ test('request should be defined in onSend Hook on post request with content type
|
|
|
149
148
|
reply.send(200)
|
|
150
149
|
})
|
|
151
150
|
|
|
152
|
-
fastify.listen({ port: 0 }
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
'content-type': 'application/json'
|
|
159
|
-
}
|
|
160
|
-
}, (err, response, body) => {
|
|
161
|
-
t.assert.ifError(err)
|
|
162
|
-
// a 400 error is expected because of no body
|
|
163
|
-
t.assert.strictEqual(response.statusCode, 400)
|
|
164
|
-
done()
|
|
165
|
-
})
|
|
151
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
152
|
+
const result = await fetch(fastifyServer, {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: {
|
|
155
|
+
'content-type': 'application/json'
|
|
156
|
+
}
|
|
166
157
|
})
|
|
158
|
+
|
|
159
|
+
t.assert.strictEqual(result.status, 400)
|
|
167
160
|
})
|
|
168
161
|
|
|
169
|
-
test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded',
|
|
170
|
-
t.plan(
|
|
162
|
+
test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded', async t => {
|
|
163
|
+
t.plan(5)
|
|
171
164
|
const fastify = require('../..')()
|
|
172
165
|
|
|
173
|
-
t.after(() => {
|
|
166
|
+
t.after(() => {
|
|
167
|
+
fastify.close()
|
|
168
|
+
})
|
|
174
169
|
|
|
175
170
|
fastify.addHook('onSend', (request, reply, payload, done) => {
|
|
176
171
|
t.assert.ok(request)
|
|
@@ -183,29 +178,25 @@ test('request should be defined in onSend Hook on post request with content type
|
|
|
183
178
|
reply.send(200)
|
|
184
179
|
})
|
|
185
180
|
|
|
186
|
-
fastify.listen({ port: 0 }
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
headers: {
|
|
193
|
-
'content-type': 'application/x-www-form-urlencoded'
|
|
194
|
-
}
|
|
195
|
-
}, (err, response, body) => {
|
|
196
|
-
t.assert.ifError(err)
|
|
197
|
-
// a 415 error is expected because of missing content type parser
|
|
198
|
-
t.assert.strictEqual(response.statusCode, 415)
|
|
199
|
-
done()
|
|
200
|
-
})
|
|
181
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
182
|
+
const result = await fetch(fastifyServer, {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: {
|
|
185
|
+
'content-type': 'application/x-www-form-urlencoded'
|
|
186
|
+
}
|
|
201
187
|
})
|
|
188
|
+
|
|
189
|
+
// a 415 error is expected because of missing content type parser
|
|
190
|
+
t.assert.strictEqual(result.status, 415)
|
|
202
191
|
})
|
|
203
192
|
|
|
204
|
-
test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded',
|
|
205
|
-
t.plan(
|
|
193
|
+
test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded', async t => {
|
|
194
|
+
t.plan(5)
|
|
206
195
|
const fastify = require('../..')()
|
|
207
196
|
|
|
208
|
-
t.after(() => {
|
|
197
|
+
t.after(() => {
|
|
198
|
+
fastify.close()
|
|
199
|
+
})
|
|
209
200
|
|
|
210
201
|
fastify.addHook('onSend', (request, reply, payload, done) => {
|
|
211
202
|
t.assert.ok(request)
|
|
@@ -218,26 +209,20 @@ test('request should be defined in onSend Hook on options request with content t
|
|
|
218
209
|
reply.send(200)
|
|
219
210
|
})
|
|
220
211
|
|
|
221
|
-
fastify.listen({ port: 0 }
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
headers: {
|
|
228
|
-
'content-type': 'application/x-www-form-urlencoded'
|
|
229
|
-
}
|
|
230
|
-
}, (err, response, body) => {
|
|
231
|
-
t.assert.ifError(err)
|
|
232
|
-
// Body parsing skipped, so no body sent
|
|
233
|
-
t.assert.strictEqual(response.statusCode, 200)
|
|
234
|
-
done()
|
|
235
|
-
})
|
|
212
|
+
const fastifyServer = await fastify.listen({ port: 0 })
|
|
213
|
+
const result = await fetch(fastifyServer, {
|
|
214
|
+
method: 'OPTIONS',
|
|
215
|
+
headers: {
|
|
216
|
+
'content-type': 'application/x-www-form-urlencoded'
|
|
217
|
+
}
|
|
236
218
|
})
|
|
219
|
+
|
|
220
|
+
// Body parsing skipped, so no body sent
|
|
221
|
+
t.assert.strictEqual(result.status, 200)
|
|
237
222
|
})
|
|
238
223
|
|
|
239
|
-
test('request should respond with an error if an unserialized payload is sent inside an async handler',
|
|
240
|
-
t.plan(
|
|
224
|
+
test('request should respond with an error if an unserialized payload is sent inside an async handler', async t => {
|
|
225
|
+
t.plan(2)
|
|
241
226
|
|
|
242
227
|
const fastify = require('../..')()
|
|
243
228
|
|
|
@@ -246,18 +231,16 @@ test('request should respond with an error if an unserialized payload is sent in
|
|
|
246
231
|
return Promise.resolve(request.headers)
|
|
247
232
|
})
|
|
248
233
|
|
|
249
|
-
fastify.inject({
|
|
234
|
+
const res = await fastify.inject({
|
|
250
235
|
method: 'GET',
|
|
251
236
|
url: '/'
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
})
|
|
261
|
-
done()
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
t.assert.strictEqual(res.statusCode, 500)
|
|
240
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), {
|
|
241
|
+
error: 'Internal Server Error',
|
|
242
|
+
code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE',
|
|
243
|
+
message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.',
|
|
244
|
+
statusCode: 500
|
|
262
245
|
})
|
|
263
246
|
})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { test } = require('node:test')
|
|
4
4
|
const { Hooks } = require('../../lib/hooks')
|
|
5
|
+
const { default: fastify } = require('../../fastify')
|
|
5
6
|
const noop = () => {}
|
|
6
7
|
|
|
7
8
|
test('hooks should have 4 array with the registered hooks', t => {
|
|
@@ -77,3 +78,19 @@ test('should throw on wrong parameters', t => {
|
|
|
77
78
|
t.assert.strictEqual(e.message, 'onSend hook should be a function, instead got [object Null]')
|
|
78
79
|
}
|
|
79
80
|
})
|
|
81
|
+
|
|
82
|
+
test('Integration test: internal function _addHook should be turned into app.ready() rejection', async (t) => {
|
|
83
|
+
const app = fastify()
|
|
84
|
+
|
|
85
|
+
app.register(async function () {
|
|
86
|
+
app.addHook('notRealHook', async () => {})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
await app.ready()
|
|
91
|
+
t.assert.fail('Expected ready() to throw')
|
|
92
|
+
} catch (err) {
|
|
93
|
+
t.assert.strictEqual(err.code, 'FST_ERR_HOOK_NOT_SUPPORTED')
|
|
94
|
+
t.assert.match(err.message, /hook not supported/i)
|
|
95
|
+
}
|
|
96
|
+
})
|
package/test/issue-4959.test.js
CHANGED
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
const { test } = require('node:test')
|
|
4
4
|
const http = require('node:http')
|
|
5
5
|
const Fastify = require('../fastify')
|
|
6
|
-
|
|
6
|
+
const { setTimeout } = require('node:timers')
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Ensure that a socket error during the request does not cause the
|
|
10
|
+
* onSend hook to be called multiple times.
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/fastify/fastify/issues/4959
|
|
13
|
+
*/
|
|
7
14
|
function runBadClientCall (reqOptions, payload) {
|
|
8
15
|
let innerResolve, innerReject
|
|
9
16
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -17,7 +24,7 @@ function runBadClientCall (reqOptions, payload) {
|
|
|
17
24
|
...reqOptions,
|
|
18
25
|
headers: {
|
|
19
26
|
'Content-Type': 'application/json',
|
|
20
|
-
'Content-Length': Buffer.byteLength(postData)
|
|
27
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
21
28
|
}
|
|
22
29
|
}, () => {
|
|
23
30
|
innerReject(new Error('Request should have failed'))
|
|
@@ -25,7 +32,9 @@ function runBadClientCall (reqOptions, payload) {
|
|
|
25
32
|
|
|
26
33
|
// Kill the socket immediately (before sending data)
|
|
27
34
|
req.on('socket', (socket) => {
|
|
28
|
-
|
|
35
|
+
socket.on('connect', () => {
|
|
36
|
+
setTimeout(() => { socket.destroy() }, 0)
|
|
37
|
+
})
|
|
29
38
|
})
|
|
30
39
|
req.on('error', innerResolve)
|
|
31
40
|
req.write(postData)
|
|
@@ -34,7 +43,7 @@ function runBadClientCall (reqOptions, payload) {
|
|
|
34
43
|
return promise
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
test('should handle a
|
|
46
|
+
test('should handle a socket error', async (t) => {
|
|
38
47
|
t.plan(4)
|
|
39
48
|
const fastify = Fastify()
|
|
40
49
|
|
|
@@ -78,7 +87,7 @@ test('should handle a soket error', async (t) => {
|
|
|
78
87
|
hostname: 'localhost',
|
|
79
88
|
port: fastify.server.address().port,
|
|
80
89
|
path: '/',
|
|
81
|
-
method: 'PUT'
|
|
90
|
+
method: 'PUT'
|
|
82
91
|
}, { test: 'me' })
|
|
83
92
|
t.assert.equal(err.code, 'ECONNRESET')
|
|
84
93
|
})
|
package/test/listen.4.test.js
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
const { test, before } = require('node:test')
|
|
4
4
|
const dns = require('node:dns').promises
|
|
5
5
|
const dnsCb = require('node:dns')
|
|
6
|
-
const sget = require('simple-get').concat
|
|
7
6
|
const Fastify = require('../fastify')
|
|
8
7
|
const helper = require('./helper')
|
|
9
|
-
const { waitForCb } = require('./toolkit')
|
|
10
8
|
|
|
11
9
|
let localhostForURL
|
|
12
10
|
|
|
@@ -90,7 +88,7 @@ test('listen logs the port as info', async t => {
|
|
|
90
88
|
|
|
91
89
|
test('listen on localhost binds IPv4 and IPv6 - promise interface', async t => {
|
|
92
90
|
const localAddresses = await dns.lookup('localhost', { all: true })
|
|
93
|
-
t.plan(
|
|
91
|
+
t.plan(3 * localAddresses.length)
|
|
94
92
|
|
|
95
93
|
const app = Fastify()
|
|
96
94
|
app.get('/', async () => 'hello localhost')
|
|
@@ -98,52 +96,42 @@ test('listen on localhost binds IPv4 and IPv6 - promise interface', async t => {
|
|
|
98
96
|
await app.listen({ port: 0, host: 'localhost' })
|
|
99
97
|
|
|
100
98
|
for (const lookup of localAddresses) {
|
|
101
|
-
await
|
|
102
|
-
|
|
103
|
-
method: 'GET',
|
|
104
|
-
url: getUrl(app, lookup)
|
|
105
|
-
}, (err, response, body) => {
|
|
106
|
-
if (err) { return reject(err) }
|
|
107
|
-
t.assert.strictEqual(response.statusCode, 200)
|
|
108
|
-
t.assert.deepStrictEqual(body.toString(), 'hello localhost')
|
|
109
|
-
resolve()
|
|
110
|
-
})
|
|
99
|
+
const result = await fetch(getUrl(app, lookup), {
|
|
100
|
+
method: 'GET'
|
|
111
101
|
})
|
|
102
|
+
|
|
103
|
+
t.assert.ok(result.ok)
|
|
104
|
+
t.assert.deepEqual(result.status, 200)
|
|
105
|
+
t.assert.deepStrictEqual(await result.text(), 'hello localhost')
|
|
112
106
|
}
|
|
113
107
|
})
|
|
114
108
|
|
|
115
|
-
test('listen on localhost binds to all interfaces (both IPv4 and IPv6 if present) - callback interface', (t
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const app = Fastify()
|
|
121
|
-
app.get('/', async () => 'hello localhost')
|
|
122
|
-
app.listen({ port: 0, host: 'localhost' }, (err) => {
|
|
123
|
-
t.assert.ifError(err)
|
|
124
|
-
t.after(() => app.close())
|
|
125
|
-
|
|
126
|
-
const { stepIn, patience } = waitForCb({ steps: lookups.length })
|
|
127
|
-
|
|
128
|
-
// Loop over each lookup and perform the assertions
|
|
129
|
-
if (lookups.length > 0) {
|
|
130
|
-
for (const lookup of lookups) {
|
|
131
|
-
sget({
|
|
132
|
-
method: 'GET',
|
|
133
|
-
url: getUrl(app, lookup)
|
|
134
|
-
}, (err, response, body) => {
|
|
135
|
-
t.assert.ifError(err)
|
|
136
|
-
t.assert.strictEqual(response.statusCode, 200)
|
|
137
|
-
t.assert.deepStrictEqual(body.toString(), 'hello localhost')
|
|
138
|
-
// Call stepIn to report that a request has been completed
|
|
139
|
-
stepIn()
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
// When all requests have been completed, call done
|
|
143
|
-
patience.then(() => done())
|
|
144
|
-
}
|
|
109
|
+
test('listen on localhost binds to all interfaces (both IPv4 and IPv6 if present) - callback interface', async (t) => {
|
|
110
|
+
const lookups = await new Promise((resolve, reject) => {
|
|
111
|
+
dnsCb.lookup('localhost', { all: true }, (err, lookups) => {
|
|
112
|
+
if (err) return reject(err)
|
|
113
|
+
resolve(lookups)
|
|
145
114
|
})
|
|
146
115
|
})
|
|
116
|
+
|
|
117
|
+
t.plan(3 * lookups.length)
|
|
118
|
+
|
|
119
|
+
const app = Fastify()
|
|
120
|
+
app.get('/', async () => 'hello localhost')
|
|
121
|
+
t.after(() => app.close())
|
|
122
|
+
|
|
123
|
+
await app.listen({ port: 0, host: 'localhost' })
|
|
124
|
+
|
|
125
|
+
// Loop over each lookup and perform the assertions
|
|
126
|
+
for (const lookup of lookups) {
|
|
127
|
+
const result = await fetch(getUrl(app, lookup), {
|
|
128
|
+
method: 'GET'
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
t.assert.ok(result.ok)
|
|
132
|
+
t.assert.deepEqual(result.status, 200)
|
|
133
|
+
t.assert.deepStrictEqual(await result.text(), 'hello localhost')
|
|
134
|
+
}
|
|
147
135
|
})
|
|
148
136
|
|
|
149
137
|
test('addresses getter', async t => {
|