itsi 0.1.20 → 0.2.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 (319) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -8
  3. data/Cargo.lock +2 -2
  4. data/LICENSE.txt +698 -0
  5. data/README.md +15 -4
  6. data/Rakefile +9 -5
  7. data/crates/itsi_acme/.gitignore +4 -0
  8. data/crates/itsi_acme/Cargo.toml +86 -0
  9. data/crates/itsi_acme/LICENSE-APACHE +201 -0
  10. data/crates/itsi_acme/LICENSE-MIT +23 -0
  11. data/crates/itsi_acme/README.md +9 -0
  12. data/crates/itsi_acme/examples/high_level.rs +63 -0
  13. data/crates/itsi_acme/examples/high_level_warp.rs +52 -0
  14. data/crates/itsi_acme/examples/low_level.rs +87 -0
  15. data/crates/itsi_acme/examples/low_level_axum.rs +66 -0
  16. data/crates/itsi_acme/src/acceptor.rs +81 -0
  17. data/crates/itsi_acme/src/acme.rs +354 -0
  18. data/crates/itsi_acme/src/axum.rs +86 -0
  19. data/crates/itsi_acme/src/cache.rs +39 -0
  20. data/crates/itsi_acme/src/caches/boxed.rs +80 -0
  21. data/crates/itsi_acme/src/caches/composite.rs +69 -0
  22. data/crates/itsi_acme/src/caches/dir.rs +106 -0
  23. data/crates/itsi_acme/src/caches/mod.rs +11 -0
  24. data/crates/itsi_acme/src/caches/no.rs +78 -0
  25. data/crates/itsi_acme/src/caches/test.rs +136 -0
  26. data/crates/itsi_acme/src/config.rs +172 -0
  27. data/crates/itsi_acme/src/https_helper.rs +69 -0
  28. data/crates/itsi_acme/src/incoming.rs +142 -0
  29. data/crates/itsi_acme/src/jose.rs +161 -0
  30. data/crates/itsi_acme/src/lib.rs +142 -0
  31. data/crates/itsi_acme/src/resolver.rs +59 -0
  32. data/crates/itsi_acme/src/state.rs +424 -0
  33. data/crates/itsi_rb_helpers/src/lib.rs +4 -3
  34. data/crates/itsi_scheduler/Cargo.toml +1 -1
  35. data/crates/itsi_scheduler/src/itsi_scheduler.rs +8 -2
  36. data/crates/itsi_scheduler/src/lib.rs +1 -0
  37. data/crates/itsi_server/Cargo.toml +1 -1
  38. data/crates/itsi_server/src/lib.rs +2 -1
  39. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +18 -1
  40. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +11 -3
  41. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +122 -63
  42. data/crates/itsi_server/src/ruby_types/itsi_server.rs +2 -0
  43. data/crates/itsi_server/src/server/binds/bind.rs +3 -0
  44. data/crates/itsi_server/src/server/binds/listener.rs +12 -5
  45. data/crates/itsi_server/src/server/binds/tls.rs +13 -5
  46. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +12 -5
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +8 -1
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +9 -1
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +48 -43
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +11 -2
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +39 -12
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +36 -27
  53. data/crates/itsi_server/src/server/middleware_stack/middlewares/csp.rs +25 -11
  54. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +12 -3
  55. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +74 -72
  56. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +15 -1
  57. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +11 -8
  58. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +19 -11
  59. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +5 -5
  60. data/crates/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +2 -2
  61. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +11 -5
  62. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +17 -20
  63. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +19 -8
  64. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +16 -37
  65. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +22 -12
  66. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +26 -11
  67. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +7 -1
  68. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +14 -4
  69. data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +19 -0
  70. data/crates/itsi_server/src/server/middleware_stack/mod.rs +49 -13
  71. data/crates/itsi_server/src/server/mod.rs +1 -0
  72. data/crates/itsi_server/src/server/redirect_type.rs +26 -0
  73. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +22 -16
  74. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +49 -12
  75. data/crates/itsi_server/src/server/signal.rs +1 -0
  76. data/crates/itsi_server/src/server/size_limited_incoming.rs +6 -0
  77. data/crates/itsi_server/src/server/thread_worker.rs +5 -1
  78. data/crates/itsi_server/src/services/itsi_http_service.rs +20 -2
  79. data/crates/itsi_server/src/services/rate_limiter.rs +15 -4
  80. data/crates/itsi_server/src/services/static_file_server.rs +33 -19
  81. data/crates/itsi_tracing/src/lib.rs +42 -22
  82. data/docs/content/_index.md +1 -2
  83. data/docs/content/acknowledgements/_index.md +5 -2
  84. data/docs/content/configuration/_index.md +8 -5
  85. data/docs/content/contact/_index.md +8 -1
  86. data/docs/content/faqs/_index.md +5 -3
  87. data/docs/content/features/_index.md +56 -50
  88. data/docs/content/getting_started/_index.md +8 -5
  89. data/docs/content/getting_started/local_development.md +68 -8
  90. data/docs/content/getting_started/logging.md +16 -9
  91. data/docs/content/getting_started/running_itsi_in_production.md +5 -3
  92. data/docs/content/getting_started/signals.md +38 -0
  93. data/docs/content/itsi_scheduler/_index.md +8 -7
  94. data/docs/content/utilities/_index.md +13 -0
  95. data/docs/content/utilities/config_file_testing.md +17 -0
  96. data/docs/content/utilities/passfile_generator.md +41 -0
  97. data/docs/content/utilities/route_testing.md +27 -0
  98. data/docs/content/utilities/secrets_management.md +30 -0
  99. data/docs/hugo.yaml +1 -1
  100. data/fairytale.txt +3 -4
  101. data/gems/scheduler/Cargo.lock +1 -1
  102. data/gems/scheduler/README.md +4 -5
  103. data/gems/scheduler/Rakefile +0 -4
  104. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  105. data/gems/scheduler/lib/itsi/scheduler.rb +9 -4
  106. data/gems/scheduler/test/test_active_record.rb +12 -7
  107. data/gems/server/Cargo.lock +1 -1
  108. data/gems/server/Rakefile +0 -4
  109. data/gems/server/exe/itsi +13 -2
  110. data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +2 -0
  111. data/gems/server/lib/itsi/http_request.rb +40 -9
  112. data/gems/server/lib/itsi/http_response.rb +2 -1
  113. data/gems/server/lib/itsi/passfile.rb +0 -1
  114. data/gems/server/lib/itsi/server/config/config_helpers.rb +20 -8
  115. data/gems/server/lib/itsi/server/config/dsl.rb +20 -435
  116. data/gems/server/lib/itsi/server/config/known_paths.rb +4 -1
  117. data/gems/server/lib/itsi/server/config/middleware/_index.md +6 -4
  118. data/gems/server/lib/itsi/server/config/middleware/allow_list.md +46 -0
  119. data/gems/server/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  120. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  121. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  122. data/gems/server/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  123. data/gems/server/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
  124. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  125. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  126. data/gems/server/lib/itsi/server/config/middleware/cache_control.md +78 -0
  127. data/gems/server/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  128. data/gems/server/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  129. data/gems/server/lib/itsi/server/config/middleware/compression.md +50 -0
  130. data/gems/server/lib/itsi/server/config/middleware/compression.rb +37 -0
  131. data/gems/server/lib/itsi/server/config/middleware/cors.md +93 -0
  132. data/gems/server/lib/itsi/server/config/middleware/cors.rb +32 -0
  133. data/gems/server/lib/itsi/server/config/middleware/csp.md +37 -0
  134. data/gems/server/lib/itsi/server/config/middleware/csp.rb +44 -0
  135. data/gems/server/lib/itsi/server/config/middleware/deny_list.md +45 -0
  136. data/gems/server/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  137. data/gems/server/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
  138. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  139. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  140. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  141. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
  142. data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
  143. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  144. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
  145. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  146. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  147. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  148. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
  149. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  150. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
  151. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  152. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
  153. data/gems/server/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  154. data/gems/server/lib/itsi/server/config/middleware/error_response.md +61 -0
  155. data/gems/server/lib/itsi/server/config/middleware/error_response.rb +36 -0
  156. data/gems/server/lib/itsi/server/config/middleware/etag.md +59 -0
  157. data/gems/server/lib/itsi/server/config/middleware/etag.rb +27 -0
  158. data/gems/server/lib/itsi/server/config/middleware/grpc.md +172 -0
  159. data/gems/server/lib/itsi/server/config/middleware/grpc.rb +54 -0
  160. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  161. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  162. data/gems/server/lib/itsi/server/config/middleware/location.md +107 -0
  163. data/gems/server/lib/itsi/server/config/middleware/location.rb +99 -0
  164. data/gems/server/lib/itsi/server/config/middleware/log_requests.md +13 -11
  165. data/gems/server/lib/itsi/server/config/middleware/log_requests.rb +1 -3
  166. data/gems/server/lib/itsi/server/config/middleware/max_body.md +18 -0
  167. data/gems/server/lib/itsi/server/config/middleware/max_body.rb +21 -0
  168. data/gems/server/lib/itsi/server/config/middleware/proxy.md +62 -0
  169. data/gems/server/lib/itsi/server/config/middleware/proxy.rb +41 -0
  170. data/gems/server/lib/itsi/server/config/middleware/rackup_file.md +54 -0
  171. data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
  172. data/gems/server/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  173. data/gems/server/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  174. data/gems/server/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  175. data/gems/server/lib/itsi/server/config/middleware/redirect.md +55 -0
  176. data/gems/server/lib/itsi/server/config/middleware/redirect.rb +25 -0
  177. data/gems/server/lib/itsi/server/config/middleware/request_headers.md +34 -0
  178. data/gems/server/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  179. data/gems/server/lib/itsi/server/config/middleware/response_headers.md +33 -0
  180. data/gems/server/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  181. data/gems/server/lib/itsi/server/config/middleware/run.md +60 -0
  182. data/gems/server/lib/itsi/server/config/middleware/run.rb +43 -0
  183. data/gems/server/lib/itsi/server/config/middleware/static_assets.md +73 -0
  184. data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +87 -0
  185. data/gems/server/lib/itsi/server/config/middleware/static_response.md +44 -0
  186. data/gems/server/lib/itsi/server/config/middleware/static_response.rb +29 -0
  187. data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
  188. data/gems/server/lib/itsi/server/config/middleware/token_source.rb +32 -0
  189. data/gems/server/lib/itsi/server/config/middleware.rb +4 -0
  190. data/gems/server/lib/itsi/server/config/option.rb +5 -0
  191. data/gems/server/lib/itsi/server/config/options/_index.md +3 -2
  192. data/gems/server/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  193. data/gems/server/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
  194. data/gems/server/lib/itsi/server/config/options/bind.md +71 -0
  195. data/gems/server/lib/itsi/server/config/options/bind.rb +26 -0
  196. data/gems/server/lib/itsi/server/config/options/certificates.md +65 -0
  197. data/gems/server/lib/itsi/server/config/options/daemonize.md +14 -0
  198. data/gems/server/lib/itsi/server/config/options/daemonize.rb +19 -0
  199. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.md +1 -2
  200. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.rb +6 -3
  201. data/gems/server/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  202. data/gems/server/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  203. data/gems/server/lib/itsi/server/config/options/hooks/_index.md +11 -0
  204. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  205. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  206. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  207. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  208. data/gems/server/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  209. data/gems/server/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  210. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  211. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  212. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  213. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  214. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  215. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  216. data/gems/server/lib/itsi/server/config/options/include.md +20 -0
  217. data/gems/server/lib/itsi/server/config/options/include.rb +36 -0
  218. data/gems/server/lib/itsi/server/config/options/listen_backlog.md +11 -0
  219. data/gems/server/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  220. data/gems/server/lib/itsi/server/config/options/log_format.md +18 -0
  221. data/gems/server/lib/itsi/server/config/options/log_format.rb +19 -0
  222. data/gems/server/lib/itsi/server/config/options/log_level.md +34 -0
  223. data/gems/server/lib/itsi/server/config/options/log_level.rb +20 -0
  224. data/gems/server/lib/itsi/server/config/options/log_target.md +38 -0
  225. data/gems/server/lib/itsi/server/config/options/log_target.rb +19 -0
  226. data/gems/server/lib/itsi/server/config/options/log_target_filters.md +17 -0
  227. data/gems/server/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  228. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  229. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  230. data/gems/server/lib/itsi/server/config/options/nodelay.md +16 -0
  231. data/gems/server/lib/itsi/server/config/options/nodelay.rb +19 -0
  232. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  233. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  234. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  235. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  236. data/gems/server/lib/itsi/server/config/options/preload.md +21 -0
  237. data/gems/server/lib/itsi/server/config/options/preload.rb +18 -0
  238. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  239. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  240. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  241. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  242. data/gems/server/lib/itsi/server/config/options/request_timeout.md +23 -0
  243. data/gems/server/lib/itsi/server/config/options/request_timeout.rb +19 -0
  244. data/gems/server/lib/itsi/server/config/options/reuse_address.md +16 -0
  245. data/gems/server/lib/itsi/server/config/options/reuse_address.rb +19 -0
  246. data/gems/server/lib/itsi/server/config/options/reuse_port.md +16 -0
  247. data/gems/server/lib/itsi/server/config/options/reuse_port.rb +19 -0
  248. data/gems/server/lib/itsi/server/config/options/scheduler_threads.md +34 -0
  249. data/gems/server/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  250. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  251. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  252. data/gems/server/lib/itsi/server/config/options/stream_body.md +32 -0
  253. data/gems/server/lib/itsi/server/config/options/stream_body.rb +18 -0
  254. data/gems/server/lib/itsi/server/config/options/threads.md +7 -2
  255. data/gems/server/lib/itsi/server/config/options/threads.rb +1 -1
  256. data/gems/server/lib/itsi/server/config/options/watch.md +16 -0
  257. data/gems/server/lib/itsi/server/config/options/watch.rb +28 -0
  258. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  259. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  260. data/gems/server/lib/itsi/server/config/options/workers.md +1 -2
  261. data/gems/server/lib/itsi/server/config/options/workers.rb +1 -1
  262. data/gems/server/lib/itsi/server/config/typed_struct.rb +59 -20
  263. data/gems/server/lib/itsi/server/config.rb +77 -48
  264. data/gems/server/lib/itsi/server/default_config/Itsi.rb +3 -3
  265. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +1 -1
  266. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +11 -4
  267. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +3 -3
  268. data/gems/server/lib/itsi/server/route_tester.rb +58 -8
  269. data/gems/server/lib/itsi/server/signal_trap.rb +1 -1
  270. data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +14 -18
  271. data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +5 -4
  272. data/gems/server/lib/itsi/server/typed_handlers.rb +12 -4
  273. data/gems/server/lib/itsi/server/version.rb +1 -1
  274. data/gems/server/lib/itsi/server.rb +98 -14
  275. data/gems/server/lib/ruby_lsp/itsi/addon.rb +20 -18
  276. data/gems/server/test/helpers/test_helper.rb +89 -29
  277. data/gems/server/test/middleware/allow_list.rb +128 -0
  278. data/gems/server/test/middleware/auth_api_key.rb +141 -0
  279. data/gems/server/test/middleware/auth_basic.rb +91 -0
  280. data/gems/server/test/middleware/auth_jwt.rb +214 -0
  281. data/gems/server/test/middleware/cache_control.rb +82 -0
  282. data/gems/server/test/middleware/cidr_to_regex.rb +46 -0
  283. data/gems/server/test/middleware/compression.rb +89 -0
  284. data/gems/server/test/middleware/cors.rb +113 -0
  285. data/gems/server/test/middleware/csp.rb +62 -0
  286. data/gems/server/test/middleware/deny_list.rb +131 -0
  287. data/gems/server/test/middleware/endpoint.rb +300 -0
  288. data/gems/server/test/middleware/etag.rb +75 -0
  289. data/gems/server/test/middleware/grpc/grpc.rb +158 -0
  290. data/gems/server/test/middleware/grpc/test_service.proto +32 -0
  291. data/gems/server/test/middleware/grpc/test_service_impl.rb +28 -0
  292. data/gems/server/test/middleware/grpc/test_service_pb.rb +18 -0
  293. data/gems/server/test/middleware/grpc/test_service_services_pb.rb +30 -0
  294. data/gems/server/test/middleware/header_interpolation.rb +35 -0
  295. data/gems/server/test/middleware/intrusion_protection.rb +259 -0
  296. data/gems/server/test/middleware/location.rb +220 -0
  297. data/gems/server/test/middleware/max_body.rb +20 -0
  298. data/gems/server/test/middleware/proxy.rb +415 -0
  299. data/gems/server/test/middleware/rate_limit.rb +211 -0
  300. data/gems/server/test/middleware/redirect.rb +85 -0
  301. data/gems/server/test/middleware/request_headers.rb +50 -0
  302. data/gems/server/test/middleware/response_headers.rb +50 -0
  303. data/gems/server/test/middleware/static_assets.rb +374 -0
  304. data/gems/server/test/middleware/static_response.rb +56 -0
  305. data/gems/server/test/middleware/string_rewrite.rb +112 -0
  306. data/gems/server/test/options/bind.rb +47 -0
  307. data/gems/server/test/options/header_read_timeout.rb +23 -0
  308. data/gems/server/test/options/test_request_timeout.rb +16 -0
  309. data/gems/server/test/options/test_workers.rb +2 -4
  310. data/gems/server/test/{test_itsi_server.rb → rack/test_rack_server.rb} +2 -2
  311. data/grpc_test/Itsi.rb +11 -0
  312. data/grpc_test/echo.proto +14 -0
  313. data/grpc_test/echo_pb.rb +16 -0
  314. data/grpc_test/echo_service_impl.rb +8 -0
  315. data/grpc_test/echo_services_pb.rb +22 -0
  316. data/lib/itsi/version.rb +1 -1
  317. data/tasks.txt +15 -72
  318. metadata +210 -7
  319. data/gems/server/lib/itsi/server/default_config/Itsi-rackup.rb +0 -119
