itsi 0.1.20 → 0.2.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 (323) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -8
  3. data/Cargo.lock +29 -30
  4. data/LICENSE.txt +698 -0
  5. data/README.md +16 -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 +148 -66
  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 +2 -3
  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/directory_listing.jpg +0 -0
  87. data/docs/content/error_page.jpg +0 -0
  88. data/docs/content/faqs/_index.md +5 -3
  89. data/docs/content/features/_index.md +56 -50
  90. data/docs/content/getting_started/_index.md +8 -5
  91. data/docs/content/getting_started/local_development.md +76 -9
  92. data/docs/content/getting_started/logging.md +15 -9
  93. data/docs/content/getting_started/running_itsi_in_production.md +5 -3
  94. data/docs/content/getting_started/signals.md +37 -0
  95. data/docs/content/itsi_scheduler/_index.md +8 -7
  96. data/docs/content/utilities/_index.md +13 -0
  97. data/docs/content/utilities/config_file_testing.md +17 -0
  98. data/docs/content/utilities/passfile_generator.md +41 -0
  99. data/docs/content/utilities/route_testing.md +27 -0
  100. data/docs/content/utilities/secrets_management.md +30 -0
  101. data/docs/hugo.yaml +4 -1
  102. data/fairytale.txt +3 -4
  103. data/gems/scheduler/Cargo.lock +74 -17
  104. data/gems/scheduler/README.md +4 -5
  105. data/gems/scheduler/Rakefile +0 -4
  106. data/gems/scheduler/itsi-scheduler.gemspec +2 -2
  107. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  108. data/gems/scheduler/lib/itsi/scheduler.rb +9 -4
  109. data/gems/scheduler/test/test_active_record.rb +12 -7
  110. data/gems/server/Cargo.lock +28 -29
  111. data/gems/server/Rakefile +0 -4
  112. data/gems/server/exe/itsi +13 -2
  113. data/gems/server/itsi-server.gemspec +2 -2
  114. data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +2 -0
  115. data/gems/server/lib/itsi/http_request.rb +58 -30
  116. data/gems/server/lib/itsi/http_response.rb +10 -7
  117. data/gems/server/lib/itsi/passfile.rb +6 -7
  118. data/gems/server/lib/itsi/server/config/config_helpers.rb +41 -29
  119. data/gems/server/lib/itsi/server/config/dsl.rb +22 -442
  120. data/gems/server/lib/itsi/server/config/known_paths.rb +14 -7
  121. data/gems/server/lib/itsi/server/config/middleware/_index.md +6 -4
  122. data/gems/server/lib/itsi/server/config/middleware/allow_list.md +46 -0
  123. data/gems/server/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  124. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  125. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  126. data/gems/server/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  127. data/gems/server/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
  128. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  129. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  130. data/gems/server/lib/itsi/server/config/middleware/cache_control.md +78 -0
  131. data/gems/server/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  132. data/gems/server/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  133. data/gems/server/lib/itsi/server/config/middleware/compression.md +50 -0
  134. data/gems/server/lib/itsi/server/config/middleware/compression.rb +37 -0
  135. data/gems/server/lib/itsi/server/config/middleware/cors.md +93 -0
  136. data/gems/server/lib/itsi/server/config/middleware/cors.rb +32 -0
  137. data/gems/server/lib/itsi/server/config/middleware/csp.md +37 -0
  138. data/gems/server/lib/itsi/server/config/middleware/csp.rb +44 -0
  139. data/gems/server/lib/itsi/server/config/middleware/deny_list.md +45 -0
  140. data/gems/server/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  141. data/gems/server/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
  142. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  143. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  144. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  145. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
  146. data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
  147. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  148. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
  149. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  150. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  151. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  152. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
  153. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  154. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
  155. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  156. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
  157. data/gems/server/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  158. data/gems/server/lib/itsi/server/config/middleware/error_response.md +74 -0
  159. data/gems/server/lib/itsi/server/config/middleware/error_response.rb +36 -0
  160. data/gems/server/lib/itsi/server/config/middleware/etag.md +59 -0
  161. data/gems/server/lib/itsi/server/config/middleware/etag.rb +27 -0
  162. data/gems/server/lib/itsi/server/config/middleware/grpc.md +172 -0
  163. data/gems/server/lib/itsi/server/config/middleware/grpc.rb +54 -0
  164. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  165. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  166. data/gems/server/lib/itsi/server/config/middleware/location.md +107 -0
  167. data/gems/server/lib/itsi/server/config/middleware/location.rb +99 -0
  168. data/gems/server/lib/itsi/server/config/middleware/log_requests.md +13 -11
  169. data/gems/server/lib/itsi/server/config/middleware/log_requests.rb +1 -3
  170. data/gems/server/lib/itsi/server/config/middleware/max_body.md +18 -0
  171. data/gems/server/lib/itsi/server/config/middleware/max_body.rb +21 -0
  172. data/gems/server/lib/itsi/server/config/middleware/proxy.md +62 -0
  173. data/gems/server/lib/itsi/server/config/middleware/proxy.rb +41 -0
  174. data/gems/server/lib/itsi/server/config/middleware/rackup_file.md +54 -0
  175. data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
  176. data/gems/server/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  177. data/gems/server/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  178. data/gems/server/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  179. data/gems/server/lib/itsi/server/config/middleware/redirect.md +55 -0
  180. data/gems/server/lib/itsi/server/config/middleware/redirect.rb +25 -0
  181. data/gems/server/lib/itsi/server/config/middleware/request_headers.md +34 -0
  182. data/gems/server/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  183. data/gems/server/lib/itsi/server/config/middleware/response_headers.md +33 -0
  184. data/gems/server/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  185. data/gems/server/lib/itsi/server/config/middleware/run.md +60 -0
  186. data/gems/server/lib/itsi/server/config/middleware/run.rb +43 -0
  187. data/gems/server/lib/itsi/server/config/middleware/static_assets.md +113 -0
  188. data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +87 -0
  189. data/gems/server/lib/itsi/server/config/middleware/static_response.md +44 -0
  190. data/gems/server/lib/itsi/server/config/middleware/static_response.rb +29 -0
  191. data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
  192. data/gems/server/lib/itsi/server/config/middleware/token_source.rb +32 -0
  193. data/gems/server/lib/itsi/server/config/middleware.rb +4 -0
  194. data/gems/server/lib/itsi/server/config/option.rb +4 -0
  195. data/gems/server/lib/itsi/server/config/options/_index.md +3 -2
  196. data/gems/server/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  197. data/gems/server/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
  198. data/gems/server/lib/itsi/server/config/options/bind.md +71 -0
  199. data/gems/server/lib/itsi/server/config/options/bind.rb +26 -0
  200. data/gems/server/lib/itsi/server/config/options/certificates.md +65 -0
  201. data/gems/server/lib/itsi/server/config/options/daemonize.md +14 -0
  202. data/gems/server/lib/itsi/server/config/options/daemonize.rb +19 -0
  203. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.md +1 -2
  204. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.rb +6 -3
  205. data/gems/server/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  206. data/gems/server/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  207. data/gems/server/lib/itsi/server/config/options/hooks/_index.md +11 -0
  208. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  209. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  210. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  211. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  212. data/gems/server/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  213. data/gems/server/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  214. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  215. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  216. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  217. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  218. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  219. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  220. data/gems/server/lib/itsi/server/config/options/include.md +20 -0
  221. data/gems/server/lib/itsi/server/config/options/include.rb +36 -0
  222. data/gems/server/lib/itsi/server/config/options/listen_backlog.md +11 -0
  223. data/gems/server/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  224. data/gems/server/lib/itsi/server/config/options/log_format.md +18 -0
  225. data/gems/server/lib/itsi/server/config/options/log_format.rb +19 -0
  226. data/gems/server/lib/itsi/server/config/options/log_level.md +34 -0
  227. data/gems/server/lib/itsi/server/config/options/log_level.rb +20 -0
  228. data/gems/server/lib/itsi/server/config/options/log_target.md +38 -0
  229. data/gems/server/lib/itsi/server/config/options/log_target.rb +19 -0
  230. data/gems/server/lib/itsi/server/config/options/log_target_filters.md +17 -0
  231. data/gems/server/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  232. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  233. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  234. data/gems/server/lib/itsi/server/config/options/nodelay.md +16 -0
  235. data/gems/server/lib/itsi/server/config/options/nodelay.rb +19 -0
  236. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  237. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  238. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  239. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  240. data/gems/server/lib/itsi/server/config/options/preload.md +21 -0
  241. data/gems/server/lib/itsi/server/config/options/preload.rb +18 -0
  242. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  243. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  244. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  245. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  246. data/gems/server/lib/itsi/server/config/options/request_timeout.md +23 -0
  247. data/gems/server/lib/itsi/server/config/options/request_timeout.rb +19 -0
  248. data/gems/server/lib/itsi/server/config/options/reuse_address.md +16 -0
  249. data/gems/server/lib/itsi/server/config/options/reuse_address.rb +19 -0
  250. data/gems/server/lib/itsi/server/config/options/reuse_port.md +16 -0
  251. data/gems/server/lib/itsi/server/config/options/reuse_port.rb +19 -0
  252. data/gems/server/lib/itsi/server/config/options/scheduler_threads.md +34 -0
  253. data/gems/server/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  254. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  255. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  256. data/gems/server/lib/itsi/server/config/options/stream_body.md +32 -0
  257. data/gems/server/lib/itsi/server/config/options/stream_body.rb +18 -0
  258. data/gems/server/lib/itsi/server/config/options/threads.md +7 -2
  259. data/gems/server/lib/itsi/server/config/options/threads.rb +1 -1
  260. data/gems/server/lib/itsi/server/config/options/watch.md +16 -0
  261. data/gems/server/lib/itsi/server/config/options/watch.rb +28 -0
  262. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  263. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  264. data/gems/server/lib/itsi/server/config/options/workers.md +1 -2
  265. data/gems/server/lib/itsi/server/config/options/workers.rb +1 -1
  266. data/gems/server/lib/itsi/server/config/typed_struct.rb +68 -32
  267. data/gems/server/lib/itsi/server/config.rb +163 -119
  268. data/gems/server/lib/itsi/server/default_app/default_app.rb +1 -1
  269. data/gems/server/lib/itsi/server/default_config/Itsi.rb +3 -3
  270. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +4 -5
  271. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +10 -4
  272. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +2 -3
  273. data/gems/server/lib/itsi/server/rack_interface.rb +0 -1
  274. data/gems/server/lib/itsi/server/route_tester.rb +61 -9
  275. data/gems/server/lib/itsi/server/signal_trap.rb +1 -1
  276. data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +14 -18
  277. data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +13 -10
  278. data/gems/server/lib/itsi/server/typed_handlers.rb +12 -4
  279. data/gems/server/lib/itsi/server/version.rb +1 -1
  280. data/gems/server/lib/itsi/server.rb +111 -27
  281. data/gems/server/lib/itsi/standard_headers.rb +80 -80
  282. data/gems/server/lib/ruby_lsp/itsi/addon.rb +20 -18
  283. data/gems/server/test/helpers/test_helper.rb +90 -29
  284. data/gems/server/test/middleware/allow_list.rb +128 -0
  285. data/gems/server/test/middleware/auth_api_key.rb +141 -0
  286. data/gems/server/test/middleware/auth_basic.rb +91 -0
  287. data/gems/server/test/middleware/auth_jwt.rb +214 -0
  288. data/gems/server/test/middleware/cache_control.rb +82 -0
  289. data/gems/server/test/middleware/cidr_to_regex.rb +46 -0
  290. data/gems/server/test/middleware/compression.rb +89 -0
  291. data/gems/server/test/middleware/cors.rb +113 -0
  292. data/gems/server/test/middleware/csp.rb +62 -0
  293. data/gems/server/test/middleware/deny_list.rb +131 -0
  294. data/gems/server/test/middleware/endpoint.rb +300 -0
  295. data/gems/server/test/middleware/etag.rb +75 -0
  296. data/gems/server/test/middleware/grpc/grpc.rb +158 -0
  297. data/gems/server/test/middleware/grpc/test_service.proto +32 -0
  298. data/gems/server/test/middleware/grpc/test_service_impl.rb +28 -0
  299. data/gems/server/test/middleware/grpc/test_service_pb.rb +18 -0
  300. data/gems/server/test/middleware/grpc/test_service_services_pb.rb +30 -0
  301. data/gems/server/test/middleware/header_interpolation.rb +35 -0
  302. data/gems/server/test/middleware/intrusion_protection.rb +259 -0
  303. data/gems/server/test/middleware/location.rb +220 -0
  304. data/gems/server/test/middleware/max_body.rb +20 -0
  305. data/gems/server/test/middleware/proxy.rb +415 -0
  306. data/gems/server/test/middleware/rate_limit.rb +211 -0
  307. data/gems/server/test/middleware/redirect.rb +85 -0
  308. data/gems/server/test/middleware/request_headers.rb +50 -0
  309. data/gems/server/test/middleware/response_headers.rb +50 -0
  310. data/gems/server/test/middleware/static_assets.rb +374 -0
  311. data/gems/server/test/middleware/static_response.rb +56 -0
  312. data/gems/server/test/middleware/string_rewrite.rb +112 -0
  313. data/gems/server/test/middleware/test_log_requests.rb +54 -2
  314. data/gems/server/test/options/bind.rb +47 -0
  315. data/gems/server/test/options/header_read_timeout.rb +23 -0
  316. data/gems/server/test/options/test_request_timeout.rb +16 -0
  317. data/gems/server/test/options/test_workers.rb +11 -6
  318. data/gems/server/test/{test_itsi_server.rb → rack/test_rack_server.rb} +2 -2
  319. data/lib/itsi/version.rb +1 -1
  320. data/tasks.txt +15 -72
  321. metadata +209 -10
  322. data/examples/static_assets_example.rb +0 -83
  323. data/gems/server/lib/itsi/server/default_config/Itsi-rackup.rb +0 -119
