fastify 5.1.0 → 5.2.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 +12 -7
- package/docs/Guides/Database.md +15 -15
- package/docs/Guides/Detecting-When-Clients-Abort.md +28 -28
- package/docs/Guides/Ecosystem.md +13 -7
- package/docs/Guides/Index.md +1 -1
- package/docs/Guides/Migration-Guide-V4.md +11 -11
- package/docs/Guides/Migration-Guide-V5.md +5 -5
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Prototype-Poisoning.md +3 -3
- package/docs/Guides/Recommendations.md +9 -9
- package/docs/Guides/Serverless.md +5 -5
- package/docs/Guides/Testing.md +8 -8
- package/docs/Guides/Write-Plugin.md +1 -1
- package/docs/Guides/Write-Type-Provider.md +3 -3
- package/docs/Reference/Decorators.md +2 -2
- package/docs/Reference/Errors.md +2 -2
- package/docs/Reference/Hooks.md +7 -7
- package/docs/Reference/LTS.md +8 -0
- package/docs/Reference/Logging.md +5 -4
- package/docs/Reference/Reply.md +54 -53
- package/docs/Reference/Request.md +49 -43
- package/docs/Reference/Routes.md +7 -7
- package/docs/Reference/Server.md +31 -27
- package/docs/Reference/TypeScript.md +9 -9
- package/docs/Reference/Validation-and-Serialization.md +5 -5
- package/examples/typescript-server.ts +1 -1
- package/fastify.d.ts +4 -4
- package/fastify.js +1 -1
- package/lib/error-handler.js +9 -9
- package/lib/errors.js +1 -1
- package/lib/hooks.js +4 -1
- package/lib/request.js +11 -10
- package/package.json +3 -4
- package/test/{allowUnsafeRegex.test.js → allow-unsafe-regex.test.js} +4 -4
- package/test/async-dispose.test.js +0 -1
- package/test/async_hooks.test.js +4 -4
- package/test/buffer.test.js +4 -4
- package/test/build-certificate.js +1 -1
- package/test/bundler/README.md +5 -5
- package/test/case-insensitive.test.js +10 -10
- package/test/check.test.js +2 -3
- package/test/{childLoggerFactory.test.js → child-logger-factory.test.js} +1 -1
- package/test/client-timeout.test.js +1 -1
- package/test/close-pipelining.test.js +0 -1
- package/test/conditional-pino.test.js +3 -3
- package/test/content-length.test.js +53 -68
- package/test/content-parser.test.js +178 -167
- package/test/content-type.test.js +8 -9
- package/test/context-config.test.js +44 -54
- package/test/custom-parser.5.test.js +32 -32
- package/test/encapsulated-child-logger-factory.test.js +8 -8
- package/test/encapsulated-error-handler.test.js +20 -20
- package/test/fastify-instance.test.js +33 -34
- package/test/{findRoute.test.js → find-route.test.js} +11 -10
- package/test/fluent-schema.test.js +33 -36
- package/test/handler-context.test.js +11 -11
- package/test/has-route.test.js +12 -15
- package/test/header-overflow.test.js +13 -12
- package/test/hooks.on-ready.test.js +2 -2
- package/test/hooks.test.js +19 -19
- package/test/http-methods/head.test.js +0 -3
- package/test/imports.test.js +2 -2
- package/test/internals/errors.test.js +1 -1
- package/test/listen.5.test.js +9 -9
- package/test/{maxRequestsPerSocket.test.js → max-requests-per-socket.test.js} +30 -30
- package/test/middleware.test.js +4 -5
- package/test/noop-set.test.js +1 -1
- package/test/post-empty-body.test.js +18 -11
- package/test/pretty-print.test.js +59 -49
- package/test/proto-poisoning.test.js +42 -37
- package/test/reply-code.test.js +34 -32
- package/test/{reply-earlyHints.test.js → reply-early-hints.test.js} +21 -19
- package/test/request-header-host.test.js +154 -12
- package/test/request-id.test.js +31 -25
- package/test/{requestTimeout.test.js → request-timeout.test.js} +11 -11
- package/test/route.3.test.js +3 -2
- package/test/route.8.test.js +20 -20
- package/test/router-options.test.js +80 -77
- package/test/schema-examples.test.js +72 -38
- package/test/server.test.js +12 -12
- package/test/set-error-handler.test.js +2 -3
- package/test/stream-serializers.test.js +10 -7
- package/test/sync-routes.test.js +18 -18
- package/test/trust-proxy.test.js +51 -45
- package/test/type-provider.test.js +8 -6
- package/test/types/content-type-parser.test-d.ts +1 -1
- package/test/types/fastify.test-d.ts +4 -4
- package/test/types/instance.test-d.ts +3 -1
- package/test/types/logger.test-d.ts +2 -2
- package/test/types/plugin.test-d.ts +2 -2
- package/test/types/register.test-d.ts +2 -2
- package/test/types/reply.test-d.ts +1 -1
- package/test/types/route.test-d.ts +1 -1
- package/test/types/serverFactory.test-d.ts +1 -1
- package/test/types/type-provider.test-d.ts +1 -1
- package/test/url-rewriting.test.js +35 -38
- package/test/{useSemicolonDelimiter.test.js → use-semicolon-delimiter.test.js} +30 -30
- package/test/validation-error-handling.test.js +259 -285
- package/types/hooks.d.ts +1 -1
- package/types/instance.d.ts +9 -2
- package/types/reply.d.ts +1 -1
- package/types/request.d.ts +0 -4
- package/types/serverFactory.d.ts +3 -3
- package/types/utils.d.ts +3 -3
- /package/test/{connectionTimeout.test.js → connection-timeout.test.js} +0 -0
- /package/test/internals/{contentTypeParser.test.js → content-type-parser.test.js} +0 -0
- /package/test/internals/{handleRequest.test.js → handle-request.test.js} +0 -0
- /package/test/internals/{hookRunner.test.js → hook-runner.test.js} +0 -0
- /package/test/internals/{initialConfig.test.js → initial-config.test.js} +0 -0
- /package/test/internals/{reqIdGenFactory.test.js → req-id-gen-factory.test.js} +0 -0
- /package/test/{wrapThenable.test.js → wrap-thenable.test.js} +0 -0
package/docs/Reference/Server.md
CHANGED
|
@@ -24,6 +24,7 @@ describes the properties available in that options object.
|
|
|
24
24
|
- [`onProtoPoisoning`](#onprotopoisoning)
|
|
25
25
|
- [`onConstructorPoisoning`](#onconstructorpoisoning)
|
|
26
26
|
- [`logger`](#logger)
|
|
27
|
+
- [`loggerInstance`](#loggerInstance)
|
|
27
28
|
- [`disableRequestLogging`](#disablerequestlogging)
|
|
28
29
|
- [`serverFactory`](#serverfactory)
|
|
29
30
|
- [`caseSensitive`](#casesensitive)
|
|
@@ -105,7 +106,7 @@ describes the properties available in that options object.
|
|
|
105
106
|
|
|
106
107
|
An object used to configure the server's listening socket. The options
|
|
107
108
|
are the same as the Node.js core [`createServer`
|
|
108
|
-
method](https://nodejs.org/
|
|
109
|
+
method](https://nodejs.org/docs/latest-v20.x/api/http.html#httpcreateserveroptions-requestlistener).
|
|
109
110
|
|
|
110
111
|
This option is ignored if options [`http2`](#factory-http2) or
|
|
111
112
|
[`https`](#factory-https) are set.
|
|
@@ -116,7 +117,7 @@ This option is ignored if options [`http2`](#factory-http2) or
|
|
|
116
117
|
+ Default: `false`
|
|
117
118
|
|
|
118
119
|
If `true` Node.js core's
|
|
119
|
-
[HTTP/2](https://nodejs.org/dist/latest-
|
|
120
|
+
[HTTP/2](https://nodejs.org/dist/latest-v20.x/docs/api/http2.html) module is
|
|
120
121
|
used for binding the socket.
|
|
121
122
|
|
|
122
123
|
### `https`
|
|
@@ -126,7 +127,7 @@ used for binding the socket.
|
|
|
126
127
|
|
|
127
128
|
An object used to configure the server's listening socket for TLS. The options
|
|
128
129
|
are the same as the Node.js core [`createServer`
|
|
129
|
-
method](https://nodejs.org/dist/latest-
|
|
130
|
+
method](https://nodejs.org/dist/latest-v20.x/docs/api/https.html#https_https_createserver_options_requestlistener).
|
|
130
131
|
When this property is `null`, the socket will not be configured for TLS.
|
|
131
132
|
|
|
132
133
|
This option also applies when the [`http2`](#factory-http2) option is set.
|
|
@@ -152,7 +153,7 @@ Defines the server keep-alive timeout in milliseconds. See documentation for
|
|
|
152
153
|
[`server.keepAliveTimeout`
|
|
153
154
|
property](https://nodejs.org/api/http.html#http_server_keepalivetimeout) to
|
|
154
155
|
understand the effect of this option. This option only applies when HTTP/1 is in
|
|
155
|
-
use.
|
|
156
|
+
use.
|
|
156
157
|
|
|
157
158
|
When `serverFactory` option is specified this option is ignored.
|
|
158
159
|
|
|
@@ -203,7 +204,7 @@ ignored.
|
|
|
203
204
|
Defines the maximum number of milliseconds for receiving the entire request from
|
|
204
205
|
the client. See [`server.requestTimeout`
|
|
205
206
|
property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
|
|
206
|
-
to understand the effect of this option.
|
|
207
|
+
to understand the effect of this option.
|
|
207
208
|
|
|
208
209
|
When `serverFactory` option is specified, this option is ignored.
|
|
209
210
|
It must be set to a non-zero value (e.g. 120 seconds) to protect against potential
|
|
@@ -329,9 +330,6 @@ The possible values this property may have are:
|
|
|
329
330
|
+ Default: `false`. The logger is disabled. All logging methods will point to a
|
|
330
331
|
null logger [abstract-logging](https://npm.im/abstract-logging) instance.
|
|
331
332
|
|
|
332
|
-
+ `pinoInstance`: a previously instantiated instance of Pino. The internal
|
|
333
|
-
logger will point to this instance.
|
|
334
|
-
|
|
335
333
|
+ `object`: a standard Pino [options
|
|
336
334
|
object](https://github.com/pinojs/pino/blob/c77d8ec5ce/docs/API.md#constructor).
|
|
337
335
|
This will be passed directly to the Pino constructor. If the following
|
|
@@ -351,9 +349,15 @@ The possible values this property may have are:
|
|
|
351
349
|
```
|
|
352
350
|
Any user-supplied serializer will override the default serializer of the
|
|
353
351
|
corresponding property.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
352
|
+
|
|
353
|
+
### `loggerInstance`
|
|
354
|
+
<a id="factory-logger-instance"></a>
|
|
355
|
+
|
|
356
|
+
+ Default: `null`
|
|
357
|
+
|
|
358
|
+
A custom logger instance. The logger must be a Pino instance or conform to the
|
|
359
|
+
Pino interface by having the following methods: `info`, `error`, `debug`,
|
|
360
|
+
`fatal`, `warn`, `trace`, `child`. For example:
|
|
357
361
|
```js
|
|
358
362
|
const pino = require('pino')();
|
|
359
363
|
|
|
@@ -387,12 +391,12 @@ attaching custom `onRequest` and `onResponse` hooks.
|
|
|
387
391
|
|
|
388
392
|
The other log entries that will be disabled are:
|
|
389
393
|
- an error log written by the default `onResponse` hook on reply callback errors
|
|
390
|
-
- the error and info logs written by the `defaultErrorHandler`
|
|
394
|
+
- the error and info logs written by the `defaultErrorHandler`
|
|
391
395
|
on error management
|
|
392
|
-
- the info log written by the `fourOhFour` handler when a
|
|
396
|
+
- the info log written by the `fourOhFour` handler when a
|
|
393
397
|
non existent route is requested
|
|
394
398
|
|
|
395
|
-
Other log messages emitted by Fastify will stay enabled,
|
|
399
|
+
Other log messages emitted by Fastify will stay enabled,
|
|
396
400
|
like deprecation warnings and messages
|
|
397
401
|
emitted when requests are received while the server is closing.
|
|
398
402
|
|
|
@@ -456,7 +460,7 @@ Please note that setting this option to `false` goes against
|
|
|
456
460
|
|
|
457
461
|
By setting `caseSensitive` to `false`, all paths will be matched as lowercase,
|
|
458
462
|
but the route parameters or wildcards will maintain their original letter
|
|
459
|
-
casing.
|
|
463
|
+
casing.
|
|
460
464
|
This option does not affect query strings, please refer to
|
|
461
465
|
[`querystringParser`](#querystringparser) to change their handling.
|
|
462
466
|
|
|
@@ -493,7 +497,7 @@ Setting `requestIdHeader` to `true` will set the `requestIdHeader` to
|
|
|
493
497
|
Setting `requestIdHeader` to a non-empty string will use
|
|
494
498
|
the specified string as the `requestIdHeader`.
|
|
495
499
|
By default `requestIdHeader` is set to `false` and will immediately use [genReqId](#genreqid).
|
|
496
|
-
Setting `requestIdHeader` to an empty String (`""`) will set the
|
|
500
|
+
Setting `requestIdHeader` to an empty String (`""`) will set the
|
|
497
501
|
requestIdHeader to `false`.
|
|
498
502
|
|
|
499
503
|
+ Default: `false`
|
|
@@ -827,7 +831,7 @@ is an instance-wide configuration.
|
|
|
827
831
|
// @param {object} req The raw Node.js HTTP request, not the `FastifyRequest` object.
|
|
828
832
|
// @this Fastify The root Fastify instance (not an encapsulated instance).
|
|
829
833
|
// @returns {string} The path that the request should be mapped to.
|
|
830
|
-
function rewriteUrl (req) {
|
|
834
|
+
function rewriteUrl (req) {
|
|
831
835
|
if (req.url === '/hi') {
|
|
832
836
|
this.log.debug({ originalUrl: req.url, url: '/hello' }, 'rewrite url');
|
|
833
837
|
return '/hello'
|
|
@@ -948,7 +952,7 @@ Starts the server and internally waits for the `.ready()` event. The signature
|
|
|
948
952
|
is `.listen([options][, callback])`. Both the `options` object and the
|
|
949
953
|
`callback` parameters extend the [Node.js
|
|
950
954
|
core](https://nodejs.org/api/net.html#serverlistenoptions-callback) options
|
|
951
|
-
object. Thus, all core options are available with the following additional
|
|
955
|
+
object. Thus, all core options are available with the following additional
|
|
952
956
|
Fastify specific options:
|
|
953
957
|
|
|
954
958
|
### `listenTextResolver`
|
|
@@ -956,13 +960,13 @@ Fastify specific options:
|
|
|
956
960
|
|
|
957
961
|
Set an optional resolver for the text to log after server has been successfully
|
|
958
962
|
started.
|
|
959
|
-
It is possible to override the default `Server listening at [address]` log
|
|
963
|
+
It is possible to override the default `Server listening at [address]` log
|
|
960
964
|
entry using this option.
|
|
961
965
|
|
|
962
966
|
```js
|
|
963
|
-
server.listen({
|
|
964
|
-
port: 9080,
|
|
965
|
-
listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }
|
|
967
|
+
server.listen({
|
|
968
|
+
port: 9080,
|
|
969
|
+
listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }
|
|
966
970
|
})
|
|
967
971
|
```
|
|
968
972
|
|
|
@@ -1090,7 +1094,7 @@ Method to add routes to the server, it also has shorthand functions, check
|
|
|
1090
1094
|
<a id="hasRoute"></a>
|
|
1091
1095
|
|
|
1092
1096
|
Method to check if a route is already registered to the internal router. It
|
|
1093
|
-
expects an object as the payload. `url` and `method` are mandatory fields. It
|
|
1097
|
+
expects an object as the payload. `url` and `method` are mandatory fields. It
|
|
1094
1098
|
is possible to also specify `constraints`. The method returns `true` if the
|
|
1095
1099
|
route is registered or `false` if not.
|
|
1096
1100
|
|
|
@@ -1110,8 +1114,8 @@ if (routeExists === false) {
|
|
|
1110
1114
|
<a id="findRoute"></a>
|
|
1111
1115
|
|
|
1112
1116
|
Method to retrieve a route already registered to the internal router. It
|
|
1113
|
-
expects an object as the payload. `url` and `method` are mandatory fields. It
|
|
1114
|
-
is possible to also specify `constraints`.
|
|
1117
|
+
expects an object as the payload. `url` and `method` are mandatory fields. It
|
|
1118
|
+
is possible to also specify `constraints`.
|
|
1115
1119
|
The method returns a route object or `null` if the route cannot be found.
|
|
1116
1120
|
|
|
1117
1121
|
```js
|
|
@@ -1351,7 +1355,7 @@ Set the schema error formatter for all routes. See
|
|
|
1351
1355
|
Set the schema serializer compiler for all routes. See
|
|
1352
1356
|
[#schema-serializer](./Validation-and-Serialization.md#schema-serializer).
|
|
1353
1357
|
|
|
1354
|
-
> **Note**
|
|
1358
|
+
> **Note**
|
|
1355
1359
|
> [`setReplySerializer`](#set-reply-serializer) has priority if set!
|
|
1356
1360
|
|
|
1357
1361
|
#### validatorCompiler
|
|
@@ -1966,7 +1970,7 @@ The properties that can currently be exposed are:
|
|
|
1966
1970
|
- requestIdHeader
|
|
1967
1971
|
- requestIdLogLabel
|
|
1968
1972
|
- http2SessionTimeout
|
|
1969
|
-
- useSemicolonDelimiter
|
|
1973
|
+
- useSemicolonDelimiter
|
|
1970
1974
|
|
|
1971
1975
|
```js
|
|
1972
1976
|
const { readFileSync } = require('node:fs')
|
|
@@ -182,7 +182,7 @@ route-level `request` object.
|
|
|
182
182
|
admin"}`
|
|
183
183
|
|
|
184
184
|
🎉 Good work, now you can define interfaces for each route and have strictly
|
|
185
|
-
typed request and reply instances. Other parts of the Fastify type system rely
|
|
185
|
+
typed request and reply instances. Other parts of the Fastify type system rely
|
|
186
186
|
on generic properties. Make sure to reference the detailed type system
|
|
187
187
|
documentation below to learn more about what is available.
|
|
188
188
|
|
|
@@ -873,11 +873,11 @@ a more detailed http server walkthrough.
|
|
|
873
873
|
|
|
874
874
|
1. Create the following imports from `@types/node` and `fastify`
|
|
875
875
|
```typescript
|
|
876
|
-
import fs from 'fs'
|
|
877
|
-
import path from 'path'
|
|
876
|
+
import fs from 'node:fs'
|
|
877
|
+
import path from 'node:path'
|
|
878
878
|
import fastify from 'fastify'
|
|
879
879
|
```
|
|
880
|
-
2. Perform the following steps before setting up a Fastify HTTPS server
|
|
880
|
+
2. Perform the following steps before setting up a Fastify HTTPS server
|
|
881
881
|
to create the `key.pem` and `cert.pem` files:
|
|
882
882
|
```sh
|
|
883
883
|
openssl genrsa -out key.pem
|
|
@@ -935,7 +935,7 @@ specified at server instantiation, the custom type becomes available on all
|
|
|
935
935
|
further instances of the custom type.
|
|
936
936
|
```typescript
|
|
937
937
|
import fastify from 'fastify'
|
|
938
|
-
import http from 'http'
|
|
938
|
+
import http from 'node:http'
|
|
939
939
|
|
|
940
940
|
interface customRequest extends http.IncomingMessage {
|
|
941
941
|
mySpecialProp: string
|
|
@@ -1123,8 +1123,8 @@ returns `http.IncomingMessage`, otherwise, it returns
|
|
|
1123
1123
|
`http2.Http2ServerRequest`.
|
|
1124
1124
|
|
|
1125
1125
|
```typescript
|
|
1126
|
-
import http from 'http'
|
|
1127
|
-
import http2 from 'http2'
|
|
1126
|
+
import http from 'node:http'
|
|
1127
|
+
import http2 from 'node:http2'
|
|
1128
1128
|
import { RawRequestDefaultExpression } from 'fastify'
|
|
1129
1129
|
|
|
1130
1130
|
RawRequestDefaultExpression<http.Server> // -> http.IncomingMessage
|
|
@@ -1183,8 +1183,8 @@ returns `http.ServerResponse`, otherwise, it returns
|
|
|
1183
1183
|
`http2.Http2ServerResponse`.
|
|
1184
1184
|
|
|
1185
1185
|
```typescript
|
|
1186
|
-
import http from 'http'
|
|
1187
|
-
import http2 from 'http2'
|
|
1186
|
+
import http from 'node:http'
|
|
1187
|
+
import http2 from 'node:http2'
|
|
1188
1188
|
import { RawReplyDefaultExpression } from 'fastify'
|
|
1189
1189
|
|
|
1190
1190
|
RawReplyDefaultExpression<http.Server> // -> http.ServerResponse
|
|
@@ -49,16 +49,16 @@ The shared schemas can be reused through the JSON Schema
|
|
|
49
49
|
[**`$ref`**](https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8)
|
|
50
50
|
keyword. Here is an overview of _how_ references work:
|
|
51
51
|
|
|
52
|
-
+ `myField: { $ref: '#foo'}` will search for field with `$id: '#foo'` inside the
|
|
52
|
+
+ `myField: { $ref: '#foo' }` will search for field with `$id: '#foo'` inside the
|
|
53
53
|
current schema
|
|
54
|
-
+ `myField: { $ref: '#/definitions/foo'}` will search for field
|
|
54
|
+
+ `myField: { $ref: '#/definitions/foo' }` will search for field
|
|
55
55
|
`definitions.foo` inside the current schema
|
|
56
|
-
+ `myField: { $ref: 'http://url.com/sh.json#'}` will search for a shared schema
|
|
56
|
+
+ `myField: { $ref: 'http://url.com/sh.json#' }` will search for a shared schema
|
|
57
57
|
added with `$id: 'http://url.com/sh.json'`
|
|
58
|
-
+ `myField: { $ref: 'http://url.com/sh.json#/definitions/foo'}` will search for
|
|
58
|
+
+ `myField: { $ref: 'http://url.com/sh.json#/definitions/foo' }` will search for
|
|
59
59
|
a shared schema added with `$id: 'http://url.com/sh.json'` and will use the
|
|
60
60
|
field `definitions.foo`
|
|
61
|
-
+ `myField: { $ref: 'http://url.com/sh.json#foo'}` will search for a shared
|
|
61
|
+
+ `myField: { $ref: 'http://url.com/sh.json#foo' }` will search for a shared
|
|
62
62
|
schema added with `$id: 'http://url.com/sh.json'` and it will look inside of
|
|
63
63
|
it for object with `$id: '#foo'`
|
|
64
64
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify'
|
|
14
|
-
import { Server, IncomingMessage, ServerResponse } from 'http'
|
|
14
|
+
import { Server, IncomingMessage, ServerResponse } from 'node:http'
|
|
15
15
|
|
|
16
16
|
// Create an http server. We pass the relevant typings for our http version used.
|
|
17
17
|
// By passing types we get correctly typed access to the underlying http objects in routes.
|
package/fastify.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as http from 'http'
|
|
2
|
-
import * as http2 from 'http2'
|
|
3
|
-
import * as https from 'https'
|
|
4
|
-
import { Socket } from 'net'
|
|
1
|
+
import * as http from 'node:http'
|
|
2
|
+
import * as http2 from 'node:http2'
|
|
3
|
+
import * as https from 'node:https'
|
|
4
|
+
import { Socket } from 'node:net'
|
|
5
5
|
|
|
6
6
|
import { Options as AjvOptions, ValidatorFactory } from '@fastify/ajv-compiler'
|
|
7
7
|
import { FastifyError } from '@fastify/error'
|
package/fastify.js
CHANGED
package/lib/error-handler.js
CHANGED
|
@@ -112,16 +112,16 @@ function fallbackErrorHandler (error, reply, cb) {
|
|
|
112
112
|
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode, reply[kReplyHeaders]['content-type'])
|
|
113
113
|
payload = (serializerFn === false)
|
|
114
114
|
? serializeError({
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
error: statusCodes[statusCode + ''],
|
|
116
|
+
code: error.code,
|
|
117
|
+
message: error.message,
|
|
118
|
+
statusCode
|
|
119
|
+
})
|
|
120
120
|
: serializerFn(Object.create(error, {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
error: { value: statusCodes[statusCode + ''] },
|
|
122
|
+
message: { value: error.message },
|
|
123
|
+
statusCode: { value: statusCode }
|
|
124
|
+
}))
|
|
125
125
|
} catch (err) {
|
|
126
126
|
if (!reply.log[kDisableRequestLogging]) {
|
|
127
127
|
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
|
package/lib/errors.js
CHANGED
|
@@ -189,7 +189,7 @@ const codes = {
|
|
|
189
189
|
|
|
190
190
|
FST_ERR_HOOK_TIMEOUT: createError(
|
|
191
191
|
'FST_ERR_HOOK_TIMEOUT',
|
|
192
|
-
"A callback for '%s' hook timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
|
192
|
+
"A callback for '%s' hook%s timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
|
193
193
|
),
|
|
194
194
|
|
|
195
195
|
/**
|
package/lib/hooks.js
CHANGED
|
@@ -98,9 +98,12 @@ function hookRunnerApplication (hookName, boot, server, cb) {
|
|
|
98
98
|
next()
|
|
99
99
|
|
|
100
100
|
function exit (err) {
|
|
101
|
+
const hookFnName = hooks[i - 1]?.name
|
|
102
|
+
const hookFnFragment = hookFnName ? ` "${hookFnName}"` : ''
|
|
103
|
+
|
|
101
104
|
if (err) {
|
|
102
105
|
if (err.code === 'AVV_ERR_READY_TIMEOUT') {
|
|
103
|
-
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName))
|
|
106
|
+
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName, hookFnFragment))
|
|
104
107
|
} else {
|
|
105
108
|
err = AVVIO_ERRORS_MAP[err.code] != null
|
|
106
109
|
? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message))
|
package/lib/request.js
CHANGED
|
@@ -117,10 +117,11 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
|
|
117
117
|
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
|
|
118
118
|
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
|
|
119
119
|
}
|
|
120
|
-
|
|
121
|
-
// support http.requireHostHeader === false
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
// the last fallback is used to support the following cases:
|
|
121
|
+
// 1. support http.requireHostHeader === false
|
|
122
|
+
// 2. support HTTP/1.0 without Host Header
|
|
123
|
+
// 3. support headers schema which may remove the Host Header
|
|
124
|
+
return this.headers.host ?? this.headers[':authority'] ?? ''
|
|
124
125
|
}
|
|
125
126
|
},
|
|
126
127
|
protocol: {
|
|
@@ -212,10 +213,11 @@ Object.defineProperties(Request.prototype, {
|
|
|
212
213
|
},
|
|
213
214
|
host: {
|
|
214
215
|
get () {
|
|
215
|
-
|
|
216
|
-
// support http.requireHostHeader === false
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
// the last fallback is used to support the following cases:
|
|
217
|
+
// 1. support http.requireHostHeader === false
|
|
218
|
+
// 2. support HTTP/1.0 without Host Header
|
|
219
|
+
// 3. support headers schema which may remove the Host Header
|
|
220
|
+
return this.raw.headers.host ?? this.raw.headers[':authority'] ?? ''
|
|
219
221
|
}
|
|
220
222
|
},
|
|
221
223
|
hostname: {
|
|
@@ -231,8 +233,7 @@ Object.defineProperties(Request.prototype, {
|
|
|
231
233
|
return portFromHost
|
|
232
234
|
}
|
|
233
235
|
// now fall back to port from host/:authority header
|
|
234
|
-
|
|
235
|
-
if (this.server.server.requireHostHeader === false) host ??= ''
|
|
236
|
+
const host = (this.headers.host ?? this.headers[':authority'] ?? '')
|
|
236
237
|
const portFromHeader = parseInt(host.split(':').slice(-1)[0])
|
|
237
238
|
if (!isNaN(portFromHeader)) {
|
|
238
239
|
return portFromHeader
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"benchmark:parser": "concurrently -k -s first \"node ./examples/benchmark/parser.js\" \"autocannon -c 100 -d 30 -p 10 -i ./examples/benchmark/body.json -H \"content-type:application/jsoff\" -m POST localhost:3000/\"",
|
|
12
12
|
"build:validation": "node build/build-error-serializer.js && node build/build-validation.js",
|
|
13
13
|
"coverage": "c8 --reporter html borp --reporter=./test/test-reporter.mjs --coverage --check-coverage --lines 100 ",
|
|
14
|
-
"coverage:ci": "c8 --reporter lcov --reporter html borp --reporter=./test/test-reporter.mjs",
|
|
15
14
|
"coverage:ci-check-coverage": "borp --reporter=./test/test-reporter.mjs --coverage --check-coverage --lines 100",
|
|
16
15
|
"lint": "npm run lint:eslint",
|
|
17
16
|
"lint:fix": "eslint --fix",
|
|
@@ -168,7 +167,7 @@
|
|
|
168
167
|
"cross-env": "^7.0.3",
|
|
169
168
|
"eslint": "^9.0.0",
|
|
170
169
|
"fast-json-body": "^1.1.0",
|
|
171
|
-
"fastify-plugin": "^
|
|
170
|
+
"fastify-plugin": "^5.0.0",
|
|
172
171
|
"fluent-json-schema": "^5.0.0",
|
|
173
172
|
"h2url": "^0.2.0",
|
|
174
173
|
"http-errors": "^2.0.0",
|
|
@@ -201,7 +200,7 @@
|
|
|
201
200
|
"process-warning": "^4.0.0",
|
|
202
201
|
"proxy-addr": "^2.0.7",
|
|
203
202
|
"rfdc": "^1.3.1",
|
|
204
|
-
"secure-json-parse": "^
|
|
203
|
+
"secure-json-parse": "^3.0.1",
|
|
205
204
|
"semver": "^7.6.0",
|
|
206
205
|
"toad-cache": "^3.7.0"
|
|
207
206
|
},
|
|
@@ -24,7 +24,7 @@ test('allow unsafe regex', (t, done) => {
|
|
|
24
24
|
url: 'http://localhost:' + fastify.server.address().port + '/1234'
|
|
25
25
|
}, (err, response, body) => {
|
|
26
26
|
t.assert.ifError(err)
|
|
27
|
-
t.assert.
|
|
27
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
28
28
|
t.assert.deepStrictEqual(JSON.parse(body), {
|
|
29
29
|
foo: '1234'
|
|
30
30
|
})
|
|
@@ -53,7 +53,7 @@ test('allow unsafe regex not match', (t, done) => {
|
|
|
53
53
|
url: 'http://localhost:' + fastify.server.address().port + '/a1234'
|
|
54
54
|
}, (err, response, body) => {
|
|
55
55
|
t.assert.ifError(err)
|
|
56
|
-
t.assert.
|
|
56
|
+
t.assert.strictEqual(response.statusCode, 404)
|
|
57
57
|
done()
|
|
58
58
|
})
|
|
59
59
|
})
|
|
@@ -111,8 +111,8 @@ test('allow unsafe regex allow unsafe', (t, done) => {
|
|
|
111
111
|
url: 'http://localhost:' + fastify.server.address().port + '/1234'
|
|
112
112
|
}, (err, response, body) => {
|
|
113
113
|
t.assert.ifError(err)
|
|
114
|
-
t.assert.
|
|
115
|
-
t.assert.
|
|
114
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
115
|
+
t.assert.deepStrictEqual(JSON.parse(body), {
|
|
116
116
|
foo: '1234'
|
|
117
117
|
})
|
|
118
118
|
done()
|
package/test/async_hooks.test.js
CHANGED
|
@@ -41,7 +41,7 @@ test('test async hooks', (t, done) => {
|
|
|
41
41
|
json: true
|
|
42
42
|
}, (err, response, body) => {
|
|
43
43
|
t.assert.ifError(err)
|
|
44
|
-
t.assert.
|
|
44
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
45
45
|
|
|
46
46
|
sget({
|
|
47
47
|
method: 'POST',
|
|
@@ -52,7 +52,7 @@ test('test async hooks', (t, done) => {
|
|
|
52
52
|
json: true
|
|
53
53
|
}, (err, response, body) => {
|
|
54
54
|
t.assert.ifError(err)
|
|
55
|
-
t.assert.
|
|
55
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
56
56
|
|
|
57
57
|
sget({
|
|
58
58
|
method: 'GET',
|
|
@@ -60,9 +60,9 @@ test('test async hooks', (t, done) => {
|
|
|
60
60
|
json: true
|
|
61
61
|
}, (err, response, body) => {
|
|
62
62
|
t.assert.ifError(err)
|
|
63
|
-
t.assert.
|
|
63
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
64
64
|
app.close()
|
|
65
|
-
t.assert.
|
|
65
|
+
t.assert.strictEqual(remainingIds.size, 0)
|
|
66
66
|
done()
|
|
67
67
|
})
|
|
68
68
|
})
|
package/test/buffer.test.js
CHANGED
|
@@ -24,8 +24,8 @@ test('Buffer test', async t => {
|
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
t.assert.ifError(response.error)
|
|
27
|
-
t.assert.
|
|
28
|
-
t.assert.
|
|
27
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
28
|
+
t.assert.deepStrictEqual(response.payload.toString(), '{"hello":"world"}')
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
await test('should return 400 if the body is empty', async t => {
|
|
@@ -41,8 +41,8 @@ test('Buffer test', async t => {
|
|
|
41
41
|
})
|
|
42
42
|
|
|
43
43
|
t.assert.ifError(response.error)
|
|
44
|
-
t.assert.
|
|
45
|
-
t.assert.
|
|
44
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
45
|
+
t.assert.deepStrictEqual(JSON.parse(response.payload.toString()), {
|
|
46
46
|
error: 'Bad Request',
|
|
47
47
|
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
|
48
48
|
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
package/test/bundler/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Bundlers test stack
|
|
2
2
|
|
|
3
|
-
In some cases, developers bundle their apps for several targets such as serverless applications.
|
|
4
|
-
Even if it's not recommended by Fastify team; we need to ensure we do not break the build process.
|
|
3
|
+
In some cases, developers bundle their apps for several targets such as serverless applications.
|
|
4
|
+
Even if it's not recommended by Fastify team; we need to ensure we do not break the build process.
|
|
5
5
|
Please note this might result in features behaving differently, like the version handling check for plugins.
|
|
6
6
|
|
|
7
7
|
## Test bundlers
|
|
8
8
|
|
|
9
|
-
The bundler test stack has been defined separately from the rest of the Unit testing stack because it's not a
|
|
9
|
+
The bundler test stack has been defined separately from the rest of the Unit testing stack because it's not a
|
|
10
10
|
part of the fastify lib itself. Note that the tests run in CI only on NodeJs LTS version.
|
|
11
11
|
Developers do not need to install every bundler to run unit tests.
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ stack dependencies. See:
|
|
|
23
23
|
|
|
24
24
|
## Bundler test development
|
|
25
25
|
|
|
26
|
-
To not break the fastify unit testing stack please name test files like this `*-test.js` and not `*.test.js`,
|
|
26
|
+
To not break the fastify unit testing stack please name test files like this `*-test.js` and not `*.test.js`,
|
|
27
27
|
otherwise it will be targeted by the regular expression used for unit tests for fastify.
|
|
28
|
-
Tests need to ensure the build process works and the fastify application can be run,
|
|
28
|
+
Tests need to ensure the build process works and the fastify application can be run,
|
|
29
29
|
no need to go in deep testing unless an issue is raised.
|
|
@@ -24,8 +24,8 @@ test('case insensitive', (t, done) => {
|
|
|
24
24
|
url: 'http://localhost:' + fastify.server.address().port + '/FOO'
|
|
25
25
|
}, (err, response, body) => {
|
|
26
26
|
t.assert.ifError(err)
|
|
27
|
-
t.assert.
|
|
28
|
-
t.assert.
|
|
27
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
28
|
+
t.assert.deepStrictEqual(JSON.parse(body), {
|
|
29
29
|
hello: 'world'
|
|
30
30
|
})
|
|
31
31
|
done()
|
|
@@ -53,8 +53,8 @@ test('case insensitive inject', (t, done) => {
|
|
|
53
53
|
url: 'http://localhost:' + fastify.server.address().port + '/FOO'
|
|
54
54
|
}, (err, response) => {
|
|
55
55
|
t.assert.ifError(err)
|
|
56
|
-
t.assert.
|
|
57
|
-
t.assert.
|
|
56
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
57
|
+
t.assert.deepStrictEqual(JSON.parse(response.payload), {
|
|
58
58
|
hello: 'world'
|
|
59
59
|
})
|
|
60
60
|
done()
|
|
@@ -71,7 +71,7 @@ test('case insensitive (parametric)', (t, done) => {
|
|
|
71
71
|
t.after(() => fastify.close())
|
|
72
72
|
|
|
73
73
|
fastify.get('/foo/:param', (req, reply) => {
|
|
74
|
-
t.assert.
|
|
74
|
+
t.assert.strictEqual(req.params.param, 'bAr')
|
|
75
75
|
reply.send({ hello: 'world' })
|
|
76
76
|
})
|
|
77
77
|
|
|
@@ -83,8 +83,8 @@ test('case insensitive (parametric)', (t, done) => {
|
|
|
83
83
|
url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr'
|
|
84
84
|
}, (err, response, body) => {
|
|
85
85
|
t.assert.ifError(err)
|
|
86
|
-
t.assert.
|
|
87
|
-
t.assert.
|
|
86
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
87
|
+
t.assert.deepStrictEqual(JSON.parse(body), {
|
|
88
88
|
hello: 'world'
|
|
89
89
|
})
|
|
90
90
|
done()
|
|
@@ -101,7 +101,7 @@ test('case insensitive (wildcard)', (t, done) => {
|
|
|
101
101
|
t.after(() => fastify.close())
|
|
102
102
|
|
|
103
103
|
fastify.get('/foo/*', (req, reply) => {
|
|
104
|
-
t.assert.
|
|
104
|
+
t.assert.strictEqual(req.params['*'], 'bAr/baZ')
|
|
105
105
|
reply.send({ hello: 'world' })
|
|
106
106
|
})
|
|
107
107
|
|
|
@@ -113,8 +113,8 @@ test('case insensitive (wildcard)', (t, done) => {
|
|
|
113
113
|
url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr/baZ'
|
|
114
114
|
}, (err, response, body) => {
|
|
115
115
|
t.assert.ifError(err)
|
|
116
|
-
t.assert.
|
|
117
|
-
t.assert.
|
|
116
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
117
|
+
t.assert.deepStrictEqual(JSON.parse(body), {
|
|
118
118
|
hello: 'world'
|
|
119
119
|
})
|
|
120
120
|
done()
|
package/test/check.test.js
CHANGED
|
@@ -72,7 +72,6 @@ const options = {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
const handler = (request, reply) => {
|
|
75
|
-
console.log('in handler')
|
|
76
75
|
if (request.body.id === '400') {
|
|
77
76
|
return reply.status(400).send({
|
|
78
77
|
statusCode: 400,
|
|
@@ -124,8 +123,8 @@ test('serialize the response for a Bad Request error, as defined on the schema',
|
|
|
124
123
|
json: true
|
|
125
124
|
}, (err, response, body) => {
|
|
126
125
|
t.assert.ifError(err)
|
|
127
|
-
t.assert.
|
|
128
|
-
t.assert.
|
|
126
|
+
t.assert.strictEqual(response.statusCode, 400)
|
|
127
|
+
t.assert.deepStrictEqual(body, {
|
|
129
128
|
statusCode: 400,
|
|
130
129
|
error: 'Bad Request',
|
|
131
130
|
message: 'body must be object'
|
|
@@ -74,7 +74,7 @@ test('req.log should be the instance returned by the factory', (t, done) => {
|
|
|
74
74
|
})
|
|
75
75
|
|
|
76
76
|
fastify.get('/', (req, reply) => {
|
|
77
|
-
t.assert.
|
|
77
|
+
t.assert.strictEqual(req.log, fastify.log)
|
|
78
78
|
req.log.info('log message')
|
|
79
79
|
reply.send()
|
|
80
80
|
})
|
|
@@ -28,7 +28,7 @@ test('requestTimeout should return 408', (t, done) => {
|
|
|
28
28
|
|
|
29
29
|
socket.on('data', c => (data = Buffer.concat([data, c])))
|
|
30
30
|
socket.on('end', () => {
|
|
31
|
-
t.assert.
|
|
31
|
+
t.assert.strictEqual(
|
|
32
32
|
data.toString('utf-8'),
|
|
33
33
|
'HTTP/1.1 408 Request Timeout\r\nContent-Length: 71\r\nContent-Type: application/json\r\n\r\n{"error":"Request Timeout","message":"Client Timeout","statusCode":408}'
|
|
34
34
|
)
|