@@ -7,7 +7,7 @@ use crate::{
7
7
  },
8
8
  };
9
9
  use derive_more::Debug;
10
- use futures::executor::block_on;
10
+ use itsi_error::ItsiError;
11
11
  use itsi_rb_helpers::{call_with_gvl, print_rb_backtrace, HeapValue};
12
12
  use itsi_tracing::{set_format, set_level, set_target, set_target_filters};
13
13
  use magnus::{
@@ -25,7 +25,11 @@ use std::{
25
25
  collections::HashMap,
26
26
  os::fd::{AsRawFd, OwnedFd, RawFd},
27
27
  path::PathBuf,
28
- sync::{Arc, OnceLock},
28
+ str::FromStr,
29
+ sync::{
30
+ atomic::{AtomicBool, Ordering::Relaxed},
31
+ Arc, OnceLock,
32
+ },
29
33
  time::Duration,
30
34
  };
31
35
  use tracing::{debug, error};
@@ -71,8 +75,33 @@ pub struct ServerParams {
71
75
  #[debug(skip)]
72
76
  pub(crate) listeners: Mutex<Vec<Listener>>,
73
77
  listener_info: Mutex<HashMap<String, i32>>,
78
+ pub itsi_server_token_preference: ItsiServerTokenPreference,
79
+ pub preloaded: AtomicBool,
80
+ socket_opts: SocketOpts,
81
+ preexisting_listeners: Option<String>,
82
+ }
83
+
84
+ #[derive(Debug, Clone)]
85
+ pub enum ItsiServerTokenPreference {
86
+ Version,
87
+ Name,
88
+ None,
89
+ }
90
+
91
+ impl FromStr for ItsiServerTokenPreference {
92
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
93
+ Ok(match s {
94
+ "version" => ItsiServerTokenPreference::Version,
95
+ "name" => ItsiServerTokenPreference::Name,
96
+ "none" => ItsiServerTokenPreference::None,
97
+ _ => ItsiServerTokenPreference::Version,
98
+ })
99
+ }
100
+
101
+ type Err = ItsiError;
74
102
  }
