itsi 0.1.9 → 0.1.12

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1542 -43
  3. data/Itsi.rb +125 -0
  4. data/Rakefile +8 -4
  5. data/crates/itsi_error/src/lib.rs +9 -0
  6. data/crates/itsi_rb_helpers/Cargo.toml +1 -0
  7. data/crates/itsi_rb_helpers/src/heap_value.rs +18 -0
  8. data/crates/itsi_rb_helpers/src/lib.rs +59 -9
  9. data/crates/itsi_server/Cargo.toml +70 -28
  10. data/crates/itsi_server/src/lib.rs +80 -80
  11. data/crates/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  12. data/{gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs → crates/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs} +22 -3
  13. data/crates/itsi_server/src/ruby_types/itsi_grpc_request.rs +147 -0
  14. data/crates/itsi_server/src/ruby_types/itsi_grpc_response.rs +19 -0
  15. data/crates/itsi_server/src/ruby_types/itsi_grpc_stream/mod.rs +216 -0
  16. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +282 -0
  17. data/crates/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +72 -41
  18. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
  19. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +355 -0
  20. data/crates/itsi_server/src/ruby_types/itsi_server.rs +82 -0
  21. data/crates/itsi_server/src/ruby_types/mod.rs +55 -0
  22. data/crates/itsi_server/src/server/bind.rs +29 -17
  23. data/crates/itsi_server/src/server/byte_frame.rs +32 -0
  24. data/crates/itsi_server/src/server/cache_store.rs +74 -0
  25. data/crates/itsi_server/src/server/itsi_service.rs +172 -0
  26. data/crates/itsi_server/src/server/lifecycle_event.rs +3 -0
  27. data/crates/itsi_server/src/server/listener.rs +111 -11
  28. data/crates/itsi_server/src/server/middleware_stack/middleware.rs +153 -0
  29. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +47 -0
  30. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +58 -0
  31. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +82 -0
  32. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +321 -0
  33. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +139 -0
  34. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +300 -0
  35. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +287 -0
  36. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +48 -0
  37. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +127 -0
  38. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +191 -0
  39. data/crates/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +72 -0
  40. data/crates/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +85 -0
  41. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +195 -0
  42. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  43. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +82 -0
  44. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +216 -0
  45. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +124 -0
  46. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +43 -0
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +34 -0
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +93 -0
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +162 -0
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +158 -0
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  53. data/crates/itsi_server/src/server/middleware_stack/mod.rs +315 -0
  54. data/crates/itsi_server/src/server/mod.rs +8 -1
  55. data/crates/itsi_server/src/server/process_worker.rs +44 -11
  56. data/crates/itsi_server/src/server/rate_limiter.rs +565 -0
  57. data/crates/itsi_server/src/server/request_job.rs +11 -0
  58. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +129 -46
  59. data/crates/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  60. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +325 -167
  61. data/crates/itsi_server/src/server/signal.rs +20 -4
  62. data/crates/itsi_server/src/server/static_file_server.rs +984 -0
  63. data/crates/itsi_server/src/server/thread_worker.rs +165 -88
  64. data/crates/itsi_server/src/server/tls.rs +1 -1
  65. data/crates/itsi_server/src/server/types.rs +43 -0
  66. data/crates/itsi_server/test.md +14 -0
  67. data/crates/itsi_tracing/Cargo.toml +1 -0
  68. data/crates/itsi_tracing/src/lib.rs +216 -45
  69. data/docs/.gitignore +7 -0
  70. data/docs/.gitpod.yml +15 -0
  71. data/docs/Itsi.rb +17 -0
  72. data/docs/content/_index.md +17 -0
  73. data/docs/content/about.md +6 -0
  74. data/docs/content/docs/_index.md +18 -0
  75. data/docs/content/docs/first-page.md +9 -0
  76. data/docs/content/docs/folder/_index.md +10 -0
  77. data/docs/content/docs/folder/leaf.md +7 -0
  78. data/docs/go.mod +5 -0
  79. data/docs/go.sum +2 -0
  80. data/docs/hugo.yaml +77 -0
  81. data/examples/static_assets_example.rb +83 -0
  82. data/gems/_index.md +18 -0
  83. data/gems/scheduler/CODE_OF_CONDUCT.md +7 -0
  84. data/gems/scheduler/Cargo.lock +75 -14
  85. data/gems/scheduler/README.md +5 -0
  86. data/gems/scheduler/_index.md +7 -0
  87. data/gems/scheduler/itsi-scheduler.gemspec +4 -1
  88. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  89. data/gems/scheduler/lib/itsi/scheduler.rb +2 -2
  90. data/gems/scheduler/test/test_file_io.rb +0 -1
  91. data/gems/scheduler/test/test_itsi_scheduler.rb +1 -1
  92. data/gems/server/CHANGELOG.md +5 -0
  93. data/gems/server/CODE_OF_CONDUCT.md +7 -0
  94. data/gems/server/Cargo.lock +1543 -43
  95. data/gems/server/README.md +4 -0
  96. data/gems/server/_index.md +6 -0
  97. data/gems/server/exe/itsi +46 -57
  98. data/gems/server/itsi-server.gemspec +3 -2
  99. data/gems/server/lib/itsi/{request.rb → http_request.rb} +29 -5
  100. data/gems/server/lib/itsi/http_response.rb +39 -0
  101. data/gems/server/lib/itsi/server/Itsi.rb +119 -0
  102. data/gems/server/lib/itsi/server/config/dsl.rb +506 -0
  103. data/gems/server/lib/itsi/server/config.rb +131 -0
  104. data/gems/server/lib/itsi/server/default_app/default_app.rb +38 -0
  105. data/gems/server/lib/itsi/server/grpc_interface.rb +213 -0
  106. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +9 -6
  107. data/gems/server/lib/itsi/server/rack_interface.rb +24 -9
  108. data/gems/server/lib/itsi/server/scheduler_interface.rb +1 -1
  109. data/gems/server/lib/itsi/server/scheduler_mode.rb +4 -0
  110. data/gems/server/lib/itsi/server/signal_trap.rb +6 -1
  111. data/gems/server/lib/itsi/server/version.rb +1 -1
  112. data/gems/server/lib/itsi/server.rb +75 -60
  113. data/gems/server/lib/itsi/standard_headers.rb +86 -0
  114. data/gems/server/test/helpers/test_helper.rb +14 -12
  115. data/gems/server/test/test_itsi_server.rb +21 -2
  116. data/lib/itsi/version.rb +1 -1
  117. data/sandbox/itsi_file/Gemfile +11 -0
  118. data/sandbox/itsi_file/Gemfile.lock +69 -0
  119. data/sandbox/itsi_file/Itsi.rb +276 -0
  120. data/sandbox/itsi_file/error.html +2 -0
  121. data/sandbox/itsi_file/organisations_controller.rb +20 -0
  122. data/sandbox/itsi_file/public/assets/image.png +0 -0
  123. data/sandbox/itsi_file/public/assets/index.html +1 -0
  124. data/sandbox/itsi_sandbox_async/Gemfile +1 -1
  125. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +2 -2
  126. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  127. data/sandbox/itsi_sandbox_rack/config.ru +2 -15
  128. data/sandbox/itsi_sandbox_rails/.dockerignore +2 -5
  129. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +1 -1
  130. data/sandbox/itsi_sandbox_rails/.gitignore +2 -1
  131. data/sandbox/itsi_sandbox_rails/Dockerfile +6 -9
  132. data/sandbox/itsi_sandbox_rails/Gemfile +16 -22
  133. data/sandbox/itsi_sandbox_rails/Gemfile.lock +100 -225
  134. data/sandbox/itsi_sandbox_rails/app/assets/config/manifest.js +4 -0
  135. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +11 -6
  136. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/channel.rb +4 -0
  137. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/connection.rb +4 -0
  138. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +7 -8
  139. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +0 -3
  140. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +2 -7
  141. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +3 -4
  142. data/sandbox/itsi_sandbox_rails/bin/setup +8 -5
  143. data/sandbox/itsi_sandbox_rails/config/application.rb +1 -35
  144. data/sandbox/itsi_sandbox_rails/config/cable.yml +3 -10
  145. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -1
  146. data/sandbox/itsi_sandbox_rails/config/database.yml +9 -19
  147. data/sandbox/itsi_sandbox_rails/config/environment.rb +1 -1
  148. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +21 -12
  149. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +49 -34
  150. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +19 -5
  151. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +5 -0
  152. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +1 -1
  153. data/sandbox/itsi_sandbox_rails/config/initializers/permissions_policy.rb +13 -0
  154. data/sandbox/itsi_sandbox_rails/config/puma.rb +2 -9
  155. data/sandbox/itsi_sandbox_rails/config.ru +0 -1
  156. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +1 -1
  157. data/sandbox/itsi_sandbox_rails/db/schema.rb +2 -2
  158. data/sandbox/itsi_sandbox_rails/lib/assets/.keep +0 -0
  159. data/sandbox/itsi_sandbox_rails/public/404.html +66 -113
  160. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +65 -113
  161. data/sandbox/itsi_sandbox_rails/public/422.html +66 -113
  162. data/sandbox/itsi_sandbox_rails/public/500.html +65 -113
  163. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  164. data/sandbox/itsi_sandbox_rails/public/icon.svg +2 -2
  165. data/sandbox/itsi_sandbox_rails/test/channels/application_cable/connection_test.rb +13 -0
  166. data/sandbox/itsi_sandbox_roda/Gemfile.lock +3 -10
  167. data/tasks.txt +72 -12
  168. metadata +94 -139
  169. data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  170. data/crates/itsi_server/src/body_proxy/mod.rs +0 -2
  171. data/crates/itsi_server/src/request/itsi_request.rs +0 -305
  172. data/crates/itsi_server/src/request/mod.rs +0 -1
  173. data/crates/itsi_server/src/response/mod.rs +0 -1
  174. data/crates/itsi_server/src/server/itsi_server.rs +0 -294
  175. data/gems/scheduler/ext/itsi_error/Cargo.lock +0 -368
  176. data/gems/scheduler/ext/itsi_error/Cargo.toml +0 -11
  177. data/gems/scheduler/ext/itsi_error/src/from.rs +0 -68
  178. data/gems/scheduler/ext/itsi_error/src/lib.rs +0 -24
  179. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +0 -15
  180. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +0 -31
  181. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +0 -355
  182. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +0 -10
  183. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  184. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +0 -178
  185. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +0 -24
  186. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +0 -6
  187. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  188. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  189. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  190. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  191. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +0 -38
  192. data/gems/scheduler/ext/itsi_server/Cargo.lock +0 -2956
  193. data/gems/scheduler/ext/itsi_server/Cargo.toml +0 -47
  194. data/gems/scheduler/ext/itsi_server/extconf.rb +0 -6
  195. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  196. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  197. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  198. data/gems/scheduler/ext/itsi_server/src/env.rs +0 -43
  199. data/gems/scheduler/ext/itsi_server/src/lib.rs +0 -112
  200. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +0 -305
  201. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +0 -1
  202. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +0 -357
  203. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +0 -1
  204. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +0 -170
  205. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  206. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +0 -104
  207. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +0 -294
  208. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  209. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +0 -318
  210. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +0 -11
  211. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +0 -196
  212. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  213. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  214. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  215. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +0 -77
  216. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +0 -367
  217. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  218. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +0 -265
  219. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +0 -274
  220. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +0 -16
  221. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +0 -58
  222. data/gems/server/ext/itsi_error/Cargo.lock +0 -368
  223. data/gems/server/ext/itsi_error/Cargo.toml +0 -11
  224. data/gems/server/ext/itsi_error/src/from.rs +0 -68
  225. data/gems/server/ext/itsi_error/src/lib.rs +0 -24
  226. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +0 -15
  227. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +0 -31
  228. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +0 -355
  229. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +0 -10
  230. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  231. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +0 -178
  232. data/gems/server/ext/itsi_scheduler/Cargo.toml +0 -24
  233. data/gems/server/ext/itsi_scheduler/extconf.rb +0 -6
  234. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  235. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  236. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  237. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  238. data/gems/server/ext/itsi_scheduler/src/lib.rs +0 -38
  239. data/gems/server/ext/itsi_server/Cargo.lock +0 -2956
  240. data/gems/server/ext/itsi_server/Cargo.toml +0 -47
  241. data/gems/server/ext/itsi_server/extconf.rb +0 -6
  242. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  243. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  244. data/gems/server/ext/itsi_server/src/env.rs +0 -43
  245. data/gems/server/ext/itsi_server/src/lib.rs +0 -112
  246. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +0 -305
  247. data/gems/server/ext/itsi_server/src/request/mod.rs +0 -1
  248. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +0 -357
  249. data/gems/server/ext/itsi_server/src/response/mod.rs +0 -1
  250. data/gems/server/ext/itsi_server/src/server/bind.rs +0 -170
  251. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  252. data/gems/server/ext/itsi_server/src/server/io_stream.rs +0 -104
  253. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +0 -294
  254. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  255. data/gems/server/ext/itsi_server/src/server/listener.rs +0 -318
  256. data/gems/server/ext/itsi_server/src/server/mod.rs +0 -11
  257. data/gems/server/ext/itsi_server/src/server/process_worker.rs +0 -196
  258. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  259. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  260. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  261. data/gems/server/ext/itsi_server/src/server/signal.rs +0 -77
  262. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +0 -367
  263. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  264. data/gems/server/ext/itsi_server/src/server/tls.rs +0 -265
  265. data/gems/server/ext/itsi_tracing/Cargo.lock +0 -274
  266. data/gems/server/ext/itsi_tracing/Cargo.toml +0 -16
  267. data/gems/server/ext/itsi_tracing/src/lib.rs +0 -58
  268. data/gems/server/lib/itsi/stream_io.rb +0 -38
  269. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +0 -3
  270. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +0 -3
  271. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +0 -14
  272. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +0 -3
  273. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +0 -3
  274. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +0 -51
  275. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +0 -47
  276. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +0 -109
  277. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  278. data/sandbox/itsi_sandbox_rails/.kamal/secrets +0 -17
  279. data/sandbox/itsi_sandbox_rails/bin/dev +0 -2
  280. data/sandbox/itsi_sandbox_rails/bin/jobs +0 -6
  281. data/sandbox/itsi_sandbox_rails/bin/kamal +0 -27
  282. data/sandbox/itsi_sandbox_rails/bin/thrust +0 -5
  283. data/sandbox/itsi_sandbox_rails/config/cache.yml +0 -16
  284. data/sandbox/itsi_sandbox_rails/config/deploy.yml +0 -116
  285. data/sandbox/itsi_sandbox_rails/config/queue.yml +0 -18
  286. data/sandbox/itsi_sandbox_rails/config/recurring.yml +0 -10
  287. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +0 -11
  288. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +0 -14
  289. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +0 -129
  290. data/sandbox/itsi_sandbox_rails/public/400.html +0 -114
  291. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +0 -9
  292. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +0 -7
  293. /data/{sandbox/itsi_sandbox_rails/script/.keep → crates/_index.md} +0 -0
  294. /data/gems/server/lib/itsi/{index.html → server/default_app/index.html} +0 -0
