node-fastify 5.8.3

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 (354) hide show
  1. package/.borp.yaml +3 -0
  2. package/.markdownlint-cli2.yaml +22 -0
  3. package/.prettierignore +1 -0
  4. package/GOVERNANCE.md +4 -0
  5. package/LICENSE +21 -0
  6. package/PROJECT_CHARTER.md +126 -0
  7. package/README.md +423 -0
  8. package/SECURITY.md +220 -0
  9. package/SPONSORS.md +24 -0
  10. package/build/build-error-serializer.js +35 -0
  11. package/build/build-validation.js +169 -0
  12. package/build/sync-version.js +11 -0
  13. package/docs/Guides/Benchmarking.md +60 -0
  14. package/docs/Guides/Database.md +321 -0
  15. package/docs/Guides/Delay-Accepting-Requests.md +608 -0
  16. package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
  17. package/docs/Guides/Ecosystem.md +726 -0
  18. package/docs/Guides/Fluent-Schema.md +127 -0
  19. package/docs/Guides/Getting-Started.md +620 -0
  20. package/docs/Guides/Index.md +43 -0
  21. package/docs/Guides/Migration-Guide-V3.md +287 -0
  22. package/docs/Guides/Migration-Guide-V4.md +267 -0
  23. package/docs/Guides/Migration-Guide-V5.md +727 -0
  24. package/docs/Guides/Plugins-Guide.md +520 -0
  25. package/docs/Guides/Prototype-Poisoning.md +383 -0
  26. package/docs/Guides/Recommendations.md +378 -0
  27. package/docs/Guides/Serverless.md +604 -0
  28. package/docs/Guides/Style-Guide.md +246 -0
  29. package/docs/Guides/Testing.md +481 -0
  30. package/docs/Guides/Write-Plugin.md +103 -0
  31. package/docs/Guides/Write-Type-Provider.md +34 -0
  32. package/docs/Reference/ContentTypeParser.md +271 -0
  33. package/docs/Reference/Decorators.md +436 -0
  34. package/docs/Reference/Encapsulation.md +194 -0
  35. package/docs/Reference/Errors.md +377 -0
  36. package/docs/Reference/HTTP2.md +94 -0
  37. package/docs/Reference/Hooks.md +958 -0
  38. package/docs/Reference/Index.md +73 -0
  39. package/docs/Reference/LTS.md +86 -0
  40. package/docs/Reference/Lifecycle.md +99 -0
  41. package/docs/Reference/Logging.md +268 -0
  42. package/docs/Reference/Middleware.md +79 -0
  43. package/docs/Reference/Plugins.md +245 -0
  44. package/docs/Reference/Principles.md +73 -0
  45. package/docs/Reference/Reply.md +1001 -0
  46. package/docs/Reference/Request.md +295 -0
  47. package/docs/Reference/Routes.md +802 -0
  48. package/docs/Reference/Server.md +2389 -0
  49. package/docs/Reference/Type-Providers.md +256 -0
  50. package/docs/Reference/TypeScript.md +1729 -0
  51. package/docs/Reference/Validation-and-Serialization.md +1130 -0
  52. package/docs/Reference/Warnings.md +58 -0
  53. package/docs/index.md +24 -0
  54. package/docs/resources/encapsulation_context.drawio +1 -0
  55. package/docs/resources/encapsulation_context.svg +3 -0
  56. package/eslint.config.js +35 -0
  57. package/examples/asyncawait.js +38 -0
  58. package/examples/benchmark/body.json +3 -0
  59. package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
  60. package/examples/benchmark/hooks-benchmark.js +52 -0
  61. package/examples/benchmark/parser.js +47 -0
  62. package/examples/benchmark/simple.js +30 -0
  63. package/examples/benchmark/webstream.js +27 -0
  64. package/examples/hooks.js +91 -0
  65. package/examples/http2.js +39 -0
  66. package/examples/https.js +38 -0
  67. package/examples/parser.js +53 -0
  68. package/examples/plugin.js +12 -0
  69. package/examples/route-prefix.js +38 -0
  70. package/examples/shared-schema.js +38 -0
  71. package/examples/simple-stream.js +20 -0
  72. package/examples/simple.js +32 -0
  73. package/examples/simple.mjs +27 -0
  74. package/examples/typescript-server.ts +79 -0
  75. package/examples/use-plugin.js +29 -0
  76. package/fastify.d.ts +253 -0
  77. package/fastify.js +985 -0
  78. package/integration/server.js +29 -0
  79. package/integration/test.sh +23 -0
  80. package/lib/config-validator.js +1266 -0
  81. package/lib/content-type-parser.js +413 -0
  82. package/lib/content-type.js +160 -0
  83. package/lib/context.js +98 -0
  84. package/lib/decorate.js +152 -0
  85. package/lib/error-handler.js +173 -0
  86. package/lib/error-serializer.js +134 -0
  87. package/lib/error-status.js +14 -0
  88. package/lib/errors.js +516 -0
  89. package/lib/four-oh-four.js +190 -0
  90. package/lib/handle-request.js +195 -0
  91. package/lib/head-route.js +45 -0
  92. package/lib/hooks.js +429 -0
  93. package/lib/initial-config-validation.js +37 -0
  94. package/lib/logger-factory.js +136 -0
  95. package/lib/logger-pino.js +68 -0
  96. package/lib/noop-set.js +10 -0
  97. package/lib/plugin-override.js +90 -0
  98. package/lib/plugin-utils.js +169 -0
  99. package/lib/promise.js +23 -0
  100. package/lib/reply.js +1030 -0
  101. package/lib/req-id-gen-factory.js +52 -0
  102. package/lib/request.js +391 -0
  103. package/lib/route.js +686 -0
  104. package/lib/schema-controller.js +164 -0
  105. package/lib/schemas.js +207 -0
  106. package/lib/server.js +441 -0
  107. package/lib/symbols.js +71 -0
  108. package/lib/validation.js +280 -0
  109. package/lib/warnings.js +57 -0
  110. package/lib/wrap-thenable.js +84 -0
  111. package/package.json +225 -0
  112. package/scripts/validate-ecosystem-links.js +179 -0
  113. package/test/404s.test.js +2035 -0
  114. package/test/500s.test.js +422 -0
  115. package/test/allow-unsafe-regex.test.js +92 -0
  116. package/test/als.test.js +65 -0
  117. package/test/async-await.test.js +705 -0
  118. package/test/async-dispose.test.js +20 -0
  119. package/test/async_hooks.test.js +52 -0
  120. package/test/body-limit.test.js +224 -0
  121. package/test/buffer.test.js +74 -0
  122. package/test/build/error-serializer.test.js +36 -0
  123. package/test/build/version.test.js +14 -0
  124. package/test/build-certificate.js +109 -0
  125. package/test/bundler/README.md +29 -0
  126. package/test/bundler/esbuild/bundler-test.js +32 -0
  127. package/test/bundler/esbuild/package.json +10 -0
  128. package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
  129. package/test/bundler/esbuild/src/index.js +9 -0
  130. package/test/bundler/webpack/bundler-test.js +32 -0
  131. package/test/bundler/webpack/package.json +11 -0
  132. package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
  133. package/test/bundler/webpack/src/index.js +9 -0
  134. package/test/bundler/webpack/webpack.config.js +15 -0
  135. package/test/case-insensitive.test.js +102 -0
  136. package/test/chainable.test.js +40 -0
  137. package/test/child-logger-factory.test.js +128 -0
  138. package/test/client-timeout.test.js +38 -0
  139. package/test/close-pipelining.test.js +78 -0
  140. package/test/close.test.js +706 -0
  141. package/test/conditional-pino.test.js +47 -0
  142. package/test/connection-timeout.test.js +42 -0
  143. package/test/constrained-routes.test.js +1138 -0
  144. package/test/content-length.test.js +174 -0
  145. package/test/content-parser.test.js +739 -0
  146. package/test/content-type.test.js +181 -0
  147. package/test/context-config.test.js +164 -0
  148. package/test/custom-http-server.test.js +118 -0
  149. package/test/custom-parser-async.test.js +59 -0
  150. package/test/custom-parser.0.test.js +701 -0
  151. package/test/custom-parser.1.test.js +266 -0
  152. package/test/custom-parser.2.test.js +91 -0
  153. package/test/custom-parser.3.test.js +208 -0
  154. package/test/custom-parser.4.test.js +218 -0
  155. package/test/custom-parser.5.test.js +130 -0
  156. package/test/custom-querystring-parser.test.js +129 -0
  157. package/test/decorator.test.js +1330 -0
  158. package/test/delete.test.js +344 -0
  159. package/test/diagnostics-channel/404.test.js +49 -0
  160. package/test/diagnostics-channel/async-delay-request.test.js +65 -0
  161. package/test/diagnostics-channel/async-request.test.js +64 -0
  162. package/test/diagnostics-channel/error-before-handler.test.js +35 -0
  163. package/test/diagnostics-channel/error-request.test.js +53 -0
  164. package/test/diagnostics-channel/error-status.test.js +123 -0
  165. package/test/diagnostics-channel/init.test.js +50 -0
  166. package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
  167. package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
  168. package/test/diagnostics-channel/sync-request.test.js +54 -0
  169. package/test/encapsulated-child-logger-factory.test.js +69 -0
  170. package/test/encapsulated-error-handler.test.js +237 -0
  171. package/test/esm/errorCodes.test.mjs +10 -0
  172. package/test/esm/esm.test.mjs +13 -0
  173. package/test/esm/index.test.js +8 -0
  174. package/test/esm/named-exports.mjs +14 -0
  175. package/test/esm/other.mjs +8 -0
  176. package/test/esm/plugin.mjs +8 -0
  177. package/test/fastify-instance.test.js +300 -0
  178. package/test/find-route.test.js +152 -0
  179. package/test/fluent-schema.test.js +209 -0
  180. package/test/genReqId.test.js +426 -0
  181. package/test/handler-context.test.js +45 -0
  182. package/test/handler-timeout.test.js +367 -0
  183. package/test/has-route.test.js +88 -0
  184. package/test/header-overflow.test.js +55 -0
  185. package/test/helper.js +496 -0
  186. package/test/hooks-async.test.js +1099 -0
  187. package/test/hooks.on-listen.test.js +1162 -0
  188. package/test/hooks.on-ready.test.js +421 -0
  189. package/test/hooks.test.js +3578 -0
  190. package/test/http-methods/copy.test.js +35 -0
  191. package/test/http-methods/custom-http-methods.test.js +114 -0
  192. package/test/http-methods/get.test.js +412 -0
  193. package/test/http-methods/head.test.js +263 -0
  194. package/test/http-methods/lock.test.js +108 -0
  195. package/test/http-methods/mkcalendar.test.js +143 -0
  196. package/test/http-methods/mkcol.test.js +35 -0
  197. package/test/http-methods/move.test.js +42 -0
  198. package/test/http-methods/propfind.test.js +136 -0
  199. package/test/http-methods/proppatch.test.js +105 -0
  200. package/test/http-methods/report.test.js +142 -0
  201. package/test/http-methods/search.test.js +233 -0
  202. package/test/http-methods/trace.test.js +21 -0
  203. package/test/http-methods/unlock.test.js +38 -0
  204. package/test/http2/closing.test.js +270 -0
  205. package/test/http2/constraint.test.js +109 -0
  206. package/test/http2/head.test.js +34 -0
  207. package/test/http2/plain.test.js +68 -0
  208. package/test/http2/secure-with-fallback.test.js +113 -0
  209. package/test/http2/secure.test.js +67 -0
  210. package/test/http2/unknown-http-method.test.js +34 -0
  211. package/test/https/custom-https-server.test.js +58 -0
  212. package/test/https/https.test.js +136 -0
  213. package/test/imports.test.js +17 -0
  214. package/test/inject.test.js +502 -0
  215. package/test/input-validation.js +335 -0
  216. package/test/internals/all.test.js +38 -0
  217. package/test/internals/content-type-parser.test.js +111 -0
  218. package/test/internals/context.test.js +31 -0
  219. package/test/internals/decorator.test.js +156 -0
  220. package/test/internals/errors.test.js +982 -0
  221. package/test/internals/handle-request.test.js +270 -0
  222. package/test/internals/hook-runner.test.js +449 -0
  223. package/test/internals/hooks.test.js +96 -0
  224. package/test/internals/initial-config.test.js +383 -0
  225. package/test/internals/logger.test.js +163 -0
  226. package/test/internals/plugin.test.js +170 -0
  227. package/test/internals/promise.test.js +63 -0
  228. package/test/internals/reply-serialize.test.js +714 -0
  229. package/test/internals/reply.test.js +1920 -0
  230. package/test/internals/req-id-gen-factory.test.js +133 -0
  231. package/test/internals/request-validate.test.js +1402 -0
  232. package/test/internals/request.test.js +506 -0
  233. package/test/internals/schema-controller-perf.test.js +40 -0
  234. package/test/internals/server.test.js +91 -0
  235. package/test/internals/validation.test.js +352 -0
  236. package/test/issue-4959.test.js +118 -0
  237. package/test/keep-alive-timeout.test.js +42 -0
  238. package/test/listen.1.test.js +154 -0
  239. package/test/listen.2.test.js +113 -0
  240. package/test/listen.3.test.js +83 -0
  241. package/test/listen.4.test.js +168 -0
  242. package/test/listen.5.test.js +122 -0
  243. package/test/logger/instantiation.test.js +341 -0
  244. package/test/logger/logger-test-utils.js +47 -0
  245. package/test/logger/logging.test.js +460 -0
  246. package/test/logger/options.test.js +579 -0
  247. package/test/logger/request.test.js +292 -0
  248. package/test/logger/response.test.js +183 -0
  249. package/test/logger/tap-parallel-not-ok +0 -0
  250. package/test/max-requests-per-socket.test.js +113 -0
  251. package/test/middleware.test.js +37 -0
  252. package/test/noop-set.test.js +19 -0
  253. package/test/nullable-validation.test.js +187 -0
  254. package/test/options.error-handler.test.js +5 -0
  255. package/test/options.test.js +5 -0
  256. package/test/output-validation.test.js +140 -0
  257. package/test/patch.error-handler.test.js +5 -0
  258. package/test/patch.test.js +5 -0
  259. package/test/plugin.1.test.js +230 -0
  260. package/test/plugin.2.test.js +314 -0
  261. package/test/plugin.3.test.js +287 -0
  262. package/test/plugin.4.test.js +504 -0
  263. package/test/plugin.helper.js +8 -0
  264. package/test/plugin.name.display.js +10 -0
  265. package/test/post-empty-body.test.js +38 -0
  266. package/test/pretty-print.test.js +366 -0
  267. package/test/promises.test.js +125 -0
  268. package/test/proto-poisoning.test.js +145 -0
  269. package/test/put.error-handler.test.js +5 -0
  270. package/test/put.test.js +5 -0
  271. package/test/register.test.js +184 -0
  272. package/test/reply-code.test.js +148 -0
  273. package/test/reply-early-hints.test.js +100 -0
  274. package/test/reply-error.test.js +815 -0
  275. package/test/reply-trailers.test.js +445 -0
  276. package/test/reply-web-stream-locked.test.js +37 -0
  277. package/test/request-error.test.js +624 -0
  278. package/test/request-header-host.test.js +339 -0
  279. package/test/request-id.test.js +118 -0
  280. package/test/request-timeout.test.js +53 -0
  281. package/test/route-hooks.test.js +635 -0
  282. package/test/route-prefix.test.js +904 -0
  283. package/test/route-shorthand.test.js +48 -0
  284. package/test/route.1.test.js +259 -0
  285. package/test/route.2.test.js +100 -0
  286. package/test/route.3.test.js +213 -0
  287. package/test/route.4.test.js +127 -0
  288. package/test/route.5.test.js +211 -0
  289. package/test/route.6.test.js +306 -0
  290. package/test/route.7.test.js +406 -0
  291. package/test/route.8.test.js +225 -0
  292. package/test/router-options.test.js +1108 -0
  293. package/test/same-shape.test.js +124 -0
  294. package/test/schema-examples.test.js +661 -0
  295. package/test/schema-feature.test.js +2198 -0
  296. package/test/schema-serialization.test.js +1171 -0
  297. package/test/schema-special-usage.test.js +1348 -0
  298. package/test/schema-validation.test.js +1572 -0
  299. package/test/scripts/validate-ecosystem-links.test.js +339 -0
  300. package/test/serialize-response.test.js +186 -0
  301. package/test/server.test.js +347 -0
  302. package/test/set-error-handler.test.js +69 -0
  303. package/test/skip-reply-send.test.js +317 -0
  304. package/test/stream-serializers.test.js +40 -0
  305. package/test/stream.1.test.js +94 -0
  306. package/test/stream.2.test.js +129 -0
  307. package/test/stream.3.test.js +198 -0
  308. package/test/stream.4.test.js +176 -0
  309. package/test/stream.5.test.js +188 -0
  310. package/test/sync-routes.test.js +32 -0
  311. package/test/throw.test.js +359 -0
  312. package/test/toolkit.js +63 -0
  313. package/test/trust-proxy.test.js +162 -0
  314. package/test/type-provider.test.js +22 -0
  315. package/test/types/content-type-parser.test-d.ts +72 -0
  316. package/test/types/decorate-request-reply.test-d.ts +18 -0
  317. package/test/types/dummy-plugin.ts +9 -0
  318. package/test/types/errors.test-d.ts +90 -0
  319. package/test/types/fastify.test-d.ts +352 -0
  320. package/test/types/hooks.test-d.ts +550 -0
  321. package/test/types/import.ts +2 -0
  322. package/test/types/instance.test-d.ts +588 -0
  323. package/test/types/logger.test-d.ts +277 -0
  324. package/test/types/plugin.test-d.ts +97 -0
  325. package/test/types/register.test-d.ts +237 -0
  326. package/test/types/reply.test-d.ts +254 -0
  327. package/test/types/request.test-d.ts +188 -0
  328. package/test/types/route.test-d.ts +553 -0
  329. package/test/types/schema.test-d.ts +135 -0
  330. package/test/types/serverFactory.test-d.ts +37 -0
  331. package/test/types/type-provider.test-d.ts +1213 -0
  332. package/test/types/using.test-d.ts +17 -0
  333. package/test/upgrade.test.js +52 -0
  334. package/test/url-rewriting.test.js +122 -0
  335. package/test/use-semicolon-delimiter.test.js +168 -0
  336. package/test/validation-error-handling.test.js +900 -0
  337. package/test/versioned-routes.test.js +603 -0
  338. package/test/web-api.test.js +616 -0
  339. package/test/wrap-thenable.test.js +30 -0
  340. package/types/content-type-parser.d.ts +75 -0
  341. package/types/context.d.ts +22 -0
  342. package/types/errors.d.ts +92 -0
  343. package/types/hooks.d.ts +875 -0
  344. package/types/instance.d.ts +609 -0
  345. package/types/logger.d.ts +107 -0
  346. package/types/plugin.d.ts +44 -0
  347. package/types/register.d.ts +42 -0
  348. package/types/reply.d.ts +81 -0
  349. package/types/request.d.ts +95 -0
  350. package/types/route.d.ts +199 -0
  351. package/types/schema.d.ts +61 -0
  352. package/types/server-factory.d.ts +19 -0
  353. package/types/type-provider.d.ts +130 -0
  354. package/types/utils.d.ts +98 -0
