fastify 4.27.0 → 5.0.0-alpha.2

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 (328) hide show
  1. package/.markdownlint-cli2.yaml +1 -1
  2. package/.tap/processinfo/09002e93-10ad-430c-bc86-c0576928b0ed.json +241 -0
  3. package/.tap/processinfo/ee66c5ab-635d-48b5-8be6-3dc3ceea5bfc.json +268 -0
  4. package/.tap/test-results/test/404s.test.js.tap +623 -0
  5. package/.tap/test-results/test/500s.test.js.tap +64 -0
  6. package/.tap/test-results/test/allowUnsafeRegex.test.js.tap +36 -0
  7. package/.tap/test-results/test/als.test.js.tap +15 -0
  8. package/.tap/test-results/test/async-await.test.js.tap +184 -0
  9. package/.tap/test-results/test/async-dispose.test.js.tap +8 -0
  10. package/.tap/test-results/test/async_hooks.test.js.tap +10 -0
  11. package/.tap/test-results/test/bodyLimit.test.js.tap +48 -0
  12. package/.tap/test-results/test/buffer.test.js.tap +20 -0
  13. package/.tap/test-results/test/build/error-serializer.test.js.tap +12 -0
  14. package/.tap/test-results/test/build/version.test.js.tap +7 -0
  15. package/.tap/test-results/test/case-insensitive.test.js.tap +36 -0
  16. package/.tap/test-results/test/chainable.test.js.tap +17 -0
  17. package/.tap/test-results/test/check.test.js.tap +10 -0
  18. package/.tap/test-results/test/childLoggerFactory.test.js.tap +23 -0
  19. package/.tap/test-results/test/client-timeout.test.js.tap +7 -0
  20. package/.tap/test-results/test/close-pipelining.test.js.tap +15 -0
  21. package/.tap/test-results/test/close.test.js.tap +172 -0
  22. package/.tap/test-results/test/connectionTimeout.test.js.tap +12 -0
  23. package/.tap/test-results/test/constrained-routes.test.js.tap +173 -0
  24. package/.tap/test-results/test/content-length.test.js.tap +46 -0
  25. package/.tap/test-results/test/content-parser.test.js.tap +266 -0
  26. package/.tap/test-results/test/content-type.test.js.tap +14 -0
  27. package/.tap/test-results/test/context-config.test.js.tap +41 -0
  28. package/.tap/test-results/test/copy.test.js.tap +14 -0
  29. package/.tap/test-results/test/custom-http-server.test.js.tap +30 -0
  30. package/.tap/test-results/test/custom-parser-async.test.js.tap +21 -0
  31. package/.tap/test-results/test/custom-parser.0.test.js.tap +199 -0
  32. package/.tap/test-results/test/custom-parser.1.test.js.tap +90 -0
  33. package/.tap/test-results/test/custom-parser.2.test.js.tap +22 -0
  34. package/.tap/test-results/test/custom-parser.3.test.js.tap +53 -0
  35. package/.tap/test-results/test/custom-parser.4.test.js.tap +45 -0
  36. package/.tap/test-results/test/custom-parser.5.test.js.tap +41 -0
  37. package/.tap/test-results/test/custom-querystring-parser.test.js.tap +46 -0
  38. package/.tap/test-results/test/decorator.test.js.tap +465 -0
  39. package/.tap/test-results/test/delete.test.js.tap +110 -0
  40. package/.tap/test-results/test/diagnostics-channel/404.test.js.tap +15 -0
  41. package/.tap/test-results/test/diagnostics-channel/async-delay-request.test.js.tap +25 -0
  42. package/.tap/test-results/test/diagnostics-channel/async-request.test.js.tap +24 -0
  43. package/.tap/test-results/test/diagnostics-channel/error-before-handler.test.js.tap +9 -0
  44. package/.tap/test-results/test/diagnostics-channel/error-request.test.js.tap +20 -0
  45. package/.tap/test-results/test/diagnostics-channel/error-status.test.js.tap +10 -0
  46. package/.tap/test-results/test/diagnostics-channel/init.test.js.tap +14 -0
  47. package/.tap/test-results/test/diagnostics-channel/sync-delay-request.test.js.tap +16 -0
  48. package/.tap/test-results/test/diagnostics-channel/sync-request-reply.test.js.tap +16 -0
  49. package/.tap/test-results/test/diagnostics-channel/sync-request.test.js.tap +19 -0
  50. package/.tap/test-results/test/encapsulated-child-logger-factory.test.js.tap +18 -0
  51. package/.tap/test-results/test/encapsulated-error-handler.test.js.tap +243 -0
  52. package/.tap/test-results/test/esm/errorCodes.test.mjs.tap +9 -0
  53. package/.tap/test-results/test/esm/esm.test.mjs.tap +8 -0
  54. package/.tap/test-results/test/esm/index.test.js.tap +8 -0
  55. package/.tap/test-results/test/fastify-instance.test.js.tap +114 -0
  56. package/.tap/test-results/test/findRoute.test.js.tap +37 -0
  57. package/.tap/test-results/test/fluent-schema.test.js.tap +36 -0
  58. package/.tap/test-results/test/genReqId.test.js.tap +106 -0
  59. package/.tap/test-results/test/get.test.js.tap +151 -0
  60. package/.tap/test-results/test/handler-context.test.js.tap +19 -0
  61. package/.tap/test-results/test/has-route.test.js.tap +30 -0
  62. package/.tap/test-results/test/head.test.js.tap +130 -0
  63. package/.tap/test-results/test/header-overflow.test.js.tap +16 -0
  64. package/.tap/test-results/test/hooks-async.test.js.tap +286 -0
  65. package/.tap/test-results/test/hooks.on-listen.test.js.tap +311 -0
  66. package/.tap/test-results/test/hooks.on-ready.test.js.tap +151 -0
  67. package/.tap/test-results/test/hooks.test.js.tap +966 -0
  68. package/.tap/test-results/test/http2/closing.test.js.tap +35 -0
  69. package/.tap/test-results/test/http2/constraint.test.js.tap +32 -0
  70. package/.tap/test-results/test/http2/head.test.js.tap +9 -0
  71. package/.tap/test-results/test/http2/missing-http2-module.test.js.tap +8 -0
  72. package/.tap/test-results/test/http2/plain.test.js.tap +22 -0
  73. package/.tap/test-results/test/http2/secure-with-fallback.test.js.tap +40 -0
  74. package/.tap/test-results/test/http2/secure.test.js.tap +27 -0
  75. package/.tap/test-results/test/http2/unknown-http-method.test.js.tap +9 -0
  76. package/.tap/test-results/test/https/custom-https-server.test.js.tap +10 -0
  77. package/.tap/test-results/test/https/https.test.js.tap +45 -0
  78. package/.tap/test-results/test/imports.test.js.tap +14 -0
  79. package/.tap/test-results/test/inject.test.js.tap +165 -0
  80. package/.tap/test-results/test/internals/all.test.js.tap +42 -0
  81. package/.tap/test-results/test/internals/contentTypeParser.test.js.tap +14 -0
  82. package/.tap/test-results/test/internals/context.test.js.tap +14 -0
  83. package/.tap/test-results/test/internals/decorator.test.js.tap +51 -0
  84. package/.tap/test-results/test/internals/errors.test.js.tap +1212 -0
  85. package/.tap/test-results/test/internals/handleRequest.test.js.tap +69 -0
  86. package/.tap/test-results/test/internals/hookRunner.test.js.tap +143 -0
  87. package/.tap/test-results/test/internals/hooks.test.js.tap +45 -0
  88. package/.tap/test-results/test/internals/initialConfig.test.js.tap +125 -0
  89. package/.tap/test-results/test/internals/logger.test.js.tap +71 -0
  90. package/.tap/test-results/test/internals/plugin.test.js.tap +48 -0
  91. package/.tap/test-results/test/internals/reply-serialize.test.js.tap +166 -0
  92. package/.tap/test-results/test/internals/reply.test.js.tap +688 -0
  93. package/.tap/test-results/test/internals/reqIdGenFactory.test.js.tap +74 -0
  94. package/.tap/test-results/test/internals/request-validate.test.js.tap +384 -0
  95. package/.tap/test-results/test/internals/request.test.js.tap +163 -0
  96. package/.tap/test-results/test/internals/server.test.js.tap +30 -0
  97. package/.tap/test-results/test/internals/validation.test.js.tap +121 -0
  98. package/.tap/test-results/test/keepAliveTimeout.test.js.tap +12 -0
  99. package/.tap/test-results/test/listen.1.test.js.tap +31 -0
  100. package/.tap/test-results/test/listen.2.test.js.tap +46 -0
  101. package/.tap/test-results/test/listen.3.test.js.tap +25 -0
  102. package/.tap/test-results/test/listen.4.test.js.tap +51 -0
  103. package/.tap/test-results/test/lock.test.js.tap +29 -0
  104. package/.tap/test-results/test/logger/instantiation.test.js.tap +92 -0
  105. package/.tap/test-results/test/logger/logging.test.js.tap +117 -0
  106. package/.tap/test-results/test/logger/options.test.js.tap +165 -0
  107. package/.tap/test-results/test/logger/request.test.js.tap +82 -0
  108. package/.tap/test-results/test/logger/response.test.js.tap +38 -0
  109. package/.tap/test-results/test/maxRequestsPerSocket.test.js.tap +44 -0
  110. package/.tap/test-results/test/method-missing.test.js.tap +8 -0
  111. package/.tap/test-results/test/middleware.test.js.tap +17 -0
  112. package/.tap/test-results/test/mkcalendar.test.js.tap +43 -0
  113. package/.tap/test-results/test/mkcol.test.js.tap +14 -0
  114. package/.tap/test-results/test/move.test.js.tap +15 -0
  115. package/.tap/test-results/test/noop-set.test.js.tap +8 -0
  116. package/.tap/test-results/test/nullable-validation.test.js.tap +36 -0
  117. package/.tap/test-results/test/options.error-handler.test.js.tap +186 -0
  118. package/.tap/test-results/test/options.test.js.tap +174 -0
  119. package/.tap/test-results/test/output-validation.test.js.tap +66 -0
  120. package/.tap/test-results/test/patch.error-handler.test.js.tap +206 -0
  121. package/.tap/test-results/test/patch.test.js.tap +182 -0
  122. package/.tap/test-results/test/plugin.1.test.js.tap +78 -0
  123. package/.tap/test-results/test/plugin.2.test.js.tap +102 -0
  124. package/.tap/test-results/test/plugin.3.test.js.tap +58 -0
  125. package/.tap/test-results/test/plugin.4.test.js.tap +164 -0
  126. package/.tap/test-results/test/post-empty-body.test.js.tap +8 -0
  127. package/.tap/test-results/test/pretty-print.test.js.tap +82 -0
  128. package/.tap/test-results/test/promises.test.js.tap +46 -0
  129. package/.tap/test-results/test/propfind.test.js.tap +43 -0
  130. package/.tap/test-results/test/proppatch.test.js.tap +29 -0
  131. package/.tap/test-results/test/proto-poisoning.test.js.tap +47 -0
  132. package/.tap/test-results/test/put.error-handler.test.js.tap +206 -0
  133. package/.tap/test-results/test/put.test.js.tap +182 -0
  134. package/.tap/test-results/test/register.test.js.tap +61 -0
  135. package/.tap/test-results/test/reply-code.test.js.tap +40 -0
  136. package/.tap/test-results/test/reply-earlyHints.test.js.tap +22 -0
  137. package/.tap/test-results/test/reply-error.test.js.tap +643 -0
  138. package/.tap/test-results/test/reply-trailers.test.js.tap +176 -0
  139. package/.tap/test-results/test/report.test.js.tap +43 -0
  140. package/.tap/test-results/test/request-error.test.js.tap +98 -0
  141. package/.tap/test-results/test/request-id.test.js.tap +38 -0
  142. package/.tap/test-results/test/request.deprecated.test.js.tap +13 -0
  143. package/.tap/test-results/test/requestTimeout.test.js.tap +21 -0
  144. package/.tap/test-results/test/route-hooks.test.js.tap +498 -0
  145. package/.tap/test-results/test/route-prefix.test.js.tap +195 -0
  146. package/.tap/test-results/test/route-shorthand.test.js.tap +190 -0
  147. package/.tap/test-results/test/route.1.test.js.tap +93 -0
  148. package/.tap/test-results/test/route.2.test.js.tap +28 -0
  149. package/.tap/test-results/test/route.3.test.js.tap +39 -0
  150. package/.tap/test-results/test/route.4.test.js.tap +32 -0
  151. package/.tap/test-results/test/route.5.test.js.tap +54 -0
  152. package/.tap/test-results/test/route.6.test.js.tap +81 -0
  153. package/.tap/test-results/test/route.7.test.js.tap +93 -0
  154. package/.tap/test-results/test/route.8.test.js.tap +38 -0
  155. package/.tap/test-results/test/router-options.test.js.tap +104 -0
  156. package/.tap/test-results/test/same-shape.test.js.tap +22 -0
  157. package/.tap/test-results/test/schema-examples.test.js.tap +85 -0
  158. package/.tap/test-results/test/schema-feature.test.js.tap +445 -0
  159. package/.tap/test-results/test/schema-serialization.test.js.tap +194 -0
  160. package/.tap/test-results/test/schema-special-usage.test.js.tap +186 -0
  161. package/.tap/test-results/test/schema-validation.test.js.tap +199 -0
  162. package/.tap/test-results/test/search.test.js.tap +77 -0
  163. package/.tap/test-results/test/serialize-response.test.js.tap +26 -0
  164. package/.tap/test-results/test/server.test.js.tap +65 -0
  165. package/.tap/test-results/test/set-error-handler.test.js.tap +7 -0
  166. package/.tap/test-results/test/skip-reply-send.test.js.tap +272 -0
  167. package/.tap/test-results/test/stream.1.test.js.tap +36 -0
  168. package/.tap/test-results/test/stream.2.test.js.tap +20 -0
  169. package/.tap/test-results/test/stream.3.test.js.tap +34 -0
  170. package/.tap/test-results/test/stream.4.test.js.tap +40 -0
  171. package/.tap/test-results/test/stream.5.test.js.tap +37 -0
  172. package/.tap/test-results/test/sync-routes.test.js.tap +19 -0
  173. package/.tap/test-results/test/throw.test.js.tap +116 -0
  174. package/.tap/test-results/test/trace.test.js.tap +7 -0
  175. package/.tap/test-results/test/trust-proxy.test.js.tap +109 -0
  176. package/.tap/test-results/test/type-provider.test.js.tap +12 -0
  177. package/.tap/test-results/test/unlock.test.js.tap +14 -0
  178. package/.tap/test-results/test/upgrade.test.js.tap +8 -0
  179. package/.tap/test-results/test/url-rewriting.test.js.tap +39 -0
  180. package/.tap/test-results/test/useSemicolonDelimiter.test.js.tap +33 -0
  181. package/.tap/test-results/test/validation-error-handling.test.js.tap +180 -0
  182. package/.tap/test-results/test/versioned-routes.test.js.tap +151 -0
  183. package/.tap/test-results/test/web-api.test.js.tap +51 -0
  184. package/.tap/test-results/test/wrapThenable.test.js.tap +11 -0
  185. package/.taprc +4 -8
  186. package/README.md +3 -6
  187. package/build/build-error-serializer.js +4 -1
  188. package/build/build-validation.js +5 -4
  189. package/docs/Guides/Database.md +1 -1
  190. package/docs/Guides/Delay-Accepting-Requests.md +3 -3
  191. package/docs/Guides/Ecosystem.md +2 -0
  192. package/docs/Guides/Migration-Guide-V5.md +20 -0
  193. package/docs/Guides/Write-Type-Provider.md +4 -2
  194. package/docs/Reference/ContentTypeParser.md +30 -1
  195. package/docs/Reference/Decorators.md +42 -16
  196. package/docs/Reference/Errors.md +10 -2
  197. package/docs/Reference/Hooks.md +48 -14
  198. package/docs/Reference/Logging.md +5 -5
  199. package/docs/Reference/Reply.md +29 -24
  200. package/docs/Reference/Request.md +5 -1
  201. package/docs/Reference/Routes.md +24 -28
  202. package/docs/Reference/Server.md +14 -53
  203. package/docs/Reference/Type-Providers.md +21 -26
  204. package/docs/Reference/TypeScript.md +46 -29
  205. package/docs/Reference/Warnings.md +2 -8
  206. package/eslint.config.js +27 -0
  207. package/examples/typescript-server.ts +14 -14
  208. package/fastify.d.ts +15 -14
  209. package/fastify.js +41 -15
  210. package/lib/configValidator.js +94 -76
  211. package/lib/contentTypeParser.js +54 -88
  212. package/lib/decorate.js +3 -7
  213. package/lib/error-serializer.js +77 -19
  214. package/lib/errors.js +31 -6
  215. package/lib/handleRequest.js +70 -39
  216. package/lib/httpMethods.js +34 -18
  217. package/lib/logger.js +24 -6
  218. package/lib/pluginUtils.js +5 -5
  219. package/lib/reply.js +16 -13
  220. package/lib/request.js +37 -19
  221. package/lib/route.js +7 -31
  222. package/lib/server.js +62 -123
  223. package/lib/warnings.js +28 -27
  224. package/lib/wrapThenable.js +46 -22
  225. package/package.json +38 -58
  226. package/test/404s.test.js +8 -12
  227. package/test/async-await.test.js +46 -2
  228. package/test/build/error-serializer.test.js +4 -2
  229. package/test/check.test.js +225 -0
  230. package/test/close-pipelining.test.js +2 -34
  231. package/test/close.test.js +1 -41
  232. package/test/content-parser.test.js +69 -117
  233. package/test/custom-parser.1.test.js +40 -1
  234. package/test/decorator-namespace.test._js_ +31 -0
  235. package/test/decorator.test.js +92 -43
  236. package/test/delete.test.js +21 -1
  237. package/test/diagnostics-channel/404.test.js +57 -0
  238. package/test/diagnostics-channel/async-delay-request.test.js +74 -0
  239. package/test/diagnostics-channel/async-request.test.js +72 -0
  240. package/test/diagnostics-channel/error-before-handler.test.js +36 -0
  241. package/test/diagnostics-channel/error-request.test.js +61 -0
  242. package/test/diagnostics-channel/error-status.test.js +39 -0
  243. package/test/{diagnostics-channel.test.js → diagnostics-channel/init.test.js} +6 -16
  244. package/test/diagnostics-channel/sync-delay-request.test.js +58 -0
  245. package/test/diagnostics-channel/sync-request-reply.test.js +58 -0
  246. package/test/diagnostics-channel/sync-request.test.js +61 -0
  247. package/test/encapsulated-error-handler.test.js +201 -14
  248. package/test/esm/index.test.js +2 -12
  249. package/test/findRoute.test.js +16 -0
  250. package/test/genReqId.test.js +9 -0
  251. package/test/get.test.js +28 -0
  252. package/test/has-route.test.js +18 -2
  253. package/test/helper.js +1 -5
  254. package/test/hooks.test.js +0 -4
  255. package/test/http2/constraint.test.js +22 -1
  256. package/test/http2/plain.test.js +21 -6
  257. package/test/http2/secure.test.js +12 -1
  258. package/test/https/https.test.js +57 -0
  259. package/test/inject.test.js +1 -2
  260. package/test/internals/decorator.test.js +0 -2
  261. package/test/internals/errors.test.js +57 -17
  262. package/test/internals/handleRequest.test.js +5 -1
  263. package/test/internals/initialConfig.test.js +5 -5
  264. package/test/internals/logger.test.js +31 -2
  265. package/test/internals/reply.test.js +38 -80
  266. package/test/internals/request.test.js +13 -11
  267. package/test/listen.1.test.js +5 -15
  268. package/test/listen.5.test.js +88 -0
  269. package/test/logger/instantiation.test.js +8 -8
  270. package/test/logger/logging.test.js +4 -4
  271. package/test/logger/options.test.js +102 -21
  272. package/test/logger/response.test.js +6 -6
  273. package/test/maxRequestsPerSocket.test.js +2 -5
  274. package/test/method-missing.test.js +24 -0
  275. package/test/plugin.1.test.js +2 -4
  276. package/test/plugin.2.test.js +0 -2
  277. package/test/plugin.3.test.js +0 -2
  278. package/test/plugin.4.test.js +92 -56
  279. package/test/register.test.js +2 -4
  280. package/test/reply-earlyHints.test.js +98 -0
  281. package/test/reply-error.test.js +0 -2
  282. package/test/route-hooks.test.js +0 -1
  283. package/test/route-shorthand.test.js +60 -0
  284. package/test/schema-special-usage.test.js +1 -1
  285. package/test/server.test.js +17 -2
  286. package/test/stream.2.test.js +1 -1
  287. package/test/stream.4.test.js +0 -42
  288. package/test/stream.5.test.js +2 -2
  289. package/test/trust-proxy.test.js +33 -27
  290. package/test/types/errors.test-d.ts +0 -2
  291. package/test/types/fastify.test-d.ts +14 -12
  292. package/test/types/hooks.test-d.ts +1 -0
  293. package/test/types/import.ts +1 -0
  294. package/test/types/instance.test-d.ts +10 -51
  295. package/test/types/logger.test-d.ts +43 -6
  296. package/test/types/plugin.test-d.ts +5 -2
  297. package/test/types/register.test-d.ts +2 -2
  298. package/test/types/reply.test-d.ts +13 -12
  299. package/test/types/request.test-d.ts +19 -8
  300. package/test/types/route.test-d.ts +30 -2
  301. package/test/types/schema.test-d.ts +2 -2
  302. package/test/types/serverFactory.test-d.ts +1 -1
  303. package/test/types/type-provider.test-d.ts +60 -13
  304. package/test/types/using.test-d.ts +4 -1
  305. package/test/url-rewriting.test.js +3 -2
  306. package/test/useSemicolonDelimiter.test.js +3 -6
  307. package/test/versioned-routes.test.js +1 -1
  308. package/test/web-api.test.js +0 -6
  309. package/types/content-type-parser.d.ts +3 -3
  310. package/types/context.d.ts +0 -1
  311. package/types/errors.d.ts +1 -0
  312. package/types/hooks.d.ts +6 -6
  313. package/types/instance.d.ts +28 -41
  314. package/types/logger.d.ts +3 -3
  315. package/types/plugin.d.ts +3 -3
  316. package/types/reply.d.ts +13 -14
  317. package/types/request.d.ts +5 -3
  318. package/types/route.d.ts +29 -29
  319. package/types/schema.d.ts +3 -3
  320. package/types/serverFactory.d.ts +2 -2
  321. package/types/type-provider.d.ts +22 -12
  322. package/types/utils.d.ts +18 -18
  323. package/.c8rc.json +0 -8
  324. package/.eslintrc +0 -4
  325. package/test/default-route.test.js +0 -88
  326. package/test/listen.deprecated.test.js +0 -229
  327. package/test/unsupported-httpversion.test.js +0 -31
  328. package/types/.eslintrc.json +0 -48
