fastify 6.0.0-alpha.3 → 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/SPONSORS.md +1 -0
- package/docs/Guides/Ecosystem.md +10 -53
- package/docs/Reference/Errors.md +0 -2
- package/docs/Reference/Reply.md +20 -2
- 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/fastify.js +1 -1
- package/lib/content-type-parser.js +28 -13
- package/lib/content-type.js +4 -4
- package/lib/errors.js +0 -5
- package/lib/handle-request.js +7 -20
- package/lib/reply.js +11 -4
- package/lib/request.js +9 -5
- package/lib/route.js +6 -2
- package/lib/validation.js +73 -14
- 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/content-type-parser-async-context.test.js +76 -0
- package/test/custom-parser.4.test.js +40 -0
- package/test/http2/plain.test.js +45 -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/internals/validation.test.js +66 -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/SPONSORS.md
CHANGED
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,10 @@ 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-
|
|
284
|
-
|
|
281
|
+
- [`fastify-arktype`](https://github.com/BlairCurrey/fastify-arktype) ArkType
|
|
282
|
+
type provider with validation and @fastify/swagger OpenAPI generation.
|
|
285
283
|
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
|
|
286
284
|
to access Fastify instance, logger, request and reply from Node.js [Async
|
|
287
285
|
Local Storage](https://nodejs.org/api/async_context.html#class-asynclocalstorage).
|
|
@@ -296,15 +294,9 @@ section.
|
|
|
296
294
|
Auth0 verification plugin for Fastify, internally uses
|
|
297
295
|
[fastify-jwt](https://www.npmjs.com/package/fastify-jwt) and
|
|
298
296
|
[jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken).
|
|
299
|
-
- [`fastify-autoroutes`](https://github.com/GiovanniCardamone/fastify-autoroutes)
|
|
300
|
-
Plugin to scan and load routes based on filesystem path from a custom
|
|
301
|
-
directory.
|
|
302
297
|
- [`fastify-aws-sns`](https://github.com/gzileni/fastify-aws-sns) Fastify plugin
|
|
303
298
|
for AWS Simple Notification Service (AWS SNS) that coordinates and manages
|
|
304
299
|
the delivery or sending of messages to subscribing endpoints or clients.
|
|
305
|
-
- [`fastify-aws-timestream`](https://github.com/gzileni/fastify-aws-timestream)
|
|
306
|
-
Fastify plugin for managing databases, tables, and querying and creating
|
|
307
|
-
scheduled queries with AWS Timestream.
|
|
308
300
|
- [`fastify-axios`](https://github.com/davidedantonio/fastify-axios) Plugin to
|
|
309
301
|
send HTTP requests via [axios](https://github.com/axios/axios).
|
|
310
302
|
- [`fastify-babel`](https://github.com/cfware/fastify-babel) Fastify plugin for
|
|
@@ -339,9 +331,6 @@ section.
|
|
|
339
331
|
Fastify plugin for CloudFlare Turnstile.
|
|
340
332
|
- [`fastify-cloudinary`](https://github.com/Vanilla-IceCream/fastify-cloudinary)
|
|
341
333
|
Plugin to share a common Cloudinary connection across Fastify.
|
|
342
|
-
- [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb)
|
|
343
|
-
Fastify plugin to connect to a CockroachDB PostgreSQL instance via the
|
|
344
|
-
Sequelize ORM.
|
|
345
334
|
- [`fastify-constraints`](https://github.com/nearform/fastify-constraints)
|
|
346
335
|
Fastify plugin to add constraints to multiple routes
|
|
347
336
|
- [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify
|
|
@@ -359,10 +348,6 @@ section.
|
|
|
359
348
|
- [`fastify-disablecache`](https://github.com/Fdawgs/fastify-disablecache)
|
|
360
349
|
Fastify plugin to disable client-side caching, inspired by
|
|
361
350
|
[nocache](https://github.com/helmetjs/nocache).
|
|
362
|
-
- [`fastify-dynamodb`](https://github.com/matrus2/fastify-dynamodb) AWS DynamoDB
|
|
363
|
-
plugin for Fastify. It exposes
|
|
364
|
-
[AWS.DynamoDB.DocumentClient()](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html)
|
|
365
|
-
object.
|
|
366
351
|
- [`fastify-dynareg`](https://github.com/greguz/fastify-dynareg) Dynamic plugin
|
|
367
352
|
register for Fastify.
|
|
368
353
|
- [`fastify-envalid`](https://github.com/alemagio/fastify-envalid) Fastify
|
|
@@ -370,9 +355,6 @@ section.
|
|
|
370
355
|
project.
|
|
371
356
|
- [`fastify-error-page`](https://github.com/hemerajs/fastify-error-page) Fastify
|
|
372
357
|
plugin to print errors in structured HTML to the browser.
|
|
373
|
-
- [`fastify-esso`](https://github.com/patrickpissurno/fastify-esso) The easiest
|
|
374
|
-
authentication plugin for Fastify, with built-in support for Single sign-on
|
|
375
|
-
(and great documentation).
|
|
376
358
|
- [`fastify-event-bus`](https://github.com/Shiva127/fastify-event-bus) Event bus
|
|
377
359
|
support for Fastify. Built upon [js-event-bus](https://github.com/bcerati/js-event-bus).
|
|
378
360
|
- [`fastify-evervault`](https://github.com/Briscoooe/fastify-evervault/) Fastify
|
|
@@ -455,14 +437,10 @@ section.
|
|
|
455
437
|
plugin to serialize JSON responses into XML.
|
|
456
438
|
- [`fastify-jwt-authz`](https://github.com/Ethan-Arrowood/fastify-jwt-authz) JWT
|
|
457
439
|
user scope verifier.
|
|
458
|
-
- [`fastify-jwt-webapp`](https://github.com/charlesread/fastify-jwt-webapp) JWT
|
|
459
|
-
authentication for Fastify-based web apps.
|
|
460
440
|
- [`fastify-kafkajs`](https://github.com/kffl/fastify-kafkajs) Fastify plugin
|
|
461
441
|
that adds support for KafkaJS - a modern Apache Kafka client library.
|
|
462
442
|
- [`fastify-keycloak-adapter`](https://github.com/yubinTW/fastify-keycloak-adapter)
|
|
463
443
|
A keycloak adapter for a Fastify app.
|
|
464
|
-
- [`fastify-koa`](https://github.com/rozzilla/fastify-koa) Convert Koa
|
|
465
|
-
middlewares into Fastify plugins
|
|
466
444
|
- [`fastify-kubernetes`](https://github.com/greguz/fastify-kubernetes) Fastify
|
|
467
445
|
Kubernetes client plugin.
|
|
468
446
|
- [`fastify-kysely`](https://github.com/alenap93/fastify-kysely) Fastify
|
|
@@ -502,6 +480,8 @@ middlewares into Fastify plugins
|
|
|
502
480
|
- [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose)
|
|
503
481
|
Fastify Mongoose plugin that connects to a MongoDB via the Mongoose plugin
|
|
504
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.
|
|
505
485
|
- [`fastify-mqtt`](https://github.com/love-lena/fastify-mqtt) Plugin to share
|
|
506
486
|
[mqtt](https://www.npmjs.com/package/mqtt) client across Fastify.
|
|
507
487
|
- [`fastify-msgpack`](https://github.com/kenriortega/fastify-msgpack) Fastify
|
|
@@ -544,8 +524,6 @@ middlewares into Fastify plugins
|
|
|
544
524
|
[`oracledb`](https://github.com/oracle/node-oracledb) connection pool to a
|
|
545
525
|
Fastify server instance.
|
|
546
526
|
- [`fastify-orama`](https://github.com/mateonunez/fastify-orama)
|
|
547
|
-
- [`fastify-osm`](https://github.com/gzileni/fastify-osm) Fastify
|
|
548
|
-
OSM plugin to run overpass queries by OpenStreetMap.
|
|
549
527
|
- [`fastify-override`](https://github.com/matthyk/fastify-override)
|
|
550
528
|
Fastify plugin to override decorators, plugins and hooks for testing purposes
|
|
551
529
|
- [`fastify-param-schema-validation`](https://github.com/Player1205/fastify-param-schema-validation)
|
|
@@ -566,8 +544,6 @@ middlewares into Fastify plugins
|
|
|
566
544
|
- [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile)
|
|
567
545
|
Plugin to integrate [PostGraphile](https://postgraphile.org/postgraphile/4/) in
|
|
568
546
|
a Fastify project.
|
|
569
|
-
- [`fastify-postgres-dot-js`](https://github.com/kylerush/fastify-postgresjs) Fastify
|
|
570
|
-
PostgreSQL connection plugin that uses [Postgres.js](https://github.com/porsager/postgres).
|
|
571
547
|
- [`fastify-prettier`](https://github.com/hsynlms/fastify-prettier) A Fastify
|
|
572
548
|
plugin that uses [prettier](https://github.com/prettier/prettier) under the
|
|
573
549
|
hood to beautify outgoing responses and/or other things in the Fastify server.
|
|
@@ -615,8 +591,6 @@ middlewares into Fastify plugins
|
|
|
615
591
|
using name and parameters.
|
|
616
592
|
- [`fastify-rob-config`](https://github.com/jeromemacias/fastify-rob-config)
|
|
617
593
|
Fastify Rob-Config integration.
|
|
618
|
-
- [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group)
|
|
619
|
-
Convenient grouping and inheritance of routes.
|
|
620
594
|
- [`fastify-route-preset`](https://github.com/inyourtime/fastify-route-preset)
|
|
621
595
|
A Fastify plugin that enables you to create route configurations that can be
|
|
622
596
|
applied to multiple routes.
|
|
@@ -624,9 +598,6 @@ middlewares into Fastify plugins
|
|
|
624
598
|
Ensure the existence of defined S3 buckets on the application startup.
|
|
625
599
|
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint)
|
|
626
600
|
Choose the JSON schema to use based on request parameters.
|
|
627
|
-
- [`fastify-schema-to-typescript`](https://github.com/thomasthiebaud/fastify-schema-to-typescript)
|
|
628
|
-
Generate typescript types based on your JSON/YAML validation schemas so they
|
|
629
|
-
are always in sync.
|
|
630
601
|
- [`fastify-sentry`](https://github.com/alex-ppg/fastify-sentry) Fastify plugin
|
|
631
602
|
to add the Sentry SDK error handler to requests.
|
|
632
603
|
- [`fastify-sequelize`](https://github.com/lyquocnam/fastify-sequelize) Fastify
|
|
@@ -637,8 +608,6 @@ middlewares into Fastify plugins
|
|
|
637
608
|
`fastify-caching`.
|
|
638
609
|
- [`fastify-ses-mailer`](https://github.com/KaranHotwani/fastify-ses-mailer) A
|
|
639
610
|
Fastify plugin for sending emails via AWS SES using AWS SDK v3.
|
|
640
|
-
- [`fastify-shared-schema`](https://github.com/Adibla/fastify-shared-schema) Plugin
|
|
641
|
-
for sharing schemas between different routes.
|
|
642
611
|
- [`fastify-slow-down`](https://github.com/nearform/fastify-slow-down) A plugin
|
|
643
612
|
to delay the response from the server.
|
|
644
613
|
- [`fastify-split-validator`](https://github.com/MetCoder95/fastify-split-validator)
|
|
@@ -663,10 +632,6 @@ middlewares into Fastify plugins
|
|
|
663
632
|
localhost-only, TLS certificate.
|
|
664
633
|
- [`fastify-totp`](https://github.com/beliven-it/fastify-totp) A plugin to handle
|
|
665
634
|
TOTP (e.g. for 2FA).
|
|
666
|
-
- [`fastify-type-provider-effect-schema`](https://github.com/daotl/fastify-type-provider-effect-schema)
|
|
667
|
-
Fastify
|
|
668
|
-
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
|
669
|
-
for [@effect/schema](https://github.com/Effect-TS/effect).
|
|
670
635
|
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
|
|
671
636
|
Fastify
|
|
672
637
|
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
|
@@ -677,10 +642,6 @@ middlewares into Fastify plugins
|
|
|
677
642
|
request's `user-agent` header.
|
|
678
643
|
- [`fastify-uws`](https://github.com/geut/fastify-uws) A Fastify plugin to
|
|
679
644
|
use the web server [uWebSockets.js](https://github.com/uNetworking/uWebSockets.js).
|
|
680
|
-
- [`fastify-vhost`](https://github.com/patrickpissurno/fastify-vhost) Proxy
|
|
681
|
-
subdomain HTTP requests to another server (useful if you want to point
|
|
682
|
-
multiple subdomains to the same IP address, while running different servers on
|
|
683
|
-
the same machine).
|
|
684
645
|
- [`fastify-vue-plugin`](https://github.com/TheNoim/fastify-vue)
|
|
685
646
|
[Nuxt.js](https://nuxt.com) plugin for Fastify. Control the routes nuxt
|
|
686
647
|
should use.
|
|
@@ -723,10 +684,6 @@ middlewares into Fastify plugins
|
|
|
723
684
|
|
|
724
685
|
#### [Community Tools](#community-tools)
|
|
725
686
|
|
|
726
|
-
- [`fast-maker`](https://github.com/imjuni/fast-maker) route configuration
|
|
727
|
-
generator by directory structure.
|
|
728
|
-
- [`fastify-flux`](https://github.com/Jnig/fastify-flux) Tool for building
|
|
729
|
-
Fastify APIs using decorators and convert Typescript interface to JSON Schema.
|
|
730
687
|
- [`fastify-intlayer`](https://intlayer.org/doc/environment/fastify)
|
|
731
688
|
i18n solution for error handling, email template
|
|
732
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
|
@@ -277,8 +277,9 @@ requires heavy resources to be sent after the `data`, for example,
|
|
|
277
277
|
as soon as possible.
|
|
278
278
|
|
|
279
279
|
> ℹ️ Note:
|
|
280
|
-
>
|
|
281
|
-
>
|
|
280
|
+
> For HTTP/1 responses, the header `Transfer-Encoding: chunked` will be added
|
|
281
|
+
> once you use a trailer. HTTP/2 does not use chunked transfer encoding and
|
|
282
|
+
> sends trailers using its native trailing headers support.
|
|
282
283
|
|
|
283
284
|
> ℹ️ Note:
|
|
284
285
|
> Any error passed to `done` callback will be ignored. If you are interested
|
|
@@ -339,6 +340,23 @@ to `302` (if status code is not already set by calling `code`).
|
|
|
339
340
|
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will
|
|
340
341
|
> result in a 500 `TypeError` response.
|
|
341
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
|
+
|
|
342
360
|
Example (no `reply.code()` call) sets status code to `302` and redirects to
|
|
343
361
|
`/home`
|
|
344
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
|
|
package/fastify.js
CHANGED
|
@@ -140,6 +140,7 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
140
140
|
// with that type.
|
|
141
141
|
parser = this.customParsers.get(contentType.mediaType)
|
|
142
142
|
if (parser !== undefined) {
|
|
143
|
+
this.cache.set(ct, parser)
|
|
143
144
|
return parser
|
|
144
145
|
}
|
|
145
146
|
|
|
@@ -203,7 +204,12 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
const resource = new AsyncResource('content-type-parser:run', request)
|
|
206
|
-
|
|
207
|
+
|
|
208
|
+
// Preserve the request's async context without the per-request function
|
|
209
|
+
// properties and wrappers created by AsyncResource.bind().
|
|
210
|
+
function done (error, body) {
|
|
211
|
+
resource.runInAsyncScope(onDone, undefined, error, body)
|
|
212
|
+
}
|
|
207
213
|
|
|
208
214
|
if (parser.asString === true || parser.asBuffer === true) {
|
|
209
215
|
rawBody(
|
|
@@ -247,12 +253,12 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
247
253
|
}
|
|
248
254
|
|
|
249
255
|
let receivedLength = 0
|
|
250
|
-
|
|
256
|
+
const chunks = []
|
|
251
257
|
const payload = request[kRequestPayloadStream] || request.raw
|
|
252
258
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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.
|
|
256
262
|
|
|
257
263
|
payload.on('data', onData)
|
|
258
264
|
payload.on('end', onEnd)
|
|
@@ -260,7 +266,11 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
260
266
|
payload.resume()
|
|
261
267
|
|
|
262
268
|
function onData (chunk) {
|
|
263
|
-
|
|
269
|
+
// A custom preParsing stream may still emit strings
|
|
270
|
+
if (typeof chunk === 'string') {
|
|
271
|
+
chunk = Buffer.from(chunk)
|
|
272
|
+
}
|
|
273
|
+
receivedLength += chunk.length
|
|
264
274
|
const { receivedEncodedLength = 0 } = payload
|
|
265
275
|
// The resulting body length must not exceed bodyLimit (see "zip bomb").
|
|
266
276
|
// The case when encoded length is larger than received length is rather theoretical,
|
|
@@ -273,11 +283,7 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
273
283
|
return
|
|
274
284
|
}
|
|
275
285
|
|
|
276
|
-
|
|
277
|
-
body += chunk
|
|
278
|
-
} else {
|
|
279
|
-
body.push(chunk)
|
|
280
|
-
}
|
|
286
|
+
chunks.push(chunk)
|
|
281
287
|
}
|
|
282
288
|
|
|
283
289
|
function onEnd (err) {
|
|
@@ -298,8 +304,17 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
298
304
|
return
|
|
299
305
|
}
|
|
300
306
|
|
|
301
|
-
|
|
302
|
-
|
|
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)
|
|
303
318
|
}
|
|
304
319
|
|
|
305
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
|
|
|
@@ -606,8 +610,11 @@ function onSendEnd (reply, payload) {
|
|
|
606
610
|
header += trailerName
|
|
607
611
|
}
|
|
608
612
|
if (header !== '') {
|
|
609
|
-
//
|
|
610
|
-
|
|
613
|
+
// HTTP/1 must use chunked encoding for trailers. HTTP/2 forbids
|
|
614
|
+
// the transfer-encoding header and handles trailers natively.
|
|
615
|
+
if (!isHttp2Reply(reply)) {
|
|
616
|
+
reply.header('Transfer-Encoding', 'chunked')
|
|
617
|
+
}
|
|
611
618
|
reply.header('Trailer', header.trim())
|
|
612
619
|
} else {
|
|
613
620
|
reply[kReplyTrailers] = null
|