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,1138 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test')
|
|
4
|
+
const Fastify = require('../fastify')
|
|
5
|
+
|
|
6
|
+
test('Should register a host constrained route', async t => {
|
|
7
|
+
t.plan(4)
|
|
8
|
+
const fastify = Fastify()
|
|
9
|
+
|
|
10
|
+
fastify.route({
|
|
11
|
+
method: 'GET',
|
|
12
|
+
url: '/',
|
|
13
|
+
constraints: { host: 'fastify.dev' },
|
|
14
|
+
handler: (req, reply) => {
|
|
15
|
+
reply.send({ hello: 'world' })
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
{
|
|
20
|
+
const res = await fastify.inject({
|
|
21
|
+
method: 'GET',
|
|
22
|
+
url: '/',
|
|
23
|
+
headers: {
|
|
24
|
+
host: 'fastify.dev'
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
|
|
28
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
const res = await fastify.inject({
|
|
33
|
+
method: 'GET',
|
|
34
|
+
url: '/',
|
|
35
|
+
headers: {
|
|
36
|
+
host: 'fastify.test'
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
const res = await fastify.inject({
|
|
45
|
+
method: 'GET',
|
|
46
|
+
url: '/'
|
|
47
|
+
})
|
|
48
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('Should register the same route with host constraints', async t => {
|
|
53
|
+
t.plan(5)
|
|
54
|
+
const fastify = Fastify()
|
|
55
|
+
|
|
56
|
+
fastify.route({
|
|
57
|
+
method: 'GET',
|
|
58
|
+
url: '/',
|
|
59
|
+
constraints: { host: 'fastify.dev' },
|
|
60
|
+
handler: (req, reply) => {
|
|
61
|
+
reply.send('fastify.dev')
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
fastify.route({
|
|
66
|
+
method: 'GET',
|
|
67
|
+
url: '/',
|
|
68
|
+
constraints: { host: 'fastify.test' },
|
|
69
|
+
handler: (req, reply) => {
|
|
70
|
+
reply.send('fastify.test')
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
const res = await fastify.inject({
|
|
76
|
+
method: 'GET',
|
|
77
|
+
url: '/',
|
|
78
|
+
headers: {
|
|
79
|
+
host: 'fastify.dev'
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
83
|
+
t.assert.strictEqual(res.payload, 'fastify.dev')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
const res = await fastify.inject({
|
|
88
|
+
method: 'GET',
|
|
89
|
+
url: '/',
|
|
90
|
+
headers: {
|
|
91
|
+
host: 'fastify.test'
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
96
|
+
t.assert.strictEqual(res.payload, 'fastify.test')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
const res = await fastify.inject({
|
|
101
|
+
method: 'GET',
|
|
102
|
+
url: '/',
|
|
103
|
+
headers: {
|
|
104
|
+
host: 'fancy.ca'
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('Should allow registering custom constrained routes', async t => {
|
|
112
|
+
t.plan(5)
|
|
113
|
+
|
|
114
|
+
const constraint = {
|
|
115
|
+
name: 'secret',
|
|
116
|
+
storage: function () {
|
|
117
|
+
const secrets = {}
|
|
118
|
+
return {
|
|
119
|
+
get: (secret) => { return secrets[secret] || null },
|
|
120
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
deriveConstraint: (req, ctx) => {
|
|
124
|
+
return req.headers['x-secret']
|
|
125
|
+
},
|
|
126
|
+
validate () { return true }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const fastify = Fastify({ constraints: { secret: constraint } })
|
|
130
|
+
|
|
131
|
+
fastify.route({
|
|
132
|
+
method: 'GET',
|
|
133
|
+
url: '/',
|
|
134
|
+
constraints: { secret: 'alpha' },
|
|
135
|
+
handler: (req, reply) => {
|
|
136
|
+
reply.send({ hello: 'from alpha' })
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
fastify.route({
|
|
141
|
+
method: 'GET',
|
|
142
|
+
url: '/',
|
|
143
|
+
constraints: { secret: 'beta' },
|
|
144
|
+
handler: (req, reply) => {
|
|
145
|
+
reply.send({ hello: 'from beta' })
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
{
|
|
150
|
+
const res = await fastify.inject({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: '/',
|
|
153
|
+
headers: {
|
|
154
|
+
'X-Secret': 'alpha'
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from alpha' })
|
|
158
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
{
|
|
162
|
+
const res = await fastify.inject({
|
|
163
|
+
method: 'GET',
|
|
164
|
+
url: '/',
|
|
165
|
+
headers: {
|
|
166
|
+
'X-Secret': 'beta'
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from beta' })
|
|
170
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
{
|
|
174
|
+
const res = await fastify.inject({
|
|
175
|
+
method: 'GET',
|
|
176
|
+
url: '/',
|
|
177
|
+
headers: {
|
|
178
|
+
'X-Secret': 'gamma'
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
test('Should allow registering custom constrained routes outside constructor', async t => {
|
|
186
|
+
t.plan(5)
|
|
187
|
+
|
|
188
|
+
const constraint = {
|
|
189
|
+
name: 'secret',
|
|
190
|
+
storage: function () {
|
|
191
|
+
const secrets = {}
|
|
192
|
+
return {
|
|
193
|
+
get: (secret) => { return secrets[secret] || null },
|
|
194
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
deriveConstraint: (req, ctx) => {
|
|
198
|
+
return req.headers['x-secret']
|
|
199
|
+
},
|
|
200
|
+
validate () { return true }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const fastify = Fastify()
|
|
204
|
+
fastify.addConstraintStrategy(constraint)
|
|
205
|
+
|
|
206
|
+
fastify.route({
|
|
207
|
+
method: 'GET',
|
|
208
|
+
url: '/',
|
|
209
|
+
constraints: { secret: 'alpha' },
|
|
210
|
+
handler: (req, reply) => {
|
|
211
|
+
reply.send({ hello: 'from alpha' })
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
fastify.route({
|
|
216
|
+
method: 'GET',
|
|
217
|
+
url: '/',
|
|
218
|
+
constraints: { secret: 'beta' },
|
|
219
|
+
handler: (req, reply) => {
|
|
220
|
+
reply.send({ hello: 'from beta' })
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
{
|
|
225
|
+
const res = await fastify.inject({
|
|
226
|
+
method: 'GET',
|
|
227
|
+
url: '/',
|
|
228
|
+
headers: {
|
|
229
|
+
'X-Secret': 'alpha'
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from alpha' })
|
|
234
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
{
|
|
238
|
+
const res = await fastify.inject({
|
|
239
|
+
method: 'GET',
|
|
240
|
+
url: '/',
|
|
241
|
+
headers: {
|
|
242
|
+
'X-Secret': 'beta'
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from beta' })
|
|
246
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
{
|
|
250
|
+
const res = await fastify.inject({
|
|
251
|
+
method: 'GET',
|
|
252
|
+
url: '/',
|
|
253
|
+
headers: {
|
|
254
|
+
'X-Secret': 'gamma'
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('Custom constrained routes registered also for HEAD method generated by fastify', (t, done) => {
|
|
262
|
+
t.plan(3)
|
|
263
|
+
|
|
264
|
+
const constraint = {
|
|
265
|
+
name: 'secret',
|
|
266
|
+
storage: function () {
|
|
267
|
+
const secrets = {}
|
|
268
|
+
return {
|
|
269
|
+
get: (secret) => { return secrets[secret] || null },
|
|
270
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
deriveConstraint: (req, ctx) => {
|
|
274
|
+
return req.headers['x-secret']
|
|
275
|
+
},
|
|
276
|
+
validate () { return true }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const fastify = Fastify({ constraints: { secret: constraint } })
|
|
280
|
+
|
|
281
|
+
fastify.route({
|
|
282
|
+
method: 'GET',
|
|
283
|
+
url: '/',
|
|
284
|
+
constraints: { secret: 'mySecret' },
|
|
285
|
+
handler: (req, reply) => {
|
|
286
|
+
reply.send('from mySecret - my length is 31')
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
fastify.inject({
|
|
291
|
+
method: 'HEAD',
|
|
292
|
+
url: '/',
|
|
293
|
+
headers: {
|
|
294
|
+
'X-Secret': 'mySecret'
|
|
295
|
+
}
|
|
296
|
+
}, (err, res) => {
|
|
297
|
+
t.assert.ifError(err)
|
|
298
|
+
t.assert.deepStrictEqual(res.headers['content-length'], '31')
|
|
299
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
300
|
+
done()
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
test('Custom constrained routes registered with addConstraintStrategy apply also for HEAD method generated by fastify', (t, done) => {
|
|
305
|
+
t.plan(3)
|
|
306
|
+
|
|
307
|
+
const constraint = {
|
|
308
|
+
name: 'secret',
|
|
309
|
+
storage: function () {
|
|
310
|
+
const secrets = {}
|
|
311
|
+
return {
|
|
312
|
+
get: (secret) => { return secrets[secret] || null },
|
|
313
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
deriveConstraint: (req, ctx) => {
|
|
317
|
+
return req.headers['x-secret']
|
|
318
|
+
},
|
|
319
|
+
validate () { return true }
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const fastify = Fastify()
|
|
323
|
+
fastify.addConstraintStrategy(constraint)
|
|
324
|
+
|
|
325
|
+
fastify.route({
|
|
326
|
+
method: 'GET',
|
|
327
|
+
url: '/',
|
|
328
|
+
constraints: { secret: 'mySecret' },
|
|
329
|
+
handler: (req, reply) => {
|
|
330
|
+
reply.send('from mySecret - my length is 31')
|
|
331
|
+
}
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
fastify.inject({
|
|
335
|
+
method: 'HEAD',
|
|
336
|
+
url: '/',
|
|
337
|
+
headers: {
|
|
338
|
+
'X-Secret': 'mySecret'
|
|
339
|
+
}
|
|
340
|
+
}, (err, res) => {
|
|
341
|
+
t.assert.ifError(err)
|
|
342
|
+
t.assert.deepStrictEqual(res.headers['content-length'], '31')
|
|
343
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
344
|
+
done()
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
test('Add a constraint strategy after fastify instance was started', (t, done) => {
|
|
349
|
+
t.plan(4)
|
|
350
|
+
|
|
351
|
+
const constraint = {
|
|
352
|
+
name: 'secret',
|
|
353
|
+
storage: function () {
|
|
354
|
+
const secrets = {}
|
|
355
|
+
return {
|
|
356
|
+
get: (secret) => { return secrets[secret] || null },
|
|
357
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
deriveConstraint: (req, ctx) => {
|
|
361
|
+
return req.headers['x-secret']
|
|
362
|
+
},
|
|
363
|
+
validate () { return true }
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const fastify = Fastify()
|
|
367
|
+
|
|
368
|
+
fastify.route({
|
|
369
|
+
method: 'GET',
|
|
370
|
+
url: '/',
|
|
371
|
+
handler: (req, reply) => { reply.send('ok') }
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
fastify.inject({
|
|
375
|
+
method: 'GET',
|
|
376
|
+
url: '/'
|
|
377
|
+
}, (err, res) => {
|
|
378
|
+
t.assert.ifError(err)
|
|
379
|
+
t.assert.deepStrictEqual(res.payload, 'ok')
|
|
380
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
381
|
+
|
|
382
|
+
t.assert.throws(
|
|
383
|
+
() => fastify.addConstraintStrategy(constraint)
|
|
384
|
+
)
|
|
385
|
+
done()
|
|
386
|
+
})
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
test('Add a constraint strategy should throw an error if there already exist custom strategy with the same name', t => {
|
|
390
|
+
t.plan(1)
|
|
391
|
+
|
|
392
|
+
const constraint = {
|
|
393
|
+
name: 'secret',
|
|
394
|
+
storage: function () {
|
|
395
|
+
const secrets = {}
|
|
396
|
+
return {
|
|
397
|
+
get: (secret) => { return secrets[secret] || null },
|
|
398
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
deriveConstraint: (req, ctx) => {
|
|
402
|
+
return req.headers['x-secret']
|
|
403
|
+
},
|
|
404
|
+
validate () { return true }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const fastify = Fastify()
|
|
408
|
+
|
|
409
|
+
fastify.addConstraintStrategy(constraint)
|
|
410
|
+
t.assert.throws(
|
|
411
|
+
() => fastify.addConstraintStrategy(constraint),
|
|
412
|
+
/^Error: There already exists a custom constraint with the name secret.$/
|
|
413
|
+
)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
test('Add a constraint strategy shouldn\'t throw an error if default constraint with the same name isn\'t used', t => {
|
|
417
|
+
t.plan(1)
|
|
418
|
+
|
|
419
|
+
const constraint = {
|
|
420
|
+
name: 'version',
|
|
421
|
+
storage: function () {
|
|
422
|
+
const secrets = {}
|
|
423
|
+
return {
|
|
424
|
+
get: (secret) => { return secrets[secret] || null },
|
|
425
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
deriveConstraint: (req, ctx) => {
|
|
429
|
+
return req.headers['x-secret']
|
|
430
|
+
},
|
|
431
|
+
validate () { return true }
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const fastify = Fastify()
|
|
435
|
+
fastify.addConstraintStrategy(constraint)
|
|
436
|
+
|
|
437
|
+
t.assert.ok(true)
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
test('Add a constraint strategy should throw an error if default constraint with the same name is used', t => {
|
|
441
|
+
t.plan(1)
|
|
442
|
+
|
|
443
|
+
const constraint = {
|
|
444
|
+
name: 'version',
|
|
445
|
+
storage: function () {
|
|
446
|
+
const secrets = {}
|
|
447
|
+
return {
|
|
448
|
+
get: (secret) => { return secrets[secret] || null },
|
|
449
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
deriveConstraint: (req, ctx) => {
|
|
453
|
+
return req.headers['x-secret']
|
|
454
|
+
},
|
|
455
|
+
validate () { return true }
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const fastify = Fastify()
|
|
459
|
+
|
|
460
|
+
fastify.route({
|
|
461
|
+
method: 'GET',
|
|
462
|
+
url: '/',
|
|
463
|
+
constraints: { version: '1.0.0' },
|
|
464
|
+
handler: (req, reply) => {
|
|
465
|
+
reply.send('ok')
|
|
466
|
+
}
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
t.assert.throws(
|
|
470
|
+
() => fastify.addConstraintStrategy(constraint),
|
|
471
|
+
/^Error: There already exists a route with version constraint.$/
|
|
472
|
+
)
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
test('The hasConstraintStrategy should return false for default constraints until they are used', t => {
|
|
476
|
+
t.plan(6)
|
|
477
|
+
|
|
478
|
+
const fastify = Fastify()
|
|
479
|
+
|
|
480
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('version'), false)
|
|
481
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('host'), false)
|
|
482
|
+
|
|
483
|
+
fastify.route({
|
|
484
|
+
method: 'GET',
|
|
485
|
+
url: '/',
|
|
486
|
+
constraints: { host: 'fastify.dev' },
|
|
487
|
+
handler: (req, reply) => {
|
|
488
|
+
reply.send({ hello: 'from any other domain' })
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('version'), false)
|
|
493
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('host'), true)
|
|
494
|
+
|
|
495
|
+
fastify.route({
|
|
496
|
+
method: 'GET',
|
|
497
|
+
url: '/',
|
|
498
|
+
constraints: { version: '1.0.0' },
|
|
499
|
+
handler: (req, reply) => {
|
|
500
|
+
reply.send({ hello: 'from any other domain' })
|
|
501
|
+
}
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('version'), true)
|
|
505
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('host'), true)
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
test('The hasConstraintStrategy should return true if there already exist a custom constraint with the same name', t => {
|
|
509
|
+
t.plan(2)
|
|
510
|
+
|
|
511
|
+
const constraint = {
|
|
512
|
+
name: 'secret',
|
|
513
|
+
storage: function () {
|
|
514
|
+
const secrets = {}
|
|
515
|
+
return {
|
|
516
|
+
get: (secret) => { return secrets[secret] || null },
|
|
517
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
deriveConstraint: (req, ctx) => {
|
|
521
|
+
return req.headers['x-secret']
|
|
522
|
+
},
|
|
523
|
+
validate () { return true }
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const fastify = Fastify()
|
|
527
|
+
|
|
528
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('secret'), false)
|
|
529
|
+
fastify.addConstraintStrategy(constraint)
|
|
530
|
+
t.assert.strictEqual(fastify.hasConstraintStrategy('secret'), true)
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
test('Should allow registering an unconstrained route after a constrained route', async t => {
|
|
534
|
+
t.plan(4)
|
|
535
|
+
const fastify = Fastify()
|
|
536
|
+
|
|
537
|
+
fastify.route({
|
|
538
|
+
method: 'GET',
|
|
539
|
+
url: '/',
|
|
540
|
+
constraints: { host: 'fastify.dev' },
|
|
541
|
+
handler: (req, reply) => {
|
|
542
|
+
reply.send({ hello: 'from fastify.dev' })
|
|
543
|
+
}
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
fastify.route({
|
|
547
|
+
method: 'GET',
|
|
548
|
+
url: '/',
|
|
549
|
+
handler: (req, reply) => {
|
|
550
|
+
reply.send({ hello: 'from any other domain' })
|
|
551
|
+
}
|
|
552
|
+
})
|
|
553
|
+
|
|
554
|
+
{
|
|
555
|
+
const res = await fastify.inject({
|
|
556
|
+
method: 'GET',
|
|
557
|
+
url: '/',
|
|
558
|
+
headers: {
|
|
559
|
+
host: 'fastify.dev'
|
|
560
|
+
}
|
|
561
|
+
})
|
|
562
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from fastify.dev' })
|
|
563
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
{
|
|
567
|
+
const res = await fastify.inject({
|
|
568
|
+
method: 'GET',
|
|
569
|
+
url: '/',
|
|
570
|
+
headers: {
|
|
571
|
+
host: 'fastify.test'
|
|
572
|
+
}
|
|
573
|
+
})
|
|
574
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from any other domain' })
|
|
575
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
test('Should allow registering constrained routes in a prefixed plugin', (t, done) => {
|
|
580
|
+
t.plan(3)
|
|
581
|
+
|
|
582
|
+
const fastify = Fastify()
|
|
583
|
+
|
|
584
|
+
fastify.register(async (scope, opts) => {
|
|
585
|
+
scope.route({
|
|
586
|
+
method: 'GET',
|
|
587
|
+
constraints: { host: 'fastify.dev' },
|
|
588
|
+
path: '/route',
|
|
589
|
+
handler: (req, reply) => {
|
|
590
|
+
reply.send({ ok: true })
|
|
591
|
+
}
|
|
592
|
+
})
|
|
593
|
+
}, { prefix: '/prefix' })
|
|
594
|
+
|
|
595
|
+
fastify.inject({
|
|
596
|
+
method: 'GET',
|
|
597
|
+
url: '/prefix/route',
|
|
598
|
+
headers: {
|
|
599
|
+
host: 'fastify.dev'
|
|
600
|
+
}
|
|
601
|
+
}, (err, res) => {
|
|
602
|
+
t.assert.ifError(err)
|
|
603
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { ok: true })
|
|
604
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
605
|
+
done()
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
test('Should allow registering a constrained GET route after a constrained HEAD route', (t, done) => {
|
|
610
|
+
t.plan(3)
|
|
611
|
+
const fastify = Fastify()
|
|
612
|
+
|
|
613
|
+
fastify.route({
|
|
614
|
+
method: 'HEAD',
|
|
615
|
+
url: '/',
|
|
616
|
+
constraints: { host: 'fastify.dev' },
|
|
617
|
+
handler: (req, reply) => {
|
|
618
|
+
reply.header('content-type', 'text/plain')
|
|
619
|
+
reply.send('custom HEAD response')
|
|
620
|
+
}
|
|
621
|
+
})
|
|
622
|
+
|
|
623
|
+
fastify.route({
|
|
624
|
+
method: 'GET',
|
|
625
|
+
url: '/',
|
|
626
|
+
constraints: { host: 'fastify.dev' },
|
|
627
|
+
handler: (req, reply) => {
|
|
628
|
+
reply.send({ hello: 'from any other domain' })
|
|
629
|
+
}
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
fastify.inject({
|
|
633
|
+
method: 'HEAD',
|
|
634
|
+
url: '/',
|
|
635
|
+
headers: {
|
|
636
|
+
host: 'fastify.dev'
|
|
637
|
+
}
|
|
638
|
+
}, (err, res) => {
|
|
639
|
+
t.assert.ifError(err)
|
|
640
|
+
t.assert.deepStrictEqual(res.payload, 'custom HEAD response')
|
|
641
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
642
|
+
done()
|
|
643
|
+
})
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
test('Should allow registering a constrained GET route after an unconstrained HEAD route', (t, done) => {
|
|
647
|
+
t.plan(3)
|
|
648
|
+
const fastify = Fastify()
|
|
649
|
+
|
|
650
|
+
fastify.route({
|
|
651
|
+
method: 'HEAD',
|
|
652
|
+
url: '/',
|
|
653
|
+
handler: (req, reply) => {
|
|
654
|
+
reply.header('content-type', 'text/plain')
|
|
655
|
+
reply.send('HEAD response: length is about 33')
|
|
656
|
+
}
|
|
657
|
+
})
|
|
658
|
+
|
|
659
|
+
fastify.route({
|
|
660
|
+
method: 'GET',
|
|
661
|
+
url: '/',
|
|
662
|
+
constraints: { host: 'fastify.dev' },
|
|
663
|
+
handler: (req, reply) => {
|
|
664
|
+
reply.header('content-type', 'text/plain')
|
|
665
|
+
reply.send('Hello from constrains: length is about 41')
|
|
666
|
+
}
|
|
667
|
+
})
|
|
668
|
+
|
|
669
|
+
fastify.inject({
|
|
670
|
+
method: 'HEAD',
|
|
671
|
+
url: '/',
|
|
672
|
+
headers: {
|
|
673
|
+
host: 'fastify.dev'
|
|
674
|
+
}
|
|
675
|
+
}, (err, res) => {
|
|
676
|
+
t.assert.ifError(err)
|
|
677
|
+
t.assert.deepStrictEqual(res.headers['content-length'], '41')
|
|
678
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
679
|
+
done()
|
|
680
|
+
})
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
test('Will not try to re-createprefixed HEAD route if it already exists and exposeHeadRoutes is true for constrained routes', async (t) => {
|
|
684
|
+
t.plan(1)
|
|
685
|
+
|
|
686
|
+
const fastify = Fastify({ exposeHeadRoutes: true })
|
|
687
|
+
|
|
688
|
+
fastify.register((scope, opts, next) => {
|
|
689
|
+
scope.route({
|
|
690
|
+
method: 'HEAD',
|
|
691
|
+
path: '/route',
|
|
692
|
+
constraints: { host: 'fastify.dev' },
|
|
693
|
+
handler: (req, reply) => {
|
|
694
|
+
reply.header('content-type', 'text/plain')
|
|
695
|
+
reply.send('custom HEAD response')
|
|
696
|
+
}
|
|
697
|
+
})
|
|
698
|
+
scope.route({
|
|
699
|
+
method: 'GET',
|
|
700
|
+
path: '/route',
|
|
701
|
+
constraints: { host: 'fastify.dev' },
|
|
702
|
+
handler: (req, reply) => {
|
|
703
|
+
reply.send({ ok: true })
|
|
704
|
+
}
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
next()
|
|
708
|
+
}, { prefix: '/prefix' })
|
|
709
|
+
|
|
710
|
+
await fastify.ready()
|
|
711
|
+
|
|
712
|
+
t.assert.ok(true)
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
test('allows separate constrained and unconstrained HEAD routes', async (t) => {
|
|
716
|
+
t.plan(1)
|
|
717
|
+
|
|
718
|
+
const fastify = Fastify({ exposeHeadRoutes: true })
|
|
719
|
+
|
|
720
|
+
fastify.register((scope, opts, next) => {
|
|
721
|
+
scope.route({
|
|
722
|
+
method: 'HEAD',
|
|
723
|
+
path: '/route',
|
|
724
|
+
handler: (req, reply) => {
|
|
725
|
+
reply.header('content-type', 'text/plain')
|
|
726
|
+
reply.send('unconstrained HEAD response')
|
|
727
|
+
}
|
|
728
|
+
})
|
|
729
|
+
|
|
730
|
+
scope.route({
|
|
731
|
+
method: 'HEAD',
|
|
732
|
+
path: '/route',
|
|
733
|
+
constraints: { host: 'fastify.dev' },
|
|
734
|
+
handler: (req, reply) => {
|
|
735
|
+
reply.header('content-type', 'text/plain')
|
|
736
|
+
reply.send('constrained HEAD response')
|
|
737
|
+
}
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
scope.route({
|
|
741
|
+
method: 'GET',
|
|
742
|
+
path: '/route',
|
|
743
|
+
constraints: { host: 'fastify.dev' },
|
|
744
|
+
handler: (req, reply) => {
|
|
745
|
+
reply.send({ ok: true })
|
|
746
|
+
}
|
|
747
|
+
})
|
|
748
|
+
|
|
749
|
+
next()
|
|
750
|
+
}, { prefix: '/prefix' })
|
|
751
|
+
|
|
752
|
+
await fastify.ready()
|
|
753
|
+
|
|
754
|
+
t.assert.ok(true)
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
test('allow async constraints', async (t) => {
|
|
758
|
+
t.plan(5)
|
|
759
|
+
|
|
760
|
+
const constraint = {
|
|
761
|
+
name: 'secret',
|
|
762
|
+
storage: function () {
|
|
763
|
+
const secrets = {}
|
|
764
|
+
return {
|
|
765
|
+
get: (secret) => { return secrets[secret] || null },
|
|
766
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
deriveConstraint: (req, ctx, done) => {
|
|
770
|
+
done(null, req.headers['x-secret'])
|
|
771
|
+
},
|
|
772
|
+
validate () { return true }
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const fastify = Fastify({ constraints: { secret: constraint } })
|
|
776
|
+
|
|
777
|
+
fastify.route({
|
|
778
|
+
method: 'GET',
|
|
779
|
+
url: '/',
|
|
780
|
+
constraints: { secret: 'alpha' },
|
|
781
|
+
handler: (req, reply) => {
|
|
782
|
+
reply.send({ hello: 'from alpha' })
|
|
783
|
+
}
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
fastify.route({
|
|
787
|
+
method: 'GET',
|
|
788
|
+
url: '/',
|
|
789
|
+
constraints: { secret: 'beta' },
|
|
790
|
+
handler: (req, reply) => {
|
|
791
|
+
reply.send({ hello: 'from beta' })
|
|
792
|
+
}
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
{
|
|
796
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
|
797
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { hello: 'from alpha' })
|
|
798
|
+
t.assert.strictEqual(statusCode, 200)
|
|
799
|
+
}
|
|
800
|
+
{
|
|
801
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
|
802
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { hello: 'from beta' })
|
|
803
|
+
t.assert.strictEqual(statusCode, 200)
|
|
804
|
+
}
|
|
805
|
+
{
|
|
806
|
+
const { statusCode } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
|
807
|
+
t.assert.strictEqual(statusCode, 404)
|
|
808
|
+
}
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
test('error in async constraints', async (t) => {
|
|
812
|
+
t.plan(8)
|
|
813
|
+
|
|
814
|
+
const constraint = {
|
|
815
|
+
name: 'secret',
|
|
816
|
+
storage: function () {
|
|
817
|
+
const secrets = {}
|
|
818
|
+
return {
|
|
819
|
+
get: (secret) => { return secrets[secret] || null },
|
|
820
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
deriveConstraint: (req, ctx, done) => {
|
|
824
|
+
done(Error('kaboom'))
|
|
825
|
+
},
|
|
826
|
+
validate () { return true }
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const fastify = Fastify({ constraints: { secret: constraint } })
|
|
830
|
+
|
|
831
|
+
fastify.route({
|
|
832
|
+
method: 'GET',
|
|
833
|
+
url: '/',
|
|
834
|
+
constraints: { secret: 'alpha' },
|
|
835
|
+
handler: (req, reply) => {
|
|
836
|
+
reply.send({ hello: 'from alpha' })
|
|
837
|
+
}
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
fastify.route({
|
|
841
|
+
method: 'GET',
|
|
842
|
+
url: '/',
|
|
843
|
+
constraints: { secret: 'beta' },
|
|
844
|
+
handler: (req, reply) => {
|
|
845
|
+
reply.send({ hello: 'from beta' })
|
|
846
|
+
}
|
|
847
|
+
})
|
|
848
|
+
|
|
849
|
+
{
|
|
850
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
|
851
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
852
|
+
t.assert.strictEqual(statusCode, 500)
|
|
853
|
+
}
|
|
854
|
+
{
|
|
855
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
|
856
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
857
|
+
t.assert.strictEqual(statusCode, 500)
|
|
858
|
+
}
|
|
859
|
+
{
|
|
860
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
|
861
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
862
|
+
t.assert.strictEqual(statusCode, 500)
|
|
863
|
+
}
|
|
864
|
+
{
|
|
865
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/' })
|
|
866
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
867
|
+
t.assert.strictEqual(statusCode, 500)
|
|
868
|
+
}
|
|
869
|
+
})
|
|
870
|
+
|
|
871
|
+
test('Allow regex constraints in routes', async t => {
|
|
872
|
+
t.plan(3)
|
|
873
|
+
|
|
874
|
+
const fastify = Fastify()
|
|
875
|
+
|
|
876
|
+
fastify.route({
|
|
877
|
+
method: 'GET',
|
|
878
|
+
url: '/',
|
|
879
|
+
constraints: { host: /.*\.fastify\.dev$/ },
|
|
880
|
+
handler: (req, reply) => {
|
|
881
|
+
reply.send({ hello: 'from fastify dev domain' })
|
|
882
|
+
}
|
|
883
|
+
})
|
|
884
|
+
|
|
885
|
+
{
|
|
886
|
+
const res = await fastify.inject({
|
|
887
|
+
method: 'GET',
|
|
888
|
+
url: '/',
|
|
889
|
+
headers: {
|
|
890
|
+
host: 'dev.fastify.dev'
|
|
891
|
+
}
|
|
892
|
+
})
|
|
893
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from fastify dev domain' })
|
|
894
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
{
|
|
898
|
+
const res = await fastify.inject({
|
|
899
|
+
method: 'GET',
|
|
900
|
+
url: '/',
|
|
901
|
+
headers: {
|
|
902
|
+
host: 'google.com'
|
|
903
|
+
}
|
|
904
|
+
})
|
|
905
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
906
|
+
}
|
|
907
|
+
})
|
|
908
|
+
|
|
909
|
+
test('Should allow registering custom rotuerOptions constrained routes', async t => {
|
|
910
|
+
t.plan(5)
|
|
911
|
+
|
|
912
|
+
const constraint = {
|
|
913
|
+
name: 'secret',
|
|
914
|
+
storage: function () {
|
|
915
|
+
const secrets = {}
|
|
916
|
+
return {
|
|
917
|
+
get: (secret) => { return secrets[secret] || null },
|
|
918
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
deriveConstraint: (req, ctx) => {
|
|
922
|
+
return req.headers['x-secret']
|
|
923
|
+
},
|
|
924
|
+
validate () { return true }
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
const fastify = Fastify({ routerOptions: { constraints: { secret: constraint } } })
|
|
928
|
+
|
|
929
|
+
fastify.route({
|
|
930
|
+
method: 'GET',
|
|
931
|
+
url: '/',
|
|
932
|
+
constraints: { secret: 'alpha' },
|
|
933
|
+
handler: (req, reply) => {
|
|
934
|
+
reply.send({ hello: 'from alpha' })
|
|
935
|
+
}
|
|
936
|
+
})
|
|
937
|
+
|
|
938
|
+
fastify.route({
|
|
939
|
+
method: 'GET',
|
|
940
|
+
url: '/',
|
|
941
|
+
constraints: { secret: 'beta' },
|
|
942
|
+
handler: (req, reply) => {
|
|
943
|
+
reply.send({ hello: 'from beta' })
|
|
944
|
+
}
|
|
945
|
+
})
|
|
946
|
+
|
|
947
|
+
{
|
|
948
|
+
const res = await fastify.inject({
|
|
949
|
+
method: 'GET',
|
|
950
|
+
url: '/',
|
|
951
|
+
headers: {
|
|
952
|
+
'X-Secret': 'alpha'
|
|
953
|
+
}
|
|
954
|
+
})
|
|
955
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from alpha' })
|
|
956
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
{
|
|
960
|
+
const res = await fastify.inject({
|
|
961
|
+
method: 'GET',
|
|
962
|
+
url: '/',
|
|
963
|
+
headers: {
|
|
964
|
+
'X-Secret': 'beta'
|
|
965
|
+
}
|
|
966
|
+
})
|
|
967
|
+
t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'from beta' })
|
|
968
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
{
|
|
972
|
+
const res = await fastify.inject({
|
|
973
|
+
method: 'GET',
|
|
974
|
+
url: '/',
|
|
975
|
+
headers: {
|
|
976
|
+
'X-Secret': 'gamma'
|
|
977
|
+
}
|
|
978
|
+
})
|
|
979
|
+
t.assert.strictEqual(res.statusCode, 404)
|
|
980
|
+
}
|
|
981
|
+
})
|
|
982
|
+
|
|
983
|
+
test('Custom rotuerOptions constrained routes registered also for HEAD method generated by fastify', (t, done) => {
|
|
984
|
+
t.plan(3)
|
|
985
|
+
|
|
986
|
+
const constraint = {
|
|
987
|
+
name: 'secret',
|
|
988
|
+
storage: function () {
|
|
989
|
+
const secrets = {}
|
|
990
|
+
return {
|
|
991
|
+
get: (secret) => { return secrets[secret] || null },
|
|
992
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
993
|
+
}
|
|
994
|
+
},
|
|
995
|
+
deriveConstraint: (req, ctx) => {
|
|
996
|
+
return req.headers['x-secret']
|
|
997
|
+
},
|
|
998
|
+
validate () { return true }
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const fastify = Fastify({ routerOptions: { constraints: { secret: constraint } } })
|
|
1002
|
+
|
|
1003
|
+
fastify.route({
|
|
1004
|
+
method: 'GET',
|
|
1005
|
+
url: '/',
|
|
1006
|
+
constraints: { secret: 'mySecret' },
|
|
1007
|
+
handler: (req, reply) => {
|
|
1008
|
+
reply.send('from mySecret - my length is 31')
|
|
1009
|
+
}
|
|
1010
|
+
})
|
|
1011
|
+
|
|
1012
|
+
fastify.inject({
|
|
1013
|
+
method: 'HEAD',
|
|
1014
|
+
url: '/',
|
|
1015
|
+
headers: {
|
|
1016
|
+
'X-Secret': 'mySecret'
|
|
1017
|
+
}
|
|
1018
|
+
}, (err, res) => {
|
|
1019
|
+
t.assert.ifError(err)
|
|
1020
|
+
t.assert.deepStrictEqual(res.headers['content-length'], '31')
|
|
1021
|
+
t.assert.strictEqual(res.statusCode, 200)
|
|
1022
|
+
done()
|
|
1023
|
+
})
|
|
1024
|
+
})
|
|
1025
|
+
|
|
1026
|
+
test('allow async rotuerOptions constraints', async (t) => {
|
|
1027
|
+
t.plan(5)
|
|
1028
|
+
|
|
1029
|
+
const constraint = {
|
|
1030
|
+
name: 'secret',
|
|
1031
|
+
storage: function () {
|
|
1032
|
+
const secrets = {}
|
|
1033
|
+
return {
|
|
1034
|
+
get: (secret) => { return secrets[secret] || null },
|
|
1035
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
deriveConstraint: (req, ctx, done) => {
|
|
1039
|
+
done(null, req.headers['x-secret'])
|
|
1040
|
+
},
|
|
1041
|
+
validate () { return true }
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
const fastify = Fastify({ routerOptions: { constraints: { secret: constraint } } })
|
|
1045
|
+
|
|
1046
|
+
fastify.route({
|
|
1047
|
+
method: 'GET',
|
|
1048
|
+
url: '/',
|
|
1049
|
+
constraints: { secret: 'alpha' },
|
|
1050
|
+
handler: (req, reply) => {
|
|
1051
|
+
reply.send({ hello: 'from alpha' })
|
|
1052
|
+
}
|
|
1053
|
+
})
|
|
1054
|
+
|
|
1055
|
+
fastify.route({
|
|
1056
|
+
method: 'GET',
|
|
1057
|
+
url: '/',
|
|
1058
|
+
constraints: { secret: 'beta' },
|
|
1059
|
+
handler: (req, reply) => {
|
|
1060
|
+
reply.send({ hello: 'from beta' })
|
|
1061
|
+
}
|
|
1062
|
+
})
|
|
1063
|
+
|
|
1064
|
+
{
|
|
1065
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
|
1066
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { hello: 'from alpha' })
|
|
1067
|
+
t.assert.strictEqual(statusCode, 200)
|
|
1068
|
+
}
|
|
1069
|
+
{
|
|
1070
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
|
1071
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { hello: 'from beta' })
|
|
1072
|
+
t.assert.strictEqual(statusCode, 200)
|
|
1073
|
+
}
|
|
1074
|
+
{
|
|
1075
|
+
const { statusCode } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
|
1076
|
+
t.assert.strictEqual(statusCode, 404)
|
|
1077
|
+
}
|
|
1078
|
+
})
|
|
1079
|
+
|
|
1080
|
+
test('error in async rotuerOptions constraints', async (t) => {
|
|
1081
|
+
t.plan(8)
|
|
1082
|
+
|
|
1083
|
+
const constraint = {
|
|
1084
|
+
name: 'secret',
|
|
1085
|
+
storage: function () {
|
|
1086
|
+
const secrets = {}
|
|
1087
|
+
return {
|
|
1088
|
+
get: (secret) => { return secrets[secret] || null },
|
|
1089
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
1090
|
+
}
|
|
1091
|
+
},
|
|
1092
|
+
deriveConstraint: (req, ctx, done) => {
|
|
1093
|
+
done(Error('kaboom'))
|
|
1094
|
+
},
|
|
1095
|
+
validate () { return true }
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
const fastify = Fastify({ routerOptions: { constraints: { secret: constraint } } })
|
|
1099
|
+
|
|
1100
|
+
fastify.route({
|
|
1101
|
+
method: 'GET',
|
|
1102
|
+
url: '/',
|
|
1103
|
+
constraints: { secret: 'alpha' },
|
|
1104
|
+
handler: (req, reply) => {
|
|
1105
|
+
reply.send({ hello: 'from alpha' })
|
|
1106
|
+
}
|
|
1107
|
+
})
|
|
1108
|
+
|
|
1109
|
+
fastify.route({
|
|
1110
|
+
method: 'GET',
|
|
1111
|
+
url: '/',
|
|
1112
|
+
constraints: { secret: 'beta' },
|
|
1113
|
+
handler: (req, reply) => {
|
|
1114
|
+
reply.send({ hello: 'from beta' })
|
|
1115
|
+
}
|
|
1116
|
+
})
|
|
1117
|
+
|
|
1118
|
+
{
|
|
1119
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
|
1120
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
1121
|
+
t.assert.strictEqual(statusCode, 500)
|
|
1122
|
+
}
|
|
1123
|
+
{
|
|
1124
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
|
1125
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
1126
|
+
t.assert.strictEqual(statusCode, 500)
|
|
1127
|
+
}
|
|
1128
|
+
{
|
|
1129
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
|
1130
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
1131
|
+
t.assert.strictEqual(statusCode, 500)
|
|
1132
|
+
}
|
|
1133
|
+
{
|
|
1134
|
+
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/' })
|
|
1135
|
+
t.assert.deepStrictEqual(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
|
1136
|
+
t.assert.strictEqual(statusCode, 500)
|
|
1137
|
+
}
|
|
1138
|
+
})
|