75
103
 
104
+ #[derive(Debug, Clone)]
76
105
  pub struct SocketOpts {
77
106
  pub reuse_address: bool,
78
107
  pub reuse_port: bool,
@@ -83,8 +112,10 @@ pub struct SocketOpts {
83
112
 
84
113
  impl ServerParams {
85
114
  pub fn preload_ruby(self: &Arc<Self>) -> Result<()> {
115
+ if self.preloaded.load(Relaxed) {
116
+ return Ok(());
117
+ }
86
118
  call_with_gvl(|ruby| -> Result<()> {
87
- debug!("Preloading Ruby");
88
119
  if self
89
120
  .scheduler_class
90
121
  .as_ref()
@@ -103,9 +134,7 @@ impl ServerParams {
103
134
  }
104
135
  })?
105
136
  .map(|mw| mw.into());
106
- debug!("Middleware routes returned");
107
137
  let middleware = MiddlewareSet::new(routes_raw)?;
108
- debug!("Middleware loaded");
109
138
  self.middleware.set(middleware).map_err(|_| {
110
139
  magnus::Error::new(
111
140
  magnus::exception::runtime_error(),
@@ -114,6 +143,7 @@ impl ServerParams {
114
143
  })?;
115
144
  Ok(())
116
145
  })?;
146
+ self.preloaded.store(true, Relaxed);
117
147
  Ok(())
118
148
  }
119
149
 
@@ -154,11 +184,11 @@ impl ServerParams {
154
184
  .transpose()?
155
185
  .unwrap_or_default();
156
186
  let preload: bool = rb_param_hash.fetch("preload")?;
157
- let request_timeout: Option<u64> = rb_param_hash.fetch("request_timeout")?;
158
- let request_timeout = request_timeout.map(Duration::from_secs);
187
+ let request_timeout: Option<f64> = rb_param_hash.fetch("request_timeout")?;
188
+ let request_timeout = request_timeout.map(Duration::from_secs_f64);
159
189
  let header_read_timeout: Duration = rb_param_hash
160
- .fetch::<_, Option<u64>>("header_read_timeout")?
161
- .map(Duration::from_secs)
190
+ .fetch::<_, Option<f64>>("header_read_timeout")?
191
+ .map(Duration::from_secs_f64)
162
192
  .unwrap_or(Duration::from_secs(1));
163
193
 
164
194
  let notify_watchers: Option<Vec<(String, Vec<Vec<String>>)>> =
@@ -226,6 +256,12 @@ impl ServerParams {
226
256
  .map(|s| s.parse())
227
257
  .collect::<itsi_error::Result<Vec<Bind>>>()?;
228
258
 
259
+ let itsi_server_token_preference: String = rb_param_hash
260
+ .fetch("itsi_server_token_preference")
261
+ .unwrap_or_default();
262
+ let itsi_server_token_preference: ItsiServerTokenPreference =
263
+ itsi_server_token_preference.parse()?;
264
+
229
265
  let socket_opts = SocketOpts {
230
266
  reuse_address,
231
267
  reuse_port,
@@ -233,10 +269,42 @@ impl ServerParams {
233
269
  nodelay,
234
270
  recv_buffer_size,
235
271
  };
236
- let listeners = if let Some(preexisting_listeners) =
237
- rb_param_hash.delete::<_, Option<String>>("listeners")?
238
- {
239
- let bind_to_fd_map: HashMap<String, i32> = serde_json::from_str(&preexisting_listeners)
272
+ let preexisting_listeners = rb_param_hash.delete::<_, Option<String>>("listeners")?;
273
+
274
+ let params = ServerParams {
275
+ workers,
276
+ worker_memory_limit,
277
+ silence,
278
+ multithreaded_reactor,
279
+ pin_worker_cores,
280
+ shutdown_timeout,
281
+ hooks,
282
+ preload,
283
+ request_timeout,
284
+ header_read_timeout,
285
+ notify_watchers,
286
+ threads,
287
+ scheduler_threads,
288
+ streamable_body,
289
+ scheduler_class,
290
+ oob_gc_responses_threshold,
291
+ binds,
292
+ itsi_server_token_preference,
293
+ socket_opts,
294
+ preexisting_listeners,
295
+ listener_info: Mutex::new(HashMap::new()),
296
+ listeners: Mutex::new(Vec::new()),
297
+ middleware_loader: middleware_loader.into(),
298
+ middleware: OnceLock::new(),
299
+ preloaded: AtomicBool::new(false),
300
+ };
301
+
302
+ Ok(params)
303
+ }
304
+
305
+ pub fn setup_listeners(&self) -> Result<()> {
306
+ let listeners = if let Some(preexisting_listeners) = self.preexisting_listeners.as_ref() {
307
+ let bind_to_fd_map: HashMap<String, i32> = serde_json::from_str(preexisting_listeners)
240
308
  .map_err(|e| {
241
309
  magnus::Error::new(
242
310
  magnus::exception::standard_error(),
@@ -244,24 +312,24 @@ impl ServerParams {
244
312
  )
245
313
  })?;
246
314
 
247
- binds
315
+ self.binds
248
316
  .iter()
249
317
  .cloned()
250
318
  .map(|bind| {
251
319
  if let Some(fd) = bind_to_fd_map.get(&bind.listener_address_string()) {
252
- Listener::inherit_fd(bind, *fd, &socket_opts)
320
+ Listener::inherit_fd(bind, *fd, &self.socket_opts)
253
321
  } else {
254
- Listener::build(bind, &socket_opts)
322
+ Listener::build(bind, &self.socket_opts)
255
323
  }
256
324
  })
257
325
  .collect::<std::result::Result<Vec<Listener>, _>>()?
258
326
  .into_iter()
259
327
  .collect::<Vec<_>>()
260
328
  } else {
261
- binds
329
+ self.binds
262
330
  .iter()
263
331
  .cloned()
264
- .map(|b| Listener::build(b, &socket_opts))
332
+ .map(|b| Listener::build(b, &self.socket_opts))
265
333
  .collect::<std::result::Result<Vec<Listener>, _>>()?
266
334
  .into_iter()
267
335
  .collect::<Vec<_>>()
@@ -276,29 +344,9 @@ impl ServerParams {
276
344
  })
277
345
  .collect::<Result<HashMap<String, i32>>>()?;
278
346
 
279
- Ok(ServerParams {
280
- workers,
281
- worker_memory_limit,
282
- silence,
283
- multithreaded_reactor,
284
- pin_worker_cores,
285
- shutdown_timeout,
286
- hooks,
287
- preload,
288
- request_timeout,
289
- header_read_timeout,
290
- notify_watchers,
291
- threads,
292
- scheduler_threads,
293
- streamable_body,
294
- scheduler_class,
295
- oob_gc_responses_threshold,
296
- binds,
297
- listener_info: Mutex::new(listener_info),
298
- listeners: Mutex::new(listeners),
299
- middleware_loader: middleware_loader.into(),
300
- middleware: OnceLock::new(),
301
- })
347
+ *self.listener_info.lock() = listener_info;
348
+ *self.listeners.lock() = listeners;
349
+ Ok(())
302
350
  }
303
351
  }
304
352
 
@@ -310,28 +358,34 @@ impl ItsiServerConfig {
310
358
  itsi_config_proc: Option<Proc>,
311
359
  ) -> Result<Self> {
312
360
  let itsi_config_proc = Arc::new(itsi_config_proc.map(HeapValue::from));
313
- let server_params = Self::combine_params(
361
+ match Self::combine_params(
314
362
  ruby,
315
363
  cli_params,
316
364
  itsifile_path.as_ref(),
317
365
  itsi_config_proc.clone(),
318
- )?;
319
-
320
- cli_params.delete::<_, Value>(Symbol::new("listeners"))?;
366
+ ) {
367
+ Ok(server_params) => {
368
+ cli_params.delete::<_, Value>(Symbol::new("listeners"))?;
321
369
 
322
- let watcher_fd = if let Some(watchers) = server_params.notify_watchers.clone() {
323
- file_watcher::watch_groups(watchers)?
324
- } else {
325
- None
326
- };
327
-
328
- Ok(ItsiServerConfig {
329
- cli_params: Arc::new(cli_params.into()),
330
- server_params: RwLock::new(server_params.clone()).into(),
331
- itsi_config_proc,
332
- itsifile_path,
333
- watcher_fd: watcher_fd.into(),
334
- })
370
+ let watcher_fd = if let Some(watchers) = server_params.notify_watchers.clone() {
371
+ file_watcher::watch_groups(watchers)?
372
+ } else {
373
+ None
374
+ };
375
+
376
+ Ok(ItsiServerConfig {
377
+ cli_params: Arc::new(cli_params.into()),
378
+ server_params: RwLock::new(server_params.clone()).into(),
379
+ itsi_config_proc,
380
+ itsifile_path,
381
+ watcher_fd: watcher_fd.into(),
382
+ })
383
+ }
384
+ Err(err) => Err(magnus::Error::new(
385
+ magnus::exception::standard_error(),
386
+ format!("Error loading initial configuration {:?}", err),
387
+ )),
388
+ }
335
389
  }
336
390
 
337
391
  /// Reload
@@ -397,7 +451,7 @@ impl ItsiServerConfig {
397
451
  Ok(())
398
452
  }
399
453
 
400
- pub fn get_config_errors(&self) -> Option<Vec<String>> {
454
+ pub async fn get_config_errors(&self) -> Option<Vec<String>> {
401
455
  let rb_param_hash = call_with_gvl(|ruby| {
402
456
  let inner = self
403
457
  .itsi_config_proc
@@ -424,8 +478,13 @@ impl ItsiServerConfig {
424
478
  let err_val = call_with_gvl(|_| format!("{}", err));
425
479
  return Some(vec![err_val]);
426
480
  }
427
- if let Err(err) =
428
- block_on(params_arc.middleware.get().unwrap().initialize_layers())
481
+
482
+ if let Err(err) = params_arc
483
+ .middleware
484
+ .get()
485
+ .unwrap()
486
+ .initialize_layers()
487
+ .await
429
488
  {
430
489
  let err_val = call_with_gvl(|_| format!("{}", err));
431
490
  return Some(vec![err_val]);
@@ -477,8 +536,8 @@ impl ItsiServerConfig {
477
536
  }
478
537
  }
479
538
 
480
- pub fn check_config(&self) -> bool {
481
- if let Some(errors) = self.get_config_errors() {
539
+ pub async fn check_config(&self) -> bool {
540
+ if let Some(errors) = self.get_config_errors().await {
482
541
  Self::print_config_errors(errors);
483
542
  return false;
484
543
  }
@@ -42,6 +42,7 @@ impl ItsiServer {
42
42
 
43
43
  #[instrument(skip(self))]
44
44
  pub fn start(&self) -> Result<()> {
45
+ self.config.lock().server_params.read().setup_listeners()?;
45
46
  let result = if self.config.lock().server_params.read().silence {
46
47
  run_silently(|| self.build_and_run_strategy())
47
48
  } else {
@@ -49,6 +50,7 @@ impl ItsiServer {
49
50
  self.build_and_run_strategy()
50
51
  };
51
52
  if let Err(e) = result {
53
+ error!("Error starting server: {:?}", e);
52
54
  if let Some(err_value) = e.value() {
53
55
  print_rb_backtrace(err_value);
54
56
  }
@@ -10,6 +10,7 @@ use std::{
10
10
  path::PathBuf,
11
11
  str::FromStr,
12
12
  };
13
+ use tracing::{instrument, Level};
13
14
 
14
15
  #[derive(Debug, Clone)]
15
16
  pub enum BindAddress {
@@ -86,6 +87,7 @@ impl std::fmt::Debug for Bind {
86
87
  impl FromStr for Bind {
87
88
  type Err = ItsiError;
88
89
 
90
+ #[instrument(ret(level = Level::DEBUG))]
89
91
  fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
90
92
  let (protocol, remainder) = if let Some((proto, rest)) = s.split_once("://") {
91
93
  (proto.parse::<BindProtocol>()?, rest)
@@ -180,6 +182,7 @@ fn parse_bind_options(query: &str) -> HashMap<String, String> {
180
182
  }
181
183
 
182
184
  /// Attempts to resolve a hostname into an IP address.
185
+ #[instrument(ret(level = Level::DEBUG))]
183
186
  fn resolve_hostname(hostname: &str) -> Option<IpAddr> {
184
187
  (hostname, 0)
185
188
  .to_socket_addrs()
@@ -418,8 +418,12 @@ fn connect_tcp_socket(addr: IpAddr, port: u16, socket_opts: &SocketOpts) -> Resu
418
418
  .set_recv_buffer_size(socket_opts.recv_buffer_size)
419
419
  .ok();
420
420
  socket.set_only_v6(false).ok();
421
- socket.bind(&socket_address.into())?;
422
- socket.listen(socket_opts.listen_backlog as i32)?;
421
+ if let Err(e) = socket.bind(&socket_address.into()) {
422
+ error!("Failed to bind socket: {}", e);
423
+ };
424
+ if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
425
+ error!("Failed to listen on socket: {}", e);
426
+ };
423
427
  Ok(socket.into())
424
428
  }
425
429
 
@@ -430,8 +434,11 @@ fn connect_unix_socket(path: &PathBuf, socket_opts: &SocketOpts) -> Result<UnixL
430
434
 
431
435
  let socket_address = socket2::SockAddr::unix(path)?;
432
436
 
433
- socket.bind(&socket_address)?;
434
- socket.listen(socket_opts.listen_backlog as i32)?;
435
-
437
+ if let Err(e) = socket.bind(&socket_address) {
438
+ error!("Failed to bind socket: {}", e);
439
+ };
440
+ if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
441
+ error!("Failed to listen on socket: {}", e);
442
+ };
436
443
  Ok(socket.into())
437
444
  }
@@ -3,8 +3,10 @@ use itsi_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
3
3
  use itsi_error::Result;
4
4
  use itsi_tracing::info;
5
5
  use locked_dir_cache::LockedDirCache;
6
+ use rcgen::ExtendedKeyUsagePurpose;
6
7
  use rcgen::{
7
- BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, SanType,
8
+ BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, KeyUsagePurpose,
9
+ SanType,
8
10
  };
9
11
  use rustls::{
10
12
  pki_types::{CertificateDer, PrivateKeyDer},
@@ -228,13 +230,14 @@ pub fn generate_ca_signed_cert(
228
230
  .push(DnType::CommonName, domains[0].clone());
229
231
 
230
232
  ee_params.use_authority_key_identifier_extension = true;
233
+ ee_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
231
234
 
232
235
  let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ca_kp).unwrap();
233
236
  let ee_cert_der = ee_cert.der().to_vec();
234
237
  let ee_cert = CertificateDer::from(ee_cert_der);
235
- let ca_cert = CertificateDer::from(ca_cert.der().to_vec());
238
+
236
239
  Ok((
237
- vec![ee_cert, ca_cert],
240
+ vec![ee_cert],
238
241
  PrivateKeyDer::try_from(ee_key.serialize_der()).unwrap(),
239
242
  ))
240
243
  }
@@ -253,12 +256,17 @@ fn get_or_create_local_dev_ca() -> Result<(String, String)> {
253
256
 
254
257
  Ok((key_pem, cert_pem))
255
258
  } else {
256
- let subject_alt_names = vec!["dev.itsi.fyi".to_string(), "localhost".to_string()];
259
+ let subject_alt_names = vec!["ca.itsi.fyi".to_string(), "localhost".to_string()];
257
260
  let mut params = CertificateParams::new(subject_alt_names)?;
258
261
  let mut distinguished_name = DistinguishedName::new();
259
- distinguished_name.push(DnType::CommonName, "Itsi Development CA");
262
+ distinguished_name.push(DnType::CommonName, "ca.itsi.fyi");
260
263
  params.distinguished_name = distinguished_name;
261
264
  params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
265
+ params.key_usages = vec![
266
+ KeyUsagePurpose::KeyCertSign,
267
+ KeyUsagePurpose::CrlSign,
268
+ KeyUsagePurpose::DigitalSignature, // useful for OCSP/CRL signing
269
+ ];
262
270
  let key_pair = KeyPair::generate()?;
263
271
  let cert = params.self_signed(&key_pair)?;
264
272
 
@@ -1,23 +1,23 @@
1
+ use super::{token_source::TokenSource, ErrorResponse, FromValue, MiddlewareLayer};
1
2
  use crate::{
2
3
  server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
3
4
  services::itsi_http_service::HttpRequestContext,
4
5
  };
5
-
6
- use super::{ErrorResponse, FromValue, MiddlewareLayer};
7
-
8
6
  use async_trait::async_trait;
9
7
  use either::Either;
10
8
  use itsi_error::ItsiError;
11
9
  use magnus::error::Result;
12
10
  use regex::RegexSet;
13
11
  use serde::Deserialize;
14
- use std::sync::OnceLock;
12
+ use std::{collections::HashMap, sync::OnceLock};
13
+ use tracing::debug;
15
14
 
16
15
  #[derive(Debug, Clone, Deserialize)]
17
16
  pub struct AllowList {
18
17
  #[serde(skip_deserializing)]
19
18
  pub allowed_ips: OnceLock<RegexSet>,
20
19
  pub allowed_patterns: Vec<String>,
20
+ pub trusted_proxies: HashMap<String, TokenSource>,
21
21
  #[serde(default = "forbidden_error_response")]
22
22
  pub error_response: ErrorResponse,
23
23
  }
@@ -42,7 +42,14 @@ impl MiddlewareLayer for AllowList {
42
42
  context: &mut HttpRequestContext,
43
43
  ) -> Result<Either<HttpRequest, HttpResponse>> {
44
44
  if let Some(allowed_ips) = self.allowed_ips.get() {
45
- if !allowed_ips.is_match(&context.addr) {
45
+ let addr = if self.trusted_proxies.contains_key(&context.addr) {
46
+ let source = self.trusted_proxies.get(&context.addr).unwrap();
47
+ source.extract_token(&req).unwrap_or(&context.addr)
48
+ } else {
49
+ &context.addr
50
+ };
51
+ if !allowed_ips.is_match(addr) {
52
+ debug!(target: "middleware::allow_list", "IP address {} is not allowed", addr);
46
53
  return Ok(Either::Right(
47
54
  self.error_response
48
55
  .to_http_response(req.accept().into())
@@ -11,6 +11,7 @@ use async_trait::async_trait;
11
11
  use either::Either;
12
12
  use magnus::error::Result;
13
13
  use serde::Deserialize;
14
+ use tracing::debug;
14
15
 
15
16
  type PasswordHash = String;
16
17
 
@@ -51,6 +52,8 @@ impl MiddlewareLayer for AuthAPIKey {
51
52
  }
52
53
  TokenSource::Query(query_name) => req.query_param(query_name),
53
54
  } {
55
+ debug!(target: "middleware::auth_api_key", "API Key Retrieved. Anonymous {}", self.key_id_source.is_none());
56
+
54
57
  if let Some(key_id) = self.key_id_source.as_ref() {
55
58
  let key_id = match &key_id {
56
59
  TokenSource::Header { name, prefix } => {
@@ -66,17 +69,21 @@ impl MiddlewareLayer for AuthAPIKey {
66
69
  }
67
70
  TokenSource::Query(query_name) => req.query_param(query_name),
68
71
  };
72
+ debug!(target: "middleware::auth_api_key", "Key ID Retrieved");
69
73
  if let Some(hash) = key_id.and_then(|kid| self.valid_keys.get(kid)) {
74
+ debug!(target: "middleware::auth_api_key", "Key for ID found");
70
75
  if password_hasher::verify_password_hash(submitted_key, hash).is_ok_and(|v| v) {
71
76
  return Ok(Either::Left(req));
72
77
  }
73
78
  }
74
- } else if self.valid_keys.iter().any(|(_key_id, key)| {
79
+ } else if self.valid_keys.values().any(|key| {
75
80
  password_hasher::verify_password_hash(submitted_key, key).is_ok_and(|v| v)
76
81
  }) {
77
82
  return Ok(Either::Left(req));
78
83
  }
79
84
  }
85
+
86
+ debug!(target: "middleware::auth_api_key", "Failed to authenticate API key");
80
87
  Ok(Either::Right(
81
88
  self.error_response
82
89
  .to_http_response(req.accept().into())
@@ -8,6 +8,7 @@ use magnus::error::Result;
8
8
  use serde::{Deserialize, Serialize};
9
9
  use std::collections::HashMap;
10
10
  use std::str;
11
+ use tracing::debug;
11
12
 
12
13
  use crate::{
13
14
  server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
@@ -48,6 +49,7 @@ impl MiddlewareLayer for AuthBasic {
48
49
  let auth_header = req.header("Authorization");
49
50
 
50
51
  if !auth_header.is_some_and(|header| header.starts_with("Basic ")) {
52
+ debug!(target: "middleware::auth_basic", "Basic auth failed. Authorization Header doesn't start with 'Basic '");
51
53
  return Ok(Either::Right(self.basic_auth_failed_response()));
52
54
  }
53
55
 
@@ -57,6 +59,7 @@ impl MiddlewareLayer for AuthBasic {
57
59
  let decoded = match general_purpose::STANDARD.decode(encoded_credentials) {
58
60
  Ok(bytes) => bytes,
59
61
  Err(_) => {
62
+ debug!(target: "middleware::auth_basic", "Basic auth failed. Decoding failed");
60
63
  return Ok(Either::Right(self.basic_auth_failed_response()));
61
64
  }
62
65
  };
@@ -64,6 +67,7 @@ impl MiddlewareLayer for AuthBasic {
64
67
  let decoded_str = match str::from_utf8(&decoded) {
65
68
  Ok(s) => s,
66
69
  Err(_) => {
70
+ debug!(target: "middleware::auth_basic", "Basic auth failed. Decoding failed");
67
71
  return Ok(Either::Right(self.basic_auth_failed_response()));
68
72
  }
69
73
  };
@@ -71,6 +75,7 @@ impl MiddlewareLayer for AuthBasic {
71
75
  let mut parts = decoded_str.splitn(2, ':');
72
76
  let username = parts.next().unwrap_or("");
73
77
  let password = parts.next().unwrap_or("");
78
+
74
79
  match self.credential_pairs.get(username) {
75
80
  Some(expected_password_hash) => {
76
81
  match verify_password_hash(password, expected_password_hash) {
@@ -78,7 +83,10 @@ impl MiddlewareLayer for AuthBasic {
78
83
  _ => Ok(Either::Right(self.basic_auth_failed_response())),
79
84
  }
80
85
  }
81
- None => Ok(Either::Right(self.basic_auth_failed_response())),
86
+ None => {
87
+ debug!(target: "middleware::auth_basic", "Basic auth failed. Username {} not found", username);
88
+ Ok(Either::Right(self.basic_auth_failed_response()))
89
+ }
82
90
  }
83
91
  }
84
92
  }