@@ -0,0 +1,347 @@
1
+ 'use strict'
2
+
3
+ const dns = require('node:dns')
4
+ const { networkInterfaces } = require('node:os')
5
+ const { test } = require('node:test')
6
+ const Fastify = require('..')
7
+ const undici = require('undici')
8
+ const proxyquire = require('proxyquire')
9
+
10
+ const isIPv6Missing = !Object.values(networkInterfaces()).flat().some(({ family }) => family === 'IPv6')
11
+
12
+ test('listen should accept null port', async t => {
13
+ const fastify = Fastify()
14
+ t.after(() => fastify.close())
15
+
16
+ await t.assert.doesNotReject(
17
+ fastify.listen({ port: null })
18
+ )
19
+ })
20
+
21
+ test('listen should accept undefined port', async t => {
22
+ const fastify = Fastify()
23
+ t.after(() => fastify.close())
24
+
25
+ await t.assert.doesNotReject(
26
+ fastify.listen({ port: undefined })
27
+ )
28
+ })
29
+
30
+ test('listen should accept stringified number port', async t => {
31
+ const fastify = Fastify()
32
+ t.after(() => fastify.close())
33
+
34
+ await t.assert.doesNotReject(
35
+ fastify.listen({ port: '1234' })
36
+ )
37
+ })
38
+
39
+ test('listen should accept log text resolution function', async t => {
40
+ const fastify = Fastify()
41
+ t.after(() => fastify.close())
42
+
43
+ await t.assert.doesNotReject(
44
+ fastify.listen({
45
+ host: '127.0.0.1',
46
+ port: '1234',
47
+ listenTextResolver: (address) => {
48
+ t.assert.strictEqual(address, 'http://127.0.0.1:1234')
49
+ return 'hardcoded text'
50
+ }
51
+ })
52
+ )
53
+ })
54
+
55
+ test('listen should reject string port', async (t) => {
56
+ const fastify = Fastify()
57
+ t.after(() => fastify.close())
58
+
59
+ try {
60
+ await fastify.listen({ port: 'hello-world' })
61
+ } catch (error) {
62
+ t.assert.strictEqual(error.code, 'ERR_SOCKET_BAD_PORT')
63
+ }
64
+
65
+ try {
66
+ await fastify.listen({ port: '1234hello' })
67
+ } catch (error) {
68
+ t.assert.strictEqual(error.code, 'ERR_SOCKET_BAD_PORT')
69
+ }
70
+ })
71
+
72
+ test('Test for hostname and port', async (t) => {
73
+ t.plan(3)
74
+ const app = Fastify()
75
+ t.after(() => app.close())
76
+ app.get('/host', (req, res) => {
77
+ t.assert.strictEqual(req.host, 'localhost:8000')
78
+ t.assert.strictEqual(req.hostname, 'localhost')
79
+ t.assert.strictEqual(req.port, 8000)
80
+ res.send('ok')
81
+ })
82
+
83
+ await app.listen({ port: 8000 })
84
+ await fetch('http://localhost:8000/host')
85
+ })
86
+
87
+ test('Test for IPV6 port', { skip: isIPv6Missing }, async (t) => {
88
+ t.plan(3)
89
+ const app = Fastify()
90
+ t.after(() => app.close())
91
+ app.get('/host', (req, res) => {
92
+ t.assert.strictEqual(req.host, '[::1]:3040')
93
+ t.assert.strictEqual(req.hostname, '[::1]')
94
+ t.assert.strictEqual(req.port, 3040)
95
+ res.send('ok')
96
+ })
97
+
98
+ await app.listen({
99
+ port: 3040,
100
+ host: '::1'
101
+ })
102
+ await fetch('http://[::1]:3040/host')
103
+ })
104
+
105
+ test('abort signal', async t => {
106
+ await t.test('should close server when aborted after', (t, end) => {
107
+ t.plan(2)
108
+ function onClose (instance, done) {
109
+ t.assert.strictEqual(instance, fastify)
110
+ done()
111
+ end()
112
+ }
113
+
114
+ const controller = new AbortController()
115
+
116
+ const fastify = Fastify()
117
+ fastify.addHook('onClose', onClose)
118
+ fastify.listen({ port: 1234, signal: controller.signal }, (err) => {
119
+ t.assert.ifError(err)
120
+ controller.abort()
121
+ })
122
+ })
123
+
124
+ await t.test('should close server when aborted after - promise', async (t) => {
125
+ t.plan(2)
126
+ const resolver = {}
127
+ resolver.promise = new Promise(function (resolve) {
128
+ resolver.resolve = resolve
129
+ })
130
+ function onClose (instance, done) {
131
+ t.assert.strictEqual(instance, fastify)
132
+ done()
133
+ resolver.resolve()
134
+ }
135
+
136
+ const controller = new AbortController()
137
+
138
+ const fastify = Fastify()
139
+ fastify.addHook('onClose', onClose)
140
+ const address = await fastify.listen({ port: 1234, signal: controller.signal })
141
+ t.assert.ok(address)
142
+ controller.abort()
143
+ await resolver.promise
144
+ })
145
+
146
+ await t.test('should close server when aborted during fastify.ready - promise', async (t) => {
147
+ t.plan(2)
148
+ const resolver = {}
149
+ resolver.promise = new Promise(function (resolve) {
150
+ resolver.resolve = resolve
151
+ })
152
+ function onClose (instance, done) {
153
+ t.assert.strictEqual(instance, fastify)
154
+ done()
155
+ resolver.resolve()
156
+ }
157
+
158
+ const controller = new AbortController()
159
+
160
+ const fastify = Fastify()
161
+ fastify.addHook('onClose', onClose)
162
+ const promise = fastify.listen({ port: 1234, signal: controller.signal })
163
+ controller.abort()
164
+ const address = await promise
165
+ // since the main server is not listening yet, or will not listen
166
+ // it should return undefined
167
+ t.assert.strictEqual(address, undefined)
168
+ await resolver.promise
169
+ })
170
+
171
+ await t.test('should close server when aborted during dns.lookup - promise', async (t) => {
172
+ t.plan(2)
173
+ const Fastify = proxyquire('..', {
174
+ './lib/server.js': proxyquire('../lib/server.js', {
175
+ 'node:dns': {
176
+ lookup: function (host, option, callback) {
177
+ controller.abort()
178
+ dns.lookup(host, option, callback)
179
+ }
180
+ }
181
+ })
182
+ })
183
+ const resolver = {}
184
+ resolver.promise = new Promise(function (resolve) {
185
+ resolver.resolve = resolve
186
+ })
187
+ function onClose (instance, done) {
188
+ t.assert.strictEqual(instance, fastify)
189
+ done()
190
+ resolver.resolve()
191
+ }
192
+
193
+ const controller = new AbortController()
194
+
195
+ const fastify = Fastify()
196
+ fastify.addHook('onClose', onClose)
197
+ const address = await fastify.listen({ port: 1234, signal: controller.signal })
198
+ // since the main server is already listening then close
199
+ // it should return address
200
+ t.assert.ok(address)
201
+ await resolver.promise
202
+ })
203
+
204
+ await t.test('should close server when aborted before', (t, end) => {
205
+ t.plan(1)
206
+ function onClose (instance, done) {
207
+ t.assert.strictEqual(instance, fastify)
208
+ done()
209
+ end()
210
+ }
211
+
212
+ const controller = new AbortController()
213
+ controller.abort()
214
+
215
+ const fastify = Fastify()
216
+ fastify.addHook('onClose', onClose)
217
+ fastify.listen({ port: 1234, signal: controller.signal }, () => {
218
+ t.assert.fail('should not reach callback')
219
+ })
220
+ })
221
+
222
+ await t.test('should close server when aborted before - promise', async (t) => {
223
+ t.plan(2)
224
+ const resolver = {}
225
+ resolver.promise = new Promise(function (resolve) {
226
+ resolver.resolve = resolve
227
+ })
228
+ function onClose (instance, done) {
229
+ t.assert.strictEqual(instance, fastify)
230
+ done()
231
+ resolver.resolve()
232
+ }
233
+
234
+ const controller = new AbortController()
235
+ controller.abort()
236
+
237
+ const fastify = Fastify()
238
+ fastify.addHook('onClose', onClose)
239
+ const address = await fastify.listen({ port: 1234, signal: controller.signal })
240
+ t.assert.strictEqual(address, undefined) // ensure the API signature
241
+ await resolver.promise
242
+ })
243
+
244
+ await t.test('listen should not start server', (t, end) => {
245
+ t.plan(2)
246
+ function onClose (instance, done) {
247
+ t.assert.strictEqual(instance, fastify)
248
+ done()
249
+ end()
250
+ }
251
+ const controller = new AbortController()
252
+
253
+ const fastify = Fastify()
254
+ fastify.addHook('onClose', onClose)
255
+ fastify.listen({ port: 1234, signal: controller.signal }, (err) => {
256
+ t.assert.ifError(err)
257
+ })
258
+ controller.abort()
259
+ t.assert.strictEqual(fastify.server.listening, false)
260
+ })
261
+
262
+ await t.test('listen should not start server if already aborted', (t, end) => {
263
+ t.plan(2)
264
+ function onClose (instance, done) {
265
+ t.assert.strictEqual(instance, fastify)
266
+ done()
267
+ end()
268
+ }
269
+
270
+ const controller = new AbortController()
271
+ controller.abort()
272
+ const fastify = Fastify()
273
+ fastify.addHook('onClose', onClose)
274
+ fastify.listen({ port: 1234, signal: controller.signal }, (err) => {
275
+ t.assert.ifError(err)
276
+ })
277
+ t.assert.strictEqual(fastify.server.listening, false)
278
+ })
279
+
280
+ await t.test('listen should throw if received invalid signal', t => {
281
+ t.plan(2)
282
+ const fastify = Fastify()
283
+
284
+ try {
285
+ fastify.listen({ port: 1234, signal: {} }, (err) => {
286
+ t.assert.ifError(err)
287
+ })
288
+ t.assert.fail('should throw')
289
+ } catch (e) {
290
+ t.assert.strictEqual(e.code, 'FST_ERR_LISTEN_OPTIONS_INVALID')
291
+ t.assert.strictEqual(e.message, 'Invalid listen options: \'Invalid options.signal\'')
292
+ }
293
+ })
294
+ })
295
+
296
+ test('#5180 - preClose should be called before closing secondary server', async (t) => {
297
+ t.plan(2)
298
+ const fastify = Fastify({ forceCloseConnections: true })
299
+ let flag = false
300
+ t.after(() => fastify.close())
301
+
302
+ fastify.addHook('preClose', () => {
303
+ flag = true
304
+ })
305
+
306
+ fastify.get('/', async (req, reply) => {
307
+ // request will be pending for 1 second to simulate a slow request
308
+ await new Promise((resolve) => { setTimeout(resolve, 1000) })
309
+ return { hello: 'world' }
310
+ })
311
+
312
+ fastify.listen({ port: 0 }, (err) => {
313
+ t.assert.ifError(err)
314
+ const addresses = fastify.addresses()
315
+ const mainServerAddress = fastify.server.address()
316
+ let secondaryAddress
317
+ for (const addr of addresses) {
318
+ if (addr.family !== mainServerAddress.family) {
319
+ secondaryAddress = addr
320
+ secondaryAddress.address = secondaryAddress.family === 'IPv6'
321
+ ? `[${secondaryAddress.address}]`
322
+ : secondaryAddress.address
323
+ break
324
+ }
325
+ }
326
+
327
+ if (!secondaryAddress) {
328
+ t.assert.ok(true, 'Secondary address not found')
329
+ return
330
+ }
331
+
332
+ undici.request(`http://${secondaryAddress.address}:${secondaryAddress.port}/`)
333
+ .then(
334
+ () => { t.assert.fail('Request should not succeed') },
335
+ () => {
336
+ t.assert.ok(flag)
337
+ }
338
+ )
339
+
340
+ // Close the server while the slow request is pending
341
+ setTimeout(fastify.close, 250)
342
+ })
343
+
344
+ // Wait 1000ms to ensure that the test is finished and async operations are
345
+ // completed
346
+ await new Promise((resolve) => { setTimeout(resolve, 1000) })
347
+ })
@@ -0,0 +1,69 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+ const { FST_ERR_ERROR_HANDLER_NOT_FN, FST_ERR_ERROR_HANDLER_ALREADY_SET } = require('../lib/errors')
6
+
7
+ test('setErrorHandler should throw an error if the handler is not a function', t => {
8
+ t.plan(1)
9
+ const fastify = Fastify()
10
+
11
+ t.assert.throws(() => fastify.setErrorHandler('not a function'), new FST_ERR_ERROR_HANDLER_NOT_FN())
12
+ })
13
+
14
+ test('setErrorHandler can be set independently in parent and child scopes', async t => {
15
+ t.plan(1)
16
+
17
+ const fastify = Fastify()
18
+
19
+ t.assert.doesNotThrow(() => {
20
+ fastify.setErrorHandler(() => {})
21
+ fastify.register(async (child) => {
22
+ child.setErrorHandler(() => {})
23
+ })
24
+ })
25
+ })
26
+
27
+ test('setErrorHandler can be overridden if allowErrorHandlerOverride is set to true', async t => {
28
+ t.plan(2)
29
+
30
+ const fastify = Fastify()
31
+ t.after(() => fastify.close())
32
+
33
+ fastify.register(async (child) => {
34
+ child.setErrorHandler(() => {})
35
+ t.assert.doesNotThrow(() => child.setErrorHandler(() => {}))
36
+ })
37
+
38
+ fastify.setErrorHandler(() => {})
39
+ t.assert.doesNotThrow(() => fastify.setErrorHandler(() => {}))
40
+
41
+ await fastify.ready()
42
+ })
43
+
44
+ test('if `allowErrorHandlerOverride` is disabled, setErrorHandler should throw if called more than once in the same scope', t => {
45
+ t.plan(1)
46
+
47
+ const fastify = Fastify({
48
+ allowErrorHandlerOverride: false
49
+ })
50
+
51
+ fastify.setErrorHandler(() => {})
52
+ t.assert.throws(() => fastify.setErrorHandler(() => {}), new FST_ERR_ERROR_HANDLER_ALREADY_SET())
53
+ })
54
+
55
+ test('if `allowErrorHandlerOverride` is disabled, setErrorHandler should throw if called more than once in the same scope 2', async t => {
56
+ t.plan(1)
57
+
58
+ const fastify = Fastify({
59
+ allowErrorHandlerOverride: false
60
+ })
61
+ t.after(() => fastify.close())
62
+
63
+ fastify.register(async (child) => {
64
+ child.setErrorHandler(() => {})
65
+ t.assert.throws(() => child.setErrorHandler(() => {}), new FST_ERR_ERROR_HANDLER_ALREADY_SET())
66
+ })
67
+
68
+ await fastify.ready()
69
+ })