@@ -9,13 +9,12 @@ sidebar:
9
9
 
10
10
  `Itsi Scheduler` is an implementation of a Ruby [Fiber Scheduler](https://docs.ruby-lang.org/en/3.2/Fiber/Scheduler.html).
11
11
 
12
- When combined with Itsi Server, you can write endpoints that look and feel exactly like regular synchronous Ruby code,
13
- but behind the scenes, the scheduler will transparently yield and resume concurrent request fibers, to prevent threads from blocking and greatly increase throughput for IO heavy workloads.
12
+ When combined with Itsi Server, you can write endpoints that look just like regular synchronous Ruby code. Behind the scenes, the scheduler will transparently pause and resume fibers to prevent threads from blocking, greatly increasing throughput for I/O-heavy workloads
14
13
 
15
- If you're purely after a light-weight, yet efficient Ruby scheduler,
14
+ If you're purely after a lightweight, yet efficient Ruby scheduler,
16
15
  you can use Itsi Scheduler as a standalone scheduler for any Ruby application.
17
16
 
18
- Just use `Fiber.set_scheduler` to set an instance `Itsi::Scheduler` as a scheduler to opt in to this IO weaving behaviour
17
+ Just use `Fiber.set_scheduler` to set an instance `Itsi::Scheduler` as a scheduler to opt in to this IO weaving behavior
19
18
  *automatically* for all blocking IO.
20
19
 
21
20
  ### Primer on Fiber Schedulers
@@ -29,7 +28,7 @@ This behind the scenes magic allows Ruby to provide async IO (just like we find
29
28
  that synchronous and asynchronous code is identical! (I.e. Ruby's functions are [colorless](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/))
30
29
 
31
30
  ## Getting Started
32
- To install and use Itsi Scheduler follow the below instructions:
31
+ To install and use Itsi Scheduler follow the instructions below:
33
32
 
34
33
 
35
34
  ### 1 - Install Itsi Scheduler
@@ -11,10 +11,6 @@ Minitest::TestTask.create(:test) do |t|
11
11
  t.test_prelude = 'require "helpers/test_helper.rb"'
12
12
  end
13
13
 
14
- require "rubocop/rake_task"
15
-
16
- RuboCop::RakeTask.new
17
-
18
14
  require "rb_sys/extensiontask"
19
15
 
20
16
  task build: :compile
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.required_rubygems_version = ">= 3.1.11"
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
- spec.metadata["source_code_uri"] = "https://github.com/wouterken/itsi/scheduler"
20
- spec.metadata["changelog_uri"] = "https://github.com/wouterken/itsi/scheduler/blob/main/CHANGELOG.md"
19
+ spec.metadata["source_code_uri"] = "https://github.com/wouterken/itsi"
20
+ spec.metadata["changelog_uri"] = "https://github.com/wouterken/itsi/blob/main/CHANGELOG.md"
21
21
 
22
22
  # Specify which files should be added to the gem when it is released.
23
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Scheduler
5
- VERSION = "0.1.20"
5
+ VERSION = "0.2.3"
6
6
  end
7
7
  end
@@ -44,7 +44,9 @@ module Itsi
44
44
  fiber = Fiber.current
45
45
  token = Scheduler.resume_token
46
46
  readiness = register_io_wait(io.fileno, events, duration, token)
47
- readiness || block(nil, duration, fiber, token)
47
+ readiness ||= block(nil, duration, fiber, token)
48
+ clear_timer(token)
49
+ readiness
48
50
  end
49
51
 
50
52
  def unblock(_blocker, fiber)
@@ -130,9 +132,12 @@ module Itsi
130
132
  # Need to defer to Process::Status rather than our extension
131
133
  # as we don't have a means of creating our own Process::Status.
132
134
  def process_wait(pid, flags)
133
- Thread.new do
134
- Process::Status.wait(pid, flags)
135
- end.value
135
+ result = nil
136
+ thread = Thread.new do
137
+ result = Process::Status.wait(pid, flags)
138
+ end
139
+ thread.join
140
+ result
136
141
  end
137
142
 
138
143
  def closed?
@@ -10,9 +10,12 @@ class TestActiveRecordFiberScheduler < Minitest::Test
10
10
  def setup
11
11
  ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
12
12
  ActiveRecord::Base.establish_connection(
13
- adapter: "postgresql",
14
- database: "fiber_scheduler_test",
15
- pool: 2, # use a small pool to test contention scenarios
13
+ adapter: "postgresql",
14
+ host: ENV.fetch("PGHOST", "localhost"),
15
+ database: ENV.fetch("PGDATABASE", "fiber_scheduler_test"),
16
+ **(ENV.fetch("PGUSER", nil).yield_self{|username| username ? {username: username} : {}}),
17
+ **(ENV.fetch("PGPASSWORD", nil).yield_self{|password| password ? {password: password} : {}}),
18
+ pool: 2,
16
19
  checkout_timeout: 5
17
20
  )
18
21
  end
@@ -77,10 +80,12 @@ class TestActiveRecordFiberScheduler < Minitest::Test
77
80
  # Re-establish connection with a pool size of 1.
78
81
  ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
79
82
  ActiveRecord::Base.establish_connection(
80
- adapter: "postgresql",
81
- host: "localhost",
82
- database: "fiber_scheduler_test",
83
- pool: 1,
83
+ adapter: "postgresql",
84
+ host: ENV.fetch("PGHOST", "localhost"),
85
+ database: ENV.fetch("PGDATABASE", "fiber_scheduler_test"),
86
+ **(ENV.fetch("PGUSER", nil).yield_self{|username| username ? {username: username} : {}}),
87
+ **(ENV.fetch("PGPASSWORD", nil).yield_self{|password| password ? {password: password} : {}}),
88
+ pool: 1,
84
89
  checkout_timeout: 0.25
85
90
  )
86
91
  # ActiveRecord::Base.connection_pool.disconnect!
@@ -117,9 +117,9 @@ dependencies = [
117
117
 
118
118
  [[package]]
119
119
  name = "anyhow"
120
- version = "1.0.97"
120
+ version = "1.0.98"
121
121
  source = "registry+https://github.com/rust-lang/crates.io-index"
122
- checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
122
+ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
123
123
 
124
124
  [[package]]
125
125
  name = "arc-swap"
@@ -253,9 +253,9 @@ dependencies = [
253
253
 
254
254
  [[package]]
255
255
  name = "aws-lc-sys"
256
- version = "0.28.0"
256
+ version = "0.28.2"
257
257
  source = "registry+https://github.com/rust-lang/crates.io-index"
258
- checksum = "b9f7720b74ed28ca77f90769a71fd8c637a0137f6fae4ae947e1050229cff57f"
258
+ checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1"
259
259
  dependencies = [
260
260
  "bindgen",
261
261
  "cc",
@@ -467,9 +467,9 @@ dependencies = [
467
467
 
468
468
  [[package]]
469
469
  name = "brotli-decompressor"
470
- version = "4.0.2"
470
+ version = "4.0.3"
471
471
  source = "registry+https://github.com/rust-lang/crates.io-index"
472
- checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
472
+ checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
473
473
  dependencies = [
474
474
  "alloc-no-stdlib",
475
475
  "alloc-stdlib",
@@ -587,9 +587,9 @@ dependencies = [
587
587
 
588
588
  [[package]]
589
589
  name = "clap"
590
- version = "4.5.36"
590
+ version = "4.5.37"
591
591
  source = "registry+https://github.com/rust-lang/crates.io-index"
592
- checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
592
+ checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
593
593
  dependencies = [
594
594
  "clap_builder",
595
595
  "clap_derive",
@@ -597,9 +597,9 @@ dependencies = [
597
597
 
598
598
  [[package]]
599
599
  name = "clap_builder"
600
- version = "4.5.36"
600
+ version = "4.5.37"
601
601
  source = "registry+https://github.com/rust-lang/crates.io-index"
602
- checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
602
+ checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
603
603
  dependencies = [
604
604
  "anstream",
605
605
  "anstyle",
@@ -764,9 +764,9 @@ dependencies = [
764
764
 
765
765
  [[package]]
766
766
  name = "data-encoding"
767
- version = "2.8.0"
767
+ version = "2.9.0"
768
768
  source = "registry+https://github.com/rust-lang/crates.io-index"
769
- checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010"
769
+ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
770
770
 
771
771
  [[package]]
772
772
  name = "der-parser"
@@ -1176,9 +1176,9 @@ dependencies = [
1176
1176
 
1177
1177
  [[package]]
1178
1178
  name = "h2"
1179
- version = "0.4.8"
1179
+ version = "0.4.9"
1180
1180
  source = "registry+https://github.com/rust-lang/crates.io-index"
1181
- checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
1181
+ checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
1182
1182
  dependencies = [
1183
1183
  "atomic-waker",
1184
1184
  "bytes",
@@ -1363,7 +1363,7 @@ dependencies = [
1363
1363
  "bytes",
1364
1364
  "futures-channel",
1365
1365
  "futures-util",
1366
- "h2 0.4.8",
1366
+ "h2 0.4.9",
1367
1367
  "http 1.3.1",
1368
1368
  "http-body 1.0.1",
1369
1369
  "httparse",
@@ -1644,7 +1644,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1644
1644
 
1645
1645
  [[package]]
1646
1646
  name = "itsi-server"
1647
- version = "0.1.20"
1647
+ version = "0.2.3"
1648
1648
  dependencies = [
1649
1649
  "argon2",
1650
1650
  "async-channel",
@@ -1681,7 +1681,7 @@ dependencies = [
1681
1681
  "parking_lot",
1682
1682
  "percent-encoding",
1683
1683
  "pin-project",
1684
- "rand 0.9.0",
1684
+ "rand 0.9.1",
1685
1685
  "rcgen",
1686
1686
  "redis",
1687
1687
  "regex",
@@ -1713,7 +1713,7 @@ dependencies = [
1713
1713
  "axum-server",
1714
1714
  "base64 0.22.1",
1715
1715
  "chrono",
1716
- "clap 4.5.36",
1716
+ "clap 4.5.37",
1717
1717
  "futures",
1718
1718
  "log",
1719
1719
  "num-bigint",
@@ -1841,9 +1841,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
1841
1841
 
1842
1842
  [[package]]
1843
1843
  name = "libc"
1844
- version = "0.2.171"
1844
+ version = "0.2.172"
1845
1845
  source = "registry+https://github.com/rust-lang/crates.io-index"
1846
- checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
1846
+ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
1847
1847
 
1848
1848
  [[package]]
1849
1849
  name = "libloading"
@@ -1852,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1852
1852
  checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
1853
1853
  dependencies = [
1854
1854
  "cfg-if",
1855
- "windows-targets 0.52.6",
1855
+ "windows-targets 0.48.5",
1856
1856
  ]
1857
1857
 
1858
1858
  [[package]]
@@ -2366,9 +2366,9 @@ dependencies = [
2366
2366
 
2367
2367
  [[package]]
2368
2368
  name = "proc-macro2"
2369
- version = "1.0.94"
2369
+ version = "1.0.95"
2370
2370
  source = "registry+https://github.com/rust-lang/crates.io-index"
2371
- checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
2371
+ checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
2372
2372
  dependencies = [
2373
2373
  "unicode-ident",
2374
2374
  ]
@@ -2401,7 +2401,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
2401
2401
  dependencies = [
2402
2402
  "bytes",
2403
2403
  "getrandom 0.3.2",
2404
- "rand 0.9.0",
2404
+ "rand 0.9.1",
2405
2405
  "ring",
2406
2406
  "rustc-hash 2.1.1",
2407
2407
  "rustls",
@@ -2466,13 +2466,12 @@ dependencies = [
2466
2466
 
2467
2467
  [[package]]
2468
2468
  name = "rand"
2469
- version = "0.9.0"
2469
+ version = "0.9.1"
2470
2470
  source = "registry+https://github.com/rust-lang/crates.io-index"
2471
- checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
2471
+ checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
2472
2472
  dependencies = [
2473
2473
  "rand_chacha 0.9.0",
2474
2474
  "rand_core 0.9.3",
2475
- "zerocopy",
2476
2475
  ]
2477
2476
 
2478
2477
  [[package]]
@@ -3062,9 +3061,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
3062
3061
 
3063
3062
  [[package]]
3064
3063
  name = "signal-hook-registry"
3065
- version = "1.4.2"
3064
+ version = "1.4.5"
3066
3065
  source = "registry+https://github.com/rust-lang/crates.io-index"
3067
- checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
3066
+ checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
3068
3067
  dependencies = [
3069
3068
  "libc",
3070
3069
  ]
data/gems/server/Rakefile CHANGED
@@ -12,10 +12,6 @@ Minitest::TestTask.create(:test) do |t|
12
12
  t.test_prelude = 'require "helpers/test_helper.rb"'
13
13
  end
14
14
 
15
- require "rubocop/rake_task"
16
-
17
- RuboCop::RakeTask.new
18
-
19
15
  require "rb_sys/extensiontask"
20
16
 
21
17
  task build: :compile
data/gems/server/exe/itsi CHANGED
@@ -7,17 +7,18 @@ require "optparse"
7
7
 
8
8
  COMMANDS = {
9
9
  "init" => "Initialize a new Itsi.rb server configuration file",
10
- "test" => "Test config file validity",
11
10
  "status" => "Show the status of the server",
12
11
  "start" => "Start the Itsi server",
13
12
  "serve" => "Start the Itsi server",
14
13
  "stop" => "Stop the server",
15
14
  "reload" => "Reload the server",
16
15
  "restart" => "Restart the server",
16
+ "test" => "Test config file validity",
17
17
  "add_worker" => "Add a new worker to the server cluster",
18
18
  "remove_worker" => "Remove a worker from the server cluster",
19
19
  "routes" => "Print the routes of the server",
20
- "passfile" => "Manage hashed users and passwords in a passfile (like .htpasswd). [add, remove, list]",
20
+ "passfile" => "Manage hashed users and passwords in a passfile (like .htpasswd). [add, echo, remove, list]",
21
+ "secret" => "Generate a new secret for use in a JWT verifier",
21
22
  "test_route" => "Test which route a request will be routed to",
22
23
  "static" => "Serve static assets in the given directory"
23
24
  }
@@ -147,6 +148,15 @@ parser = OptionParser.new do |opts|
147
148
  opts.on("--algorithm ALGORITHM", String, "Algorithm for password hashing") do |algorithm|
148
149
  options[:algorithm] = algorithm
149
150
  end
151
+
152
+ opts.on("-dDIR", "--dir=DIR", "(For use with secret) Save keys/secret to DIR instead of printing") do |d|
153
+ options[:save_dir] = d
154
+ end
155
+
156
+ opts.on("-v", "--version", "Show version") do
157
+ puts "Itsi version #{Itsi::Server::VERSION}"
158
+ exit(0)
159
+ end
150
160
  end
151
161
 
152
162
  if ENV['COMP_LINE'] || ARGV.include?('--completion')
@@ -155,6 +165,7 @@ if ENV['COMP_LINE'] || ARGV.include?('--completion')
155
165
  end
156
166
 
157
167
  parser.parse!
168
+
158
169
  case (command = ARGV.shift)
159
170
  when *COMMANDS.keys
160
171
  required_arity = Itsi::Server.method(command).parameters&.select{|c| c.first == :req }&.length&.succ || 2
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.required_rubygems_version = ">= 3.1"
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
- spec.metadata["source_code_uri"] = "https://github.com/wouterken/itsi/server"
20
- spec.metadata["changelog_uri"] = "https://github.com/wouterken/itsi/server/blob/main/CHANGELOG.md"
19
+ spec.metadata["source_code_uri"] = "https://github.com/wouterken/itsi"
20
+ spec.metadata["changelog_uri"] = "https://github.com/wouterken/itsi/blob/main/CHANGELOG.md"
21
21
 
22
22
  # Specify which files should be added to the gem when it is released.
23
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -66,6 +66,8 @@ module Itsi
66
66
  511 => :network_authentication_required
67
67
  }.freeze
68
68
 
69
+ HTTP_STATUS_NAME_TO_CODE_MAP = HTTP_STATUS_CODES.invert.freeze
70
+
69
71
  HTTP_STATUS_CODES.each do |code, name|
70
72
  define_method(name) {|*args, **kwargs| respond(*args, **kwargs, status: code) }
71
73
  end
@@ -3,7 +3,7 @@
3
3
  require "stringio"
4
4
  require "socket"
5
5
  require "uri"
6
- require_relative 'http_request/response_status_shortcodes'
6
+ require_relative "http_request/response_status_shortcodes"
7
7
 
8
8
  module Itsi
9
9
  class HttpRequest
@@ -22,7 +22,7 @@ module Itsi
22
22
  end
23
23
  [header, rack_form]
24
24
  end.to_h.tap do |hm|
25
- hm.default_proc = proc { |hsh, key| "HTTP_#{key.upcase.gsub(/-/, "_")}" }
25
+ hm.default_proc = proc { |_, key| "HTTP_#{key.upcase.gsub(/-/, "_")}" }
26
26
  end
27
27
 
28
28
  def to_rack_env
@@ -78,7 +78,7 @@ module Itsi
78
78
  end
79
79
 
80
80
  def respond(
81
- _body = nil, _status = 200, _headers = nil,
81
+ _body = nil, _status = 200, _headers = nil, # rubocop:disable Lint/UnderscorePrefixedVariableName
82
82
  json: nil,
83
83
  html: nil,
84
84
  text: nil,
@@ -90,9 +90,15 @@ module Itsi
90
90
  body: _body,
91
91
  &blk
92
92
  )
93
-
94
93
  if json
95
- validate!(json, as: as) if as
94
+ if as
95
+ begin
96
+ validate!(json, as: as)
97
+ rescue ValidationError => e
98
+ json = { type: "error", message: "Validation Error: #{e.message}" }
99
+ status = 400
100
+ end
101
+ end
96
102
  body = json.to_json
97
103
  headers ||= {}
98
104
  headers["Content-Type"] ||= "application/json"
@@ -117,19 +123,23 @@ module Itsi
117
123
  self.hijacked = true
118
124
  UNIXSocket.pair.yield_self do |(server_sock, app_sock)|
119
125
  server_sock.autoclose = false
120
- self.response.hijack(server_sock.fileno)
126
+ response.hijack(server_sock.fileno)
121
127
  server_sock.sync = true
122
128
  app_sock.sync = true
123
129
  app_sock
124
130
  end
125
131
  end
126
132
 
133
+ def body
134
+ @body ||= build_input_io
135
+ end
136
+
127
137
  def build_input_io
128
- case body
138
+ case body_parts
129
139
  when nil then EMPTY_IO
130
- when String then StringIO.new(body)
131
- when Array then File.open(body.first, "rb")
132
- else body
140
+ when String then StringIO.new(body_parts)
141
+ when Array then File.open(body_parts.first, "rb")
142
+ else body_parts
133
143
  end
134
144
  end
135
145
 
@@ -137,33 +147,51 @@ module Itsi
137
147
  as ? apply_schema!(params, as) : params
138
148
  end
139
149
 
140
- def params(schema=nil)
141
- params = case
142
- when url_encoded? then URI.decode_www_form(build_input_io.read).to_h
143
- when json? then JSON.parse(build_input_io.read)
144
- when multipart?
145
- Rack::Multipart::Parser.parse(
146
- build_input_io,
147
- content_length,
148
- content_type,
149
- Rack::Multipart::Parser::TEMPFILE_FACTORY,
150
- Rack::Multipart::Parser::BUFSIZE,
151
- Rack::Utils.default_query_parser
152
- ).params
153
- else
154
- {}
155
- end
150
+ def params(schema = nil)
151
+ params = if url_encoded?
152
+ URI.decode_www_form(build_input_io.read).to_h
153
+ elsif json?
154
+ JSON.parse(build_input_io.read)
155
+ elsif multipart?
156
+ Rack::Multipart::Parser.parse(
157
+ build_input_io,
158
+ content_length,
159
+ content_type,
160
+ Rack::Multipart::Parser::TEMPFILE_FACTORY,
161
+ Rack::Multipart::Parser::BUFSIZE,
162
+ Rack::Utils.default_query_parser
163
+ ).params
164
+ else
165
+ {}
166
+ end
156
167
 
157
168
  params.merge!(query_params).merge!(url_params)
169
+ validated = schema ? apply_schema!(params, schema) : params
170
+ if block_given?
171
+ yield validated
172
+ else
173
+ raise "#params must take a block for multipart requests" if multipart?
158
174
 
159
- yield schema ? apply_schema!(params, schema) : params
175
+ validated
160
176
 
161
- rescue StandardError => e
177
+ end
178
+ rescue ValidationError => e
162
179
  if response.json?
163
- respond(json: {error: e.message}, status: 400)
180
+ respond(json: { error: e.message }, status: 400)
164
181
  else
165
182
  respond(e.message, 400)
166
183
  end
184
+ rescue StandardError => e
185
+ Itsi.log_error e.message
186
+ puts e.backtrace
187
+
188
+ # Unexpected error.
189
+ # Don't reveal potential sensitive information to client.
190
+ if response.json?
191
+ respond(json: { error: "Internal Server Error" }, status: 500)
192
+ else
193
+ respond("Internal Server Error", 500)
194
+ end
167
195
  ensure
168
196
  clean_temp_files(params)
169
197
  end
@@ -174,7 +202,7 @@ module Itsi
174
202
  if params.key?(:tempfile)
175
203
  params[:tempfile].unlink
176
204
  else
177
- params.each_value { |v| clean_temp_files(v) }
205
+ params.each_value { |v| clean_temp_files(v) }
178
206
  end
179
207
  when Array then params.each { |v| clean_temp_files(v) }
180
208
  end
@@ -1,14 +1,17 @@
1
1
  # frozen_string_literal: true
2
- require 'forwardable'
2
+
3
+ require "forwardable"
3
4
  require "stringio"
4
5
  require "socket"
5
6
 
6
7
  module Itsi
7
-
8
8
  class HttpResponse
9
-
10
- def respond _body=nil, _status=200, _header=nil, status: _status, headers: _header, body: _body, hijack: false, &blk
11
- self.status = status
9
+ def respond(
10
+ _body = nil, _status = 200, _header = nil, # rubocop:disable Lint/UnderscorePrefixedVariableName
11
+ status: _status, headers: _header, body: _body,
12
+ hijack: false
13
+ )
14
+ self.status = status.is_a?(Symbol) ? HTTP_STATUS_NAME_TO_CODE_MAP.fetch(status) : status.to_i
12
15
 
13
16
  body = body.to_s unless body.is_a?(String)
14
17
 
@@ -32,9 +35,9 @@ module Itsi
32
35
 
33
36
  # If you hijack the connection, you are responsible for closing it.
34
37
  # Otherwise, the response will be closed automatically.
35
- self.close unless hijack
38
+ close unless hijack
36
39
  else
37
- self.close
40
+ close
38
41
  end
39
42
  end
40
43
  end
@@ -1,8 +1,7 @@
1
1
  module Itsi
2
2
  class Server
3
-
4
3
  module Passfile
5
- require 'io/console'
4
+ require "io/console"
6
5
 
7
6
  module_function
8
7
 
@@ -18,7 +17,7 @@ module Itsi
18
17
  line.chomp!
19
18
  next if line.empty?
20
19
 
21
- user, pass = line.split(':', 2)
20
+ user, pass = line.split(":", 2)
22
21
  creds[user] = pass
23
22
  end
24
23
  end
@@ -26,15 +25,14 @@ module Itsi
26
25
  end
27
26
 
28
27
  def save(creds, filename)
29
- File.open(filename, 'w', 0o600) do |f|
28
+ File.open(filename, "w", 0o600) do |f|
30
29
  creds.each do |u, p|
31
30
  f.puts "#{u}:#{p}"
32
31
  end
33
32
  end
34
33
  end
35
34
 
36
- def echo(filename, algorithm)
37
- return unless (creds = load(filename))
35
+ def echo(_, algorithm)
38
36
  print "Enter username: "
39
37
  username = $stdin.gets.chomp
40
38
 
@@ -57,6 +55,7 @@ module Itsi
57
55
 
58
56
  def add(filename, algorithm)
59
57
  return unless (creds = load(filename))
58
+
60
59
  print "Enter username: "
61
60
  username = $stdin.gets.chomp
62
61
 
@@ -99,11 +98,11 @@ module Itsi
99
98
  def list(filename)
100
99
  puts "Current credentials in '#{filename}':"
101
100
  return unless (creds = load(filename))
101
+
102
102
  creds.each do |u, p|
103
103
  puts "#{u}:#{p}"
104
104
  end
105
105
  end
106
-
107
106
  end
108
107
  end
109
108
  end