fastify 5.3.2 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/build/build-validation.js +2 -1
- package/docs/Guides/Delay-Accepting-Requests.md +3 -3
- package/docs/Guides/Ecosystem.md +16 -7
- package/docs/Guides/Serverless.md +28 -69
- package/docs/Reference/ContentTypeParser.md +1 -1
- package/docs/Reference/Errors.md +2 -4
- package/docs/Reference/Hooks.md +14 -14
- package/docs/Reference/Logging.md +3 -3
- package/docs/Reference/Middleware.md +1 -1
- package/docs/Reference/Reply.md +8 -8
- package/docs/Reference/Request.md +1 -1
- package/docs/Reference/Routes.md +3 -3
- package/docs/Reference/Server.md +40 -10
- package/docs/Reference/Validation-and-Serialization.md +1 -1
- package/eslint.config.js +17 -9
- package/fastify.d.ts +2 -1
- package/fastify.js +20 -4
- package/lib/configValidator.js +1 -1
- package/lib/decorate.js +2 -2
- package/lib/errors.js +6 -8
- package/lib/logger-factory.js +1 -1
- package/lib/logger-pino.js +2 -2
- package/lib/pluginOverride.js +3 -1
- package/lib/reply.js +9 -13
- package/lib/request.js +4 -11
- package/lib/server.js +30 -51
- package/lib/symbols.js +1 -0
- package/lib/warnings.js +8 -0
- package/package.json +11 -7
- package/test/404s.test.js +226 -325
- package/test/allow-unsafe-regex.test.js +19 -48
- package/test/als.test.js +28 -40
- package/test/async-await.test.js +11 -2
- package/test/body-limit.test.js +41 -65
- package/test/build-certificate.js +1 -1
- package/test/close-pipelining.test.js +5 -4
- package/test/custom-parser-async.test.js +17 -22
- package/test/decorator-namespace.test._js_ +3 -4
- package/test/decorator.test.js +422 -341
- package/test/diagnostics-channel/async-delay-request.test.js +7 -16
- package/test/diagnostics-channel/sync-delay-request.test.js +7 -16
- package/test/helper.js +108 -70
- package/test/hooks-async.test.js +248 -218
- package/test/hooks.on-listen.test.js +255 -239
- package/test/hooks.on-ready.test.js +110 -92
- package/test/hooks.test.js +910 -769
- package/test/http-methods/lock.test.js +31 -31
- package/test/http-methods/mkcol.test.js +5 -9
- package/test/http-methods/proppatch.test.js +23 -29
- package/test/http-methods/report.test.js +44 -69
- package/test/http-methods/search.test.js +67 -82
- package/test/http2/closing.test.js +38 -20
- package/test/http2/secure-with-fallback.test.js +28 -27
- package/test/https/https.test.js +56 -53
- package/test/inject.test.js +114 -97
- package/test/input-validation.js +63 -53
- package/test/internals/errors.test.js +0 -10
- package/test/internals/handle-request.test.js +49 -66
- package/test/internals/hooks.test.js +17 -0
- package/test/issue-4959.test.js +14 -5
- package/test/listen.4.test.js +31 -43
- package/test/logger/response.test.js +19 -20
- package/test/nullable-validation.test.js +33 -46
- package/test/options.error-handler.test.js +1 -1
- package/test/options.test.js +1 -1
- package/test/output-validation.test.js +49 -72
- package/test/patch.error-handler.test.js +1 -1
- package/test/patch.test.js +1 -1
- package/test/plugin.1.test.js +71 -60
- package/test/plugin.2.test.js +104 -86
- package/test/plugin.3.test.js +56 -35
- package/test/plugin.4.test.js +124 -119
- package/test/promises.test.js +36 -30
- package/test/proto-poisoning.test.js +78 -97
- package/test/put.error-handler.test.js +1 -1
- package/test/put.test.js +1 -1
- package/test/reply-error.test.js +169 -148
- package/test/reply-trailers.test.js +119 -108
- package/test/request-error.test.js +0 -46
- package/test/route-hooks.test.js +112 -92
- package/test/route-prefix.test.js +194 -133
- package/test/schema-feature.test.js +309 -238
- package/test/schema-serialization.test.js +177 -154
- package/test/schema-special-usage.test.js +165 -132
- package/test/schema-validation.test.js +278 -199
- package/test/set-error-handler.test.js +58 -1
- package/test/skip-reply-send.test.js +64 -69
- package/test/stream.1.test.js +30 -27
- package/test/stream.2.test.js +20 -10
- package/test/stream.3.test.js +37 -31
- package/test/trust-proxy.test.js +32 -58
- package/test/types/errors.test-d.ts +0 -1
- package/test/types/fastify.test-d.ts +3 -0
- package/test/types/plugin.test-d.ts +1 -1
- package/test/types/register.test-d.ts +1 -1
- package/test/types/request.test-d.ts +1 -0
- package/test/url-rewriting.test.js +45 -62
- package/test/use-semicolon-delimiter.test.js +1 -1
- package/types/errors.d.ts +0 -1
- package/types/request.d.ts +1 -0
- package/.taprc +0 -7
- package/test/http2/missing-http2-module.test.js +0 -17
package/docs/Reference/Server.md
CHANGED
|
@@ -45,6 +45,7 @@ describes the properties available in that options object.
|
|
|
45
45
|
- [`clientErrorHandler`](#clienterrorhandler)
|
|
46
46
|
- [`rewriteUrl`](#rewriteurl)
|
|
47
47
|
- [`useSemicolonDelimiter`](#usesemicolondelimiter)
|
|
48
|
+
- [`allowErrorHandlerOverride`](#allowerrorhandleroverride)
|
|
48
49
|
- [Instance](#instance)
|
|
49
50
|
- [Server Methods](#server-methods)
|
|
50
51
|
- [server](#server)
|
|
@@ -193,7 +194,7 @@ to understand the effect of this option. This option only applies when HTTP/1.1
|
|
|
193
194
|
is in use. Also, when `serverFactory` option is specified, this option is
|
|
194
195
|
ignored.
|
|
195
196
|
|
|
196
|
-
>
|
|
197
|
+
> ℹ️ Note:
|
|
197
198
|
> At the time of writing, only node >= v16.10.0 supports this option.
|
|
198
199
|
|
|
199
200
|
### `requestTimeout`
|
|
@@ -211,7 +212,7 @@ It must be set to a non-zero value (e.g. 120 seconds) to protect against potenti
|
|
|
211
212
|
Denial-of-Service attacks in case the server is deployed without a reverse proxy
|
|
212
213
|
in front.
|
|
213
214
|
|
|
214
|
-
>
|
|
215
|
+
> ℹ️ Note:
|
|
215
216
|
> At the time of writing, only node >= v14.11.0 supports this option
|
|
216
217
|
|
|
217
218
|
### `ignoreTrailingSlash`
|
|
@@ -529,7 +530,7 @@ Especially in distributed systems, you may want to override the default ID
|
|
|
529
530
|
generation behavior as shown below. For generating `UUID`s you may want to check
|
|
530
531
|
out [hyperid](https://github.com/mcollina/hyperid).
|
|
531
532
|
|
|
532
|
-
>
|
|
533
|
+
> ℹ️ Note:
|
|
533
534
|
> `genReqId` will be not called if the header set in
|
|
534
535
|
> <code>[requestIdHeader](#requestidheader)</code> is available (defaults to
|
|
535
536
|
> 'request-id').
|
|
@@ -581,7 +582,7 @@ fastify.get('/', (request, reply) => {
|
|
|
581
582
|
})
|
|
582
583
|
```
|
|
583
584
|
|
|
584
|
-
>
|
|
585
|
+
> ℹ️ Note:
|
|
585
586
|
> If a request contains multiple `x-forwarded-host` or `x-forwarded-proto`
|
|
586
587
|
> headers, it is only the last one that is used to derive `request.hostname`
|
|
587
588
|
> and `request.protocol`.
|
|
@@ -736,7 +737,7 @@ Fastify provides default error handlers for the most common use cases. It is
|
|
|
736
737
|
possible to override one or more of those handlers with custom code using this
|
|
737
738
|
option.
|
|
738
739
|
|
|
739
|
-
>
|
|
740
|
+
> ℹ️ Note:
|
|
740
741
|
> Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at present.
|
|
741
742
|
|
|
742
743
|
```js
|
|
@@ -789,7 +790,7 @@ function defaultClientErrorHandler (err, socket) {
|
|
|
789
790
|
}
|
|
790
791
|
```
|
|
791
792
|
|
|
792
|
-
>
|
|
793
|
+
> ℹ️ Note:
|
|
793
794
|
> `clientErrorHandler` operates with raw sockets. The handler is expected to
|
|
794
795
|
> return a properly formed HTTP response that includes a status line, HTTP headers
|
|
795
796
|
> and a message body. Before attempting to write the socket, the handler should
|
|
@@ -866,6 +867,29 @@ fastify.get('/dev', async (request, reply) => {
|
|
|
866
867
|
})
|
|
867
868
|
```
|
|
868
869
|
|
|
870
|
+
### `allowErrorHandlerOverride`
|
|
871
|
+
<a id="allow-error-handler-override"></a>
|
|
872
|
+
|
|
873
|
+
* **Default:** `true`
|
|
874
|
+
|
|
875
|
+
> ⚠ **Warning:** This option will be set to `false` by default
|
|
876
|
+
> in the next major release.
|
|
877
|
+
|
|
878
|
+
When set to `false`, it prevents `setErrorHandler` from being called
|
|
879
|
+
multiple times within the same scope, ensuring that the previous error
|
|
880
|
+
handler is not unintentionally overridden.
|
|
881
|
+
|
|
882
|
+
#### Example of incorrect usage:
|
|
883
|
+
|
|
884
|
+
```js
|
|
885
|
+
app.setErrorHandler(function freeSomeResources () {
|
|
886
|
+
// Never executed, memory leaks
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
app.setErrorHandler(function anotherErrorHandler () {
|
|
890
|
+
// Overrides the previous handler
|
|
891
|
+
})
|
|
892
|
+
```
|
|
869
893
|
|
|
870
894
|
## Instance
|
|
871
895
|
|
|
@@ -1357,7 +1381,7 @@ Set the schema error formatter for all routes. See
|
|
|
1357
1381
|
Set the schema serializer compiler for all routes. See
|
|
1358
1382
|
[#schema-serializer](./Validation-and-Serialization.md#schema-serializer).
|
|
1359
1383
|
|
|
1360
|
-
>
|
|
1384
|
+
> ℹ️ Note:
|
|
1361
1385
|
> [`setReplySerializer`](#set-reply-serializer) has priority if set!
|
|
1362
1386
|
|
|
1363
1387
|
#### validatorCompiler
|
|
@@ -1490,7 +1514,7 @@ lifecycle](./Lifecycle.md#lifecycle). *async-await* is supported as well.
|
|
|
1490
1514
|
You can also register [`preValidation`](./Hooks.md#route-hooks) and
|
|
1491
1515
|
[`preHandler`](./Hooks.md#route-hooks) hooks for the 404 handler.
|
|
1492
1516
|
|
|
1493
|
-
>
|
|
1517
|
+
> ℹ️ Note:
|
|
1494
1518
|
> The `preValidation` hook registered using this method will run for a
|
|
1495
1519
|
> route that Fastify does not recognize and **not** when a route handler manually
|
|
1496
1520
|
> calls [`reply.callNotFound`](./Reply.md#call-not-found). In which case, only
|
|
@@ -1526,10 +1550,10 @@ plugins are registered. If you would like to augment the behavior of the default
|
|
|
1526
1550
|
arguments `fastify.setNotFoundHandler()` within the context of these registered
|
|
1527
1551
|
plugins.
|
|
1528
1552
|
|
|
1529
|
-
>
|
|
1553
|
+
> ℹ️ Note:
|
|
1530
1554
|
> Some config properties from the request object will be
|
|
1531
1555
|
> undefined inside the custom not found handler. E.g.:
|
|
1532
|
-
> `request.
|
|
1556
|
+
> `request.routeOptions.url`, `routeOptions.method` and `routeOptions.config`.
|
|
1533
1557
|
> This method design goal is to allow calling the common not found route.
|
|
1534
1558
|
> To return a per-route customized 404 response, you can do it in
|
|
1535
1559
|
> the response itself.
|
|
@@ -1574,6 +1598,12 @@ if (statusCode >= 500) {
|
|
|
1574
1598
|
log.error(error)
|
|
1575
1599
|
}
|
|
1576
1600
|
```
|
|
1601
|
+
|
|
1602
|
+
> ⚠ Warning:
|
|
1603
|
+
> Avoid calling setErrorHandler multiple times in the same scope.
|
|
1604
|
+
> See [`allowErrorHandlerOverride`](#allowerrorhandleroverride).
|
|
1605
|
+
|
|
1606
|
+
|
|
1577
1607
|
#### setChildLoggerFactory
|
|
1578
1608
|
<a id="set-child-logger-factory"></a>
|
|
1579
1609
|
|
|
@@ -432,7 +432,7 @@ fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
|
|
432
432
|
return ajv.compile(schema)
|
|
433
433
|
})
|
|
434
434
|
```
|
|
435
|
-
>
|
|
435
|
+
> ℹ️ Note: When using a custom validator instance, add schemas to the validator
|
|
436
436
|
> instead of Fastify. Fastify's `addSchema` method will not recognize the custom
|
|
437
437
|
> validator.
|
|
438
438
|
|
package/eslint.config.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
const neostandard = require('neostandard')
|
|
2
3
|
|
|
3
|
-
module.exports =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
module.exports = [
|
|
5
|
+
...neostandard({
|
|
6
|
+
ignores: [
|
|
7
|
+
'lib/configValidator.js',
|
|
8
|
+
'lib/error-serializer.js',
|
|
9
|
+
'test/same-shape.test.js',
|
|
10
|
+
'test/types/import.js'
|
|
11
|
+
],
|
|
12
|
+
ts: true
|
|
13
|
+
}),
|
|
14
|
+
{
|
|
15
|
+
rules: {
|
|
16
|
+
'comma-dangle': ['error', 'never']
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
]
|
package/fastify.d.ts
CHANGED
|
@@ -157,7 +157,8 @@ declare namespace fastify {
|
|
|
157
157
|
* listener to error events emitted by client connections
|
|
158
158
|
*/
|
|
159
159
|
clientErrorHandler?: (error: ConnectionError, socket: Socket) => void,
|
|
160
|
-
childLoggerFactory?: FastifyChildLoggerFactory
|
|
160
|
+
childLoggerFactory?: FastifyChildLoggerFactory,
|
|
161
|
+
allowErrorHandlerOverride?: boolean
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
/**
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '5.
|
|
3
|
+
const VERSION = '5.4.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -31,7 +31,8 @@ const {
|
|
|
31
31
|
kErrorHandler,
|
|
32
32
|
kKeepAliveConnections,
|
|
33
33
|
kChildLoggerFactory,
|
|
34
|
-
kGenReqId
|
|
34
|
+
kGenReqId,
|
|
35
|
+
kErrorHandlerAlreadySet
|
|
35
36
|
} = require('./lib/symbols.js')
|
|
36
37
|
|
|
37
38
|
const { createServer } = require('./lib/server')
|
|
@@ -72,10 +73,12 @@ const {
|
|
|
72
73
|
FST_ERR_ROUTE_REWRITE_NOT_STR,
|
|
73
74
|
FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN,
|
|
74
75
|
FST_ERR_ERROR_HANDLER_NOT_FN,
|
|
76
|
+
FST_ERR_ERROR_HANDLER_ALREADY_SET,
|
|
75
77
|
FST_ERR_ROUTE_METHOD_INVALID
|
|
76
78
|
} = errorCodes
|
|
77
79
|
|
|
78
80
|
const { buildErrorHandler } = require('./lib/error-handler.js')
|
|
81
|
+
const { FSTWRN004 } = require('./lib/warnings.js')
|
|
79
82
|
|
|
80
83
|
const initChannel = diagnostics.channel('fastify.initialization')
|
|
81
84
|
|
|
@@ -149,6 +152,7 @@ function fastify (options) {
|
|
|
149
152
|
options.disableRequestLogging = disableRequestLogging
|
|
150
153
|
options.ajv = ajvOptions
|
|
151
154
|
options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler
|
|
155
|
+
options.allowErrorHandlerOverride = options.allowErrorHandlerOverride ?? defaultInitOptions.allowErrorHandlerOverride
|
|
152
156
|
|
|
153
157
|
const initialConfig = getSecuredInitialConfig(options)
|
|
154
158
|
|
|
@@ -237,6 +241,7 @@ function fastify (options) {
|
|
|
237
241
|
[kSchemaController]: schemaController,
|
|
238
242
|
[kSchemaErrorFormatter]: null,
|
|
239
243
|
[kErrorHandler]: buildErrorHandler(),
|
|
244
|
+
[kErrorHandlerAlreadySet]: false,
|
|
240
245
|
[kChildLoggerFactory]: defaultChildLoggerFactory,
|
|
241
246
|
[kReplySerializerDefault]: null,
|
|
242
247
|
[kContentTypeParser]: new ContentTypeParser(
|
|
@@ -681,8 +686,12 @@ function fastify (options) {
|
|
|
681
686
|
this[kHooks].add(name, fn)
|
|
682
687
|
} else {
|
|
683
688
|
this.after((err, done) => {
|
|
684
|
-
|
|
685
|
-
|
|
689
|
+
try {
|
|
690
|
+
_addHook.call(this, name, fn)
|
|
691
|
+
done(err)
|
|
692
|
+
} catch (err) {
|
|
693
|
+
done(err)
|
|
694
|
+
}
|
|
686
695
|
})
|
|
687
696
|
}
|
|
688
697
|
return this
|
|
@@ -854,6 +863,13 @@ function fastify (options) {
|
|
|
854
863
|
throw new FST_ERR_ERROR_HANDLER_NOT_FN()
|
|
855
864
|
}
|
|
856
865
|
|
|
866
|
+
if (!options.allowErrorHandlerOverride && this[kErrorHandlerAlreadySet]) {
|
|
867
|
+
throw new FST_ERR_ERROR_HANDLER_ALREADY_SET()
|
|
868
|
+
} else if (this[kErrorHandlerAlreadySet]) {
|
|
869
|
+
FSTWRN004("To disable this behavior, set 'allowErrorHandlerOverride' to false or ignore this message. For more information, visit: https://fastify.dev/docs/latest/Reference/Server/#allowerrorhandleroverride")
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
this[kErrorHandlerAlreadySet] = true
|
|
857
873
|
this[kErrorHandler] = buildErrorHandler(this[kErrorHandler], func.bind(this))
|
|
858
874
|
return this
|
|
859
875
|
}
|
package/lib/configValidator.js
CHANGED
|
@@ -1100,5 +1100,5 @@ return errors === 0;
|
|
|
1100
1100
|
}
|
|
1101
1101
|
|
|
1102
1102
|
|
|
1103
|
-
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false}
|
|
1103
|
+
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false,"allowErrorHandlerOverride":true}
|
|
1104
1104
|
/* c8 ignore stop */
|
package/lib/decorate.js
CHANGED
|
@@ -4,7 +4,7 @@ const {
|
|
|
4
4
|
kReply,
|
|
5
5
|
kRequest,
|
|
6
6
|
kState,
|
|
7
|
-
kHasBeenDecorated
|
|
7
|
+
kHasBeenDecorated
|
|
8
8
|
} = require('./symbols.js')
|
|
9
9
|
|
|
10
10
|
const {
|
|
@@ -13,7 +13,7 @@ const {
|
|
|
13
13
|
FST_ERR_DEC_AFTER_START,
|
|
14
14
|
FST_ERR_DEC_REFERENCE_TYPE,
|
|
15
15
|
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE,
|
|
16
|
-
FST_ERR_DEC_UNDECLARED
|
|
16
|
+
FST_ERR_DEC_UNDECLARED
|
|
17
17
|
} = require('./errors')
|
|
18
18
|
|
|
19
19
|
function decorate (instance, name, fn, dependencies) {
|
package/lib/errors.js
CHANGED
|
@@ -64,6 +64,12 @@ const codes = {
|
|
|
64
64
|
500,
|
|
65
65
|
TypeError
|
|
66
66
|
),
|
|
67
|
+
FST_ERR_ERROR_HANDLER_ALREADY_SET: createError(
|
|
68
|
+
'FST_ERR_ERROR_HANDLER_ALREADY_SET',
|
|
69
|
+
"Error Handler already set in this scope. Set 'allowErrorHandlerOverride: true' to allow overriding.",
|
|
70
|
+
500,
|
|
71
|
+
TypeError
|
|
72
|
+
),
|
|
67
73
|
|
|
68
74
|
/**
|
|
69
75
|
* ContentTypeParser
|
|
@@ -328,14 +334,6 @@ const codes = {
|
|
|
328
334
|
'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }'
|
|
329
335
|
),
|
|
330
336
|
|
|
331
|
-
/**
|
|
332
|
-
* http2
|
|
333
|
-
*/
|
|
334
|
-
FST_ERR_HTTP2_INVALID_VERSION: createError(
|
|
335
|
-
'FST_ERR_HTTP2_INVALID_VERSION',
|
|
336
|
-
'HTTP2 is available only from node >= 8.8.1'
|
|
337
|
-
),
|
|
338
|
-
|
|
339
337
|
/**
|
|
340
338
|
* initialConfig
|
|
341
339
|
*/
|
package/lib/logger-factory.js
CHANGED
package/lib/logger-pino.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
const pino = require('pino')
|
|
10
10
|
const { serializersSym } = pino.symbols
|
|
11
11
|
const {
|
|
12
|
-
FST_ERR_LOG_INVALID_DESTINATION
|
|
12
|
+
FST_ERR_LOG_INVALID_DESTINATION
|
|
13
13
|
} = require('./errors')
|
|
14
14
|
|
|
15
15
|
function createPinoLogger (opts) {
|
|
@@ -64,5 +64,5 @@ const serializers = {
|
|
|
64
64
|
|
|
65
65
|
module.exports = {
|
|
66
66
|
serializers,
|
|
67
|
-
createPinoLogger
|
|
67
|
+
createPinoLogger
|
|
68
68
|
}
|
package/lib/pluginOverride.js
CHANGED
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
kReply,
|
|
13
13
|
kRequest,
|
|
14
14
|
kFourOhFour,
|
|
15
|
-
kPluginNameChain
|
|
15
|
+
kPluginNameChain,
|
|
16
|
+
kErrorHandlerAlreadySet
|
|
16
17
|
} = require('./symbols.js')
|
|
17
18
|
|
|
18
19
|
const Reply = require('./reply')
|
|
@@ -57,6 +58,7 @@ module.exports = function override (old, fn, opts) {
|
|
|
57
58
|
// Track the plugin chain since the root instance.
|
|
58
59
|
// When an non-encapsulated plugin is added, the chain will be updated.
|
|
59
60
|
instance[kPluginNameChain] = [fnName]
|
|
61
|
+
instance[kErrorHandlerAlreadySet] = false
|
|
60
62
|
|
|
61
63
|
if (instance[kLogSerializers] || opts.logSerializers) {
|
|
62
64
|
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
|
package/lib/reply.js
CHANGED
|
@@ -22,7 +22,7 @@ const {
|
|
|
22
22
|
kReplyCacheSerializeFns,
|
|
23
23
|
kSchemaController,
|
|
24
24
|
kOptions,
|
|
25
|
-
kRouteContext
|
|
25
|
+
kRouteContext
|
|
26
26
|
} = require('./symbols.js')
|
|
27
27
|
const {
|
|
28
28
|
onSendHookRunner,
|
|
@@ -53,7 +53,7 @@ const {
|
|
|
53
53
|
FST_ERR_BAD_TRAILER_VALUE,
|
|
54
54
|
FST_ERR_MISSING_SERIALIZATION_FN,
|
|
55
55
|
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN,
|
|
56
|
-
FST_ERR_DEC_UNDECLARED
|
|
56
|
+
FST_ERR_DEC_UNDECLARED
|
|
57
57
|
} = require('./errors')
|
|
58
58
|
const decorators = require('./decorate')
|
|
59
59
|
|
|
@@ -215,12 +215,8 @@ Reply.prototype.send = function (payload) {
|
|
|
215
215
|
|
|
216
216
|
Reply.prototype.getHeader = function (key) {
|
|
217
217
|
key = key.toLowerCase()
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
if (value === undefined && res.hasHeader(key)) {
|
|
221
|
-
value = res.getHeader(key)
|
|
222
|
-
}
|
|
223
|
-
return value
|
|
218
|
+
const value = this[kReplyHeaders][key]
|
|
219
|
+
return value !== undefined ? value : this.raw.getHeader(key)
|
|
224
220
|
}
|
|
225
221
|
|
|
226
222
|
Reply.prototype.getHeaders = function () {
|
|
@@ -315,12 +311,12 @@ Reply.prototype.removeTrailer = function (key) {
|
|
|
315
311
|
}
|
|
316
312
|
|
|
317
313
|
Reply.prototype.code = function (code) {
|
|
318
|
-
const
|
|
319
|
-
if (
|
|
314
|
+
const statusCode = +code
|
|
315
|
+
if (!(statusCode >= 100 && statusCode <= 599)) {
|
|
320
316
|
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
|
|
321
317
|
}
|
|
322
318
|
|
|
323
|
-
this.raw.statusCode =
|
|
319
|
+
this.raw.statusCode = statusCode
|
|
324
320
|
this[kReplyHasStatusCode] = true
|
|
325
321
|
return this
|
|
326
322
|
}
|
|
@@ -500,11 +496,11 @@ function preSerializationHook (reply, payload) {
|
|
|
500
496
|
preSerializationHookEnd
|
|
501
497
|
)
|
|
502
498
|
} else {
|
|
503
|
-
preSerializationHookEnd(null,
|
|
499
|
+
preSerializationHookEnd(null, undefined, reply, payload)
|
|
504
500
|
}
|
|
505
501
|
}
|
|
506
502
|
|
|
507
|
-
function preSerializationHookEnd (err,
|
|
503
|
+
function preSerializationHookEnd (err, _request, reply, payload) {
|
|
508
504
|
if (err != null) {
|
|
509
505
|
onErrorHook(reply, err)
|
|
510
506
|
return
|
package/lib/request.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
kOptions,
|
|
12
12
|
kRequestCacheValidateFns,
|
|
13
13
|
kRouteContext,
|
|
14
|
-
kRequestOriginalUrl
|
|
14
|
+
kRequestOriginalUrl
|
|
15
15
|
} = require('./symbols')
|
|
16
16
|
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
|
|
17
17
|
const decorators = require('./decorate')
|
|
@@ -188,19 +188,12 @@ Object.defineProperties(Request.prototype, {
|
|
|
188
188
|
exposeHeadRoute: context.exposeHeadRoute,
|
|
189
189
|
prefixTrailingSlash: context.prefixTrailingSlash,
|
|
190
190
|
handler: context.handler,
|
|
191
|
+
config: context.config,
|
|
192
|
+
schema: context.schema,
|
|
191
193
|
version
|
|
192
194
|
}
|
|
193
195
|
|
|
194
|
-
|
|
195
|
-
config: {
|
|
196
|
-
get: () => context.config
|
|
197
|
-
},
|
|
198
|
-
schema: {
|
|
199
|
-
get: () => context.schema
|
|
200
|
-
}
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
return Object.freeze(options)
|
|
196
|
+
return options
|
|
204
197
|
}
|
|
205
198
|
},
|
|
206
199
|
is404: {
|
package/lib/server.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const http = require('node:http')
|
|
4
4
|
const https = require('node:https')
|
|
5
|
+
const http2 = require('node:http2')
|
|
5
6
|
const dns = require('node:dns')
|
|
6
7
|
const os = require('node:os')
|
|
7
8
|
|
|
@@ -9,7 +10,6 @@ const { kState, kOptions, kServerBindings } = require('./symbols')
|
|
|
9
10
|
const { FSTWRN003 } = require('./warnings')
|
|
10
11
|
const { onListenHookRunner } = require('./hooks')
|
|
11
12
|
const {
|
|
12
|
-
FST_ERR_HTTP2_INVALID_VERSION,
|
|
13
13
|
FST_ERR_REOPENED_CLOSE_SERVER,
|
|
14
14
|
FST_ERR_REOPENED_SERVER,
|
|
15
15
|
FST_ERR_LISTEN_OPTIONS_INVALID
|
|
@@ -98,7 +98,6 @@ function createServer (options, httpHandler) {
|
|
|
98
98
|
|
|
99
99
|
if (cb === undefined) {
|
|
100
100
|
const listening = listenPromise.call(this, server, listenOptions)
|
|
101
|
-
/* istanbul ignore else */
|
|
102
101
|
return listening.then(address => {
|
|
103
102
|
return new Promise((resolve, reject) => {
|
|
104
103
|
if (host === 'localhost') {
|
|
@@ -192,7 +191,6 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
192
191
|
// to the secondary servers. It is valid only when the user is
|
|
193
192
|
// listening on localhost
|
|
194
193
|
const originUnref = mainServer.unref
|
|
195
|
-
/* c8 ignore next 4 */
|
|
196
194
|
mainServer.unref = function () {
|
|
197
195
|
originUnref.call(mainServer)
|
|
198
196
|
mainServer.emit('unref')
|
|
@@ -218,7 +216,8 @@ function listenCallback (server, listenOptions) {
|
|
|
218
216
|
|
|
219
217
|
if (this[kState].listening && this[kState].closing) {
|
|
220
218
|
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
|
221
|
-
}
|
|
219
|
+
}
|
|
220
|
+
if (this[kState].listening) {
|
|
222
221
|
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
|
|
223
222
|
}
|
|
224
223
|
|
|
@@ -234,7 +233,8 @@ function listenCallback (server, listenOptions) {
|
|
|
234
233
|
function listenPromise (server, listenOptions) {
|
|
235
234
|
if (this[kState].listening && this[kState].closing) {
|
|
236
235
|
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
|
237
|
-
}
|
|
236
|
+
}
|
|
237
|
+
if (this[kState].listening) {
|
|
238
238
|
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -272,41 +272,38 @@ function listenPromise (server, listenOptions) {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
function getServerInstance (options, httpHandler) {
|
|
275
|
-
let server = null
|
|
276
|
-
// node@20 do not accepts options as boolean
|
|
277
|
-
// we need to provide proper https option
|
|
278
|
-
const httpsOptions = options.https === true ? {} : options.https
|
|
279
275
|
if (options.serverFactory) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (typeof httpsOptions === 'object') {
|
|
283
|
-
server = http2().createSecureServer(httpsOptions, httpHandler)
|
|
284
|
-
} else {
|
|
285
|
-
server = http2().createServer(httpHandler)
|
|
286
|
-
}
|
|
287
|
-
server.on('session', sessionTimeout(options.http2SessionTimeout))
|
|
288
|
-
} else {
|
|
289
|
-
// this is http1
|
|
290
|
-
if (httpsOptions) {
|
|
291
|
-
server = https.createServer(httpsOptions, httpHandler)
|
|
292
|
-
} else {
|
|
293
|
-
server = http.createServer(options.http, httpHandler)
|
|
294
|
-
}
|
|
295
|
-
server.keepAliveTimeout = options.keepAliveTimeout
|
|
296
|
-
server.requestTimeout = options.requestTimeout
|
|
297
|
-
// we treat zero as null
|
|
298
|
-
// and null is the default setting from nodejs
|
|
299
|
-
// so we do not pass the option to server
|
|
300
|
-
if (options.maxRequestsPerSocket > 0) {
|
|
301
|
-
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
|
302
|
-
}
|
|
276
|
+
// User provided server instance
|
|
277
|
+
return options.serverFactory(httpHandler, options)
|
|
303
278
|
}
|
|
304
279
|
|
|
305
|
-
|
|
280
|
+
// We have accepted true as a valid way to init https but node requires an options obj
|
|
281
|
+
const httpsOptions = options.https === true ? {} : options.https
|
|
282
|
+
|
|
283
|
+
if (options.http2) {
|
|
284
|
+
const server = typeof httpsOptions === 'object' ? http2.createSecureServer(httpsOptions, httpHandler) : http2.createServer(options.http, httpHandler)
|
|
285
|
+
server.on('session', (session) => session.setTimeout(options.http2SessionTimeout, function closeSession () {
|
|
286
|
+
this.close()
|
|
287
|
+
}))
|
|
288
|
+
|
|
306
289
|
server.setTimeout(options.connectionTimeout)
|
|
290
|
+
|
|
291
|
+
return server
|
|
307
292
|
}
|
|
293
|
+
|
|
294
|
+
// HTTP1 server instance
|
|
295
|
+
const server = httpsOptions ? https.createServer(httpsOptions, httpHandler) : http.createServer(options.http, httpHandler)
|
|
296
|
+
server.keepAliveTimeout = options.keepAliveTimeout
|
|
297
|
+
server.requestTimeout = options.requestTimeout
|
|
298
|
+
server.setTimeout(options.connectionTimeout)
|
|
299
|
+
// We treat zero as null(node default) so we do not pass zero to the server instance
|
|
300
|
+
if (options.maxRequestsPerSocket > 0) {
|
|
301
|
+
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
|
302
|
+
}
|
|
303
|
+
|
|
308
304
|
return server
|
|
309
305
|
}
|
|
306
|
+
|
|
310
307
|
/**
|
|
311
308
|
* Inspects the provided `server.address` object and returns a
|
|
312
309
|
* normalized list of IP address strings. Normalization in this
|
|
@@ -355,21 +352,3 @@ function logServerAddress (server, listenTextResolver) {
|
|
|
355
352
|
}
|
|
356
353
|
return addresses[0]
|
|
357
354
|
}
|
|
358
|
-
|
|
359
|
-
function http2 () {
|
|
360
|
-
try {
|
|
361
|
-
return require('node:http2')
|
|
362
|
-
} catch (err) {
|
|
363
|
-
throw new FST_ERR_HTTP2_INVALID_VERSION()
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function sessionTimeout (timeout) {
|
|
368
|
-
return function (session) {
|
|
369
|
-
session.setTimeout(timeout, close)
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function close () {
|
|
374
|
-
this.close()
|
|
375
|
-
}
|
package/lib/symbols.js
CHANGED
|
@@ -56,6 +56,7 @@ const keys = {
|
|
|
56
56
|
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
|
57
57
|
kTestInternals: Symbol('fastify.testInternals'),
|
|
58
58
|
kErrorHandler: Symbol('fastify.errorHandler'),
|
|
59
|
+
kErrorHandlerAlreadySet: Symbol('fastify.errorHandlerAlreadySet'),
|
|
59
60
|
kChildLoggerFactory: Symbol('fastify.childLoggerFactory'),
|
|
60
61
|
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
|
|
61
62
|
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'),
|
package/lib/warnings.js
CHANGED
|
@@ -25,6 +25,13 @@ const FSTWRN003 = createWarning({
|
|
|
25
25
|
unlimited: true
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
+
const FSTWRN004 = createWarning({
|
|
29
|
+
name: 'FastifyWarning',
|
|
30
|
+
code: 'FSTWRN004',
|
|
31
|
+
message: 'It seems that you are overriding an errorHandler in the same scope, which can lead to subtle bugs.',
|
|
32
|
+
unlimited: true
|
|
33
|
+
})
|
|
34
|
+
|
|
28
35
|
const FSTSEC001 = createWarning({
|
|
29
36
|
name: 'FastifySecurity',
|
|
30
37
|
code: 'FSTSEC001',
|
|
@@ -35,5 +42,6 @@ const FSTSEC001 = createWarning({
|
|
|
35
42
|
module.exports = {
|
|
36
43
|
FSTWRN001,
|
|
37
44
|
FSTWRN003,
|
|
45
|
+
FSTWRN004,
|
|
38
46
|
FSTSEC001
|
|
39
47
|
}
|