node-fastify 5.8.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/.borp.yaml +3 -0
- package/.markdownlint-cli2.yaml +22 -0
- package/.prettierignore +1 -0
- package/GOVERNANCE.md +4 -0
- package/LICENSE +21 -0
- package/PROJECT_CHARTER.md +126 -0
- package/README.md +423 -0
- package/SECURITY.md +220 -0
- package/SPONSORS.md +24 -0
- package/build/build-error-serializer.js +35 -0
- package/build/build-validation.js +169 -0
- package/build/sync-version.js +11 -0
- package/docs/Guides/Benchmarking.md +60 -0
- package/docs/Guides/Database.md +321 -0
- package/docs/Guides/Delay-Accepting-Requests.md +608 -0
- package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
- package/docs/Guides/Ecosystem.md +726 -0
- package/docs/Guides/Fluent-Schema.md +127 -0
- package/docs/Guides/Getting-Started.md +620 -0
- package/docs/Guides/Index.md +43 -0
- package/docs/Guides/Migration-Guide-V3.md +287 -0
- package/docs/Guides/Migration-Guide-V4.md +267 -0
- package/docs/Guides/Migration-Guide-V5.md +727 -0
- package/docs/Guides/Plugins-Guide.md +520 -0
- package/docs/Guides/Prototype-Poisoning.md +383 -0
- package/docs/Guides/Recommendations.md +378 -0
- package/docs/Guides/Serverless.md +604 -0
- package/docs/Guides/Style-Guide.md +246 -0
- package/docs/Guides/Testing.md +481 -0
- package/docs/Guides/Write-Plugin.md +103 -0
- package/docs/Guides/Write-Type-Provider.md +34 -0
- package/docs/Reference/ContentTypeParser.md +271 -0
- package/docs/Reference/Decorators.md +436 -0
- package/docs/Reference/Encapsulation.md +194 -0
- package/docs/Reference/Errors.md +377 -0
- package/docs/Reference/HTTP2.md +94 -0
- package/docs/Reference/Hooks.md +958 -0
- package/docs/Reference/Index.md +73 -0
- package/docs/Reference/LTS.md +86 -0
- package/docs/Reference/Lifecycle.md +99 -0
- package/docs/Reference/Logging.md +268 -0
- package/docs/Reference/Middleware.md +79 -0
- package/docs/Reference/Plugins.md +245 -0
- package/docs/Reference/Principles.md +73 -0
- package/docs/Reference/Reply.md +1001 -0
- package/docs/Reference/Request.md +295 -0
- package/docs/Reference/Routes.md +802 -0
- package/docs/Reference/Server.md +2389 -0
- package/docs/Reference/Type-Providers.md +256 -0
- package/docs/Reference/TypeScript.md +1729 -0
- package/docs/Reference/Validation-and-Serialization.md +1130 -0
- package/docs/Reference/Warnings.md +58 -0
- package/docs/index.md +24 -0
- package/docs/resources/encapsulation_context.drawio +1 -0
- package/docs/resources/encapsulation_context.svg +3 -0
- package/eslint.config.js +35 -0
- package/examples/asyncawait.js +38 -0
- package/examples/benchmark/body.json +3 -0
- package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
- package/examples/benchmark/hooks-benchmark.js +52 -0
- package/examples/benchmark/parser.js +47 -0
- package/examples/benchmark/simple.js +30 -0
- package/examples/benchmark/webstream.js +27 -0
- package/examples/hooks.js +91 -0
- package/examples/http2.js +39 -0
- package/examples/https.js +38 -0
- package/examples/parser.js +53 -0
- package/examples/plugin.js +12 -0
- package/examples/route-prefix.js +38 -0
- package/examples/shared-schema.js +38 -0
- package/examples/simple-stream.js +20 -0
- package/examples/simple.js +32 -0
- package/examples/simple.mjs +27 -0
- package/examples/typescript-server.ts +79 -0
- package/examples/use-plugin.js +29 -0
- package/fastify.d.ts +253 -0
- package/fastify.js +985 -0
- package/integration/server.js +29 -0
- package/integration/test.sh +23 -0
- package/lib/config-validator.js +1266 -0
- package/lib/content-type-parser.js +413 -0
- package/lib/content-type.js +160 -0
- package/lib/context.js +98 -0
- package/lib/decorate.js +152 -0
- package/lib/error-handler.js +173 -0
- package/lib/error-serializer.js +134 -0
- package/lib/error-status.js +14 -0
- package/lib/errors.js +516 -0
- package/lib/four-oh-four.js +190 -0
- package/lib/handle-request.js +195 -0
- package/lib/head-route.js +45 -0
- package/lib/hooks.js +429 -0
- package/lib/initial-config-validation.js +37 -0
- package/lib/logger-factory.js +136 -0
- package/lib/logger-pino.js +68 -0
- package/lib/noop-set.js +10 -0
- package/lib/plugin-override.js +90 -0
- package/lib/plugin-utils.js +169 -0
- package/lib/promise.js +23 -0
- package/lib/reply.js +1030 -0
- package/lib/req-id-gen-factory.js +52 -0
- package/lib/request.js +391 -0
- package/lib/route.js +686 -0
- package/lib/schema-controller.js +164 -0
- package/lib/schemas.js +207 -0
- package/lib/server.js +441 -0
- package/lib/symbols.js +71 -0
- package/lib/validation.js +280 -0
- package/lib/warnings.js +57 -0
- package/lib/wrap-thenable.js +84 -0
- package/package.json +225 -0
- package/scripts/validate-ecosystem-links.js +179 -0
- package/test/404s.test.js +2035 -0
- package/test/500s.test.js +422 -0
- package/test/allow-unsafe-regex.test.js +92 -0
- package/test/als.test.js +65 -0
- package/test/async-await.test.js +705 -0
- package/test/async-dispose.test.js +20 -0
- package/test/async_hooks.test.js +52 -0
- package/test/body-limit.test.js +224 -0
- package/test/buffer.test.js +74 -0
- package/test/build/error-serializer.test.js +36 -0
- package/test/build/version.test.js +14 -0
- package/test/build-certificate.js +109 -0
- package/test/bundler/README.md +29 -0
- package/test/bundler/esbuild/bundler-test.js +32 -0
- package/test/bundler/esbuild/package.json +10 -0
- package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
- package/test/bundler/esbuild/src/index.js +9 -0
- package/test/bundler/webpack/bundler-test.js +32 -0
- package/test/bundler/webpack/package.json +11 -0
- package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
- package/test/bundler/webpack/src/index.js +9 -0
- package/test/bundler/webpack/webpack.config.js +15 -0
- package/test/case-insensitive.test.js +102 -0
- package/test/chainable.test.js +40 -0
- package/test/child-logger-factory.test.js +128 -0
- package/test/client-timeout.test.js +38 -0
- package/test/close-pipelining.test.js +78 -0
- package/test/close.test.js +706 -0
- package/test/conditional-pino.test.js +47 -0
- package/test/connection-timeout.test.js +42 -0
- package/test/constrained-routes.test.js +1138 -0
- package/test/content-length.test.js +174 -0
- package/test/content-parser.test.js +739 -0
- package/test/content-type.test.js +181 -0
- package/test/context-config.test.js +164 -0
- package/test/custom-http-server.test.js +118 -0
- package/test/custom-parser-async.test.js +59 -0
- package/test/custom-parser.0.test.js +701 -0
- package/test/custom-parser.1.test.js +266 -0
- package/test/custom-parser.2.test.js +91 -0
- package/test/custom-parser.3.test.js +208 -0
- package/test/custom-parser.4.test.js +218 -0
- package/test/custom-parser.5.test.js +130 -0
- package/test/custom-querystring-parser.test.js +129 -0
- package/test/decorator.test.js +1330 -0
- package/test/delete.test.js +344 -0
- package/test/diagnostics-channel/404.test.js +49 -0
- package/test/diagnostics-channel/async-delay-request.test.js +65 -0
- package/test/diagnostics-channel/async-request.test.js +64 -0
- package/test/diagnostics-channel/error-before-handler.test.js +35 -0
- package/test/diagnostics-channel/error-request.test.js +53 -0
- package/test/diagnostics-channel/error-status.test.js +123 -0
- package/test/diagnostics-channel/init.test.js +50 -0
- package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
- package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
- package/test/diagnostics-channel/sync-request.test.js +54 -0
- package/test/encapsulated-child-logger-factory.test.js +69 -0
- package/test/encapsulated-error-handler.test.js +237 -0
- package/test/esm/errorCodes.test.mjs +10 -0
- package/test/esm/esm.test.mjs +13 -0
- package/test/esm/index.test.js +8 -0
- package/test/esm/named-exports.mjs +14 -0
- package/test/esm/other.mjs +8 -0
- package/test/esm/plugin.mjs +8 -0
- package/test/fastify-instance.test.js +300 -0
- package/test/find-route.test.js +152 -0
- package/test/fluent-schema.test.js +209 -0
- package/test/genReqId.test.js +426 -0
- package/test/handler-context.test.js +45 -0
- package/test/handler-timeout.test.js +367 -0
- package/test/has-route.test.js +88 -0
- package/test/header-overflow.test.js +55 -0
- package/test/helper.js +496 -0
- package/test/hooks-async.test.js +1099 -0
- package/test/hooks.on-listen.test.js +1162 -0
- package/test/hooks.on-ready.test.js +421 -0
- package/test/hooks.test.js +3578 -0
- package/test/http-methods/copy.test.js +35 -0
- package/test/http-methods/custom-http-methods.test.js +114 -0
- package/test/http-methods/get.test.js +412 -0
- package/test/http-methods/head.test.js +263 -0
- package/test/http-methods/lock.test.js +108 -0
- package/test/http-methods/mkcalendar.test.js +143 -0
- package/test/http-methods/mkcol.test.js +35 -0
- package/test/http-methods/move.test.js +42 -0
- package/test/http-methods/propfind.test.js +136 -0
- package/test/http-methods/proppatch.test.js +105 -0
- package/test/http-methods/report.test.js +142 -0
- package/test/http-methods/search.test.js +233 -0
- package/test/http-methods/trace.test.js +21 -0
- package/test/http-methods/unlock.test.js +38 -0
- package/test/http2/closing.test.js +270 -0
- package/test/http2/constraint.test.js +109 -0
- package/test/http2/head.test.js +34 -0
- package/test/http2/plain.test.js +68 -0
- package/test/http2/secure-with-fallback.test.js +113 -0
- package/test/http2/secure.test.js +67 -0
- package/test/http2/unknown-http-method.test.js +34 -0
- package/test/https/custom-https-server.test.js +58 -0
- package/test/https/https.test.js +136 -0
- package/test/imports.test.js +17 -0
- package/test/inject.test.js +502 -0
- package/test/input-validation.js +335 -0
- package/test/internals/all.test.js +38 -0
- package/test/internals/content-type-parser.test.js +111 -0
- package/test/internals/context.test.js +31 -0
- package/test/internals/decorator.test.js +156 -0
- package/test/internals/errors.test.js +982 -0
- package/test/internals/handle-request.test.js +270 -0
- package/test/internals/hook-runner.test.js +449 -0
- package/test/internals/hooks.test.js +96 -0
- package/test/internals/initial-config.test.js +383 -0
- package/test/internals/logger.test.js +163 -0
- package/test/internals/plugin.test.js +170 -0
- package/test/internals/promise.test.js +63 -0
- package/test/internals/reply-serialize.test.js +714 -0
- package/test/internals/reply.test.js +1920 -0
- package/test/internals/req-id-gen-factory.test.js +133 -0
- package/test/internals/request-validate.test.js +1402 -0
- package/test/internals/request.test.js +506 -0
- package/test/internals/schema-controller-perf.test.js +40 -0
- package/test/internals/server.test.js +91 -0
- package/test/internals/validation.test.js +352 -0
- package/test/issue-4959.test.js +118 -0
- package/test/keep-alive-timeout.test.js +42 -0
- package/test/listen.1.test.js +154 -0
- package/test/listen.2.test.js +113 -0
- package/test/listen.3.test.js +83 -0
- package/test/listen.4.test.js +168 -0
- package/test/listen.5.test.js +122 -0
- package/test/logger/instantiation.test.js +341 -0
- package/test/logger/logger-test-utils.js +47 -0
- package/test/logger/logging.test.js +460 -0
- package/test/logger/options.test.js +579 -0
- package/test/logger/request.test.js +292 -0
- package/test/logger/response.test.js +183 -0
- package/test/logger/tap-parallel-not-ok +0 -0
- package/test/max-requests-per-socket.test.js +113 -0
- package/test/middleware.test.js +37 -0
- package/test/noop-set.test.js +19 -0
- package/test/nullable-validation.test.js +187 -0
- package/test/options.error-handler.test.js +5 -0
- package/test/options.test.js +5 -0
- package/test/output-validation.test.js +140 -0
- package/test/patch.error-handler.test.js +5 -0
- package/test/patch.test.js +5 -0
- package/test/plugin.1.test.js +230 -0
- package/test/plugin.2.test.js +314 -0
- package/test/plugin.3.test.js +287 -0
- package/test/plugin.4.test.js +504 -0
- package/test/plugin.helper.js +8 -0
- package/test/plugin.name.display.js +10 -0
- package/test/post-empty-body.test.js +38 -0
- package/test/pretty-print.test.js +366 -0
- package/test/promises.test.js +125 -0
- package/test/proto-poisoning.test.js +145 -0
- package/test/put.error-handler.test.js +5 -0
- package/test/put.test.js +5 -0
- package/test/register.test.js +184 -0
- package/test/reply-code.test.js +148 -0
- package/test/reply-early-hints.test.js +100 -0
- package/test/reply-error.test.js +815 -0
- package/test/reply-trailers.test.js +445 -0
- package/test/reply-web-stream-locked.test.js +37 -0
- package/test/request-error.test.js +624 -0
- package/test/request-header-host.test.js +339 -0
- package/test/request-id.test.js +118 -0
- package/test/request-timeout.test.js +53 -0
- package/test/route-hooks.test.js +635 -0
- package/test/route-prefix.test.js +904 -0
- package/test/route-shorthand.test.js +48 -0
- package/test/route.1.test.js +259 -0
- package/test/route.2.test.js +100 -0
- package/test/route.3.test.js +213 -0
- package/test/route.4.test.js +127 -0
- package/test/route.5.test.js +211 -0
- package/test/route.6.test.js +306 -0
- package/test/route.7.test.js +406 -0
- package/test/route.8.test.js +225 -0
- package/test/router-options.test.js +1108 -0
- package/test/same-shape.test.js +124 -0
- package/test/schema-examples.test.js +661 -0
- package/test/schema-feature.test.js +2198 -0
- package/test/schema-serialization.test.js +1171 -0
- package/test/schema-special-usage.test.js +1348 -0
- package/test/schema-validation.test.js +1572 -0
- package/test/scripts/validate-ecosystem-links.test.js +339 -0
- package/test/serialize-response.test.js +186 -0
- package/test/server.test.js +347 -0
- package/test/set-error-handler.test.js +69 -0
- package/test/skip-reply-send.test.js +317 -0
- package/test/stream-serializers.test.js +40 -0
- package/test/stream.1.test.js +94 -0
- package/test/stream.2.test.js +129 -0
- package/test/stream.3.test.js +198 -0
- package/test/stream.4.test.js +176 -0
- package/test/stream.5.test.js +188 -0
- package/test/sync-routes.test.js +32 -0
- package/test/throw.test.js +359 -0
- package/test/toolkit.js +63 -0
- package/test/trust-proxy.test.js +162 -0
- package/test/type-provider.test.js +22 -0
- package/test/types/content-type-parser.test-d.ts +72 -0
- package/test/types/decorate-request-reply.test-d.ts +18 -0
- package/test/types/dummy-plugin.ts +9 -0
- package/test/types/errors.test-d.ts +90 -0
- package/test/types/fastify.test-d.ts +352 -0
- package/test/types/hooks.test-d.ts +550 -0
- package/test/types/import.ts +2 -0
- package/test/types/instance.test-d.ts +588 -0
- package/test/types/logger.test-d.ts +277 -0
- package/test/types/plugin.test-d.ts +97 -0
- package/test/types/register.test-d.ts +237 -0
- package/test/types/reply.test-d.ts +254 -0
- package/test/types/request.test-d.ts +188 -0
- package/test/types/route.test-d.ts +553 -0
- package/test/types/schema.test-d.ts +135 -0
- package/test/types/serverFactory.test-d.ts +37 -0
- package/test/types/type-provider.test-d.ts +1213 -0
- package/test/types/using.test-d.ts +17 -0
- package/test/upgrade.test.js +52 -0
- package/test/url-rewriting.test.js +122 -0
- package/test/use-semicolon-delimiter.test.js +168 -0
- package/test/validation-error-handling.test.js +900 -0
- package/test/versioned-routes.test.js +603 -0
- package/test/web-api.test.js +616 -0
- package/test/wrap-thenable.test.js +30 -0
- package/types/content-type-parser.d.ts +75 -0
- package/types/context.d.ts +22 -0
- package/types/errors.d.ts +92 -0
- package/types/hooks.d.ts +875 -0
- package/types/instance.d.ts +609 -0
- package/types/logger.d.ts +107 -0
- package/types/plugin.d.ts +44 -0
- package/types/register.d.ts +42 -0
- package/types/reply.d.ts +81 -0
- package/types/request.d.ts +95 -0
- package/types/route.d.ts +199 -0
- package/types/schema.d.ts +61 -0
- package/types/server-factory.d.ts +19 -0
- package/types/type-provider.d.ts +130 -0
- package/types/utils.d.ts +98 -0
|
@@ -0,0 +1,1108 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const split = require('split2')
|
|
4
|
+
const { test } = require('node:test')
|
|
5
|
+
const querystring = require('node:querystring')
|
|
6
|
+
const Fastify = require('../')
|
|
7
|
+
const {
|
|
8
|
+
FST_ERR_BAD_URL,
|
|
9
|
+
FST_ERR_ASYNC_CONSTRAINT
|
|
10
|
+
} = require('../lib/errors')
|
|
11
|
+
|
|
12
|
+
test('Should honor ignoreTrailingSlash option', async t => {
|
|
13
|
+
t.plan(4)
|
|
14
|
+
const fastify = Fastify({
|
|
15
|
+
ignoreTrailingSlash: true
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
fastify.get('/test', (req, res) => {
|
|
19
|
+
res.send('test')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
let res = await fastify.inject('/test')
|
|
23
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
24
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
25
|
+
|
|
26
|
+
res = await fastify.inject('/test/')
|
|
27
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
28
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('Should honor ignoreDuplicateSlashes option', async t => {
|
|
32
|
+
t.plan(4)
|
|
33
|
+
const fastify = Fastify({
|
|
34
|
+
ignoreDuplicateSlashes: true
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
fastify.get('/test//test///test', (req, res) => {
|
|
38
|
+
res.send('test')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
let res = await fastify.inject('/test/test/test')
|
|
42
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
43
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
44
|
+
|
|
45
|
+
res = await fastify.inject('/test//test///test')
|
|
46
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
47
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', async t => {
|
|
51
|
+
t.plan(4)
|
|
52
|
+
const fastify = Fastify({
|
|
53
|
+
ignoreTrailingSlash: true,
|
|
54
|
+
ignoreDuplicateSlashes: true
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
fastify.get('/test//test///test', (req, res) => {
|
|
58
|
+
res.send('test')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
let res = await fastify.inject('/test/test/test/')
|
|
62
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
63
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
64
|
+
|
|
65
|
+
res = await fastify.inject('/test//test///test//')
|
|
66
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
67
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('Should honor maxParamLength option', async (t) => {
|
|
71
|
+
const fastify = Fastify({ maxParamLength: 10 })
|
|
72
|
+
|
|
73
|
+
fastify.get('/test/:id', (req, reply) => {
|
|
74
|
+
reply.send({ hello: 'world' })
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const res = await fastify.inject({
|
|
78
|
+
method: 'GET',
|
|
79
|
+
url: '/test/123456789'
|
|
80
|
+
})
|
|
81
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
82
|
+
|
|
83
|
+
const resError = await fastify.inject({
|
|
84
|
+
method: 'GET',
|
|
85
|
+
url: '/test/123456789abcd'
|
|
86
|
+
})
|
|
87
|
+
t.assert.strictEqual(resError.statusCode, 404)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('Should expose router options via getters on request and reply', (t, done) => {
|
|
91
|
+
t.plan(9)
|
|
92
|
+
const fastify = Fastify()
|
|
93
|
+
const expectedSchema = {
|
|
94
|
+
params: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {
|
|
97
|
+
id: { type: 'integer' }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fastify.get('/test/:id', {
|
|
103
|
+
schema: expectedSchema
|
|
104
|
+
}, (req, reply) => {
|
|
105
|
+
t.assert.strictEqual(reply.routeOptions.config.url, '/test/:id')
|
|
106
|
+
t.assert.strictEqual(reply.routeOptions.config.method, 'GET')
|
|
107
|
+
t.assert.deepStrictEqual(req.routeOptions.schema, expectedSchema)
|
|
108
|
+
t.assert.strictEqual(typeof req.routeOptions.handler, 'function')
|
|
109
|
+
t.assert.strictEqual(req.routeOptions.config.url, '/test/:id')
|
|
110
|
+
t.assert.strictEqual(req.routeOptions.config.method, 'GET')
|
|
111
|
+
t.assert.strictEqual(req.is404, false)
|
|
112
|
+
reply.send({ hello: 'world' })
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
fastify.inject({
|
|
116
|
+
method: 'GET',
|
|
117
|
+
url: '/test/123456789'
|
|
118
|
+
}, (error, res) => {
|
|
119
|
+
t.assert.ifError(error)
|
|
120
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
121
|
+
done()
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test('Should set is404 flag for unmatched paths', (t, done) => {
|
|
126
|
+
t.plan(3)
|
|
127
|
+
const fastify = Fastify()
|
|
128
|
+
|
|
129
|
+
fastify.setNotFoundHandler((req, reply) => {
|
|
130
|
+
t.assert.strictEqual(req.is404, true)
|
|
131
|
+
reply.code(404).send({ error: 'Not Found', message: 'Four oh for', statusCode: 404 })
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
fastify.inject({
|
|
135
|
+
method: 'GET',
|
|
136
|
+
url: '/nonexist/123456789'
|
|
137
|
+
}, (error, res) => {
|
|
138
|
+
t.assert.ifError(error)
|
|
139
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
140
|
+
done()
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('Should honor frameworkErrors option - FST_ERR_BAD_URL', (t, done) => {
|
|
145
|
+
t.plan(3)
|
|
146
|
+
const fastify = Fastify({
|
|
147
|
+
frameworkErrors: function (err, req, res) {
|
|
148
|
+
if (err instanceof FST_ERR_BAD_URL) {
|
|
149
|
+
t.assert.ok(true)
|
|
150
|
+
} else {
|
|
151
|
+
t.assert.fail()
|
|
152
|
+
}
|
|
153
|
+
res.send(`${err.message} - ${err.code}`)
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
fastify.get('/test/:id', (req, res) => {
|
|
158
|
+
res.send('{ hello: \'world\' }')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
fastify.inject(
|
|
162
|
+
{
|
|
163
|
+
method: 'GET',
|
|
164
|
+
url: '/test/%world'
|
|
165
|
+
},
|
|
166
|
+
(err, res) => {
|
|
167
|
+
t.assert.ifError(err)
|
|
168
|
+
t.assert.strictEqual(res.body, '\'/test/%world\' is not a valid url component - FST_ERR_BAD_URL')
|
|
169
|
+
done()
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('Should supply Fastify request to the logger in frameworkErrors wrapper - FST_ERR_BAD_URL', (t, done) => {
|
|
175
|
+
t.plan(8)
|
|
176
|
+
|
|
177
|
+
const REQ_ID = 'REQ-1234'
|
|
178
|
+
const logStream = split(JSON.parse)
|
|
179
|
+
|
|
180
|
+
const fastify = Fastify({
|
|
181
|
+
frameworkErrors: function (err, req, res) {
|
|
182
|
+
t.assert.deepStrictEqual(req.id, REQ_ID)
|
|
183
|
+
t.assert.deepStrictEqual(req.raw.httpVersion, '1.1')
|
|
184
|
+
res.send(`${err.message} - ${err.code}`)
|
|
185
|
+
},
|
|
186
|
+
logger: {
|
|
187
|
+
stream: logStream,
|
|
188
|
+
serializers: {
|
|
189
|
+
req (request) {
|
|
190
|
+
t.assert.deepStrictEqual(request.id, REQ_ID)
|
|
191
|
+
return { httpVersion: request.raw.httpVersion }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
genReqId: () => REQ_ID
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
fastify.get('/test/:id', (req, res) => {
|
|
199
|
+
res.send('{ hello: \'world\' }')
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
logStream.on('data', (json) => {
|
|
203
|
+
t.assert.deepStrictEqual(json.msg, 'incoming request')
|
|
204
|
+
t.assert.deepStrictEqual(json.reqId, REQ_ID)
|
|
205
|
+
t.assert.deepStrictEqual(json.req.httpVersion, '1.1')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
fastify.inject(
|
|
209
|
+
{
|
|
210
|
+
method: 'GET',
|
|
211
|
+
url: '/test/%world'
|
|
212
|
+
},
|
|
213
|
+
(err, res) => {
|
|
214
|
+
t.assert.ifError(err)
|
|
215
|
+
t.assert.strictEqual(res.body, '\'/test/%world\' is not a valid url component - FST_ERR_BAD_URL')
|
|
216
|
+
done()
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('Should honor disableRequestLogging option in frameworkErrors wrapper - FST_ERR_BAD_URL', (t, done) => {
|
|
222
|
+
t.plan(2)
|
|
223
|
+
|
|
224
|
+
const logStream = split(JSON.parse)
|
|
225
|
+
|
|
226
|
+
const fastify = Fastify({
|
|
227
|
+
disableRequestLogging: true,
|
|
228
|
+
frameworkErrors: function (err, req, res) {
|
|
229
|
+
res.send(`${err.message} - ${err.code}`)
|
|
230
|
+
},
|
|
231
|
+
logger: {
|
|
232
|
+
stream: logStream,
|
|
233
|
+
serializers: {
|
|
234
|
+
req () {
|
|
235
|
+
t.assert.fail('should not be called')
|
|
236
|
+
},
|
|
237
|
+
res () {
|
|
238
|
+
t.assert.fail('should not be called')
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
fastify.get('/test/:id', (req, res) => {
|
|
245
|
+
res.send('{ hello: \'world\' }')
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
logStream.on('data', (json) => {
|
|
249
|
+
t.assert.fail('should not be called')
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
fastify.inject(
|
|
253
|
+
{
|
|
254
|
+
method: 'GET',
|
|
255
|
+
url: '/test/%world'
|
|
256
|
+
},
|
|
257
|
+
(err, res) => {
|
|
258
|
+
t.assert.ifError(err)
|
|
259
|
+
t.assert.strictEqual(res.body, '\'/test/%world\' is not a valid url component - FST_ERR_BAD_URL')
|
|
260
|
+
done()
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
test('Should honor frameworkErrors option - FST_ERR_ASYNC_CONSTRAINT', (t, done) => {
|
|
266
|
+
t.plan(3)
|
|
267
|
+
|
|
268
|
+
const constraint = {
|
|
269
|
+
name: 'secret',
|
|
270
|
+
storage: function () {
|
|
271
|
+
const secrets = {}
|
|
272
|
+
return {
|
|
273
|
+
get: (secret) => { return secrets[secret] || null },
|
|
274
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
deriveConstraint: (req, ctx, done) => {
|
|
278
|
+
done(Error('kaboom'))
|
|
279
|
+
},
|
|
280
|
+
validate () { return true }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const fastify = Fastify({
|
|
284
|
+
frameworkErrors: function (err, req, res) {
|
|
285
|
+
if (err instanceof FST_ERR_ASYNC_CONSTRAINT) {
|
|
286
|
+
t.assert.ok(true)
|
|
287
|
+
} else {
|
|
288
|
+
t.assert.fail()
|
|
289
|
+
}
|
|
290
|
+
res.send(`${err.message} - ${err.code}`)
|
|
291
|
+
},
|
|
292
|
+
constraints: { secret: constraint }
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
fastify.route({
|
|
296
|
+
method: 'GET',
|
|
297
|
+
url: '/',
|
|
298
|
+
constraints: { secret: 'alpha' },
|
|
299
|
+
handler: (req, reply) => {
|
|
300
|
+
reply.send({ hello: 'from alpha' })
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
fastify.inject(
|
|
305
|
+
{
|
|
306
|
+
method: 'GET',
|
|
307
|
+
url: '/'
|
|
308
|
+
},
|
|
309
|
+
(err, res) => {
|
|
310
|
+
t.assert.ifError(err)
|
|
311
|
+
t.assert.strictEqual(res.body, 'Unexpected error from async constraint - FST_ERR_ASYNC_CONSTRAINT')
|
|
312
|
+
done()
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
test('Should supply Fastify request to the logger in frameworkErrors wrapper - FST_ERR_ASYNC_CONSTRAINT', (t, done) => {
|
|
318
|
+
t.plan(8)
|
|
319
|
+
|
|
320
|
+
const constraint = {
|
|
321
|
+
name: 'secret',
|
|
322
|
+
storage: function () {
|
|
323
|
+
const secrets = {}
|
|
324
|
+
return {
|
|
325
|
+
get: (secret) => { return secrets[secret] || null },
|
|
326
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
deriveConstraint: (req, ctx, done) => {
|
|
330
|
+
done(Error('kaboom'))
|
|
331
|
+
},
|
|
332
|
+
validate () { return true }
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const REQ_ID = 'REQ-1234'
|
|
336
|
+
const logStream = split(JSON.parse)
|
|
337
|
+
|
|
338
|
+
const fastify = Fastify({
|
|
339
|
+
constraints: { secret: constraint },
|
|
340
|
+
frameworkErrors: function (err, req, res) {
|
|
341
|
+
t.assert.deepStrictEqual(req.id, REQ_ID)
|
|
342
|
+
t.assert.deepStrictEqual(req.raw.httpVersion, '1.1')
|
|
343
|
+
res.send(`${err.message} - ${err.code}`)
|
|
344
|
+
},
|
|
345
|
+
logger: {
|
|
346
|
+
stream: logStream,
|
|
347
|
+
serializers: {
|
|
348
|
+
req (request) {
|
|
349
|
+
t.assert.deepStrictEqual(request.id, REQ_ID)
|
|
350
|
+
return { httpVersion: request.raw.httpVersion }
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
genReqId: () => REQ_ID
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
fastify.route({
|
|
358
|
+
method: 'GET',
|
|
359
|
+
url: '/',
|
|
360
|
+
constraints: { secret: 'alpha' },
|
|
361
|
+
handler: (req, reply) => {
|
|
362
|
+
reply.send({ hello: 'from alpha' })
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
logStream.on('data', (json) => {
|
|
367
|
+
t.assert.deepStrictEqual(json.msg, 'incoming request')
|
|
368
|
+
t.assert.deepStrictEqual(json.reqId, REQ_ID)
|
|
369
|
+
t.assert.deepStrictEqual(json.req.httpVersion, '1.1')
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
fastify.inject(
|
|
373
|
+
{
|
|
374
|
+
method: 'GET',
|
|
375
|
+
url: '/'
|
|
376
|
+
},
|
|
377
|
+
(err, res) => {
|
|
378
|
+
t.assert.ifError(err)
|
|
379
|
+
t.assert.strictEqual(res.body, 'Unexpected error from async constraint - FST_ERR_ASYNC_CONSTRAINT')
|
|
380
|
+
done()
|
|
381
|
+
}
|
|
382
|
+
)
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
test('Should honor disableRequestLogging option in frameworkErrors wrapper - FST_ERR_ASYNC_CONSTRAINT', (t, done) => {
|
|
386
|
+
t.plan(2)
|
|
387
|
+
|
|
388
|
+
const constraint = {
|
|
389
|
+
name: 'secret',
|
|
390
|
+
storage: function () {
|
|
391
|
+
const secrets = {}
|
|
392
|
+
return {
|
|
393
|
+
get: (secret) => { return secrets[secret] || null },
|
|
394
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
deriveConstraint: (req, ctx, done) => {
|
|
398
|
+
done(Error('kaboom'))
|
|
399
|
+
},
|
|
400
|
+
validate () { return true }
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const logStream = split(JSON.parse)
|
|
404
|
+
|
|
405
|
+
const fastify = Fastify({
|
|
406
|
+
constraints: { secret: constraint },
|
|
407
|
+
disableRequestLogging: true,
|
|
408
|
+
frameworkErrors: function (err, req, res) {
|
|
409
|
+
res.send(`${err.message} - ${err.code}`)
|
|
410
|
+
},
|
|
411
|
+
logger: {
|
|
412
|
+
stream: logStream,
|
|
413
|
+
serializers: {
|
|
414
|
+
req () {
|
|
415
|
+
t.assert.fail('should not be called')
|
|
416
|
+
},
|
|
417
|
+
res () {
|
|
418
|
+
t.assert.fail('should not be called')
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
fastify.route({
|
|
425
|
+
method: 'GET',
|
|
426
|
+
url: '/',
|
|
427
|
+
constraints: { secret: 'alpha' },
|
|
428
|
+
handler: (req, reply) => {
|
|
429
|
+
reply.send({ hello: 'from alpha' })
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
logStream.on('data', (json) => {
|
|
434
|
+
t.assert.fail('should not be called')
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
fastify.inject(
|
|
438
|
+
{
|
|
439
|
+
method: 'GET',
|
|
440
|
+
url: '/'
|
|
441
|
+
},
|
|
442
|
+
(err, res) => {
|
|
443
|
+
t.assert.ifError(err)
|
|
444
|
+
t.assert.strictEqual(res.body, 'Unexpected error from async constraint - FST_ERR_ASYNC_CONSTRAINT')
|
|
445
|
+
done()
|
|
446
|
+
}
|
|
447
|
+
)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
test('Should honor disableRequestLogging function in frameworkErrors wrapper - FST_ERR_BAD_URL', (t, done) => {
|
|
451
|
+
t.plan(4)
|
|
452
|
+
|
|
453
|
+
let logCallCount = 0
|
|
454
|
+
const logStream = split(JSON.parse)
|
|
455
|
+
|
|
456
|
+
const fastify = Fastify({
|
|
457
|
+
disableRequestLogging: (req) => {
|
|
458
|
+
// Disable logging for URLs containing 'silent'
|
|
459
|
+
return req.url.includes('silent')
|
|
460
|
+
},
|
|
461
|
+
frameworkErrors: function (err, req, res) {
|
|
462
|
+
res.send(`${err.message} - ${err.code}`)
|
|
463
|
+
},
|
|
464
|
+
logger: {
|
|
465
|
+
stream: logStream,
|
|
466
|
+
level: 'info'
|
|
467
|
+
}
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
fastify.get('/test/:id', (req, res) => {
|
|
471
|
+
res.send('{ hello: \'world\' }')
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
logStream.on('data', (json) => {
|
|
475
|
+
if (json.msg === 'incoming request') {
|
|
476
|
+
logCallCount++
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
// First request: URL does not contain 'silent', so logging should happen
|
|
481
|
+
fastify.inject(
|
|
482
|
+
{
|
|
483
|
+
method: 'GET',
|
|
484
|
+
url: '/test/%world'
|
|
485
|
+
},
|
|
486
|
+
(err, res) => {
|
|
487
|
+
t.assert.ifError(err)
|
|
488
|
+
t.assert.strictEqual(res.body, '\'/test/%world\' is not a valid url component - FST_ERR_BAD_URL')
|
|
489
|
+
|
|
490
|
+
// Second request: URL contains 'silent', so logging should be disabled
|
|
491
|
+
fastify.inject(
|
|
492
|
+
{
|
|
493
|
+
method: 'GET',
|
|
494
|
+
url: '/silent/%world'
|
|
495
|
+
},
|
|
496
|
+
(err2, res2) => {
|
|
497
|
+
t.assert.ifError(err2)
|
|
498
|
+
// Give time for any potential log events
|
|
499
|
+
setImmediate(() => {
|
|
500
|
+
// Only the first request should have logged
|
|
501
|
+
t.assert.strictEqual(logCallCount, 1)
|
|
502
|
+
done()
|
|
503
|
+
})
|
|
504
|
+
}
|
|
505
|
+
)
|
|
506
|
+
}
|
|
507
|
+
)
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
test('Should honor disableRequestLogging function in frameworkErrors wrapper - FST_ERR_ASYNC_CONSTRAINT', (t, done) => {
|
|
511
|
+
t.plan(4)
|
|
512
|
+
|
|
513
|
+
let logCallCount = 0
|
|
514
|
+
|
|
515
|
+
const constraint = {
|
|
516
|
+
name: 'secret',
|
|
517
|
+
storage: function () {
|
|
518
|
+
const secrets = {}
|
|
519
|
+
return {
|
|
520
|
+
get: (secret) => { return secrets[secret] || null },
|
|
521
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
deriveConstraint: (req, ctx, done) => {
|
|
525
|
+
done(Error('kaboom'))
|
|
526
|
+
},
|
|
527
|
+
validate () { return true }
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const logStream = split(JSON.parse)
|
|
531
|
+
|
|
532
|
+
const fastify = Fastify({
|
|
533
|
+
constraints: { secret: constraint },
|
|
534
|
+
disableRequestLogging: (req) => {
|
|
535
|
+
// Disable logging for URLs containing 'silent'
|
|
536
|
+
return req.url.includes('silent')
|
|
537
|
+
},
|
|
538
|
+
frameworkErrors: function (err, req, res) {
|
|
539
|
+
res.send(`${err.message} - ${err.code}`)
|
|
540
|
+
},
|
|
541
|
+
logger: {
|
|
542
|
+
stream: logStream,
|
|
543
|
+
level: 'info'
|
|
544
|
+
}
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
fastify.route({
|
|
548
|
+
method: 'GET',
|
|
549
|
+
url: '/',
|
|
550
|
+
constraints: { secret: 'alpha' },
|
|
551
|
+
handler: (req, reply) => {
|
|
552
|
+
reply.send({ hello: 'from alpha' })
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
fastify.route({
|
|
557
|
+
method: 'GET',
|
|
558
|
+
url: '/silent',
|
|
559
|
+
constraints: { secret: 'alpha' },
|
|
560
|
+
handler: (req, reply) => {
|
|
561
|
+
reply.send({ hello: 'from alpha' })
|
|
562
|
+
}
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
logStream.on('data', (json) => {
|
|
566
|
+
if (json.msg === 'incoming request') {
|
|
567
|
+
logCallCount++
|
|
568
|
+
}
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
// First request: URL does not contain 'silent', so logging should happen
|
|
572
|
+
fastify.inject(
|
|
573
|
+
{
|
|
574
|
+
method: 'GET',
|
|
575
|
+
url: '/'
|
|
576
|
+
},
|
|
577
|
+
(err, res) => {
|
|
578
|
+
t.assert.ifError(err)
|
|
579
|
+
t.assert.strictEqual(res.body, 'Unexpected error from async constraint - FST_ERR_ASYNC_CONSTRAINT')
|
|
580
|
+
|
|
581
|
+
// Second request: URL contains 'silent', so logging should be disabled
|
|
582
|
+
fastify.inject(
|
|
583
|
+
{
|
|
584
|
+
method: 'GET',
|
|
585
|
+
url: '/silent'
|
|
586
|
+
},
|
|
587
|
+
(err2, res2) => {
|
|
588
|
+
t.assert.ifError(err2)
|
|
589
|
+
// Give time for any potential log events
|
|
590
|
+
setImmediate(() => {
|
|
591
|
+
// Only the first request should have logged
|
|
592
|
+
t.assert.strictEqual(logCallCount, 1)
|
|
593
|
+
done()
|
|
594
|
+
})
|
|
595
|
+
}
|
|
596
|
+
)
|
|
597
|
+
}
|
|
598
|
+
)
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
test('Should honor routerOptions.defaultRoute', async t => {
|
|
602
|
+
t.plan(3)
|
|
603
|
+
const fastify = Fastify({
|
|
604
|
+
routerOptions: {
|
|
605
|
+
defaultRoute: function (_, res) {
|
|
606
|
+
t.assert.ok('default route called')
|
|
607
|
+
res.statusCode = 404
|
|
608
|
+
res.end('default route')
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
})
|
|
612
|
+
|
|
613
|
+
const res = await fastify.inject('/')
|
|
614
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
615
|
+
t.assert.strictEqual(res.payload, 'default route')
|
|
616
|
+
})
|
|
617
|
+
|
|
618
|
+
test('Should honor routerOptions.badUrl', async t => {
|
|
619
|
+
t.plan(3)
|
|
620
|
+
const fastify = Fastify({
|
|
621
|
+
routerOptions: {
|
|
622
|
+
defaultRoute: function (_, res) {
|
|
623
|
+
t.asset.fail('default route should not be called')
|
|
624
|
+
},
|
|
625
|
+
onBadUrl: function (path, _, res) {
|
|
626
|
+
t.assert.ok('bad url called')
|
|
627
|
+
res.statusCode = 400
|
|
628
|
+
res.end(`Bath URL: ${path}`)
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
})
|
|
632
|
+
|
|
633
|
+
fastify.get('/hello/:id', (req, res) => {
|
|
634
|
+
res.send({ hello: 'world' })
|
|
635
|
+
})
|
|
636
|
+
|
|
637
|
+
const res = await fastify.inject('/hello/%world')
|
|
638
|
+
t.assert.strictEqual(res.statusCode, 400)
|
|
639
|
+
t.assert.strictEqual(res.payload, 'Bath URL: /hello/%world')
|
|
640
|
+
})
|
|
641
|
+
|
|
642
|
+
test('Should honor routerOptions.ignoreTrailingSlash', async t => {
|
|
643
|
+
t.plan(4)
|
|
644
|
+
const fastify = Fastify({
|
|
645
|
+
routerOptions: {
|
|
646
|
+
ignoreTrailingSlash: true
|
|
647
|
+
}
|
|
648
|
+
})
|
|
649
|
+
|
|
650
|
+
fastify.get('/test', (req, res) => {
|
|
651
|
+
res.send('test')
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
let res = await fastify.inject('/test')
|
|
655
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
656
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
657
|
+
|
|
658
|
+
res = await fastify.inject('/test/')
|
|
659
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
660
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
661
|
+
})
|
|
662
|
+
|
|
663
|
+
test('Should honor routerOptions.ignoreDuplicateSlashes', async t => {
|
|
664
|
+
t.plan(4)
|
|
665
|
+
const fastify = Fastify({
|
|
666
|
+
routerOptions: {
|
|
667
|
+
ignoreDuplicateSlashes: true
|
|
668
|
+
}
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
fastify.get('/test//test///test', (req, res) => {
|
|
672
|
+
res.send('test')
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
let res = await fastify.inject('/test/test/test')
|
|
676
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
677
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
678
|
+
|
|
679
|
+
res = await fastify.inject('/test//test///test')
|
|
680
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
681
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
test('Should honor routerOptions.ignoreTrailingSlash and routerOptions.ignoreDuplicateSlashes', async t => {
|
|
685
|
+
t.plan(4)
|
|
686
|
+
const fastify = Fastify({
|
|
687
|
+
routerOptions: {
|
|
688
|
+
ignoreTrailingSlash: true,
|
|
689
|
+
ignoreDuplicateSlashes: true
|
|
690
|
+
}
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
t.after(() => fastify.close())
|
|
694
|
+
|
|
695
|
+
fastify.get('/test//test///test', (req, res) => {
|
|
696
|
+
res.send('test')
|
|
697
|
+
})
|
|
698
|
+
|
|
699
|
+
let res = await fastify.inject('/test/test/test/')
|
|
700
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
701
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
702
|
+
|
|
703
|
+
res = await fastify.inject('/test//test///test//')
|
|
704
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
705
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
test('Should honor routerOptions.maxParamLength', async (t) => {
|
|
709
|
+
const fastify = Fastify({
|
|
710
|
+
routerOptions:
|
|
711
|
+
{
|
|
712
|
+
maxParamLength: 10
|
|
713
|
+
}
|
|
714
|
+
})
|
|
715
|
+
|
|
716
|
+
fastify.get('/test/:id', (req, reply) => {
|
|
717
|
+
reply.send({ hello: 'world' })
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
const res = await fastify.inject({
|
|
721
|
+
method: 'GET',
|
|
722
|
+
url: '/test/123456789'
|
|
723
|
+
})
|
|
724
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
725
|
+
|
|
726
|
+
const resError = await fastify.inject({
|
|
727
|
+
method: 'GET',
|
|
728
|
+
url: '/test/123456789abcd'
|
|
729
|
+
})
|
|
730
|
+
t.assert.strictEqual(resError.statusCode, 404)
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
test('Should honor routerOptions.allowUnsafeRegex', async (t) => {
|
|
734
|
+
const fastify = Fastify({
|
|
735
|
+
routerOptions:
|
|
736
|
+
{
|
|
737
|
+
allowUnsafeRegex: true
|
|
738
|
+
}
|
|
739
|
+
})
|
|
740
|
+
|
|
741
|
+
fastify.get('/test/:id(([a-f0-9]{3},?)+)', (req, reply) => {
|
|
742
|
+
reply.send({ hello: 'world' })
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
let res = await fastify.inject({
|
|
746
|
+
method: 'GET',
|
|
747
|
+
url: '/test/bac,1ea'
|
|
748
|
+
})
|
|
749
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
750
|
+
|
|
751
|
+
res = await fastify.inject({
|
|
752
|
+
method: 'GET',
|
|
753
|
+
url: '/test/qwerty'
|
|
754
|
+
})
|
|
755
|
+
|
|
756
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
757
|
+
})
|
|
758
|
+
|
|
759
|
+
test('Should honor routerOptions.caseSensitive', async (t) => {
|
|
760
|
+
const fastify = Fastify({
|
|
761
|
+
routerOptions:
|
|
762
|
+
{
|
|
763
|
+
caseSensitive: false
|
|
764
|
+
}
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
fastify.get('/TeSt', (req, reply) => {
|
|
768
|
+
reply.send('test')
|
|
769
|
+
})
|
|
770
|
+
|
|
771
|
+
let res = await fastify.inject({
|
|
772
|
+
method: 'GET',
|
|
773
|
+
url: '/test'
|
|
774
|
+
})
|
|
775
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
776
|
+
|
|
777
|
+
res = await fastify.inject({
|
|
778
|
+
method: 'GET',
|
|
779
|
+
url: '/tEsT'
|
|
780
|
+
})
|
|
781
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
782
|
+
|
|
783
|
+
res = await fastify.inject({
|
|
784
|
+
method: 'GET',
|
|
785
|
+
url: '/TEST'
|
|
786
|
+
})
|
|
787
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
788
|
+
})
|
|
789
|
+
|
|
790
|
+
test('Should honor routerOptions.queryStringParser', async (t) => {
|
|
791
|
+
t.plan(4)
|
|
792
|
+
const fastify = Fastify({
|
|
793
|
+
routerOptions:
|
|
794
|
+
{
|
|
795
|
+
querystringParser: function (str) {
|
|
796
|
+
t.assert.ok('custom query string parser called')
|
|
797
|
+
return querystring.parse(str)
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
fastify.get('/test', (req, reply) => {
|
|
803
|
+
t.assert.deepStrictEqual(req.query.foo, 'bar')
|
|
804
|
+
t.assert.deepStrictEqual(req.query.baz, 'faz')
|
|
805
|
+
reply.send('test')
|
|
806
|
+
})
|
|
807
|
+
|
|
808
|
+
const res = await fastify.inject({
|
|
809
|
+
method: 'GET',
|
|
810
|
+
url: '/test?foo=bar&baz=faz'
|
|
811
|
+
})
|
|
812
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
test('Should honor routerOptions.useSemicolonDelimiter', async (t) => {
|
|
816
|
+
t.plan(6)
|
|
817
|
+
const fastify = Fastify({
|
|
818
|
+
routerOptions:
|
|
819
|
+
{
|
|
820
|
+
useSemicolonDelimiter: true
|
|
821
|
+
}
|
|
822
|
+
})
|
|
823
|
+
|
|
824
|
+
fastify.get('/test', (req, reply) => {
|
|
825
|
+
t.assert.deepStrictEqual(req.query.foo, 'bar')
|
|
826
|
+
t.assert.deepStrictEqual(req.query.baz, 'faz')
|
|
827
|
+
reply.send('test')
|
|
828
|
+
})
|
|
829
|
+
|
|
830
|
+
// Support semicolon delimiter
|
|
831
|
+
let res = await fastify.inject({
|
|
832
|
+
method: 'GET',
|
|
833
|
+
url: '/test;foo=bar&baz=faz'
|
|
834
|
+
})
|
|
835
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
836
|
+
|
|
837
|
+
// Support query string `?` delimiter
|
|
838
|
+
res = await fastify.inject({
|
|
839
|
+
method: 'GET',
|
|
840
|
+
url: '/test?foo=bar&baz=faz'
|
|
841
|
+
})
|
|
842
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
843
|
+
})
|
|
844
|
+
|
|
845
|
+
test('Should honor routerOptions.buildPrettyMeta', async (t) => {
|
|
846
|
+
t.plan(10)
|
|
847
|
+
const fastify = Fastify({
|
|
848
|
+
routerOptions:
|
|
849
|
+
{
|
|
850
|
+
buildPrettyMeta: function (route) {
|
|
851
|
+
t.assert.ok('custom buildPrettyMeta called')
|
|
852
|
+
return { metaKey: route.path }
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
})
|
|
856
|
+
|
|
857
|
+
fastify.get('/test', () => {})
|
|
858
|
+
fastify.get('/test/hello', () => {})
|
|
859
|
+
fastify.get('/testing', () => {})
|
|
860
|
+
fastify.get('/testing/:param', () => {})
|
|
861
|
+
fastify.put('/update', () => {})
|
|
862
|
+
|
|
863
|
+
await fastify.ready()
|
|
864
|
+
|
|
865
|
+
const result = fastify.printRoutes({ includeMeta: true })
|
|
866
|
+
const expected = `\
|
|
867
|
+
└── /
|
|
868
|
+
├── test (GET, HEAD)
|
|
869
|
+
│ • (metaKey) "/test"
|
|
870
|
+
│ ├── /hello (GET, HEAD)
|
|
871
|
+
│ │ • (metaKey) "/test/hello"
|
|
872
|
+
│ └── ing (GET, HEAD)
|
|
873
|
+
│ • (metaKey) "/testing"
|
|
874
|
+
│ └── /
|
|
875
|
+
│ └── :param (GET, HEAD)
|
|
876
|
+
│ • (metaKey) "/testing/:param"
|
|
877
|
+
└── update (PUT)
|
|
878
|
+
• (metaKey) "/update"
|
|
879
|
+
`
|
|
880
|
+
|
|
881
|
+
t.assert.strictEqual(result, expected)
|
|
882
|
+
})
|
|
883
|
+
|
|
884
|
+
test('Should honor routerOptions.ignoreTrailingSlash and routerOptions.ignoreDuplicateSlashes over top level options', async t => {
|
|
885
|
+
t.plan(4)
|
|
886
|
+
const fastify = Fastify({
|
|
887
|
+
ignoreTrailingSlash: false,
|
|
888
|
+
ignoreDuplicateSlashes: false,
|
|
889
|
+
routerOptions: {
|
|
890
|
+
ignoreTrailingSlash: true,
|
|
891
|
+
ignoreDuplicateSlashes: true
|
|
892
|
+
}
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
fastify.get('/test//test///test', (req, res) => {
|
|
896
|
+
res.send('test')
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
let res = await fastify.inject('/test/test/test/')
|
|
900
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
901
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
902
|
+
|
|
903
|
+
res = await fastify.inject('/test//test///test//')
|
|
904
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
905
|
+
t.assert.strictEqual(res.payload.toString(), 'test')
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
test('Should honor routerOptions.maxParamLength over maxParamLength option', async (t) => {
|
|
909
|
+
const fastify = Fastify({
|
|
910
|
+
maxParamLength: 0,
|
|
911
|
+
routerOptions:
|
|
912
|
+
{
|
|
913
|
+
maxParamLength: 10
|
|
914
|
+
}
|
|
915
|
+
})
|
|
916
|
+
|
|
917
|
+
fastify.get('/test/:id', (req, reply) => {
|
|
918
|
+
reply.send({ hello: 'world' })
|
|
919
|
+
})
|
|
920
|
+
|
|
921
|
+
const res = await fastify.inject({
|
|
922
|
+
method: 'GET',
|
|
923
|
+
url: '/test/123456789'
|
|
924
|
+
})
|
|
925
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
926
|
+
|
|
927
|
+
const resError = await fastify.inject({
|
|
928
|
+
method: 'GET',
|
|
929
|
+
url: '/test/123456789abcd'
|
|
930
|
+
})
|
|
931
|
+
t.assert.strictEqual(resError.statusCode, 404)
|
|
932
|
+
})
|
|
933
|
+
|
|
934
|
+
test('Should honor routerOptions.allowUnsafeRegex over allowUnsafeRegex option', async (t) => {
|
|
935
|
+
const fastify = Fastify({
|
|
936
|
+
allowUnsafeRegex: false,
|
|
937
|
+
routerOptions:
|
|
938
|
+
{
|
|
939
|
+
allowUnsafeRegex: true
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
|
|
943
|
+
fastify.get('/test/:id(([a-f0-9]{3},?)+)', (req, reply) => {
|
|
944
|
+
reply.send({ hello: 'world' })
|
|
945
|
+
})
|
|
946
|
+
|
|
947
|
+
let res = await fastify.inject({
|
|
948
|
+
method: 'GET',
|
|
949
|
+
url: '/test/bac,1ea'
|
|
950
|
+
})
|
|
951
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
952
|
+
|
|
953
|
+
res = await fastify.inject({
|
|
954
|
+
method: 'GET',
|
|
955
|
+
url: '/test/qwerty'
|
|
956
|
+
})
|
|
957
|
+
|
|
958
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
959
|
+
})
|
|
960
|
+
|
|
961
|
+
test('Should honor routerOptions.caseSensitive over caseSensitive option', async (t) => {
|
|
962
|
+
const fastify = Fastify({
|
|
963
|
+
caseSensitive: true,
|
|
964
|
+
routerOptions:
|
|
965
|
+
{
|
|
966
|
+
caseSensitive: false
|
|
967
|
+
}
|
|
968
|
+
})
|
|
969
|
+
|
|
970
|
+
fastify.get('/TeSt', (req, reply) => {
|
|
971
|
+
reply.send('test')
|
|
972
|
+
})
|
|
973
|
+
|
|
974
|
+
let res = await fastify.inject({
|
|
975
|
+
method: 'GET',
|
|
976
|
+
url: '/test'
|
|
977
|
+
})
|
|
978
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
979
|
+
|
|
980
|
+
res = await fastify.inject({
|
|
981
|
+
method: 'GET',
|
|
982
|
+
url: '/tEsT'
|
|
983
|
+
})
|
|
984
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
985
|
+
|
|
986
|
+
res = await fastify.inject({
|
|
987
|
+
method: 'GET',
|
|
988
|
+
url: '/TEST'
|
|
989
|
+
})
|
|
990
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
991
|
+
})
|
|
992
|
+
|
|
993
|
+
test('Should honor routerOptions.queryStringParser over queryStringParser option', async (t) => {
|
|
994
|
+
t.plan(4)
|
|
995
|
+
const fastify = Fastify({
|
|
996
|
+
queryStringParser: undefined,
|
|
997
|
+
routerOptions:
|
|
998
|
+
{
|
|
999
|
+
querystringParser: function (str) {
|
|
1000
|
+
t.assert.ok('custom query string parser called')
|
|
1001
|
+
return querystring.parse(str)
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
})
|
|
1005
|
+
|
|
1006
|
+
fastify.get('/test', (req, reply) => {
|
|
1007
|
+
t.assert.deepStrictEqual(req.query.foo, 'bar')
|
|
1008
|
+
t.assert.deepStrictEqual(req.query.baz, 'faz')
|
|
1009
|
+
reply.send('test')
|
|
1010
|
+
})
|
|
1011
|
+
|
|
1012
|
+
const res = await fastify.inject({
|
|
1013
|
+
method: 'GET',
|
|
1014
|
+
url: '/test?foo=bar&baz=faz'
|
|
1015
|
+
})
|
|
1016
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
test('Should honor routerOptions.useSemicolonDelimiter over useSemicolonDelimiter option', async (t) => {
|
|
1020
|
+
t.plan(6)
|
|
1021
|
+
const fastify = Fastify({
|
|
1022
|
+
useSemicolonDelimiter: false,
|
|
1023
|
+
routerOptions:
|
|
1024
|
+
{
|
|
1025
|
+
useSemicolonDelimiter: true
|
|
1026
|
+
}
|
|
1027
|
+
})
|
|
1028
|
+
|
|
1029
|
+
fastify.get('/test', (req, reply) => {
|
|
1030
|
+
t.assert.deepStrictEqual(req.query.foo, 'bar')
|
|
1031
|
+
t.assert.deepStrictEqual(req.query.baz, 'faz')
|
|
1032
|
+
reply.send('test')
|
|
1033
|
+
})
|
|
1034
|
+
|
|
1035
|
+
// Support semicolon delimiter
|
|
1036
|
+
let res = await fastify.inject({
|
|
1037
|
+
method: 'GET',
|
|
1038
|
+
url: '/test;foo=bar&baz=faz'
|
|
1039
|
+
})
|
|
1040
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
1041
|
+
|
|
1042
|
+
// Support query string `?` delimiter
|
|
1043
|
+
res = await fastify.inject({
|
|
1044
|
+
method: 'GET',
|
|
1045
|
+
url: '/test?foo=bar&baz=faz'
|
|
1046
|
+
})
|
|
1047
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
1048
|
+
})
|
|
1049
|
+
|
|
1050
|
+
test('Should support extra find-my-way options', async t => {
|
|
1051
|
+
t.plan(1)
|
|
1052
|
+
// Use a real upstream option from find-my-way
|
|
1053
|
+
const fastify = Fastify({
|
|
1054
|
+
routerOptions: {
|
|
1055
|
+
buildPrettyMeta: (route) => {
|
|
1056
|
+
const cleanMeta = Object.assign({}, route.store)
|
|
1057
|
+
return cleanMeta
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
})
|
|
1061
|
+
|
|
1062
|
+
t.after(() => fastify.close())
|
|
1063
|
+
|
|
1064
|
+
await fastify.ready()
|
|
1065
|
+
|
|
1066
|
+
// Ensure the option is preserved after validation
|
|
1067
|
+
t.assert.strictEqual(typeof fastify.initialConfig.routerOptions.buildPrettyMeta, 'function')
|
|
1068
|
+
})
|
|
1069
|
+
|
|
1070
|
+
test('Should allow reusing a routerOptions object across instances', async t => {
|
|
1071
|
+
t.plan(1)
|
|
1072
|
+
|
|
1073
|
+
const options = {
|
|
1074
|
+
routerOptions: {
|
|
1075
|
+
maxParamLength: 2048
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
const app1 = Fastify(options)
|
|
1080
|
+
const app2 = Fastify(options)
|
|
1081
|
+
|
|
1082
|
+
t.after(() => Promise.all([
|
|
1083
|
+
app1.close(),
|
|
1084
|
+
app2.close()
|
|
1085
|
+
]))
|
|
1086
|
+
|
|
1087
|
+
const response = await app2.inject('/not-found')
|
|
1088
|
+
t.assert.strictEqual(response.statusCode, 404)
|
|
1089
|
+
})
|
|
1090
|
+
|
|
1091
|
+
test('Should not mutate user-provided routerOptions object', async t => {
|
|
1092
|
+
t.plan(4)
|
|
1093
|
+
|
|
1094
|
+
const routerOptions = {
|
|
1095
|
+
maxParamLength: 2048
|
|
1096
|
+
}
|
|
1097
|
+
const options = { routerOptions }
|
|
1098
|
+
|
|
1099
|
+
const app = Fastify(options)
|
|
1100
|
+
t.after(() => app.close())
|
|
1101
|
+
|
|
1102
|
+
await app.ready()
|
|
1103
|
+
|
|
1104
|
+
t.assert.deepStrictEqual(Object.keys(routerOptions), ['maxParamLength'])
|
|
1105
|
+
t.assert.strictEqual(routerOptions.maxParamLength, 2048)
|
|
1106
|
+
t.assert.strictEqual(routerOptions.defaultRoute, undefined)
|
|
1107
|
+
t.assert.strictEqual(routerOptions.onBadUrl, undefined)
|
|
1108
|
+
})
|