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.
Files changed (111) hide show
  1. package/README.md +12 -7
  2. package/docs/Guides/Database.md +15 -15
  3. package/docs/Guides/Detecting-When-Clients-Abort.md +28 -28
  4. package/docs/Guides/Ecosystem.md +13 -7
  5. package/docs/Guides/Index.md +1 -1
  6. package/docs/Guides/Migration-Guide-V4.md +11 -11
  7. package/docs/Guides/Migration-Guide-V5.md +5 -5
  8. package/docs/Guides/Plugins-Guide.md +1 -1
  9. package/docs/Guides/Prototype-Poisoning.md +3 -3
  10. package/docs/Guides/Recommendations.md +9 -9
  11. package/docs/Guides/Serverless.md +5 -5
  12. package/docs/Guides/Testing.md +8 -8
  13. package/docs/Guides/Write-Plugin.md +1 -1
  14. package/docs/Guides/Write-Type-Provider.md +3 -3
  15. package/docs/Reference/Decorators.md +2 -2
  16. package/docs/Reference/Errors.md +2 -2
  17. package/docs/Reference/Hooks.md +7 -7
  18. package/docs/Reference/LTS.md +8 -0
  19. package/docs/Reference/Logging.md +5 -4
  20. package/docs/Reference/Reply.md +54 -53
  21. package/docs/Reference/Request.md +49 -43
  22. package/docs/Reference/Routes.md +7 -7
  23. package/docs/Reference/Server.md +31 -27
  24. package/docs/Reference/TypeScript.md +9 -9
  25. package/docs/Reference/Validation-and-Serialization.md +5 -5
  26. package/examples/typescript-server.ts +1 -1
  27. package/fastify.d.ts +4 -4
  28. package/fastify.js +1 -1
  29. package/lib/error-handler.js +9 -9
  30. package/lib/errors.js +1 -1
  31. package/lib/hooks.js +4 -1
  32. package/lib/request.js +11 -10
  33. package/package.json +3 -4
  34. package/test/{allowUnsafeRegex.test.js → allow-unsafe-regex.test.js} +4 -4
  35. package/test/async-dispose.test.js +0 -1
  36. package/test/async_hooks.test.js +4 -4
  37. package/test/buffer.test.js +4 -4
  38. package/test/build-certificate.js +1 -1
  39. package/test/bundler/README.md +5 -5
  40. package/test/case-insensitive.test.js +10 -10
  41. package/test/check.test.js +2 -3
  42. package/test/{childLoggerFactory.test.js → child-logger-factory.test.js} +1 -1
  43. package/test/client-timeout.test.js +1 -1
  44. package/test/close-pipelining.test.js +0 -1
  45. package/test/conditional-pino.test.js +3 -3
  46. package/test/content-length.test.js +53 -68
  47. package/test/content-parser.test.js +178 -167
  48. package/test/content-type.test.js +8 -9
  49. package/test/context-config.test.js +44 -54
  50. package/test/custom-parser.5.test.js +32 -32
  51. package/test/encapsulated-child-logger-factory.test.js +8 -8
  52. package/test/encapsulated-error-handler.test.js +20 -20
  53. package/test/fastify-instance.test.js +33 -34
  54. package/test/{findRoute.test.js → find-route.test.js} +11 -10
  55. package/test/fluent-schema.test.js +33 -36
  56. package/test/handler-context.test.js +11 -11
  57. package/test/has-route.test.js +12 -15
  58. package/test/header-overflow.test.js +13 -12
  59. package/test/hooks.on-ready.test.js +2 -2
  60. package/test/hooks.test.js +19 -19
  61. package/test/http-methods/head.test.js +0 -3
  62. package/test/imports.test.js +2 -2
  63. package/test/internals/errors.test.js +1 -1
  64. package/test/listen.5.test.js +9 -9
  65. package/test/{maxRequestsPerSocket.test.js → max-requests-per-socket.test.js} +30 -30
  66. package/test/middleware.test.js +4 -5
  67. package/test/noop-set.test.js +1 -1
  68. package/test/post-empty-body.test.js +18 -11
  69. package/test/pretty-print.test.js +59 -49
  70. package/test/proto-poisoning.test.js +42 -37
  71. package/test/reply-code.test.js +34 -32
  72. package/test/{reply-earlyHints.test.js → reply-early-hints.test.js} +21 -19
  73. package/test/request-header-host.test.js +154 -12
  74. package/test/request-id.test.js +31 -25
  75. package/test/{requestTimeout.test.js → request-timeout.test.js} +11 -11
  76. package/test/route.3.test.js +3 -2
  77. package/test/route.8.test.js +20 -20
  78. package/test/router-options.test.js +80 -77
  79. package/test/schema-examples.test.js +72 -38
  80. package/test/server.test.js +12 -12
  81. package/test/set-error-handler.test.js +2 -3
  82. package/test/stream-serializers.test.js +10 -7
  83. package/test/sync-routes.test.js +18 -18
  84. package/test/trust-proxy.test.js +51 -45
  85. package/test/type-provider.test.js +8 -6
  86. package/test/types/content-type-parser.test-d.ts +1 -1
  87. package/test/types/fastify.test-d.ts +4 -4
  88. package/test/types/instance.test-d.ts +3 -1
  89. package/test/types/logger.test-d.ts +2 -2
  90. package/test/types/plugin.test-d.ts +2 -2
  91. package/test/types/register.test-d.ts +2 -2
  92. package/test/types/reply.test-d.ts +1 -1
  93. package/test/types/route.test-d.ts +1 -1
  94. package/test/types/serverFactory.test-d.ts +1 -1
  95. package/test/types/type-provider.test-d.ts +1 -1
  96. package/test/url-rewriting.test.js +35 -38
  97. package/test/{useSemicolonDelimiter.test.js → use-semicolon-delimiter.test.js} +30 -30
  98. package/test/validation-error-handling.test.js +259 -285
  99. package/types/hooks.d.ts +1 -1
  100. package/types/instance.d.ts +9 -2
  101. package/types/reply.d.ts +1 -1
  102. package/types/request.d.ts +0 -4
  103. package/types/serverFactory.d.ts +3 -3
  104. package/types/utils.d.ts +3 -3
  105. /package/test/{connectionTimeout.test.js → connection-timeout.test.js} +0 -0
  106. /package/test/internals/{contentTypeParser.test.js → content-type-parser.test.js} +0 -0
  107. /package/test/internals/{handleRequest.test.js → handle-request.test.js} +0 -0
  108. /package/test/internals/{hookRunner.test.js → hook-runner.test.js} +0 -0
  109. /package/test/internals/{initialConfig.test.js → initial-config.test.js} +0 -0
  110. /package/test/internals/{reqIdGenFactory.test.js → req-id-gen-factory.test.js} +0 -0
  111. /package/test/{wrapThenable.test.js → wrap-thenable.test.js} +0 -0
