fastify 4.21.0 → 4.22.1
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/docs/Guides/Database.md +1 -1
- package/docs/Guides/Ecosystem.md +11 -3
- package/docs/Guides/Getting-Started.md +1 -1
- package/docs/Guides/Serverless.md +2 -2
- package/docs/Reference/Errors.md +1 -1
- package/docs/Reference/HTTP2.md +2 -1
- package/docs/Reference/Hooks.md +4 -1
- package/docs/Reference/Server.md +5 -1
- package/docs/Reference/Validation-and-Serialization.md +1 -1
- package/fastify.d.ts +7 -10
- package/fastify.js +3 -3
- package/lib/contentTypeParser.js +7 -4
- package/lib/error-serializer.js +31 -29
- package/lib/handleRequest.js +3 -3
- package/lib/hooks.js +7 -4
- package/lib/logger.js +1 -1
- package/lib/pluginOverride.js +10 -3
- package/lib/pluginUtils.js +13 -10
- package/lib/reply.js +19 -14
- package/lib/request.js +2 -2
- package/lib/schemas.js +1 -1
- package/lib/server.js +4 -4
- package/lib/validation.js +1 -1
- package/out +25874 -0
- package/package.json +7 -6
- package/test/bodyLimit.test.js +69 -0
- package/test/build/error-serializer.test.js +2 -2
- package/test/custom-http-server.test.js +2 -1
- package/test/https/custom-https-server.test.js +2 -1
- package/test/internals/plugin.test.js +17 -2
- package/test/plugin.test.js +26 -0
- package/test/post-empty-body.test.js +31 -0
- package/test/types/fastify.test-d.ts +8 -3
- package/test/types/hooks.test-d.ts +13 -0
- package/test/types/instance.test-d.ts +7 -2
- package/test/types/request.test-d.ts +1 -1
- package/test/types/type-provider.test-d.ts +26 -1
- package/types/hooks.d.ts +104 -4
- package/types/instance.d.ts +52 -143
- package/types/request.d.ts +1 -1
- package/types/route.d.ts +6 -1
- package/types/schema.d.ts +1 -1
- package/types/tsconfig.eslint.json +2 -2
package/docs/Guides/Database.md
CHANGED
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -44,6 +44,9 @@ section.
|
|
|
44
44
|
Fastify.
|
|
45
45
|
- [`@fastify/diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel)
|
|
46
46
|
Plugin to deal with `diagnostics_channel` on Fastify
|
|
47
|
+
- [`@fastify/early-hints`](https://github.com/fastify/fastify-early-hints) Plugin
|
|
48
|
+
to add HTTP 103 feature based on [RFC
|
|
49
|
+
8297](https://datatracker.ietf.org/doc/html/rfc8297).
|
|
47
50
|
- [`@fastify/elasticsearch`](https://github.com/fastify/fastify-elasticsearch)
|
|
48
51
|
Plugin to share the same ES client.
|
|
49
52
|
- [`@fastify/env`](https://github.com/fastify/fastify-env) Load and check
|
|
@@ -118,6 +121,8 @@ section.
|
|
|
118
121
|
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
|
|
119
122
|
serving Swagger/OpenAPI documentation for Fastify, supporting dynamic
|
|
120
123
|
generation.
|
|
124
|
+
- [`@fastify/throttle`](https://github.com/fastify/fastify-throttle) Plugin for
|
|
125
|
+
- throttling the download speed of a request.
|
|
121
126
|
- [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
|
|
122
127
|
Fastify
|
|
123
128
|
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/)
|
|
@@ -304,9 +309,6 @@ section.
|
|
|
304
309
|
object.
|
|
305
310
|
- [`fastify-dynareg`](https://github.com/greguz/fastify-dynareg) Dynamic plugin
|
|
306
311
|
register for Fastify.
|
|
307
|
-
- [`fastify-early-hints`](https://github.com/zekth/fastify-early-hints) Plugin
|
|
308
|
-
to add HTTP 103 feature based on [RFC
|
|
309
|
-
8297](https://httpwg.org/specs/rfc8297.html)
|
|
310
312
|
- [`fastify-envalid`](https://github.com/alemagio/fastify-envalid) Fastify
|
|
311
313
|
plugin to integrate [envalid](https://github.com/af/envalid) in your Fastify
|
|
312
314
|
project.
|
|
@@ -358,6 +360,8 @@ section.
|
|
|
358
360
|
Providers.
|
|
359
361
|
- [`fastify-guard`](https://github.com/hsynlms/fastify-guard) A Fastify plugin
|
|
360
362
|
that protects endpoints by checking authenticated user roles and/or scopes.
|
|
363
|
+
- [`fastify-hashids`](https://github.com/andersonjoseph/fastify-hashids) A Fastify
|
|
364
|
+
plugin to encode/decode IDs using [hashids](https://github.com/niieani/hashids.js).
|
|
361
365
|
- [`fastify-hasura`](https://github.com/ManUtopiK/fastify-hasura) A Fastify
|
|
362
366
|
plugin to have fun with [Hasura](https://github.com/hasura/graphql-engine).
|
|
363
367
|
- [`fastify-healthcheck`](https://github.com/smartiniOnGitHub/fastify-healthcheck)
|
|
@@ -518,6 +522,10 @@ middlewares into Fastify plugins
|
|
|
518
522
|
- [`fastify-qs`](https://github.com/vanodevium/fastify-qs) A plugin for Fastify
|
|
519
523
|
that adds support for parsing URL query parameters with
|
|
520
524
|
[qs](https://github.com/ljharb/qs).
|
|
525
|
+
- [`fastify-rabbitmq`](https://github.com/Bugs5382/fastify-rabbitmq) Fastify
|
|
526
|
+
RabbitMQ plugin that uses
|
|
527
|
+
[node-amqp-connection-manager](https://github.com/jwalton/node-amqp-connection-manager)
|
|
528
|
+
plugin as a wrapper.
|
|
521
529
|
- [`fastify-racing`](https://github.com/metcoder95/fastify-racing) Fastify's
|
|
522
530
|
plugin that adds support to handle an aborted request asynchronous.
|
|
523
531
|
- [`fastify-ravendb`](https://github.com/nearform/fastify-ravendb) RavenDB
|
|
@@ -277,7 +277,7 @@ async function dbConnector (fastify, options) {
|
|
|
277
277
|
|
|
278
278
|
// Wrapping a plugin function with fastify-plugin exposes the decorators
|
|
279
279
|
// and hooks, declared inside the plugin to the parent scope.
|
|
280
|
-
|
|
280
|
+
export default fastifyPlugin(dbConnector)
|
|
281
281
|
|
|
282
282
|
```
|
|
283
283
|
|
|
@@ -487,10 +487,10 @@ with your GitHub account.
|
|
|
487
487
|
Create your first application and a static workspace: be careful to download the
|
|
488
488
|
API key as an env file, e.g. `yourworkspace.txt`.
|
|
489
489
|
|
|
490
|
-
Then, you can easily deploy your application with the following
|
|
490
|
+
Then, you can easily deploy your application with the following command:
|
|
491
491
|
|
|
492
492
|
```bash
|
|
493
|
-
platformatic deploy --keys `
|
|
493
|
+
platformatic deploy --keys `yourworkspace.txt`
|
|
494
494
|
```
|
|
495
495
|
|
|
496
496
|
Check out the [Full Guide](https://blog.platformatic.dev/how-to-migrate-a-fastify-app-to-platformatic-service)
|
package/docs/Reference/Errors.md
CHANGED
|
@@ -510,7 +510,7 @@ Impossible to load plugin because the parent (mapped directly from `avvio`)
|
|
|
510
510
|
#### FST_ERR_PLUGIN_TIMEOUT
|
|
511
511
|
<a id="FST_ERR_PLUGIN_TIMEOUT"></a>
|
|
512
512
|
|
|
513
|
-
Plugin did not start in time. Default timeout (in
|
|
513
|
+
Plugin did not start in time. Default timeout (in milliseconds): `10000`
|
|
514
514
|
|
|
515
515
|
#### FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
|
|
516
516
|
<a id="FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE"></a>
|
package/docs/Reference/HTTP2.md
CHANGED
|
@@ -32,7 +32,8 @@ fastify.get('/', function (request, reply) {
|
|
|
32
32
|
fastify.listen({ port: 3000 })
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
ALPN negotiation allows
|
|
35
|
+
[ALPN negotiation](https://datatracker.ietf.org/doc/html/rfc7301) allows
|
|
36
|
+
support for both HTTPS and HTTP/2 over the same socket.
|
|
36
37
|
Node core `req` and `res` objects can be either
|
|
37
38
|
[HTTP/1](https://nodejs.org/api/http.html) or
|
|
38
39
|
[HTTP/2](https://nodejs.org/api/http2.html). _Fastify_ supports this out of the
|
package/docs/Reference/Hooks.md
CHANGED
|
@@ -80,7 +80,7 @@ hooks, and a stream with the current request payload.
|
|
|
80
80
|
If it returns a value (via `return` or via the callback function), it must
|
|
81
81
|
return a stream.
|
|
82
82
|
|
|
83
|
-
For instance, you can
|
|
83
|
+
For instance, you can decompress the request body:
|
|
84
84
|
|
|
85
85
|
```js
|
|
86
86
|
fastify.addHook('preParsing', (request, reply, payload, done) => {
|
|
@@ -106,6 +106,9 @@ returned stream. This property is used to correctly match the request payload
|
|
|
106
106
|
with the `Content-Length` header value. Ideally, this property should be updated
|
|
107
107
|
on each received chunk.
|
|
108
108
|
|
|
109
|
+
**Notice:** The size of the returned stream is checked to not exceed the limit
|
|
110
|
+
set in [`bodyLimit`](./Server.md#bodylimit) option.
|
|
111
|
+
|
|
109
112
|
### preValidation
|
|
110
113
|
|
|
111
114
|
If you are using the `preValidation` hook, you can change the payload before it
|
package/docs/Reference/Server.md
CHANGED
|
@@ -282,6 +282,10 @@ attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_
|
|
|
282
282
|
+ Default: `1048576` (1MiB)
|
|
283
283
|
|
|
284
284
|
Defines the maximum payload, in bytes, the server is allowed to accept.
|
|
285
|
+
The default body reader sends [`FST_ERR_CTP_BODY_TOO_LARGE`](./Errors.md#fst_err_ctp_body_too_large)
|
|
286
|
+
reply, if the size of the body exceeds this limit.
|
|
287
|
+
If [`preParsing` hook](./Hooks.md#preparsing) is provided, this limit is applied
|
|
288
|
+
to the size of the stream the hook returns (i.e. the size of "decoded" body).
|
|
285
289
|
|
|
286
290
|
### `onProtoPoisoning`
|
|
287
291
|
<a id="factory-on-proto-poisoning"></a>
|
|
@@ -476,7 +480,7 @@ is not equal to `/Foo`.
|
|
|
476
480
|
When `false` then routes are case-insensitive.
|
|
477
481
|
|
|
478
482
|
Please note that setting this option to `false` goes against
|
|
479
|
-
[RFC3986](https://
|
|
483
|
+
[RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
|
|
480
484
|
|
|
481
485
|
By setting `caseSensitive` to `false`, all paths will be matched as lowercase,
|
|
482
486
|
but the route parameters or wildcards will maintain their original letter
|
|
@@ -397,7 +397,7 @@ configuration](https://github.com/fastify/ajv-compiler#ajv-configuration) is:
|
|
|
397
397
|
{
|
|
398
398
|
coerceTypes: 'array', // change data type of data to match type keyword
|
|
399
399
|
useDefaults: true, // replace missing properties and items with the values from corresponding default keyword
|
|
400
|
-
removeAdditional: true, // remove additional properties
|
|
400
|
+
removeAdditional: true, // remove additional properties if additionalProperties is set to false, see: https://ajv.js.org/guide/modifying-data.html#removing-additional-properties
|
|
401
401
|
uriResolver: require('fast-uri'),
|
|
402
402
|
addUsedSchema: false,
|
|
403
403
|
// Explicitly set allErrors to `false`.
|
package/fastify.d.ts
CHANGED
|
@@ -20,15 +20,15 @@ import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './type
|
|
|
20
20
|
import { FastifyReply } from './types/reply'
|
|
21
21
|
import { FastifyRequest, RequestGenericInterface } from './types/request'
|
|
22
22
|
import { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler, RouteGenericInterface } from './types/route'
|
|
23
|
-
import { FastifySchema, FastifySchemaCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
|
23
|
+
import { FastifySchema, FastifySchemaCompiler, FastifySchemaValidationError, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
|
24
24
|
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
|
|
25
25
|
import { FastifyTypeProvider, FastifyTypeProviderDefault } from './types/type-provider'
|
|
26
26
|
import { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './types/utils'
|
|
27
27
|
|
|
28
28
|
declare module '@fastify/error' {
|
|
29
29
|
interface FastifyError {
|
|
30
|
-
validation?: fastify.ValidationResult[];
|
|
31
30
|
validationContext?: SchemaErrorDataVar;
|
|
31
|
+
validation?: FastifySchemaValidationError[];
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -162,13 +162,10 @@ declare namespace fastify {
|
|
|
162
162
|
clientErrorHandler?: (error: ConnectionError, socket: Socket) => void,
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
params: Record<string, string | string[]>;
|
|
170
|
-
message?: string;
|
|
171
|
-
}
|
|
165
|
+
/**
|
|
166
|
+
* @deprecated use {@link FastifySchemaValidationError}
|
|
167
|
+
*/
|
|
168
|
+
export type ValidationResult = FastifySchemaValidationError;
|
|
172
169
|
|
|
173
170
|
/* Export additional types */
|
|
174
171
|
export type {
|
|
@@ -241,4 +238,4 @@ declare function fastify<
|
|
|
241
238
|
|
|
242
239
|
// CJS export
|
|
243
240
|
// const fastify = require('fastify')
|
|
244
|
-
export = fastify
|
|
241
|
+
export = fastify
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '4.
|
|
3
|
+
const VERSION = '4.22.1'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
@@ -241,7 +241,7 @@ function fastify (options) {
|
|
|
241
241
|
[kReply]: Reply.buildReply(Reply),
|
|
242
242
|
[kRequest]: Request.buildRequest(Request, options.trustProxy),
|
|
243
243
|
[kFourOhFour]: fourOhFour,
|
|
244
|
-
[pluginUtils.
|
|
244
|
+
[pluginUtils.kRegisteredPlugins]: [],
|
|
245
245
|
[kPluginNameChain]: ['fastify'],
|
|
246
246
|
[kAvvioBoot]: null,
|
|
247
247
|
// routing method
|
|
@@ -312,7 +312,7 @@ function fastify (options) {
|
|
|
312
312
|
close: null,
|
|
313
313
|
printPlugins: null,
|
|
314
314
|
hasPlugin: function (name) {
|
|
315
|
-
return this[kPluginNameChain].includes(name)
|
|
315
|
+
return this[pluginUtils.kRegisteredPlugins].includes(name) || this[kPluginNameChain].includes(name)
|
|
316
316
|
},
|
|
317
317
|
// http server
|
|
318
318
|
listen,
|
package/lib/contentTypeParser.js
CHANGED
|
@@ -102,7 +102,7 @@ ContentTypeParser.prototype.getParser = function (contentType) {
|
|
|
102
102
|
const parsed = safeParseContentType(contentType)
|
|
103
103
|
|
|
104
104
|
// dummyContentType always the same object
|
|
105
|
-
// we can use === for the
|
|
105
|
+
// we can use === for the comparison and return early
|
|
106
106
|
if (parsed === defaultContentType) {
|
|
107
107
|
return this.customParsers.get('')
|
|
108
108
|
}
|
|
@@ -226,8 +226,11 @@ function rawBody (request, reply, options, parser, done) {
|
|
|
226
226
|
|
|
227
227
|
function onData (chunk) {
|
|
228
228
|
receivedLength += chunk.length
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
const { receivedEncodedLength = 0 } = payload
|
|
230
|
+
// The resulting body length must not exceed bodyLimit (see "zip bomb").
|
|
231
|
+
// The case when encoded length is larger than received length is rather theoretical,
|
|
232
|
+
// unless the stream returned by preParsing hook is broken and reports wrong value.
|
|
233
|
+
if (receivedLength > limit || receivedEncodedLength > limit) {
|
|
231
234
|
payload.removeListener('data', onData)
|
|
232
235
|
payload.removeListener('end', onEnd)
|
|
233
236
|
payload.removeListener('error', onEnd)
|
|
@@ -396,7 +399,7 @@ function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
|
|
|
396
399
|
function ParserListItem (contentType) {
|
|
397
400
|
this.name = contentType
|
|
398
401
|
// we pre-calculate all the needed information
|
|
399
|
-
// before content-type
|
|
402
|
+
// before content-type comparison
|
|
400
403
|
const parsed = safeParseContentType(contentType)
|
|
401
404
|
this.isEssence = contentType.indexOf(';') === -1
|
|
402
405
|
// we should not allow empty string for parser list item
|
package/lib/error-serializer.js
CHANGED
|
@@ -16,41 +16,43 @@
|
|
|
16
16
|
) {
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
function anonymous0 (input) {
|
|
20
|
-
// #
|
|
21
19
|
|
|
20
|
+
// #
|
|
21
|
+
function anonymous0 (input) {
|
|
22
22
|
const obj = (input && typeof input.toJSON === 'function')
|
|
23
23
|
? input.toJSON()
|
|
24
24
|
: input
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
let addComma = false
|
|
28
|
+
let json = '{'
|
|
29
|
+
|
|
30
|
+
if (obj["statusCode"] !== undefined) {
|
|
31
|
+
!addComma && (addComma = true) || (json += ',')
|
|
32
|
+
json += "\"statusCode\":"
|
|
33
|
+
json += serializer.asNumber(obj["statusCode"])
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (obj["code"] !== undefined) {
|
|
37
|
+
!addComma && (addComma = true) || (json += ',')
|
|
38
|
+
json += "\"code\":"
|
|
39
|
+
json += serializer.asString(obj["code"])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (obj["error"] !== undefined) {
|
|
43
|
+
!addComma && (addComma = true) || (json += ',')
|
|
44
|
+
json += "\"error\":"
|
|
45
|
+
json += serializer.asString(obj["error"])
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (obj["message"] !== undefined) {
|
|
49
|
+
!addComma && (addComma = true) || (json += ',')
|
|
50
|
+
json += "\"message\":"
|
|
51
|
+
json += serializer.asString(obj["message"])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return json + '}'
|
|
28
55
|
|
|
29
|
-
if (obj["statusCode"] !== undefined) {
|
|
30
|
-
!addComma && (addComma = true) || (json += ',')
|
|
31
|
-
json += "\"statusCode\":"
|
|
32
|
-
json += serializer.asNumber(obj["statusCode"])
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (obj["code"] !== undefined) {
|
|
36
|
-
!addComma && (addComma = true) || (json += ',')
|
|
37
|
-
json += "\"code\":"
|
|
38
|
-
json += serializer.asString(obj["code"])
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (obj["error"] !== undefined) {
|
|
42
|
-
!addComma && (addComma = true) || (json += ',')
|
|
43
|
-
json += "\"error\":"
|
|
44
|
-
json += serializer.asString(obj["error"])
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (obj["message"] !== undefined) {
|
|
48
|
-
!addComma && (addComma = true) || (json += ',')
|
|
49
|
-
json += "\"message\":"
|
|
50
|
-
json += serializer.asString(obj["message"])
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return json + '}'
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
const main = anonymous0
|
package/lib/handleRequest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { validate: validateSchema } = require('./validation')
|
|
4
|
-
const {
|
|
4
|
+
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
|
5
5
|
const wrapThenable = require('./wrapThenable')
|
|
6
6
|
const {
|
|
7
7
|
kReplyIsError,
|
|
@@ -65,7 +65,7 @@ function handleRequest (err, request, reply) {
|
|
|
65
65
|
function handler (request, reply) {
|
|
66
66
|
try {
|
|
67
67
|
if (request[kRouteContext].preValidation !== null) {
|
|
68
|
-
|
|
68
|
+
preValidationHookRunner(
|
|
69
69
|
request[kRouteContext].preValidation,
|
|
70
70
|
request,
|
|
71
71
|
reply,
|
|
@@ -111,7 +111,7 @@ function validationCompleted (request, reply, validationErr) {
|
|
|
111
111
|
|
|
112
112
|
// preHandler hook
|
|
113
113
|
if (request[kRouteContext].preHandler !== null) {
|
|
114
|
-
|
|
114
|
+
preHandlerHookRunner(
|
|
115
115
|
request[kRouteContext].preHandler,
|
|
116
116
|
request,
|
|
117
117
|
reply,
|
package/lib/hooks.js
CHANGED
|
@@ -217,8 +217,8 @@ function onResponseHookIterator (fn, request, reply, next) {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
const onResponseHookRunner = hookRunnerGenerator(onResponseHookIterator)
|
|
220
|
-
const
|
|
221
|
-
const
|
|
220
|
+
const preValidationHookRunner = hookRunnerGenerator(hookIterator)
|
|
221
|
+
const preHandlerHookRunner = hookRunnerGenerator(hookIterator)
|
|
222
222
|
const onTimeoutHookRunner = hookRunnerGenerator(hookIterator)
|
|
223
223
|
const onRequestHookRunner = hookRunnerGenerator(hookIterator)
|
|
224
224
|
|
|
@@ -267,6 +267,8 @@ function onSendHookRunner (functions, request, reply, payload, cb) {
|
|
|
267
267
|
next()
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
const preSerializationHookRunner = onSendHookRunner
|
|
271
|
+
|
|
270
272
|
function preParsingHookRunner (functions, request, reply, cb) {
|
|
271
273
|
let i = 0
|
|
272
274
|
|
|
@@ -360,11 +362,12 @@ module.exports = {
|
|
|
360
362
|
preParsingHookRunner,
|
|
361
363
|
onResponseHookRunner,
|
|
362
364
|
onSendHookRunner,
|
|
365
|
+
preSerializationHookRunner,
|
|
363
366
|
onRequestAbortHookRunner,
|
|
364
367
|
hookIterator,
|
|
365
368
|
hookRunnerApplication,
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
preHandlerHookRunner,
|
|
370
|
+
preValidationHookRunner,
|
|
368
371
|
onRequestHookRunner,
|
|
369
372
|
onTimeoutHookRunner,
|
|
370
373
|
lifecycleHooks,
|
package/lib/logger.js
CHANGED
|
@@ -144,7 +144,7 @@ function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
|
|
144
144
|
}
|
|
145
145
|
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
|
146
146
|
|
|
147
|
-
//
|
|
147
|
+
// Optimization: bypass validation if the factory is our own default factory
|
|
148
148
|
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
|
149
149
|
validateLogger(child, true) // throw if the child is not a valid logger
|
|
150
150
|
}
|
package/lib/pluginOverride.js
CHANGED
|
@@ -27,9 +27,10 @@ const pluginUtils = require('./pluginUtils')
|
|
|
27
27
|
module.exports = function override (old, fn, opts) {
|
|
28
28
|
const shouldSkipOverride = pluginUtils.registerPlugin.call(old, fn)
|
|
29
29
|
|
|
30
|
+
const fnName = pluginUtils.getPluginName(fn) || pluginUtils.getFuncPreview(fn)
|
|
30
31
|
if (shouldSkipOverride) {
|
|
31
32
|
// after every plugin registration we will enter a new name
|
|
32
|
-
old[kPluginNameChain].push(
|
|
33
|
+
old[kPluginNameChain].push(fnName)
|
|
33
34
|
return old
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -48,8 +49,14 @@ module.exports = function override (old, fn, opts) {
|
|
|
48
49
|
instance[kSchemaController] = SchemaController.buildSchemaController(old[kSchemaController])
|
|
49
50
|
instance.getSchema = instance[kSchemaController].getSchema.bind(instance[kSchemaController])
|
|
50
51
|
instance.getSchemas = instance[kSchemaController].getSchemas.bind(instance[kSchemaController])
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
|
|
53
|
+
// Track the registered and loaded plugins since the root instance.
|
|
54
|
+
// It does not track the current encapsulated plugin.
|
|
55
|
+
instance[pluginUtils.kRegisteredPlugins] = Object.create(instance[pluginUtils.kRegisteredPlugins])
|
|
56
|
+
|
|
57
|
+
// Track the plugin chain since the root instance.
|
|
58
|
+
// When an non-encapsulated plugin is added, the chain will be updated.
|
|
59
|
+
instance[kPluginNameChain] = [fnName]
|
|
53
60
|
|
|
54
61
|
if (instance[kLogSerializers] || opts.logSerializers) {
|
|
55
62
|
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
|
package/lib/pluginUtils.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const semver = require('semver')
|
|
4
4
|
const assert = require('assert')
|
|
5
|
-
const
|
|
5
|
+
const kRegisteredPlugins = Symbol.for('registered-plugin')
|
|
6
6
|
const {
|
|
7
7
|
kTestInternals
|
|
8
8
|
} = require('./symbols.js')
|
|
@@ -25,12 +25,15 @@ function getPluginName (func) {
|
|
|
25
25
|
// let's see if this is a file, and in that case use that
|
|
26
26
|
// this is common for plugins
|
|
27
27
|
const cache = require.cache
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
// cache is undefined inside SEA
|
|
29
|
+
if (cache) {
|
|
30
|
+
const keys = Object.keys(cache)
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33
|
+
const key = keys[i]
|
|
34
|
+
if (cache[key].exports === func) {
|
|
35
|
+
return key
|
|
36
|
+
}
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -65,7 +68,7 @@ function checkDependencies (fn) {
|
|
|
65
68
|
|
|
66
69
|
dependencies.forEach(dependency => {
|
|
67
70
|
assert(
|
|
68
|
-
this[
|
|
71
|
+
this[kRegisteredPlugins].indexOf(dependency) > -1,
|
|
69
72
|
`The dependency '${dependency}' of plugin '${meta.name}' is not registered`
|
|
70
73
|
)
|
|
71
74
|
})
|
|
@@ -128,7 +131,7 @@ function registerPluginName (fn) {
|
|
|
128
131
|
|
|
129
132
|
const name = meta.name
|
|
130
133
|
if (!name) return
|
|
131
|
-
this[
|
|
134
|
+
this[kRegisteredPlugins].push(name)
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
function registerPlugin (fn) {
|
|
@@ -142,7 +145,7 @@ function registerPlugin (fn) {
|
|
|
142
145
|
module.exports = {
|
|
143
146
|
getPluginName,
|
|
144
147
|
getFuncPreview,
|
|
145
|
-
|
|
148
|
+
kRegisteredPlugins,
|
|
146
149
|
getDisplayName,
|
|
147
150
|
registerPlugin
|
|
148
151
|
}
|
package/lib/reply.js
CHANGED
|
@@ -23,7 +23,12 @@ const {
|
|
|
23
23
|
kOptions,
|
|
24
24
|
kRouteContext
|
|
25
25
|
} = require('./symbols.js')
|
|
26
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
onSendHookRunner,
|
|
28
|
+
onResponseHookRunner,
|
|
29
|
+
preHandlerHookRunner,
|
|
30
|
+
preSerializationHookRunner
|
|
31
|
+
} = require('./hooks')
|
|
27
32
|
|
|
28
33
|
const internals = require('./handleRequest')[Symbol.for('internals')]
|
|
29
34
|
const loggerUtils = require('./logger')
|
|
@@ -166,7 +171,7 @@ Reply.prototype.send = function (payload) {
|
|
|
166
171
|
|
|
167
172
|
if (this[kReplySerializer] !== null) {
|
|
168
173
|
if (typeof payload !== 'string') {
|
|
169
|
-
|
|
174
|
+
preSerializationHook(this, payload)
|
|
170
175
|
return this
|
|
171
176
|
} else {
|
|
172
177
|
payload = this[kReplySerializer](payload)
|
|
@@ -189,7 +194,7 @@ Reply.prototype.send = function (payload) {
|
|
|
189
194
|
}
|
|
190
195
|
}
|
|
191
196
|
if (typeof payload !== 'string') {
|
|
192
|
-
|
|
197
|
+
preSerializationHook(this, payload)
|
|
193
198
|
return this
|
|
194
199
|
}
|
|
195
200
|
}
|
|
@@ -233,7 +238,7 @@ Reply.prototype.header = function (key, value = '') {
|
|
|
233
238
|
key = key.toLowerCase()
|
|
234
239
|
|
|
235
240
|
if (this[kReplyHeaders][key] && key === 'set-cookie') {
|
|
236
|
-
// https://
|
|
241
|
+
// https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.2
|
|
237
242
|
if (typeof this[kReplyHeaders][key] === 'string') {
|
|
238
243
|
this[kReplyHeaders][key] = [this[kReplyHeaders][key]]
|
|
239
244
|
}
|
|
@@ -262,7 +267,7 @@ Reply.prototype.headers = function (headers) {
|
|
|
262
267
|
}
|
|
263
268
|
|
|
264
269
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer#directives
|
|
265
|
-
// https://
|
|
270
|
+
// https://datatracker.ietf.org/doc/html/rfc7230.html#chunked.trailer.part
|
|
266
271
|
const INVALID_TRAILERS = new Set([
|
|
267
272
|
'transfer-encoding',
|
|
268
273
|
'content-length',
|
|
@@ -476,21 +481,21 @@ Reply.prototype.then = function (fulfilled, rejected) {
|
|
|
476
481
|
})
|
|
477
482
|
}
|
|
478
483
|
|
|
479
|
-
function
|
|
484
|
+
function preSerializationHook (reply, payload) {
|
|
480
485
|
if (reply[kRouteContext].preSerialization !== null) {
|
|
481
|
-
|
|
486
|
+
preSerializationHookRunner(
|
|
482
487
|
reply[kRouteContext].preSerialization,
|
|
483
488
|
reply.request,
|
|
484
489
|
reply,
|
|
485
490
|
payload,
|
|
486
|
-
|
|
491
|
+
preSerializationHookEnd
|
|
487
492
|
)
|
|
488
493
|
} else {
|
|
489
|
-
|
|
494
|
+
preSerializationHookEnd(null, reply.request, reply, payload)
|
|
490
495
|
}
|
|
491
496
|
}
|
|
492
497
|
|
|
493
|
-
function
|
|
498
|
+
function preSerializationHookEnd (err, request, reply, payload) {
|
|
494
499
|
if (err != null) {
|
|
495
500
|
onErrorHook(reply, err)
|
|
496
501
|
return
|
|
@@ -505,7 +510,7 @@ function preserializeHookEnd (err, request, reply, payload) {
|
|
|
505
510
|
payload = serialize(reply[kRouteContext], payload, reply.raw.statusCode, reply[kReplyHeaders]['content-type'])
|
|
506
511
|
}
|
|
507
512
|
} catch (e) {
|
|
508
|
-
|
|
513
|
+
wrapSerializationError(e, reply)
|
|
509
514
|
onErrorHook(reply, e)
|
|
510
515
|
return
|
|
511
516
|
}
|
|
@@ -513,7 +518,7 @@ function preserializeHookEnd (err, request, reply, payload) {
|
|
|
513
518
|
onSendHook(reply, payload)
|
|
514
519
|
}
|
|
515
520
|
|
|
516
|
-
function
|
|
521
|
+
function wrapSerializationError (error, reply) {
|
|
517
522
|
error.serialization = reply[kRouteContext].config
|
|
518
523
|
}
|
|
519
524
|
|
|
@@ -571,7 +576,7 @@ function onSendEnd (reply, payload) {
|
|
|
571
576
|
}
|
|
572
577
|
|
|
573
578
|
if (payload === undefined || payload === null) {
|
|
574
|
-
// according to https://
|
|
579
|
+
// according to https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
|
|
575
580
|
// we cannot send a content-length for 304 and 204, and all status code
|
|
576
581
|
// < 200
|
|
577
582
|
// A sender MUST NOT send a Content-Length header field in any message
|
|
@@ -846,7 +851,7 @@ function notFound (reply) {
|
|
|
846
851
|
|
|
847
852
|
// preHandler hook
|
|
848
853
|
if (reply[kRouteContext].preHandler !== null) {
|
|
849
|
-
|
|
854
|
+
preHandlerHookRunner(
|
|
850
855
|
reply[kRouteContext].preHandler,
|
|
851
856
|
reply.request,
|
|
852
857
|
reply,
|
package/lib/request.js
CHANGED
|
@@ -51,8 +51,8 @@ function getTrustProxyFn (tp) {
|
|
|
51
51
|
}
|
|
52
52
|
if (typeof tp === 'string') {
|
|
53
53
|
// Support comma-separated tps
|
|
54
|
-
const
|
|
55
|
-
return proxyAddr.compile(
|
|
54
|
+
const values = tp.split(',').map(it => it.trim())
|
|
55
|
+
return proxyAddr.compile(values)
|
|
56
56
|
}
|
|
57
57
|
return proxyAddr.compile(tp)
|
|
58
58
|
}
|
package/lib/schemas.js
CHANGED
|
@@ -23,7 +23,7 @@ Schemas.prototype.add = function (inputSchema) {
|
|
|
23
23
|
: inputSchema
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// developers can add schemas without $id, but with $def instead
|
|
27
27
|
const id = schema.$id
|
|
28
28
|
if (!id) {
|
|
29
29
|
throw new FST_ERR_SCH_MISSING_ID()
|
package/lib/server.js
CHANGED
|
@@ -132,7 +132,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
132
132
|
const isMainServerListening = mainServer.listening && serverOpts.serverFactory
|
|
133
133
|
|
|
134
134
|
let binding = 0
|
|
135
|
-
let
|
|
135
|
+
let bound = 0
|
|
136
136
|
if (!isMainServerListening) {
|
|
137
137
|
const primaryAddress = mainServer.address()
|
|
138
138
|
for (const adr of addresses) {
|
|
@@ -142,7 +142,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
142
142
|
host: adr.address,
|
|
143
143
|
port: primaryAddress.port,
|
|
144
144
|
cb: (_ignoreErr) => {
|
|
145
|
-
|
|
145
|
+
bound++
|
|
146
146
|
|
|
147
147
|
/* istanbul ignore next: the else won't be taken unless listening fails */
|
|
148
148
|
if (!_ignoreErr) {
|
|
@@ -172,7 +172,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
172
172
|
})
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
if (
|
|
175
|
+
if (bound === binding) {
|
|
176
176
|
// regardless of the error, we are done
|
|
177
177
|
onListen()
|
|
178
178
|
}
|
|
@@ -200,7 +200,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
|
|
200
200
|
// to the secondary servers. It is valid only when the user is
|
|
201
201
|
// listening on localhost
|
|
202
202
|
const originUnref = mainServer.unref
|
|
203
|
-
/*
|
|
203
|
+
/* c8 ignore next 4 */
|
|
204
204
|
mainServer.unref = function () {
|
|
205
205
|
originUnref.call(mainServer)
|
|
206
206
|
mainServer.emit('unref')
|