@@ -0,0 +1,225 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const { S } = require('fluent-json-schema')
6
+ const Fastify = require('..')
7
+ const sget = require('simple-get').concat
8
+
9
+ const BadRequestSchema = S.object()
10
+ .prop('statusCode', S.number())
11
+ .prop('error', S.string())
12
+ .prop('message', S.string())
13
+
14
+ const InternalServerErrorSchema = S.object()
15
+ .prop('statusCode', S.number())
16
+ .prop('error', S.string())
17
+ .prop('message', S.string())
18
+
19
+ const NotFoundSchema = S.object()
20
+ .prop('statusCode', S.number())
21
+ .prop('error', S.string())
22
+ .prop('message', S.string())
23
+
24
+ const options = {
25
+ schema: {
26
+ body: {
27
+ type: 'object',
28
+ properties: {
29
+ id: { type: 'string' }
30
+ }
31
+ },
32
+ response: {
33
+ 200: {
34
+ type: 'object',
35
+ properties: {
36
+ id: { type: 'string' }
37
+ }
38
+ },
39
+ 400: {
40
+ description: 'Bad Request',
41
+ content: {
42
+ 'application/json': {
43
+ schema: BadRequestSchema.valueOf()
44
+ }
45
+ }
46
+ },
47
+ 404: {
48
+ description: 'Resource not found',
49
+ content: {
50
+ 'application/json': {
51
+ schema: NotFoundSchema.valueOf(),
52
+ example: {
53
+ statusCode: 404,
54
+ error: 'Not Found',
55
+ message: 'Not Found'
56
+ }
57
+ }
58
+ }
59
+ },
60
+ 500: {
61
+ description: 'Internal Server Error',
62
+ content: {
63
+ 'application/json': {
64
+ schema: InternalServerErrorSchema.valueOf(),
65
+ example: {
66
+ message: 'Internal Server Error'
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ const handler = (request, reply) => {
76
+ console.log('in handler')
77
+ if (request.body.id === '400') {
78
+ return reply.status(400).send({
79
+ statusCode: 400,
80
+ error: 'Bad Request',
81
+ message: 'Custom message',
82
+ extra: 'This should not be in the response'
83
+ })
84
+ }
85
+
86
+ if (request.body.id === '404') {
87
+ return reply.status(404).send({
88
+ statusCode: 404,
89
+ error: 'Not Found',
90
+ message: 'Custom Not Found',
91
+ extra: 'This should not be in the response'
92
+ })
93
+ }
94
+
95
+ if (request.body.id === '500') {
96
+ reply.status(500).send({
97
+ statusCode: 500,
98
+ error: 'Internal Server Error',
99
+ message: 'Custom Internal Server Error',
100
+ extra: 'This should not be in the response'
101
+ })
102
+ }
103
+
104
+ reply.send({
105
+ id: request.body.id,
106
+ extra: 'This should not be in the response'
107
+ })
108
+ }
109
+
110
+ test('serialize the response for a Bad Request error, as defined on the schema', t => {
111
+ const fastify = Fastify({})
112
+
113
+ t.teardown(fastify.close.bind(fastify))
114
+
115
+ fastify.post('/', options, handler)
116
+
117
+ fastify.listen({ port: 0 }, err => {
118
+ t.error(err)
119
+
120
+ const url = `http://localhost:${fastify.server.address().port}/`
121
+
122
+ sget({
123
+ method: 'POST',
124
+ url,
125
+ json: true
126
+ }, (err, response, body) => {
127
+ t.error(err)
128
+ t.equal(response.statusCode, 400)
129
+ t.same(body, {
130
+ statusCode: 400,
131
+ error: 'Bad Request',
132
+ message: 'body must be object'
133
+ })
134
+ t.end()
135
+ })
136
+ })
137
+ })
138
+
139
+ // test('serialize the response for a Not Found error, as defined on the schema', t => {
140
+ // const fastify = Fastify({})
141
+
142
+ // t.teardown(fastify.close.bind(fastify))
143
+
144
+ // fastify.post('/', options, handler)
145
+
146
+ // fastify.listen({ port: 0 }, err => {
147
+ // t.error(err)
148
+
149
+ // const url = `http://localhost:${fastify.server.address().port}/`
150
+
151
+ // sget({
152
+ // method: 'POST',
153
+ // url,
154
+ // json: true,
155
+ // body: { id: '404' }
156
+ // }, (err, response, body) => {
157
+ // t.error(err)
158
+ // t.equal(response.statusCode, 404)
159
+ // t.same(body, {
160
+ // statusCode: 404,
161
+ // error: 'Not Found',
162
+ // message: 'Custom Not Found'
163
+ // })
164
+ // t.end()
165
+ // })
166
+ // })
167
+ // })
168
+
169
+ // test('serialize the response for a Internal Server Error error, as defined on the schema', t => {
170
+ // const fastify = Fastify({})
171
+
172
+ // t.teardown(fastify.close.bind(fastify))
173
+
174
+ // fastify.post('/', options, handler)
175
+
176
+ // fastify.listen({ port: 0 }, err => {
177
+ // t.error(err)
178
+
179
+ // const url = `http://localhost:${fastify.server.address().port}/`
180
+
181
+ // sget({
182
+ // method: 'POST',
183
+ // url,
184
+ // json: true,
185
+ // body: { id: '500' }
186
+ // }, (err, response, body) => {
187
+ // t.error(err)
188
+ // t.equal(response.statusCode, 500)
189
+ // t.same(body, {
190
+ // statusCode: 500,
191
+ // error: 'Internal Server Error',
192
+ // message: 'Custom Internal Server Error'
193
+ // })
194
+ // t.end()
195
+ // })
196
+ // })
197
+ // })
198
+
199
+ // test('serialize the success response, as defined on the schema', t => {
200
+ // const fastify = Fastify({})
201
+
202
+ // t.teardown(fastify.close.bind(fastify))
203
+
204
+ // fastify.post('/', options, handler)
205
+
206
+ // fastify.listen({ port: 0 }, err => {
207
+ // t.error(err)
208
+
209
+ // const url = `http://localhost:${fastify.server.address().port}/`
210
+
211
+ // sget({
212
+ // method: 'POST',
213
+ // url,
214
+ // json: true,
215
+ // body: { id: 'test' }
216
+ // }, (err, response, body) => {
217
+ // t.error(err)
218
+ // t.equal(response.statusCode, 200)
219
+ // t.same(body, {
220
+ // id: 'test'
221
+ // })
222
+ // t.end()
223
+ // })
224
+ // })
225
+ // })
@@ -4,7 +4,6 @@ const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
6
  const { Client } = require('undici')
7
- const semver = require('semver')
8
7
 
9
8
  test('Should return 503 while closing - pipelining', async t => {
10
9
  const fastify = Fastify({
@@ -36,39 +35,8 @@ test('Should return 503 while closing - pipelining', async t => {
36
35
  await instance.close()
37
36
  })
38
37
 
39
- const isNodeVersionGte1819 = semver.gte(process.version, '18.19.0')
40
- test('Should not return 503 while closing - pipelining - return503OnClosing: false, skip Node >= v18.19.x', { skip: isNodeVersionGte1819 }, async t => {
41
- const fastify = Fastify({
42
- return503OnClosing: false,
43
- forceCloseConnections: false
44
- })
45
-
46
- fastify.get('/', (req, reply) => {
47
- fastify.close()
48
- reply.send({ hello: 'world' })
49
- })
50
-
51
- await fastify.listen({ port: 0 })
52
-
53
- const instance = new Client('http://localhost:' + fastify.server.address().port, {
54
- pipelining: 2
55
- })
56
-
57
- const codes = [200, 200, 200]
58
- const responses = await Promise.all([
59
- instance.request({ path: '/', method: 'GET' }),
60
- instance.request({ path: '/', method: 'GET' }),
61
- instance.request({ path: '/', method: 'GET' })
62
- ])
63
- const actual = responses.map(r => r.statusCode)
64
-
65
- t.same(actual, codes)
66
-
67
- await instance.close()
68
- })
69
-
70
- test('Should close the socket abruptly - pipelining - return503OnClosing: false, skip Node < v18.19.x', { skip: !isNodeVersionGte1819 }, async t => {
71
- // Since Node v18, we will always invoke server.closeIdleConnections()
38
+ test('Should close the socket abruptly - pipelining - return503OnClosing: false', async t => {
39
+ // Since Node v20, we will always invoke server.closeIdleConnections()
72
40
  // therefore our socket will be closed
73
41
  const fastify = Fastify({
74
42
  return503OnClosing: false,
@@ -5,7 +5,6 @@ const http = require('node:http')
5
5
  const { test } = require('tap')
6
6
  const Fastify = require('..')
7
7
  const { Client } = require('undici')
8
- const semver = require('semver')
9
8
  const split = require('split2')
10
9
  const { sleep } = require('./helper')
11
10
 
@@ -204,46 +203,7 @@ test('Should return error while closing (callback) - injection', t => {
204
203
  })
205
204
  })
206
205
 
207
- const isNodeVersionGte1819 = semver.gte(process.version, '18.19.0')
208
- test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node >= v18.19.x', { skip: isNodeVersionGte1819 }, t => {
209
- const fastify = Fastify({
210
- return503OnClosing: false,
211
- forceCloseConnections: false
212
- })
213
-
214
- fastify.get('/', (req, reply) => {
215
- fastify.close()
216
- reply.send({ hello: 'world' })
217
- })
218
-
219
- fastify.listen({ port: 0 }, err => {
220
- t.error(err)
221
-
222
- const port = fastify.server.address().port
223
- const client = net.createConnection({ port }, () => {
224
- client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
225
-
226
- client.once('data', data => {
227
- t.match(data.toString(), /Connection:\s*keep-alive/i)
228
- t.match(data.toString(), /200 OK/i)
229
-
230
- client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
231
-
232
- client.once('data', data => {
233
- t.match(data.toString(), /Connection:\s*close/i)
234
- t.match(data.toString(), /200 OK/i)
235
-
236
- // Test that fastify closes the TCP connection
237
- client.once('close', () => {
238
- t.end()
239
- })
240
- })
241
- })
242
- })
243
- })
244
- })
245
-
246
- test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node < v18.19.x', { skip: !isNodeVersionGte1819 }, t => {
206
+ test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false', t => {
247
207
  t.plan(4)
248
208
  const fastify = Fastify({
249
209
  return503OnClosing: false,
@@ -12,19 +12,20 @@ const third = function (req, payload, done) {}
12
12
 
13
13
  test('hasContentTypeParser', t => {
14
14
  test('should know about internal parsers', t => {
15
- t.plan(4)
15
+ t.plan(5)
16
16
 
17
17
  const fastify = Fastify()
18
18
  fastify.ready(err => {
19
19
  t.error(err)
20
20
  t.ok(fastify.hasContentTypeParser('application/json'))
21
21
  t.ok(fastify.hasContentTypeParser('text/plain'))
22
+ t.ok(fastify.hasContentTypeParser(' text/plain '))
22
23
  t.notOk(fastify.hasContentTypeParser('application/jsoff'))
23
24
  })
24
25
  })
25
26
 
26
- test('should work with string and RegExp', t => {
27
- t.plan(7)
27
+ test('should only work with string and RegExp', t => {
28
+ t.plan(8)
28
29
 
29
30
  const fastify = Fastify()
30
31
  fastify.addContentTypeParser(/^image\/.*/, first)
@@ -38,6 +39,7 @@ test('hasContentTypeParser', t => {
38
39
  t.notOk(fastify.hasContentTypeParser(/^image\/.+\+xml/))
39
40
  t.notOk(fastify.hasContentTypeParser('image/png'))
40
41
  t.notOk(fastify.hasContentTypeParser('*'))
42
+ t.throws(() => fastify.hasContentTypeParser(123), FST_ERR_CTP_INVALID_TYPE)
41
43
  })
42
44
 
43
45
  t.end()
@@ -45,7 +47,7 @@ test('hasContentTypeParser', t => {
45
47
 
46
48
  test('getParser', t => {
47
49
  test('should return matching parser', t => {
48
- t.plan(3)
50
+ t.plan(6)
49
51
 
50
52
  const fastify = Fastify()
51
53
 
@@ -56,9 +58,12 @@ test('getParser', t => {
56
58
  t.equal(fastify[keys.kContentTypeParser].getParser('application/t+xml').fn, second)
57
59
  t.equal(fastify[keys.kContentTypeParser].getParser('image/png').fn, first)
58
60
  t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
61
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/html; charset=utf-8').fn, third)
62
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/html ; charset=utf-8').fn, third)
63
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/htmlINVALID')?.fn, undefined)
59
64
  })
60
65
 
61
- test('should return matching parser with caching', t => {
66
+ test('should return matching parser with caching /1', t => {
62
67
  t.plan(6)
63
68
 
64
69
  const fastify = Fastify()
@@ -73,6 +78,21 @@ test('getParser', t => {
73
78
  t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
74
79
  })
75
80
 
81
+ test('should return matching parser with caching /2', t => {
82
+ t.plan(6)
83
+
84
+ const fastify = Fastify()
85
+
86
+ fastify.addContentTypeParser(/^text\/html(;\s*charset=[^;]+)?$/, first)
87
+
88
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
89
+ t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
90
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
91
+ t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
92
+ t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
93
+ t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
94
+ })
95
+
76
96
  test('should prefer content type parser with string value', t => {
77
97
  t.plan(2)
78
98
 
@@ -199,6 +219,36 @@ test('add', t => {
199
219
  t.equal(contentTypeParser.customParsers.get('').fn, first)
200
220
  })
201
221
 
222
+ test('should lowercase contentTypeParser name', async t => {
223
+ t.plan(1)
224
+ const fastify = Fastify()
225
+ fastify.addContentTypeParser('text/html', function (req, done) {
226
+ done()
227
+ })
228
+ try {
229
+ fastify.addContentTypeParser('TEXT/html', function (req, done) {
230
+ done()
231
+ })
232
+ } catch (err) {
233
+ t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
234
+ }
235
+ })
236
+
237
+ test('should trim contentTypeParser name', async t => {
238
+ t.plan(1)
239
+ const fastify = Fastify()
240
+ fastify.addContentTypeParser('text/html', function (req, done) {
241
+ done()
242
+ })
243
+ try {
244
+ fastify.addContentTypeParser(' text/html', function (req, done) {
245
+ done()
246
+ })
247
+ } catch (err) {
248
+ t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
249
+ }
250
+ })
251
+
202
252
  t.end()
203
253
  })
204
254
 
@@ -256,7 +306,7 @@ test('Error thrown 415 from content type is null and make post request to server
256
306
 
257
307
  test('remove', t => {
258
308
  test('should remove default parser', t => {
259
- t.plan(3)
309
+ t.plan(6)
260
310
 
261
311
  const fastify = Fastify()
262
312
  const contentTypeParser = fastify[keys.kContentTypeParser]
@@ -264,6 +314,9 @@ test('remove', t => {
264
314
  t.ok(contentTypeParser.remove('application/json'))
265
315
  t.notOk(contentTypeParser.customParsers['application/json'])
266
316
  t.notOk(contentTypeParser.parserList.find(parser => parser === 'application/json'))
317
+ t.ok(contentTypeParser.remove(' text/plain '))
318
+ t.notOk(contentTypeParser.customParsers['text/plain'])
319
+ t.notOk(contentTypeParser.parserList.find(parser => parser === 'text/plain'))
267
320
  })
268
321
 
269
322
  test('should remove RegExp parser', t => {
@@ -421,32 +474,25 @@ test('Safeguard against content-type spoofing - string', async t => {
421
474
  })
422
475
  })
423
476
 
424
- test('Safeguard against content-type spoofing - regexp', async t => {
425
- t.plan(1)
477
+ test('Warning against improper content-type - regexp', t => {
478
+ t.plan(2)
426
479
 
427
480
  const fastify = Fastify()
481
+
482
+ process.on('warning', onWarning)
483
+ function onWarning (warning) {
484
+ t.equal(warning.name, 'FastifySecurity')
485
+ t.equal(warning.code, 'FSTSEC001')
486
+ }
487
+ t.teardown(() => process.removeListener('warning', onWarning))
488
+
428
489
  fastify.removeAllContentTypeParsers()
429
490
  fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
430
- t.pass('should be called')
431
491
  done(null, body)
432
492
  })
433
493
  fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
434
- t.fail('shouldn\'t be called')
435
494
  done(null, body)
436
495
  })
437
-
438
- fastify.post('/', async () => {
439
- return 'ok'
440
- })
441
-
442
- await fastify.inject({
443
- method: 'POST',
444
- path: '/',
445
- headers: {
446
- 'content-type': 'text/plain; content-type="application/json"'
447
- },
448
- body: ''
449
- })
450
496
  })
451
497
 
452
498
  test('content-type match parameters - string 1', async t => {
@@ -477,34 +523,6 @@ test('content-type match parameters - string 1', async t => {
477
523
  })
478
524
  })
479
525
 
480
- test('content-type match parameters - string 2', async t => {
481
- t.plan(1)
482
-
483
- const fastify = Fastify()
484
- fastify.removeAllContentTypeParsers()
485
- fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
486
- t.pass('should be called')
487
- done(null, body)
488
- })
489
- fastify.addContentTypeParser('text/plain; charset=utf8; foo=bar', function (request, body, done) {
490
- t.fail('shouldn\'t be called')
491
- done(null, body)
492
- })
493
-
494
- fastify.post('/', async () => {
495
- return 'ok'
496
- })
497
-
498
- await fastify.inject({
499
- method: 'POST',
500
- path: '/',
501
- headers: {
502
- 'content-type': 'application/json; foo=bar; charset=utf8'
503
- },
504
- body: ''
505
- })
506
- })
507
-
508
526
  test('content-type match parameters - regexp', async t => {
509
527
  t.plan(1)
510
528
 
@@ -650,72 +668,6 @@ test('content-type regexp list should be cloned when plugin override', async t =
650
668
  }
651
669
  })
652
670
 
653
- test('allow partial content-type - essence check', async t => {
654
- t.plan(1)
655
-
656
- const fastify = Fastify()
657
- fastify.removeAllContentTypeParsers()
658
- fastify.addContentTypeParser('json', function (request, body, done) {
659
- t.pass('should be called')
660
- done(null, body)
661
- })
662
-
663
- fastify.post('/', async () => {
664
- return 'ok'
665
- })
666
-
667
- await fastify.inject({
668
- method: 'POST',
669
- path: '/',
670
- headers: {
671
- 'content-type': 'application/json; foo=bar; charset=utf8'
672
- },
673
- body: ''
674
- })
675
-
676
- await fastify.inject({
677
- method: 'POST',
678
- path: '/',
679
- headers: {
680
- 'content-type': 'image/jpeg'
681
- },
682
- body: ''
683
- })
684
- })
685
-
686
- test('allow partial content-type - not essence check', async t => {
687
- t.plan(1)
688
-
689
- const fastify = Fastify()
690
- fastify.removeAllContentTypeParsers()
691
- fastify.addContentTypeParser('json;', function (request, body, done) {
692
- t.pass('should be called')
693
- done(null, body)
694
- })
695
-
696
- fastify.post('/', async () => {
697
- return 'ok'
698
- })
699
-
700
- await fastify.inject({
701
- method: 'POST',
702
- path: '/',
703
- headers: {
704
- 'content-type': 'application/json; foo=bar; charset=utf8'
705
- },
706
- body: ''
707
- })
708
-
709
- await fastify.inject({
710
- method: 'POST',
711
- path: '/',
712
- headers: {
713
- 'content-type': 'image/jpeg'
714
- },
715
- body: ''
716
- })
717
- })
718
-
719
671
  test('edge case content-type - ;', async t => {
720
672
  t.plan(1)
721
673
 
@@ -63,7 +63,7 @@ test('Should have typeof body object with no custom parser defined, undefined bo
63
63
  })
64
64
  })
65
65
 
66
- test('Should get the body as string', t => {
66
+ test('Should get the body as string /1', t => {
67
67
  t.plan(6)
68
68
  const fastify = Fastify()
69
69
 
@@ -102,6 +102,45 @@ test('Should get the body as string', t => {
102
102
  })
103
103
  })
104
104
 
105
+ test('Should get the body as string /2', t => {
106
+ t.plan(6)
107
+ const fastify = Fastify()
108
+
109
+ fastify.post('/', (req, reply) => {
110
+ reply.send(req.body)
111
+ })
112
+
113
+ fastify.addContentTypeParser('text/plain/test', { parseAs: 'string' }, function (req, body, done) {
114
+ t.ok('called')
115
+ t.ok(typeof body === 'string')
116
+ try {
117
+ const plainText = body
118
+ done(null, plainText)
119
+ } catch (err) {
120
+ err.statusCode = 400
121
+ done(err, undefined)
122
+ }
123
+ })
124
+
125
+ fastify.listen({ port: 0 }, err => {
126
+ t.error(err)
127
+
128
+ sget({
129
+ method: 'POST',
130
+ url: getServerUrl(fastify),
131
+ body: 'hello world',
132
+ headers: {
133
+ 'Content-Type': ' text/plain/test '
134
+ }
135
+ }, (err, response, body) => {
136
+ t.error(err)
137
+ t.equal(response.statusCode, 200)
138
+ t.equal(body.toString(), 'hello world')
139
+ fastify.close()
140
+ })
141
+ })
142
+ })
143
+
105
144
  test('Should get the body as buffer', t => {
106
145
  t.plan(6)
107
146
  const fastify = Fastify()
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ /* eslint no-prototype-builtins: 0 */
4
+
5
+ const t = require('tap')
6
+ const test = t.test
7
+ const Fastify = require('..')
8
+ const fp = require('fastify-plugin')
9
+
10
+ test('plugin namespace', async t => {
11
+ t.plan(2)
12
+ const app = Fastify()
13
+
14
+ await app.register(async function plugin (app, opts) {
15
+ app.decorate('utility', function () {
16
+ return 'utility'
17
+ })
18
+
19
+ app.get('/', function (req, reply) {
20
+ // ! here the plugin would use app.utility()
21
+ // ! the plugin does not know about the namespace
22
+ reply.send({ utility: app.utility() })
23
+ })
24
+ }, { namepace: 'foo' })
25
+
26
+ // ! but outside the plugin the decorator would be app.foo.utility()
27
+ t.ok(app.foo.utility)
28
+
29
+ const res = await app.inject('/')
30
+ t.same(res.json(), { utility: 'utility' })
31
+ })