@@ -0,0 +1,315 @@
1
+ mod middleware;
2
+ mod middlewares;
3
+ use super::types::HttpRequest;
4
+ use http::header::{ACCEPT, CONTENT_TYPE, HOST};
5
+ use itsi_rb_helpers::HeapVal;
6
+ use magnus::{error::Result, value::ReprValue, RArray, RHash, Ruby, TryConvert, Value};
7
+ pub use middleware::Middleware;
8
+ pub use middlewares::*;
9
+ use regex::{Regex, RegexSet};
10
+ use std::{collections::HashMap, sync::Arc};
11
+ use tracing::info;
12
+
13
+ #[derive(Debug)]
14
+ pub struct MiddlewareSet {
15
+ pub route_set: RegexSet,
16
+ pub patterns: Vec<Arc<Regex>>,
17
+ pub stacks: HashMap<usize, MiddlewareStack>,
18
+ pub default_stack: Vec<Middleware>,
19
+ }
20
+
21
+ #[derive(Debug)]
22
+ pub struct MiddlewareStack {
23
+ layers: Vec<Middleware>,
24
+ methods: Option<Vec<StringMatch>>,
25
+ protocols: Option<Vec<StringMatch>>,
26
+ hosts: Option<Vec<StringMatch>>,
27
+ extensions: Option<Vec<StringMatch>>,
28
+ ports: Option<Vec<StringMatch>>,
29
+ content_types: Option<Vec<StringMatch>>,
30
+ accepts: Option<Vec<StringMatch>>,
31
+ }
32
+
33
+ #[derive(Debug)]
34
+ enum StringMatch {
35
+ Exact(String),
36
+ Wildcard(Regex),
37
+ }
38
+
39
+ impl StringMatch {
40
+ fn from_value(value: Value) -> Result<Self> {
41
+ let ruby = Ruby::get().unwrap();
42
+ if value.is_kind_of(ruby.class_regexp()) {
43
+ let src_str = value.funcall::<_, _, String>("source", ())?;
44
+ let regex = Regex::new(&src_str).map_err(|e| {
45
+ magnus::Error::new(
46
+ magnus::exception::exception(),
47
+ format!("Invalid regexp: {}", e),
48
+ )
49
+ })?;
50
+ Ok(StringMatch::Wildcard(regex))
51
+ } else {
52
+ Ok(StringMatch::Exact(value.to_string()))
53
+ }
54
+ }
55
+
56
+ fn matches(&self, value: &str) -> bool {
57
+ match self {
58
+ StringMatch::Exact(s) => s.eq_ignore_ascii_case(value),
59
+ StringMatch::Wildcard(re) => re.is_match(value),
60
+ }
61
+ }
62
+ }
63
+
64
+ impl MiddlewareStack {
65
+ pub fn matches(&self, request: &HttpRequest) -> bool {
66
+ if let Some(methods) = &self.methods {
67
+ let method = request.method().as_str();
68
+ if !methods.iter().any(|m| m.matches(method)) {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ if let (Some(protocols), Some(protocol)) = (&self.protocols, request.uri().scheme()) {
74
+ if !protocols.iter().any(|p| p.matches(protocol.as_str())) {
75
+ return false;
76
+ }
77
+ }
78
+
79
+ if let (Some(hosts), Some(host)) = (&self.hosts, request.headers().get(HOST)) {
80
+ if let Ok(host) = host.to_str() {
81
+ if !hosts.iter().any(|d| d.matches(host)) {
82
+ return false;
83
+ }
84
+ }
85
+ }
86
+
87
+ if let (Some(ports), Some(port)) = (&self.ports, request.uri().port()) {
88
+ if !ports.iter().any(|d| d.matches(port.as_str())) {
89
+ info!("No match between port {} and {:?}", port, ports);
90
+ return false;
91
+ }
92
+ }
93
+
94
+ if let Some(extensions) = &self.extensions {
95
+ let extension = request.uri().path().split('.').next_back().unwrap_or("");
96
+ if !extensions.iter().any(|e| e.matches(extension)) {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ if let Some(content_types) = &self.content_types {
102
+ if let Some(content_type) = request.headers().get(CONTENT_TYPE) {
103
+ if !content_types
104
+ .iter()
105
+ .any(|ct| ct.matches(content_type.to_str().unwrap_or("")))
106
+ {
107
+ return false;
108
+ }
109
+ }
110
+ }
111
+
112
+ if let Some(accepts) = &self.accepts {
113
+ if let Some(accept) = request.headers().get(ACCEPT) {
114
+ if !accepts
115
+ .iter()
116
+ .any(|a| a.matches(accept.to_str().unwrap_or("")))
117
+ {
118
+ return false;
119
+ }
120
+ }
121
+ }
122
+
123
+ true
124
+ }
125
+ }
126
+
127
+ impl MiddlewareSet {
128
+ pub fn new(routes_raw: Option<HeapVal>, default_app: HeapVal) -> Result<Self> {
129
+ if let Some(routes_raw) = routes_raw {
130
+ let mut stacks = HashMap::new();
131
+ let mut routes = vec![];
132
+ for (index, route) in RArray::from_value(*routes_raw)
133
+ .ok_or(magnus::Error::new(
134
+ magnus::exception::exception(),
135
+ format!("Routes must be an array. Got {:?}", routes_raw),
136
+ ))?
137
+ .into_iter()
138
+ .enumerate()
139
+ {
140
+ let route_hash: RHash = RHash::try_convert(route)?;
141
+ let route_raw = route_hash
142
+ .get("route")
143
+ .ok_or(magnus::Error::new(
144
+ magnus::exception::exception(),
145
+ "Route is missing :route key",
146
+ ))?
147
+ .funcall::<_, _, String>("source", ())?;
148
+ let middleware =
149
+ RArray::from_value(route_hash.get("middleware").ok_or(magnus::Error::new(
150
+ magnus::exception::exception(),
151
+ "Route is missing middleware key",
152
+ ))?)
153
+ .ok_or(magnus::Error::new(
154
+ magnus::exception::exception(),
155
+ format!("middleware must be an array. Got {:?}", routes_raw),
156
+ ))?;
157
+
158
+ let mut layers = middleware
159
+ .into_iter()
160
+ .map(MiddlewareSet::parse_middleware)
161
+ .collect::<Result<Vec<_>>>()?;
162
+ layers.push(Middleware::RubyApp(RubyApp::from_value(
163
+ default_app.clone(),
164
+ )?));
165
+ routes.push(route_raw);
166
+ layers.sort();
167
+ stacks.insert(
168
+ index,
169
+ MiddlewareStack {
170
+ layers,
171
+ methods: extract_optional_match_array(route_hash, "methods")?,
172
+ protocols: extract_optional_match_array(route_hash, "protocols")?,
173
+ hosts: extract_optional_match_array(route_hash, "hosts")?,
174
+ extensions: extract_optional_match_array(route_hash, "extensions")?,
175
+ ports: extract_optional_match_array(route_hash, "ports")?,
176
+ content_types: extract_optional_match_array(route_hash, "content_types")?,
177
+ accepts: extract_optional_match_array(route_hash, "accepts")?,
178
+ },
179
+ );
180
+ }
181
+ info!("Routes are {:?}", routes);
182
+ Ok(Self {
183
+ route_set: RegexSet::new(&routes).map_err(|e| {
184
+ magnus::Error::new(
185
+ magnus::exception::exception(),
186
+ format!("Failed to create route set: {}", e),
187
+ )
188
+ })?,
189
+ patterns: routes
190
+ .into_iter()
191
+ .map(|r| Regex::new(&r))
192
+ .collect::<std::result::Result<Vec<Regex>, regex::Error>>()
193
+ .map_err(|e| {
194
+ magnus::Error::new(
195
+ magnus::exception::exception(),
196
+ format!("Failed to create route set: {}", e),
197
+ )
198
+ })?
199
+ .into_iter()
200
+ .map(Arc::new)
201
+ .collect(),
202
+ stacks,
203
+ default_stack: vec![Middleware::RubyApp(RubyApp::from_value(default_app)?)],
204
+ })
205
+ } else {
206
+ Ok(Self {
207
+ route_set: RegexSet::empty(),
208
+ patterns: Vec::new(),
209
+ stacks: HashMap::new(),
210
+ default_stack: vec![Middleware::RubyApp(RubyApp::from_value(default_app)?)],
211
+ })
212
+ }
213
+ }
214
+
215
+ pub fn stack_for(&self, request: &HttpRequest) -> (&Vec<Middleware>, Option<Arc<Regex>>) {
216
+ let binding = self.route_set.matches(request.uri().path());
217
+ let matches = binding.iter();
218
+ for index in matches {
219
+ let matching_pattern = self.patterns.get(index).cloned();
220
+ if let Some(stack) = self.stacks.get(&index) {
221
+ if stack.matches(request) {
222
+ return (&stack.layers, matching_pattern);
223
+ }
224
+ }
225
+ }
226
+ (self.default_stack(), None)
227
+ }
228
+
229
+ pub fn parse_middleware(middleware: Value) -> Result<Middleware> {
230
+ let middleware_hash = RHash::from_value(middleware).ok_or(magnus::Error::new(
231
+ magnus::exception::exception(),
232
+ format!("Filter must be a hash. Got {:?}", middleware),
233
+ ))?;
234
+ let middleware_type: String = middleware_hash
235
+ .get("type")
236
+ .ok_or(magnus::Error::new(
237
+ magnus::exception::exception(),
238
+ format!("Filter must have a :type key. Got {:?}", middleware_hash),
239
+ ))?
240
+ .to_string();
241
+
242
+ let parameters: Value = middleware_hash.get("parameters").ok_or(magnus::Error::new(
243
+ magnus::exception::exception(),
244
+ format!(
245
+ "Filter must have a :parameters key. Got {:?}",
246
+ middleware_hash
247
+ ),
248
+ ))?;
249
+
250
+ let result = match middleware_type.as_str() {
251
+ "allow_list" => Middleware::AllowList(AllowList::from_value(parameters)?),
252
+ "auth_basic" => Middleware::AuthBasic(AuthBasic::from_value(parameters)?),
253
+ "auth_jwt" => Middleware::AuthJwt(Box::new(AuthJwt::from_value(parameters)?)),
254
+ "auth_api_key" => Middleware::AuthAPIKey(AuthAPIKey::from_value(parameters)?),
255
+ "cache_control" => Middleware::CacheControl(CacheControl::from_value(parameters)?),
256
+ "deny_list" => Middleware::DenyList(DenyList::from_value(parameters)?),
257
+ "etag" => Middleware::ETag(ETag::from_value(parameters)?),
258
+ "intrusion_protection" => {
259
+ Middleware::IntrusionProtection(IntrusionProtection::from_value(parameters)?)
260
+ }
261
+ "rate_limit" => Middleware::RateLimit(RateLimit::from_value(parameters)?),
262
+ "cors" => Middleware::Cors(Box::new(Cors::from_value(parameters)?)),
263
+ "request_headers" => {
264
+ Middleware::RequestHeaders(RequestHeaders::from_value(parameters)?)
265
+ }
266
+ "response_headers" => {
267
+ Middleware::ResponseHeaders(ResponseHeaders::from_value(parameters)?)
268
+ }
269
+ "static_assets" => Middleware::StaticAssets(StaticAssets::from_value(parameters)?),
270
+ "compression" => Middleware::Compression(Compression::from_value(parameters)?),
271
+ "log_requests" => Middleware::LogRequests(LogRequests::from_value(parameters)?),
272
+ "redirect" => Middleware::Redirect(Redirect::from_value(parameters)?),
273
+ "app" => Middleware::RubyApp(RubyApp::from_value(parameters.into())?),
274
+ "proxy" => Middleware::Proxy(Proxy::from_value(parameters)?),
275
+ _ => {
276
+ return Err(magnus::Error::new(
277
+ magnus::exception::exception(),
278
+ format!("Unknown filter type: {}", middleware_type),
279
+ ))
280
+ }
281
+ };
282
+
283
+ Ok(result)
284
+ }
285
+
286
+ fn default_stack(&self) -> &Vec<Middleware> {
287
+ &self.default_stack
288
+ }
289
+
290
+ pub async fn initialize_layers(&self) -> Result<()> {
291
+ for middleware in &self.default_stack {
292
+ middleware.initialize().await?;
293
+ }
294
+ for stack in self.stacks.values() {
295
+ for middleware in &stack.layers {
296
+ middleware.initialize().await?;
297
+ }
298
+ }
299
+ Ok(())
300
+ }
301
+ }
302
+
303
+ fn extract_optional_match_array(route_hash: RHash, arg: &str) -> Result<Option<Vec<StringMatch>>> {
304
+ let rarray = route_hash.aref::<_, Option<RArray>>(arg)?;
305
+ if let Some(array) = rarray {
306
+ Ok(Some(
307
+ array
308
+ .into_iter()
309
+ .map(StringMatch::from_value)
310
+ .collect::<Result<Vec<StringMatch>>>()?,
311
+ ))
312
+ } else {
313
+ Ok(None)
314
+ }
315
+ }
@@ -1,11 +1,18 @@
1
1
  pub mod bind;
2
2
  pub mod bind_protocol;
3
+ pub mod byte_frame;
4
+ pub mod cache_store;
3
5
  pub mod io_stream;
4
- pub mod itsi_server;
6
+ pub mod itsi_service;
5
7
  pub mod lifecycle_event;
6
8
  pub mod listener;
9
+ pub mod middleware_stack;
7
10
  pub mod process_worker;
11
+ pub mod rate_limiter;
12
+ pub mod request_job;
8
13
  pub mod serve_strategy;
9
14
  pub mod signal;
15
+ pub mod static_file_server;
10
16
  pub mod thread_worker;
11
17
  pub mod tls;
18
+ pub mod types;
@@ -7,7 +7,7 @@ use nix::{
7
7
  sys::{
8
8
  signal::{
9
9
  kill,
10
- Signal::{SIGKILL, SIGTERM},
10
+ Signal::{SIGINFO, SIGKILL, SIGTERM},
11
11
  },
12
12
  wait::{waitpid, WaitPidFlag, WaitStatus},
13
13
  },
@@ -54,7 +54,17 @@ impl ProcessWorker {
54
54
  *self.child_pid.lock() = None;
55
55
  }
56
56
 
57
- match call_with_gvl(|_ruby| fork(cluster_template.server.after_fork.lock().clone())) {
57
+ match call_with_gvl(|_ruby| {
58
+ fork(
59
+ cluster_template
60
+ .server_config
61
+ .server_params
62
+ .read()
63
+ .hooks
64
+ .get("after_fork")
65
+ .cloned(),
66
+ )
67
+ }) {
58
68
  Some(pid) => {
59
69
  *self.child_pid.lock() = Some(Pid::from_raw(pid));
60
70
  }
@@ -65,11 +75,7 @@ impl ProcessWorker {
65
75
  ) {
66
76
  error!("Failed to set process group ID: {}", e);
67
77
  }
68
- match SingleMode::new(
69
- cluster_template.server.clone(),
70
- cluster_template.listeners.clone(),
71
- cluster_template.lifecycle_channel.clone(),
72
- ) {
78
+ match SingleMode::new(cluster_template.server_config.clone()) {
73
79
  Ok(single_mode) => {
74
80
  Arc::new(single_mode).run().ok();
75
81
  }
@@ -83,6 +89,13 @@ impl ProcessWorker {
83
89
  Ok(())
84
90
  }
85
91
 
92
+ pub fn pid(&self) -> i32 {
93
+ if let Some(pid) = *self.child_pid.lock() {
94
+ return pid.as_raw();
95
+ }
96
+ 0
97
+ }
98
+
86
99
  pub(crate) fn memory_usage(&self) -> Option<u64> {
87
100
  if let Some(pid) = *self.child_pid.lock() {
88
101
  let s = System::new_all();
@@ -122,8 +135,14 @@ impl ProcessWorker {
122
135
  pub(crate) async fn graceful_shutdown(&self, cluster_template: Arc<ClusterMode>) {
123
136
  let self_clone = self.clone();
124
137
  self_clone.request_shutdown();
125
- let force_kill_time =
126
- Instant::now() + Duration::from_secs_f64(cluster_template.server.shutdown_timeout);
138
+ let force_kill_time = Instant::now()
139
+ + Duration::from_secs_f64(
140
+ cluster_template
141
+ .server_config
142
+ .server_params
143
+ .read()
144
+ .shutdown_timeout,
145
+ );
127
146
  while self_clone.is_alive() && force_kill_time > Instant::now() {
128
147
  tokio::time::sleep(Duration::from_millis(100)).await;
129
148
  }
@@ -164,12 +183,26 @@ impl ProcessWorker {
164
183
  pub(crate) fn force_kill(&self) {
165
184
  let child_pid = *self.child_pid.lock();
166
185
  if let Some(pid) = child_pid {
167
- if let Err(e) = kill(pid, SIGKILL) {
168
- error!("Failed to force kill process {}: {}", pid, e);
186
+ if self.is_alive() {
187
+ if let Err(e) = kill(pid, SIGKILL) {
188
+ error!("Failed to force kill process {}: {}", pid, e);
189
+ }
169
190
  }
170
191
  }
171
192
  }
172
193
 
194
+ pub fn print_info(&self) -> Result<()> {
195
+ let child_pid = *self.child_pid.lock();
196
+ if let Some(pid) = child_pid {
197
+ println!("Worker {:?}, PID: {:?}", self.worker_id, pid);
198
+ if let Err(e) = kill(pid, SIGINFO) {
199
+ error!("Failed to send SIGINFO to process {}: {}", pid, e);
200
+ }
201
+ }
202
+
203
+ Ok(())
204
+ }
205
+
173
206
  pub(crate) fn just_started(&self) -> bool {
174
207
  let now = Instant::now();
175
208
  now.duration_since(self.started_at).as_millis() < 2000