fastify 6.0.0-alpha.4 → 6.0.0-alpha.5
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/SECURITY.md +6 -0
- package/docs/Guides/Ecosystem.md +8 -53
- package/docs/Reference/Errors.md +0 -2
- package/docs/Reference/Reply.md +17 -0
- package/docs/Reference/Request.md +8 -0
- package/docs/Reference/Routes.md +6 -2
- package/docs/Reference/Server.md +2 -2
- package/docs/Reference/Validation-and-Serialization.md +33 -0
- package/docs/Reference/Warnings.md +2 -0
- package/lib/content-type-parser.js +21 -12
- package/lib/content-type.js +4 -4
- package/lib/errors.js +0 -5
- package/lib/handle-request.js +7 -20
- package/lib/reply.js +6 -2
- package/lib/request.js +9 -5
- package/lib/route.js +6 -2
- package/lib/validation.js +67 -10
- package/lib/warnings.js +10 -1
- package/package.json +1 -1
- package/test/child-logger-factory.test.js +25 -0
- package/test/content-parser.test.js +60 -0
- package/test/internals/errors.test.js +1 -11
- package/test/internals/reply-serialize.test.js +20 -0
- package/test/internals/reply.test.js +30 -1
- package/test/internals/request.test.js +50 -0
- package/test/reply-media-type.test.js +57 -0
- package/test/rfc-10008.test.js +6 -9
- package/test/schema-feature.test.js +1 -1
- package/test/schema-validation.test.js +251 -1
- package/test/types/errors.tst.ts +0 -1
- package/test/types/fastify.tst.ts +5 -0
- package/test/types/route.tst.ts +21 -0
- package/types/errors.d.ts +0 -1
- package/types/instance.d.ts +4 -4
- package/types/route.d.ts +3 -2
package/SECURITY.md
CHANGED
|
@@ -30,6 +30,12 @@ The following are **not** considered vulnerabilities in Fastify:
|
|
|
30
30
|
|
|
31
31
|
- **Application code vulnerabilities**: XSS, SQL injection, or other flaws in
|
|
32
32
|
user-written route handlers, hooks, or plugins
|
|
33
|
+
- **Unvalidated template selection**: Passing untrusted input directly as a
|
|
34
|
+
template name or path (for example, `reply.view(request.query.page)`) without
|
|
35
|
+
validating or allowlisting it is an application-level vulnerability. A template
|
|
36
|
+
root used to resolve filenames is not a security sandbox unless the API
|
|
37
|
+
explicitly guarantees path containment. Bypasses of documented containment
|
|
38
|
+
or built-in path validation remain in scope.
|
|
33
39
|
- **Malicious application code**: Issues caused by intentionally malicious
|
|
34
40
|
plugins or handlers (application code is trusted)
|
|
35
41
|
- **Validation schema issues**: Weak or incorrect schemas provided by developers
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -172,8 +172,6 @@ section.
|
|
|
172
172
|
A plugin to help with caching API responses using AWS DynamoDB.
|
|
173
173
|
- [`@clerk/fastify`](https://github.com/clerk/javascript/tree/main/packages/fastify)
|
|
174
174
|
Add authentication and user management to your Fastify application with Clerk.
|
|
175
|
-
- [`@coobaha/typed-fastify`](https://github.com/Coobaha/typed-fastify) Strongly
|
|
176
|
-
typed routes with a runtime validation using JSON schema generated from types.
|
|
177
175
|
- [`@dnlup/fastify-doc`](https://github.com/dnlup/fastify-doc) A plugin for
|
|
178
176
|
sampling process metrics.
|
|
179
177
|
- [`@dnlup/fastify-traps`](https://github.com/dnlup/fastify-traps) A plugin to
|
|
@@ -211,6 +209,9 @@ section.
|
|
|
211
209
|
- [`@matths/fastify-svelte-view`](https://github.com/matths/fastify-svelte-view)
|
|
212
210
|
A Fastify plugin for rendering Svelte components with support for SSR
|
|
213
211
|
(Server-Side Rendering), CSR (Client-Side Rendering), and SSR with hydration.
|
|
212
|
+
- [`@melroy89/fastify-mariadb`](https://github.com/melroy89/fastify-mariadb)
|
|
213
|
+
Fastify MariaDB connection plugin that shares a connection pool across the
|
|
214
|
+
server.
|
|
214
215
|
- [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit)
|
|
215
216
|
A plugin to close the server gracefully
|
|
216
217
|
- [`@mgcrea/fastify-request-logger`](https://github.com/mgcrea/fastify-request-logger)
|
|
@@ -240,6 +241,9 @@ section.
|
|
|
240
241
|
method with a body).
|
|
241
242
|
- [`@trubavuong/fastify-seaweedfs`](https://github.com/trubavuong/fastify-seaweedfs)
|
|
242
243
|
SeaweedFS for Fastify
|
|
244
|
+
- [`@validex/fastify`](https://github.com/chiptoma/validex/tree/main/packages/fastify)
|
|
245
|
+
Zod 4 validation plugin with 25 typed rules, structured error codes, and
|
|
246
|
+
`request.validate()` decorator.
|
|
243
247
|
- [`@yeliex/fastify-problem-details`](https://github.com/yeliex/fastify-problem-details)
|
|
244
248
|
RFC 9457 Problem Details implementation for Fastify, with typed HTTP errors.
|
|
245
249
|
- [`@zrosenbauer/fastify-prisma`](https://github.com/zrosenbauer/fastify-prisma)
|
|
@@ -249,8 +253,6 @@ section.
|
|
|
249
253
|
logging and monitoring tool.
|
|
250
254
|
- [`arecibo`](https://github.com/ducktors/arecibo) Fastify ping responder for
|
|
251
255
|
Kubernetes Liveness and Readiness Probes.
|
|
252
|
-
- [`aws-xray-sdk-fastify`](https://github.com/aws/aws-xray-sdk-node/tree/master/sdk_contrib/fastify)
|
|
253
|
-
A Fastify plugin to log requests and subsegments through AWSXray.
|
|
254
256
|
- [`cls-rtracer`](https://github.com/puzpuzpuz/cls-rtracer) Fastify middleware
|
|
255
257
|
for CLS-based request ID generation. An out-of-the-box solution for adding
|
|
256
258
|
request IDs into your logs.
|
|
@@ -274,14 +276,8 @@ section.
|
|
|
274
276
|
- [`fastify-amqp-async`](https://github.com/kffl/fastify-amqp-async) Fastify
|
|
275
277
|
AMQP plugin with a Promise-based API provided by
|
|
276
278
|
[`amqplib-as-promised`](https://github.com/twawszczak/amqplib-as-promised).
|
|
277
|
-
- [`fastify-angular-universal`](https://github.com/exequiel09/fastify-angular-universal)
|
|
278
|
-
Angular server-side rendering support using
|
|
279
|
-
[`@angular/platform-server`](https://github.com/angular/angular/tree/master/packages/platform-server)
|
|
280
|
-
for Fastify
|
|
281
279
|
- [`fastify-api-key`](https://github.com/arkerone/fastify-api-key) Fastify
|
|
282
280
|
plugin to authenticate HTTP requests based on API key and signature
|
|
283
|
-
- [`fastify-appwrite`](https://github.com/maniecodes/fastify-appwrite) Fastify
|
|
284
|
-
Plugin for interacting with Appwrite server.
|
|
285
281
|
- [`fastify-arktype`](https://github.com/BlairCurrey/fastify-arktype) ArkType
|
|
286
282
|
type provider with validation and @fastify/swagger OpenAPI generation.
|
|
287
283
|
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
|
|
@@ -298,15 +294,9 @@ section.
|
|
|
298
294
|
Auth0 verification plugin for Fastify, internally uses
|
|
299
295
|
[fastify-jwt](https://www.npmjs.com/package/fastify-jwt) and
|
|
300
296
|
[jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken).
|
|
301
|
-
- [`fastify-autoroutes`](https://github.com/GiovanniCardamone/fastify-autoroutes)
|
|
302
|
-
Plugin to scan and load routes based on filesystem path from a custom
|
|
303
|
-
directory.
|
|
304
297
|
- [`fastify-aws-sns`](https://github.com/gzileni/fastify-aws-sns) Fastify plugin
|
|
305
298
|
for AWS Simple Notification Service (AWS SNS) that coordinates and manages
|
|
306
299
|
the delivery or sending of messages to subscribing endpoints or clients.
|
|
307
|
-
- [`fastify-aws-timestream`](https://github.com/gzileni/fastify-aws-timestream)
|
|
308
|
-
Fastify plugin for managing databases, tables, and querying and creating
|
|
309
|
-
scheduled queries with AWS Timestream.
|
|
310
300
|
- [`fastify-axios`](https://github.com/davidedantonio/fastify-axios) Plugin to
|
|
311
301
|
send HTTP requests via [axios](https://github.com/axios/axios).
|
|
312
302
|
- [`fastify-babel`](https://github.com/cfware/fastify-babel) Fastify plugin for
|
|
@@ -341,9 +331,6 @@ section.
|
|
|
341
331
|
Fastify plugin for CloudFlare Turnstile.
|
|
342
332
|
- [`fastify-cloudinary`](https://github.com/Vanilla-IceCream/fastify-cloudinary)
|
|
343
333
|
Plugin to share a common Cloudinary connection across Fastify.
|
|
344
|
-
- [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb)
|
|
345
|
-
Fastify plugin to connect to a CockroachDB PostgreSQL instance via the
|
|
346
|
-
Sequelize ORM.
|
|
347
334
|
- [`fastify-constraints`](https://github.com/nearform/fastify-constraints)
|
|
348
335
|
Fastify plugin to add constraints to multiple routes
|
|
349
336
|
- [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify
|
|
@@ -361,10 +348,6 @@ section.
|
|
|
361
348
|
- [`fastify-disablecache`](https://github.com/Fdawgs/fastify-disablecache)
|
|
362
349
|
Fastify plugin to disable client-side caching, inspired by
|
|
363
350
|
[nocache](https://github.com/helmetjs/nocache).
|
|
364
|
-
- [`fastify-dynamodb`](https://github.com/matrus2/fastify-dynamodb) AWS DynamoDB
|
|
365
|
-
plugin for Fastify. It exposes
|
|
366
|
-
[AWS.DynamoDB.DocumentClient()](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html)
|
|
367
|
-
object.
|
|
368
351
|
- [`fastify-dynareg`](https://github.com/greguz/fastify-dynareg) Dynamic plugin
|
|
369
352
|
register for Fastify.
|
|
370
353
|
- [`fastify-envalid`](https://github.com/alemagio/fastify-envalid) Fastify
|
|
@@ -372,9 +355,6 @@ section.
|
|
|
372
355
|
project.
|
|
373
356
|
- [`fastify-error-page`](https://github.com/hemerajs/fastify-error-page) Fastify
|
|
374
357
|
plugin to print errors in structured HTML to the browser.
|
|
375
|
-
- [`fastify-esso`](https://github.com/patrickpissurno/fastify-esso) The easiest
|
|
376
|
-
authentication plugin for Fastify, with built-in support for Single sign-on
|
|
377
|
-
(and great documentation).
|
|
378
358
|
- [`fastify-event-bus`](https://github.com/Shiva127/fastify-event-bus) Event bus
|
|
379
359
|
support for Fastify. Built upon [js-event-bus](https://github.com/bcerati/js-event-bus).
|
|
380
360
|
- [`fastify-evervault`](https://github.com/Briscoooe/fastify-evervault/) Fastify
|
|
@@ -457,14 +437,10 @@ section.
|
|
|
457
437
|
plugin to serialize JSON responses into XML.
|
|
458
438
|
- [`fastify-jwt-authz`](https://github.com/Ethan-Arrowood/fastify-jwt-authz) JWT
|
|
459
439
|
user scope verifier.
|
|
460
|
-
- [`fastify-jwt-webapp`](https://github.com/charlesread/fastify-jwt-webapp) JWT
|
|
461
|
-
authentication for Fastify-based web apps.
|
|
462
440
|
- [`fastify-kafkajs`](https://github.com/kffl/fastify-kafkajs) Fastify plugin
|
|
463
441
|
that adds support for KafkaJS - a modern Apache Kafka client library.
|
|
464
442
|
- [`fastify-keycloak-adapter`](https://github.com/yubinTW/fastify-keycloak-adapter)
|
|
465
443
|
A keycloak adapter for a Fastify app.
|
|
466
|
-
- [`fastify-koa`](https://github.com/rozzilla/fastify-koa) Convert Koa
|
|
467
|
-
middlewares into Fastify plugins
|
|
468
444
|
- [`fastify-kubernetes`](https://github.com/greguz/fastify-kubernetes) Fastify
|
|
469
445
|
Kubernetes client plugin.
|
|
470
446
|
- [`fastify-kysely`](https://github.com/alenap93/fastify-kysely) Fastify
|
|
@@ -504,6 +480,8 @@ middlewares into Fastify plugins
|
|
|
504
480
|
- [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose)
|
|
505
481
|
Fastify Mongoose plugin that connects to a MongoDB via the Mongoose plugin
|
|
506
482
|
with support for Models.
|
|
483
|
+
- [`fastify-mosquitto-dynsec`](https://github.com/LuizTakeda/fastify-mosquitto-dynsec)
|
|
484
|
+
Fastify plugin to manage Mosquitto Dynamic Security over MQTT.
|
|
507
485
|
- [`fastify-mqtt`](https://github.com/love-lena/fastify-mqtt) Plugin to share
|
|
508
486
|
[mqtt](https://www.npmjs.com/package/mqtt) client across Fastify.
|
|
509
487
|
- [`fastify-msgpack`](https://github.com/kenriortega/fastify-msgpack) Fastify
|
|
@@ -546,8 +524,6 @@ middlewares into Fastify plugins
|
|
|
546
524
|
[`oracledb`](https://github.com/oracle/node-oracledb) connection pool to a
|
|
547
525
|
Fastify server instance.
|
|
548
526
|
- [`fastify-orama`](https://github.com/mateonunez/fastify-orama)
|
|
549
|
-
- [`fastify-osm`](https://github.com/gzileni/fastify-osm) Fastify
|
|
550
|
-
OSM plugin to run overpass queries by OpenStreetMap.
|
|
551
527
|
- [`fastify-override`](https://github.com/matthyk/fastify-override)
|
|
552
528
|
Fastify plugin to override decorators, plugins and hooks for testing purposes
|
|
553
529
|
- [`fastify-param-schema-validation`](https://github.com/Player1205/fastify-param-schema-validation)
|
|
@@ -568,8 +544,6 @@ middlewares into Fastify plugins
|
|
|
568
544
|
- [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile)
|
|
569
545
|
Plugin to integrate [PostGraphile](https://postgraphile.org/postgraphile/4/) in
|
|
570
546
|
a Fastify project.
|
|
571
|
-
- [`fastify-postgres-dot-js`](https://github.com/kylerush/fastify-postgresjs) Fastify
|
|
572
|
-
PostgreSQL connection plugin that uses [Postgres.js](https://github.com/porsager/postgres).
|
|
573
547
|
- [`fastify-prettier`](https://github.com/hsynlms/fastify-prettier) A Fastify
|
|
574
548
|
plugin that uses [prettier](https://github.com/prettier/prettier) under the
|
|
575
549
|
hood to beautify outgoing responses and/or other things in the Fastify server.
|
|
@@ -617,8 +591,6 @@ middlewares into Fastify plugins
|
|
|
617
591
|
using name and parameters.
|
|
618
592
|
- [`fastify-rob-config`](https://github.com/jeromemacias/fastify-rob-config)
|
|
619
593
|
Fastify Rob-Config integration.
|
|
620
|
-
- [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group)
|
|
621
|
-
Convenient grouping and inheritance of routes.
|
|
622
594
|
- [`fastify-route-preset`](https://github.com/inyourtime/fastify-route-preset)
|
|
623
595
|
A Fastify plugin that enables you to create route configurations that can be
|
|
624
596
|
applied to multiple routes.
|
|
@@ -626,9 +598,6 @@ middlewares into Fastify plugins
|
|
|
626
598
|
Ensure the existence of defined S3 buckets on the application startup.
|
|
627
599
|
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint)
|
|
628
600
|
Choose the JSON schema to use based on request parameters.
|
|
629
|
-
- [`fastify-schema-to-typescript`](https://github.com/thomasthiebaud/fastify-schema-to-typescript)
|
|
630
|
-
Generate typescript types based on your JSON/YAML validation schemas so they
|
|
631
|
-
are always in sync.
|
|
632
601
|
- [`fastify-sentry`](https://github.com/alex-ppg/fastify-sentry) Fastify plugin
|
|
633
602
|
to add the Sentry SDK error handler to requests.
|
|
634
603
|
- [`fastify-sequelize`](https://github.com/lyquocnam/fastify-sequelize) Fastify
|
|
@@ -639,8 +608,6 @@ middlewares into Fastify plugins
|
|
|
639
608
|
`fastify-caching`.
|
|
640
609
|
- [`fastify-ses-mailer`](https://github.com/KaranHotwani/fastify-ses-mailer) A
|
|
641
610
|
Fastify plugin for sending emails via AWS SES using AWS SDK v3.
|
|
642
|
-
- [`fastify-shared-schema`](https://github.com/Adibla/fastify-shared-schema) Plugin
|
|
643
|
-
for sharing schemas between different routes.
|
|
644
611
|
- [`fastify-slow-down`](https://github.com/nearform/fastify-slow-down) A plugin
|
|
645
612
|
to delay the response from the server.
|
|
646
613
|
- [`fastify-split-validator`](https://github.com/MetCoder95/fastify-split-validator)
|
|
@@ -665,10 +632,6 @@ middlewares into Fastify plugins
|
|
|
665
632
|
localhost-only, TLS certificate.
|
|
666
633
|
- [`fastify-totp`](https://github.com/beliven-it/fastify-totp) A plugin to handle
|
|
667
634
|
TOTP (e.g. for 2FA).
|
|
668
|
-
- [`fastify-type-provider-effect-schema`](https://github.com/daotl/fastify-type-provider-effect-schema)
|
|
669
|
-
Fastify
|
|
670
|
-
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
|
671
|
-
for [@effect/schema](https://github.com/Effect-TS/effect).
|
|
672
635
|
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
|
|
673
636
|
Fastify
|
|
674
637
|
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
|
@@ -679,10 +642,6 @@ middlewares into Fastify plugins
|
|
|
679
642
|
request's `user-agent` header.
|
|
680
643
|
- [`fastify-uws`](https://github.com/geut/fastify-uws) A Fastify plugin to
|
|
681
644
|
use the web server [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js).
|
|
682
|
-
- [`fastify-vhost`](https://github.com/patrickpissurno/fastify-vhost) Proxy
|
|
683
|
-
subdomain HTTP requests to another server (useful if you want to point
|
|
684
|
-
multiple subdomains to the same IP address, while running different servers on
|
|
685
|
-
the same machine).
|
|
686
645
|
- [`fastify-vue-plugin`](https://github.com/TheNoim/fastify-vue)
|
|
687
646
|
[Nuxt.js](https://nuxt.com) plugin for Fastify. Control the routes nuxt
|
|
688
647
|
should use.
|
|
@@ -725,10 +684,6 @@ middlewares into Fastify plugins
|
|
|
725
684
|
|
|
726
685
|
#### [Community Tools](#community-tools)
|
|
727
686
|
|
|
728
|
-
- [`fast-maker`](https://github.com/imjuni/fast-maker) route configuration
|
|
729
|
-
generator by directory structure.
|
|
730
|
-
- [`fastify-flux`](https://github.com/Jnig/fastify-flux) Tool for building
|
|
731
|
-
Fastify APIs using decorators and convert Typescript interface to JSON Schema.
|
|
732
687
|
- [`fastify-intlayer`](https://intlayer.org/doc/environment/fastify)
|
|
733
688
|
i18n solution for error handling, email template
|
|
734
689
|
- [`jeasx`](https://www.jeasx.dev)
|
package/docs/Reference/Errors.md
CHANGED
|
@@ -94,7 +94,6 @@
|
|
|
94
94
|
- [FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT](#fst_err_route_handler_timeout_option_not_int)
|
|
95
95
|
- [FST_ERR_ROUTE_REWRITE_NOT_STR](#fst_err_route_rewrite_not_str)
|
|
96
96
|
- [FST_ERR_ROUTE_MISSING_CONTENT_TYPE](#fst_err_route_missing_content_type)
|
|
97
|
-
- [FST_ERR_ROUTE_MISSING_CONTENT](#fst_err_route_missing_content)
|
|
98
97
|
- [FST_ERR_REOPENED_CLOSE_SERVER](#fst_err_reopened_close_server)
|
|
99
98
|
- [FST_ERR_REOPENED_SERVER](#fst_err_reopened_server)
|
|
100
99
|
- [FST_ERR_PLUGIN_VERSION_MISMATCH](#fst_err_plugin_version_mismatch)
|
|
@@ -447,7 +446,6 @@ Below is a table with all the error codes used by Fastify.
|
|
|
447
446
|
| <a id="fst_err_route_handler_timeout_option_not_int">FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT</a> | `handlerTimeout` option must be a positive integer. | Use a positive integer for the `handlerTimeout` option. | - |
|
|
448
447
|
| <a id="fst_err_route_rewrite_not_str">FST_ERR_ROUTE_REWRITE_NOT_STR</a> | `rewriteUrl` needs to be of type `string`. | Use a string for the `rewriteUrl`. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
|
449
448
|
| <a id="fst_err_route_missing_content_type">FST_ERR_ROUTE_MISSING_CONTENT_TYPE</a> | `Content-Type` header is required for the request. | Send request with `Content-Type` header. | [#6832](https://github.com/fastify/fastify/pull/6832) |
|
|
450
|
-
| <a id="fst_err_route_missing_content">FST_ERR_ROUTE_MISSING_CONTENT</a> | Body is required for the request. | Send request with payload. | [#6832](https://github.com/fastify/fastify/pull/6832) |
|
|
451
449
|
| <a id="fst_err_reopened_close_server">FST_ERR_REOPENED_CLOSE_SERVER</a> | Fastify has already been closed and cannot be reopened. | - | [#2415](https://github.com/fastify/fastify/pull/2415) |
|
|
452
450
|
| <a id="fst_err_reopened_server">FST_ERR_REOPENED_SERVER</a> | Fastify is already started. | - | [#2415](https://github.com/fastify/fastify/pull/2415) |
|
|
453
451
|
| <a id="fst_err_plugin_version_mismatch">FST_ERR_PLUGIN_VERSION_MISMATCH</a> | Installed Fastify plugin mismatched expected version. | Use a compatible version of the plugin. | [#2549](https://github.com/fastify/fastify/pull/2549) |
|
package/docs/Reference/Reply.md
CHANGED
|
@@ -340,6 +340,23 @@ to `302` (if status code is not already set by calling `code`).
|
|
|
340
340
|
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will
|
|
341
341
|
> result in a 500 `TypeError` response.
|
|
342
342
|
|
|
343
|
+
> ⚠️ Security:
|
|
344
|
+
> Encoding alone does **not** prevent open redirects. Neither `encodeURI`
|
|
345
|
+
> nor `encodeurl` escapes `/`, so a caller-supplied target such as
|
|
346
|
+
> `//evil.com` or `/\evil.com` survives encoding and is resolved by the
|
|
347
|
+
> browser as a new host (a protocol-relative, authority-opening
|
|
348
|
+
> reference). When `dest` can be influenced by request input
|
|
349
|
+
> (`req.query`, `req.body`, `req.params`, cookies, or headers), validate
|
|
350
|
+
> that the resolved target is same-origin or on an explicit allowlist
|
|
351
|
+
> instead of relying on encoding:
|
|
352
|
+
>
|
|
353
|
+
> ```js
|
|
354
|
+
> const target = new URL(dest, 'https://your-site.example')
|
|
355
|
+
> if (target.origin !== 'https://your-site.example') {
|
|
356
|
+
> return reply.code(400).send()
|
|
357
|
+
> }
|
|
358
|
+
> ```
|
|
359
|
+
|
|
343
360
|
Example (no `reply.code()` call) sets status code to `302` and redirects to
|
|
344
361
|
`/home`
|
|
345
362
|
```js
|
|
@@ -122,6 +122,14 @@ to headers on `not found` routes.
|
|
|
122
122
|
> Schema validation may mutate the `request.headers` and
|
|
123
123
|
> `request.raw.headers` objects, causing the headers to become empty.
|
|
124
124
|
|
|
125
|
+
> ℹ️ Note:
|
|
126
|
+
> The setter is additive, so it cannot be used to *remove* a header, and a
|
|
127
|
+
> `headers` schema validator's synchronous `{ value }` result is applied through
|
|
128
|
+
> this same setter. `request.headers` is therefore the incoming request's
|
|
129
|
+
> headers (plus any additive values), not a sanitized or authoritative view. If
|
|
130
|
+
> your application needs an allow-listed header subset, build and consume it
|
|
131
|
+
> explicitly from the validated data or from `request.raw.headers`.
|
|
132
|
+
|
|
125
133
|
```js
|
|
126
134
|
fastify.post('/:params', options, function (request, reply) {
|
|
127
135
|
console.log(request.body)
|
package/docs/Reference/Routes.md
CHANGED
|
@@ -32,7 +32,7 @@ fastify.route(options)
|
|
|
32
32
|
<a id="options"></a>
|
|
33
33
|
|
|
34
34
|
* `method`: currently it supports `GET`, `HEAD`, `TRACE`, `DELETE`,
|
|
35
|
-
`OPTIONS`, `PATCH`, `PUT` and `
|
|
35
|
+
`OPTIONS`, `PATCH`, `PUT`, `POST` and `QUERY`. To accept more methods,
|
|
36
36
|
the [`addHttpMethod`](./Server.md#addHttpMethod) must be used.
|
|
37
37
|
It could also be an array of methods.
|
|
38
38
|
* `url`: the path of the URL to match this route (alias: `path`).
|
|
@@ -41,7 +41,7 @@ fastify.route(options)
|
|
|
41
41
|
[here](./Validation-and-Serialization.md) for more info.
|
|
42
42
|
|
|
43
43
|
* `body`: validates the body of the request if it is a POST, PUT, PATCH,
|
|
44
|
-
TRACE, SEARCH, PROPFIND, PROPPATCH or
|
|
44
|
+
TRACE, SEARCH, PROPFIND, PROPPATCH, LOCK or QUERY method.
|
|
45
45
|
* `querystring` or `query`: validates the querystring. This can be a complete
|
|
46
46
|
JSON Schema object, with the property `type` of `object` and `properties`
|
|
47
47
|
object of parameters, or simply the values of what would be contained in the
|
|
@@ -198,6 +198,10 @@ The above route declaration is more *Hapi*-like, but if you prefer an
|
|
|
198
198
|
|
|
199
199
|
`fastify.patch(path, [options], handler)`
|
|
200
200
|
|
|
201
|
+
`fastify.query(path, [options], handler)`
|
|
202
|
+
|
|
203
|
+
> The `QUERY` method (RFC 10008) requires a `Content-Type` header.
|
|
204
|
+
|
|
201
205
|
Example:
|
|
202
206
|
```js
|
|
203
207
|
const opts = {
|
package/docs/Reference/Server.md
CHANGED
|
@@ -213,7 +213,7 @@ ignored.
|
|
|
213
213
|
|
|
214
214
|
Defines the maximum number of milliseconds for receiving the entire request from
|
|
215
215
|
the client. See [`server.requestTimeout`
|
|
216
|
-
property](https://nodejs.org/dist/latest/docs/api/http.html#
|
|
216
|
+
property](https://nodejs.org/dist/latest/docs/api/http.html#serverrequesttimeout)
|
|
217
217
|
to understand the effect of this option.
|
|
218
218
|
|
|
219
219
|
When `serverFactory` option is specified, this option is ignored.
|
|
@@ -1046,7 +1046,7 @@ be invoked.
|
|
|
1046
1046
|
|
|
1047
1047
|
This can be useful especially if you have a regex-based route, protecting you
|
|
1048
1048
|
against [ReDoS
|
|
1049
|
-
attacks](https://owasp.org/
|
|
1049
|
+
attacks](https://community.owasp.org/attacks/Regular_expression_Denial_of_Service_-_ReDoS).
|
|
1050
1050
|
|
|
1051
1051
|
|
|
1052
1052
|
### `onBadUrl`
|
|
@@ -167,6 +167,22 @@ parameters at the top level.
|
|
|
167
167
|
> ℹ For using the latest Ajv (v8), refer to the
|
|
168
168
|
> [`schemaController`](./Server.md#schema-controller) section.
|
|
169
169
|
|
|
170
|
+
##### Header name case
|
|
171
|
+
|
|
172
|
+
Node.js exposes request header names in lowercase. Fastify normalizes header
|
|
173
|
+
names in a `headers` schema to lowercase before compilation, so assertions
|
|
174
|
+
written in the canonical header-name case still match the request, for example
|
|
175
|
+
`required: ['X-Api-Key']`, `dependencies`, and a `propertyNames` deny-list that
|
|
176
|
+
uses `enum` or `const`.
|
|
177
|
+
|
|
178
|
+
Regular-expression constraints on header names are the exception. A
|
|
179
|
+
`patternProperties` key and a `propertyNames` `pattern` are regular expressions
|
|
180
|
+
matched against the already-lowercased header names, and Fastify cannot safely
|
|
181
|
+
rewrite a regular expression. Author them to match lowercase (for example
|
|
182
|
+
`^x-debug-.*$`, not `^X-Debug-.*$`) or make them case-insensitive. A pattern
|
|
183
|
+
written in canonical case will not match, and the assertion it guards will not
|
|
184
|
+
apply.
|
|
185
|
+
|
|
170
186
|
Example:
|
|
171
187
|
```js
|
|
172
188
|
const bodyJsonSchema = {
|
|
@@ -639,6 +655,23 @@ an application.
|
|
|
639
655
|
> failure by rejecting (throwing), and it cannot coerce the request part through
|
|
640
656
|
> a resolved `value`.
|
|
641
657
|
|
|
658
|
+
##### `headers` and the `{ value }` result
|
|
659
|
+
|
|
660
|
+
For the `headers` part specifically, the synchronous success `value` is applied
|
|
661
|
+
through the additive [`request.headers`](./Request.md#headers) setter. That
|
|
662
|
+
setter *adds or overrides* headers on top of the raw request headers; it does
|
|
663
|
+
**not** replace them. Raw request headers remain separately available as
|
|
664
|
+
`request.raw.headers`, and any incoming header that is not present in the
|
|
665
|
+
returned `value` is still visible on `request.headers`.
|
|
666
|
+
|
|
667
|
+
Consequently, a synchronous custom `headers` validator cannot remove a header by
|
|
668
|
+
simply omitting it from `value`. The same applies to the default Ajv validator:
|
|
669
|
+
`request.headers` is the incoming request's headers (plus any additive values)
|
|
670
|
+
and is not a sanitized, authoritative view. If your application needs a
|
|
671
|
+
sanitized or allow-listed header view — for example to drive an authorization
|
|
672
|
+
decision — build and consume that view explicitly from the validated data rather
|
|
673
|
+
than re-reading `request.headers`.
|
|
674
|
+
|
|
642
675
|
##### .statusCode property
|
|
643
676
|
|
|
644
677
|
All validation errors have a `.statusCode` property set to `400`, ensuring the
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- [Fastify Security Codes](#fastify-security-codes)
|
|
11
11
|
- [FSTSEC001](#FSTSEC001)
|
|
12
12
|
- [FSTSEC002](#FSTSEC002)
|
|
13
|
+
- [FSTSEC003](#FSTSEC003)
|
|
13
14
|
- [Fastify Deprecation Codes](#fastify-deprecation-codes)
|
|
14
15
|
|
|
15
16
|
## Warnings
|
|
@@ -51,6 +52,7 @@ Disabling warnings is not recommended and may cause unexpected behavior.
|
|
|
51
52
|
| ---- | ----------- | ------------ | ---------- |
|
|
52
53
|
| <a id="FSTSEC001">FSTSEC001</a> | A `RegExp` Content-Type is used that may be vulnerable to a CORS bypass, because it does not anchor the essence MIME type. | Start the `RegExp` with `^` or include `;?` so the essence MIME type is detected correctly. | [#4450](https://github.com/fastify/fastify/pull/4450) |
|
|
53
54
|
| <a id="FSTSEC002">FSTSEC002</a> | A headers schema references an external `$ref` (a schema registered with `addSchema`) that is not reached by header case normalization. Header names in the referenced schema keep their original case and do not match the lowercased request headers, so case-insensitive assertions such as `required` and `dependencies` may not apply. | Inline the header schema instead of referencing it with an external `$ref`. | - |
|
|
55
|
+
| <a id="FSTSEC003">FSTSEC003</a> | A headers schema uses a `$ref` inside `propertyNames` that is not reached by header case normalization. Header names held in the referenced schema keep their original case and do not match the lowercased request headers, so a case-insensitive deny-list or allow-list on header names may not apply. | Inline the `propertyNames` constraint instead of referencing it with a `$ref`. | - |
|
|
54
56
|
|
|
55
57
|
### Fastify Deprecation Codes
|
|
56
58
|
|
|
@@ -253,12 +253,12 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
let receivedLength = 0
|
|
256
|
-
|
|
256
|
+
const chunks = []
|
|
257
257
|
const payload = request[kRequestPayloadStream] || request.raw
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
// Always read raw Buffers and decode once at the end: setEncoding() would
|
|
260
|
+
// allocate a StringDecoder per request and force a Buffer.byteLength()
|
|
261
|
+
// rescan of every decoded chunk just to enforce the byte limit.
|
|
262
262
|
|
|
263
263
|
payload.on('data', onData)
|
|
264
264
|
payload.on('end', onEnd)
|
|
@@ -266,7 +266,11 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
266
266
|
payload.resume()
|
|
267
267
|
|
|
268
268
|
function onData (chunk) {
|
|
269
|
-
|
|
269
|
+
// A custom preParsing stream may still emit strings
|
|
270
|
+
if (typeof chunk === 'string') {
|
|
271
|
+
chunk = Buffer.from(chunk)
|
|
272
|
+
}
|
|
273
|
+
receivedLength += chunk.length
|
|
270
274
|
const { receivedEncodedLength = 0 } = payload
|
|
271
275
|
// The resulting body length must not exceed bodyLimit (see "zip bomb").
|
|
272
276
|
// The case when encoded length is larger than received length is rather theoretical,
|
|
@@ -279,11 +283,7 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
279
283
|
return
|
|
280
284
|
}
|
|
281
285
|
|
|
282
|
-
|
|
283
|
-
body += chunk
|
|
284
|
-
} else {
|
|
285
|
-
body.push(chunk)
|
|
286
|
-
}
|
|
286
|
+
chunks.push(chunk)
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
function onEnd (err) {
|
|
@@ -304,8 +304,17 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
304
304
|
return
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
|
|
308
|
-
|
|
307
|
+
let body
|
|
308
|
+
if (asString) {
|
|
309
|
+
// Decoding the whole body at once also keeps multi-byte characters
|
|
310
|
+
// split across chunks intact
|
|
311
|
+
body = chunks.length === 1
|
|
312
|
+
? chunks[0].toString('utf8')
|
|
313
|
+
: Buffer.concat(chunks, receivedLength).toString('utf8')
|
|
314
|
+
} else {
|
|
315
|
+
// Always copy so the parser never receives a view over the shared
|
|
316
|
+
// socket read buffer
|
|
317
|
+
body = Buffer.concat(chunks, receivedLength)
|
|
309
318
|
}
|
|
310
319
|
|
|
311
320
|
const result = parser.fn(request, body, done)
|
package/lib/content-type.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { FifoMap: Fifo } = require('toad-cache')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* keyValuePairsReg matches a single `parameter-name "=" parameter-value`
|
|
@@ -61,9 +61,9 @@ const subtypeNameReg = /^[\w!#$%&'*+.^`|~-]+\s*$/
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Content-Type internal shared cache
|
|
64
|
-
* @type {
|
|
64
|
+
* @type {Fifo<ContentType>}
|
|
65
65
|
*/
|
|
66
|
-
const cache = new
|
|
66
|
+
const cache = new Fifo(100)
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* ContentType parses and represents the value of the content-type header.
|
|
@@ -82,7 +82,7 @@ class ContentType {
|
|
|
82
82
|
/**
|
|
83
83
|
* The shared cache of ContentType instances. The cache is used to avoid
|
|
84
84
|
* creating multiple instances of ContentType for the same header value.
|
|
85
|
-
* @type {
|
|
85
|
+
* @type {Fifo<ContentType>}
|
|
86
86
|
*/
|
|
87
87
|
static get cache () { return cache }
|
|
88
88
|
|
package/lib/errors.js
CHANGED
|
@@ -466,11 +466,6 @@ const codes = {
|
|
|
466
466
|
"Method '%s' must provide a 'Content-Type' header.",
|
|
467
467
|
400
|
|
468
468
|
),
|
|
469
|
-
FST_ERR_ROUTE_MISSING_CONTENT: createError(
|
|
470
|
-
'FST_ERR_ROUTE_MISSING_CONTENT',
|
|
471
|
-
"Method '%s' must provide a request body.",
|
|
472
|
-
400
|
|
473
|
-
),
|
|
474
469
|
|
|
475
470
|
/**
|
|
476
471
|
* again listen when close server
|
package/lib/handle-request.js
CHANGED
|
@@ -6,8 +6,7 @@ const { validate: validateSchema } = require('./validation')
|
|
|
6
6
|
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
|
7
7
|
const {
|
|
8
8
|
FST_ERR_CTP_INVALID_MEDIA_TYPE,
|
|
9
|
-
FST_ERR_ROUTE_MISSING_CONTENT_TYPE
|
|
10
|
-
FST_ERR_ROUTE_MISSING_CONTENT
|
|
9
|
+
FST_ERR_ROUTE_MISSING_CONTENT_TYPE
|
|
11
10
|
} = require('./errors')
|
|
12
11
|
const { setErrorStatusCode } = require('./error-status')
|
|
13
12
|
const {
|
|
@@ -51,20 +50,15 @@ function handleRequest (err, request, reply) {
|
|
|
51
50
|
reply.status(400).send(new FST_ERR_ROUTE_MISSING_CONTENT_TYPE(method))
|
|
52
51
|
return
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
if (isEmptyBody(headers)) {
|
|
56
|
-
// https://datatracker.ietf.org/doc/html/rfc10008#section-2
|
|
57
|
-
// Servers MUST fail the request if the Content-Type request field
|
|
58
|
-
// ([HTTP], Section 8.3) is missing or is inconsistent with the
|
|
59
|
-
// request content.
|
|
60
|
-
reply[kReplyIsError] = true
|
|
61
|
-
reply.status(400).send(new FST_ERR_ROUTE_MISSING_CONTENT(method))
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
53
|
}
|
|
65
54
|
|
|
66
55
|
if (ctHeader === undefined) {
|
|
67
|
-
|
|
56
|
+
const contentLength = headers['content-length']
|
|
57
|
+
const transferEncoding = headers['transfer-encoding']
|
|
58
|
+
const isEmptyBody = transferEncoding === undefined &&
|
|
59
|
+
(contentLength === undefined || contentLength === '0')
|
|
60
|
+
|
|
61
|
+
if (isEmptyBody) {
|
|
68
62
|
// Request has no body to parse
|
|
69
63
|
handler(request, reply)
|
|
70
64
|
return
|
|
@@ -109,13 +103,6 @@ function handler (request, reply) {
|
|
|
109
103
|
}
|
|
110
104
|
}
|
|
111
105
|
|
|
112
|
-
function isEmptyBody (headers) {
|
|
113
|
-
const contentLength = headers['content-length']
|
|
114
|
-
const transferEncoding = headers['transfer-encoding']
|
|
115
|
-
return transferEncoding === undefined &&
|
|
116
|
-
(contentLength === undefined || contentLength === '0')
|
|
117
|
-
}
|
|
118
|
-
|
|
119
106
|
function preValidationCallback (err, request, reply) {
|
|
120
107
|
if (reply.sent === true) return
|
|
121
108
|
|
package/lib/reply.js
CHANGED
|
@@ -95,7 +95,7 @@ Object.defineProperties(Reply.prototype, {
|
|
|
95
95
|
},
|
|
96
96
|
mediaType: {
|
|
97
97
|
get () {
|
|
98
|
-
const contentTypeHeader = this
|
|
98
|
+
const contentTypeHeader = this.getHeader('content-type')
|
|
99
99
|
return ContentType.from(contentTypeHeader).mediaType
|
|
100
100
|
}
|
|
101
101
|
},
|
|
@@ -284,6 +284,10 @@ Reply.prototype.header = function (key, value = '') {
|
|
|
284
284
|
} else {
|
|
285
285
|
this[kReplyHeaders][key].push(value)
|
|
286
286
|
}
|
|
287
|
+
} else if (key === 'set-cookie' && Array.isArray(value)) {
|
|
288
|
+
// Copy the array: later calls push into the stored one, and the caller's
|
|
289
|
+
// array (often a module-level constant) must not grow across requests.
|
|
290
|
+
this[kReplyHeaders][key] = value.slice()
|
|
287
291
|
} else {
|
|
288
292
|
this[kReplyHeaders][key] = value
|
|
289
293
|
}
|
|
@@ -370,7 +374,7 @@ Reply.prototype.getSerializationFunction = function (schemaOrStatus, contentType
|
|
|
370
374
|
return serialize
|
|
371
375
|
}
|
|
372
376
|
|
|
373
|
-
Reply.prototype.compileSerializationSchema = function (schema, httpStatus
|
|
377
|
+
Reply.prototype.compileSerializationSchema = function (schema, httpStatus, contentType) {
|
|
374
378
|
const { request } = this
|
|
375
379
|
const { method, url } = request
|
|
376
380
|
|
package/lib/request.js
CHANGED
|
@@ -122,8 +122,10 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
|
|
122
122
|
host: {
|
|
123
123
|
get () {
|
|
124
124
|
const socket = this.raw.socket
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
// The headers getter may allocate a new object, so read it once.
|
|
126
|
+
const headers = this.headers
|
|
127
|
+
if (headers['x-forwarded-host'] && socket != null && proxyFn(socket.remoteAddress, 0)) {
|
|
128
|
+
return getLastEntryInMultiHeaderValue(headers['x-forwarded-host'])
|
|
127
129
|
}
|
|
128
130
|
/**
|
|
129
131
|
* The last fallback supports the following cases:
|
|
@@ -131,14 +133,16 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
|
|
131
133
|
* 2. HTTP/1.0 without a Host Header
|
|
132
134
|
* 3. Headers schema that may remove the Host Header
|
|
133
135
|
*/
|
|
134
|
-
return
|
|
136
|
+
return headers.host ?? headers[':authority'] ?? ''
|
|
135
137
|
}
|
|
136
138
|
},
|
|
137
139
|
protocol: {
|
|
138
140
|
get () {
|
|
139
141
|
const socket = this.raw.socket
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
// The headers getter may allocate a new object, so read it once.
|
|
143
|
+
const headers = this.headers
|
|
144
|
+
if (headers['x-forwarded-proto'] && socket != null && proxyFn(socket.remoteAddress, 0)) {
|
|
145
|
+
return getLastEntryInMultiHeaderValue(headers['x-forwarded-proto'])
|
|
142
146
|
}
|
|
143
147
|
if (this.socket) {
|
|
144
148
|
return this.socket.encrypted ? 'https' : 'http'
|
package/lib/route.js
CHANGED
|
@@ -466,8 +466,12 @@ function buildRouting (options) {
|
|
|
466
466
|
// the child logger creation altogether
|
|
467
467
|
childLogger = logger
|
|
468
468
|
} else {
|
|
469
|
-
const loggerOpts = {
|
|
470
|
-
|
|
469
|
+
const loggerOpts = {}
|
|
470
|
+
|
|
471
|
+
// An empty level means "inherit". Passing it would make pino treat it
|
|
472
|
+
// as a level change and rebuild every log method of each request child.
|
|
473
|
+
if (context.logLevel) {
|
|
474
|
+
loggerOpts.level = context.logLevel
|
|
471
475
|
}
|
|
472
476
|
|
|
473
477
|
if (context.logSerializers) {
|