@@ -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/dist/latest-v14.x/docs/api/http.html#http_http_createserver_options_requestlistener).
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-v14.x/docs/api/http2.html) module is
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-v14.x/docs/api/https.html#https_https_createserver_options_requestlistener).
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
- + `loggerInstance`: a custom logger instance. The logger must conform to the
355
- Pino interface by having the following methods: `info`, `error`, `debug`,
356
- `fatal`, `warn`, `trace`, `child`. For example:
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
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '5.1.0'
3
+ const VERSION = '5.2.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('node:http')
@@ -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
- error: statusCodes[statusCode + ''],
116
- code: error.code,
117
- message: error.message,
118
- statusCode
119
- })
115
+ error: statusCodes[statusCode + ''],
116
+ code: error.code,
117
+ message: error.message,
118
+ statusCode
119
+ })
120
120
  : serializerFn(Object.create(error, {
121
- error: { value: statusCodes[statusCode + ''] },
122
- message: { value: error.message },
123
- statusCode: { value: statusCode }
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
- let host = this.headers.host ?? this.headers[':authority']
121
- // support http.requireHostHeader === false
122
- if (this.server.server.requireHostHeader === false) host ??= ''
123
- return host
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
- let host = this.raw.headers.host ?? this.raw.headers[':authority']
216
- // support http.requireHostHeader === false
217
- if (this.server.server.requireHostHeader === false) host ??= ''
218
- return host
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
- let host = (this.headers.host ?? this.headers[':authority'])
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.1.0",
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": "^4.5.1",
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": "^2.7.0",
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.equal(response.statusCode, 200)
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.equal(response.statusCode, 404)
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.equal(response.statusCode, 200)
115
- t.assert.deepEqual(JSON.parse(body), {
114
+ t.assert.strictEqual(response.statusCode, 200)
115
+ t.assert.deepStrictEqual(JSON.parse(body), {
116
116
  foo: '1234'
117
117
  })
118
118
  done()
@@ -16,6 +16,5 @@ test('async dispose should close fastify', { skip: !('asyncDispose' in Symbol) }
16
16
  // the same as syntax sugar for
17
17
  // await using app = fastify()
18
18
  await fastify[Symbol.asyncDispose]()
19
-
20
19
  t.assert.strictEqual(fastify.server.listening, false)
21
20
  })
@@ -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.equal(response.statusCode, 200)
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.equal(response.statusCode, 200)
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.equal(response.statusCode, 200)
63
+ t.assert.strictEqual(response.statusCode, 200)
64
64
  app.close()
65
- t.assert.equal(remainingIds.size, 0)
65
+ t.assert.strictEqual(remainingIds.size, 0)
66
66
  done()
67
67
  })
68
68
  })
@@ -24,8 +24,8 @@ test('Buffer test', async t => {
24
24
  })
25
25
 
26
26
  t.assert.ifError(response.error)
27
- t.assert.equal(response.statusCode, 200)
28
- t.assert.deepEqual(response.payload.toString(), '{"hello":"world"}')
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.equal(response.statusCode, 400)
45
- t.assert.deepEqual(JSON.parse(response.payload.toString()), {
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\'',
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const os = require('os')
3
+ const os = require('node:os')
4
4
  const forge = require('node-forge')
5
5
 
6
6
  // from self-cert module
@@ -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.equal(response.statusCode, 200)
28
- t.assert.deepEqual(JSON.parse(body), {
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.equal(response.statusCode, 200)
57
- t.assert.deepEqual(JSON.parse(response.payload), {
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.equal(req.params.param, 'bAr')
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.equal(response.statusCode, 200)
87
- t.assert.deepEqual(JSON.parse(body), {
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.equal(req.params['*'], 'bAr/baZ')
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.equal(response.statusCode, 200)
117
- t.assert.deepEqual(JSON.parse(body), {
116
+ t.assert.strictEqual(response.statusCode, 200)
117
+ t.assert.deepStrictEqual(JSON.parse(body), {
118
118
  hello: 'world'
119
119
  })
120
120
  done()
@@ -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.equal(response.statusCode, 400)
128
- t.assert.deepEqual(body, {
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.equal(req.log, fastify.log)
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.equal(
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
  )