itsi 0.1.11 → 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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1535 -45
  3. data/{sandbox/itsi_itsi_file/Itsi.rb → Itsi.rb} +19 -13
  4. data/Rakefile +8 -7
  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 +34 -7
  9. data/crates/itsi_server/Cargo.toml +69 -30
  10. data/crates/itsi_server/src/lib.rs +79 -147
  11. data/crates/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  12. data/crates/itsi_server/src/{body_proxy/itsi_body_proxy.rs → 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/{gems/server/ext/itsi_server/src/request/itsi_request.rs → crates/itsi_server/src/ruby_types/itsi_http_request.rs} +101 -117
  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 +13 -5
  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 +102 -2
  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 +38 -12
  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 +119 -42
  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 +256 -111
  61. data/crates/itsi_server/src/server/signal.rs +19 -0
  62. data/crates/itsi_server/src/server/static_file_server.rs +984 -0
  63. data/crates/itsi_server/src/server/thread_worker.rs +139 -94
  64. data/crates/itsi_server/src/server/types.rs +43 -0
  65. data/crates/itsi_server/test.md +14 -0
  66. data/crates/itsi_tracing/Cargo.toml +1 -0
  67. data/crates/itsi_tracing/src/lib.rs +216 -45
  68. data/docs/.gitignore +7 -0
  69. data/docs/.gitpod.yml +15 -0
  70. data/docs/Itsi.rb +17 -0
  71. data/docs/content/_index.md +17 -0
  72. data/docs/content/about.md +6 -0
  73. data/docs/content/docs/_index.md +18 -0
  74. data/docs/content/docs/first-page.md +9 -0
  75. data/docs/content/docs/folder/_index.md +10 -0
  76. data/docs/content/docs/folder/leaf.md +7 -0
  77. data/docs/go.mod +5 -0
  78. data/docs/go.sum +2 -0
  79. data/docs/hugo.yaml +77 -0
  80. data/examples/static_assets_example.rb +83 -0
  81. data/gems/_index.md +18 -0
  82. data/gems/scheduler/CODE_OF_CONDUCT.md +7 -0
  83. data/gems/scheduler/Cargo.lock +75 -14
  84. data/gems/scheduler/README.md +5 -0
  85. data/gems/scheduler/_index.md +7 -0
  86. data/gems/scheduler/itsi-scheduler.gemspec +4 -1
  87. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  88. data/gems/scheduler/lib/itsi/scheduler.rb +2 -2
  89. data/gems/scheduler/test/test_file_io.rb +0 -1
  90. data/gems/scheduler/test/test_itsi_scheduler.rb +1 -1
  91. data/gems/server/CHANGELOG.md +5 -0
  92. data/gems/server/CODE_OF_CONDUCT.md +7 -0
  93. data/gems/server/Cargo.lock +1536 -45
  94. data/gems/server/README.md +4 -0
  95. data/gems/server/_index.md +6 -0
  96. data/gems/server/exe/itsi +33 -74
  97. data/gems/server/itsi-server.gemspec +3 -2
  98. data/gems/server/lib/itsi/{request.rb → http_request.rb} +29 -5
  99. data/gems/server/lib/itsi/http_response.rb +39 -0
  100. data/gems/server/lib/itsi/server/Itsi.rb +11 -19
  101. data/gems/server/lib/itsi/server/config/dsl.rb +506 -0
  102. data/gems/server/lib/itsi/server/config.rb +103 -8
  103. data/gems/server/lib/itsi/server/default_app/default_app.rb +38 -0
  104. data/gems/server/lib/itsi/server/grpc_interface.rb +213 -0
  105. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +8 -17
  106. data/gems/server/lib/itsi/server/rack_interface.rb +23 -4
  107. data/gems/server/lib/itsi/server/scheduler_interface.rb +1 -1
  108. data/gems/server/lib/itsi/server/scheduler_mode.rb +4 -0
  109. data/gems/server/lib/itsi/server/signal_trap.rb +7 -1
  110. data/gems/server/lib/itsi/server/version.rb +1 -1
  111. data/gems/server/lib/itsi/server.rb +74 -63
  112. data/gems/server/lib/itsi/standard_headers.rb +86 -0
  113. data/gems/server/test/helpers/test_helper.rb +12 -12
  114. data/gems/server/test/test_itsi_server.rb +2 -2
  115. data/lib/itsi/version.rb +1 -1
  116. data/sandbox/itsi_file/Gemfile +11 -0
  117. data/sandbox/itsi_file/Gemfile.lock +69 -0
  118. data/sandbox/itsi_file/Itsi.rb +276 -0
  119. data/sandbox/itsi_file/error.html +2 -0
  120. data/sandbox/itsi_file/organisations_controller.rb +20 -0
  121. data/sandbox/itsi_file/public/assets/image.png +0 -0
  122. data/sandbox/itsi_file/public/assets/index.html +1 -0
  123. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +2 -2
  124. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  125. data/sandbox/itsi_sandbox_rack/config.ru +2 -15
  126. data/sandbox/itsi_sandbox_rails/.dockerignore +2 -5
  127. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +1 -1
  128. data/sandbox/itsi_sandbox_rails/.gitignore +2 -1
  129. data/sandbox/itsi_sandbox_rails/Dockerfile +6 -9
  130. data/sandbox/itsi_sandbox_rails/Gemfile +16 -22
  131. data/sandbox/itsi_sandbox_rails/Gemfile.lock +100 -225
  132. data/sandbox/itsi_sandbox_rails/app/assets/config/manifest.js +4 -0
  133. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +11 -6
  134. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/channel.rb +4 -0
  135. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/connection.rb +4 -0
  136. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +7 -8
  137. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +0 -3
  138. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +2 -7
  139. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +3 -4
  140. data/sandbox/itsi_sandbox_rails/bin/setup +8 -5
  141. data/sandbox/itsi_sandbox_rails/config/application.rb +1 -35
  142. data/sandbox/itsi_sandbox_rails/config/cable.yml +3 -10
  143. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -1
  144. data/sandbox/itsi_sandbox_rails/config/database.yml +9 -19
  145. data/sandbox/itsi_sandbox_rails/config/environment.rb +1 -1
  146. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +21 -12
  147. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +49 -34
  148. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +19 -5
  149. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +5 -0
  150. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +1 -1
  151. data/sandbox/itsi_sandbox_rails/config/initializers/permissions_policy.rb +13 -0
  152. data/sandbox/itsi_sandbox_rails/config/puma.rb +2 -9
  153. data/sandbox/itsi_sandbox_rails/config.ru +0 -1
  154. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +1 -1
  155. data/sandbox/itsi_sandbox_rails/db/schema.rb +2 -2
  156. data/sandbox/itsi_sandbox_rails/lib/assets/.keep +0 -0
  157. data/sandbox/itsi_sandbox_rails/public/404.html +66 -113
  158. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +65 -113
  159. data/sandbox/itsi_sandbox_rails/public/422.html +66 -113
  160. data/sandbox/itsi_sandbox_rails/public/500.html +65 -113
  161. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  162. data/sandbox/itsi_sandbox_rails/public/icon.svg +2 -2
  163. data/sandbox/itsi_sandbox_rails/test/channels/application_cable/connection_test.rb +13 -0
  164. data/sandbox/itsi_sandbox_roda/Gemfile.lock +3 -10
  165. data/tasks.txt +72 -35
  166. metadata +89 -139
  167. data/crates/itsi_server/src/body_proxy/mod.rs +0 -2
  168. data/crates/itsi_server/src/request/itsi_request.rs +0 -298
  169. data/crates/itsi_server/src/request/mod.rs +0 -1
  170. data/crates/itsi_server/src/response/mod.rs +0 -1
  171. data/crates/itsi_server/src/server/itsi_server.rs +0 -288
  172. data/gems/scheduler/ext/itsi_error/Cargo.lock +0 -368
  173. data/gems/scheduler/ext/itsi_error/Cargo.toml +0 -11
  174. data/gems/scheduler/ext/itsi_error/src/from.rs +0 -68
  175. data/gems/scheduler/ext/itsi_error/src/lib.rs +0 -24
  176. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +0 -15
  177. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +0 -31
  178. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +0 -355
  179. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +0 -10
  180. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  181. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +0 -201
  182. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +0 -24
  183. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +0 -6
  184. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  185. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  186. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  187. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  188. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +0 -38
  189. data/gems/scheduler/ext/itsi_server/Cargo.lock +0 -2956
  190. data/gems/scheduler/ext/itsi_server/Cargo.toml +0 -50
  191. data/gems/scheduler/ext/itsi_server/extconf.rb +0 -6
  192. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  193. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  194. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  195. data/gems/scheduler/ext/itsi_server/src/env.rs +0 -43
  196. data/gems/scheduler/ext/itsi_server/src/lib.rs +0 -180
  197. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +0 -298
  198. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +0 -1
  199. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +0 -357
  200. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +0 -1
  201. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +0 -174
  202. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  203. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +0 -104
  204. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +0 -288
  205. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  206. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +0 -318
  207. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +0 -11
  208. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +0 -203
  209. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -260
  210. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  211. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -276
  212. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +0 -74
  213. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +0 -399
  214. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  215. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +0 -265
  216. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +0 -274
  217. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +0 -16
  218. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +0 -58
  219. data/gems/server/ext/itsi_error/Cargo.lock +0 -368
  220. data/gems/server/ext/itsi_error/Cargo.toml +0 -11
  221. data/gems/server/ext/itsi_error/src/from.rs +0 -68
  222. data/gems/server/ext/itsi_error/src/lib.rs +0 -24
  223. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +0 -15
  224. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +0 -31
  225. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +0 -355
  226. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +0 -10
  227. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  228. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +0 -201
  229. data/gems/server/ext/itsi_scheduler/Cargo.toml +0 -24
  230. data/gems/server/ext/itsi_scheduler/extconf.rb +0 -6
  231. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  232. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  233. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  234. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  235. data/gems/server/ext/itsi_scheduler/src/lib.rs +0 -38
  236. data/gems/server/ext/itsi_server/Cargo.lock +0 -2956
  237. data/gems/server/ext/itsi_server/Cargo.toml +0 -50
  238. data/gems/server/ext/itsi_server/extconf.rb +0 -6
  239. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  240. data/gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  241. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  242. data/gems/server/ext/itsi_server/src/env.rs +0 -43
  243. data/gems/server/ext/itsi_server/src/lib.rs +0 -180
  244. data/gems/server/ext/itsi_server/src/request/mod.rs +0 -1
  245. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +0 -357
  246. data/gems/server/ext/itsi_server/src/response/mod.rs +0 -1
  247. data/gems/server/ext/itsi_server/src/server/bind.rs +0 -174
  248. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  249. data/gems/server/ext/itsi_server/src/server/io_stream.rs +0 -104
  250. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +0 -288
  251. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  252. data/gems/server/ext/itsi_server/src/server/listener.rs +0 -318
  253. data/gems/server/ext/itsi_server/src/server/mod.rs +0 -11
  254. data/gems/server/ext/itsi_server/src/server/process_worker.rs +0 -203
  255. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -260
  256. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  257. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -276
  258. data/gems/server/ext/itsi_server/src/server/signal.rs +0 -74
  259. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +0 -399
  260. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  261. data/gems/server/ext/itsi_server/src/server/tls.rs +0 -265
  262. data/gems/server/ext/itsi_tracing/Cargo.lock +0 -274
  263. data/gems/server/ext/itsi_tracing/Cargo.toml +0 -16
  264. data/gems/server/ext/itsi_tracing/src/lib.rs +0 -58
  265. data/gems/server/lib/itsi/server/options_dsl.rb +0 -401
  266. data/gems/server/lib/itsi/stream_io.rb +0 -38
  267. data/location_dsl.rb +0 -381
  268. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +0 -3
  269. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +0 -3
  270. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +0 -14
  271. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +0 -3
  272. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +0 -3
  273. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +0 -51
  274. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +0 -47
  275. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +0 -109
  276. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  277. data/sandbox/itsi_sandbox_rails/.kamal/secrets +0 -17
  278. data/sandbox/itsi_sandbox_rails/bin/dev +0 -2
  279. data/sandbox/itsi_sandbox_rails/bin/jobs +0 -6
  280. data/sandbox/itsi_sandbox_rails/bin/kamal +0 -27
  281. data/sandbox/itsi_sandbox_rails/bin/thrust +0 -5
  282. data/sandbox/itsi_sandbox_rails/config/cache.yml +0 -16
  283. data/sandbox/itsi_sandbox_rails/config/deploy.yml +0 -116
  284. data/sandbox/itsi_sandbox_rails/config/queue.yml +0 -18
  285. data/sandbox/itsi_sandbox_rails/config/recurring.yml +0 -10
  286. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +0 -11
  287. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +0 -14
  288. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +0 -129
  289. data/sandbox/itsi_sandbox_rails/public/400.html +0 -114
  290. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +0 -9
  291. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +0 -7
  292. /data/{sandbox/itsi_sandbox_rails/script/.keep → crates/_index.md} +0 -0
  293. /data/gems/server/lib/itsi/{index.html → server/default_app/index.html} +0 -0
@@ -0,0 +1,93 @@
1
+ use super::MiddlewareLayer;
2
+ use crate::ruby_types::itsi_grpc_request::ItsiGrpcRequest;
3
+ use crate::server::static_file_server::ROOT_STATIC_FILE_SERVER;
4
+ use crate::{
5
+ ruby_types::itsi_http_request::ItsiHttpRequest,
6
+ server::{
7
+ itsi_service::RequestContext,
8
+ types::{HttpRequest, HttpResponse},
9
+ },
10
+ };
11
+ use async_trait::async_trait;
12
+ use derive_more::Debug;
13
+ use either::Either;
14
+ use itsi_rb_helpers::{HeapVal, HeapValue};
15
+ use magnus::{block::Proc, error::Result, value::ReprValue, Symbol};
16
+ use std::str::FromStr;
17
+ use std::sync::Arc;
18
+
19
+ #[derive(Debug)]
20
+ pub struct RubyApp {
21
+ app: Arc<HeapValue<Proc>>,
22
+ request_type: RequestType,
23
+ sendfile: bool,
24
+ }
25
+
26
+ #[derive(Debug)]
27
+ pub enum RequestType {
28
+ Http,
29
+ Grpc,
30
+ }
31
+
32
+ impl FromStr for RequestType {
33
+ type Err = &'static str;
34
+
35
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
36
+ match s {
37
+ "http" => Ok(RequestType::Http),
38
+ "grpc" => Ok(RequestType::Grpc),
39
+ _ => Err("Invalid request type"),
40
+ }
41
+ }
42
+ }
43
+
44
+ impl RubyApp {
45
+ pub fn from_value(params: HeapVal) -> magnus::error::Result<Self> {
46
+ let app = params.funcall::<_, _, Proc>(Symbol::new("[]"), ("app_proc",))?;
47
+ let sendfile = params
48
+ .funcall::<_, _, bool>(Symbol::new("[]"), ("sendfile",))
49
+ .unwrap_or(true);
50
+ let request_type: RequestType = params
51
+ .funcall::<_, _, String>(Symbol::new("[]"), ("request_type",))
52
+ .unwrap_or("http".to_string())
53
+ .parse()
54
+ .unwrap_or(RequestType::Http);
55
+
56
+ Ok(RubyApp {
57
+ app: Arc::new(app.into()),
58
+ sendfile,
59
+ request_type,
60
+ })
61
+ }
62
+ }
63
+
64
+ #[async_trait]
65
+ impl MiddlewareLayer for RubyApp {
66
+ async fn before(
67
+ &self,
68
+ req: HttpRequest,
69
+ context: &mut RequestContext,
70
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
71
+ match self.request_type {
72
+ RequestType::Http => ItsiHttpRequest::process_request(self.app.clone(), req, context)
73
+ .await
74
+ .map_err(|e| e.into())
75
+ .map(Either::Right),
76
+ RequestType::Grpc => ItsiGrpcRequest::process_request(self.app.clone(), req, context)
77
+ .await
78
+ .map_err(|e| e.into())
79
+ .map(Either::Right),
80
+ }
81
+ }
82
+
83
+ async fn after(&self, resp: HttpResponse, _context: &mut RequestContext) -> HttpResponse {
84
+ if self.sendfile {
85
+ if let Some(sendfile_header) = resp.headers().get("X-Sendfile") {
86
+ return ROOT_STATIC_FILE_SERVER
87
+ .serve_single(sendfile_header.to_str().unwrap())
88
+ .await;
89
+ }
90
+ }
91
+ resp
92
+ }
93
+ }
@@ -0,0 +1,162 @@
1
+ use super::{FromValue, MiddlewareLayer};
2
+ use crate::server::{
3
+ itsi_service::RequestContext,
4
+ static_file_server::{NotFoundBehavior, ServeRange, StaticFileServer, StaticFileServerConfig},
5
+ types::{HttpRequest, HttpResponse},
6
+ };
7
+ use async_trait::async_trait;
8
+ use either::Either;
9
+ use http::{
10
+ header::{IF_MODIFIED_SINCE, RANGE},
11
+ HeaderMap, Method,
12
+ };
13
+ use itsi_error::ItsiError;
14
+ use magnus::error::Result;
15
+ use serde::Deserialize;
16
+ use std::{collections::HashMap, path::PathBuf, sync::OnceLock, time::Duration};
17
+
18
+ #[derive(Debug, Deserialize)]
19
+ pub struct StaticAssets {
20
+ pub root_dir: PathBuf,
21
+ pub not_found_behavior: NotFoundBehavior,
22
+ pub auto_index: bool,
23
+ pub try_html_extension: bool,
24
+ pub max_file_size_in_memory: u64,
25
+ pub max_files_in_memory: u64,
26
+ pub file_check_interval: u64,
27
+ pub headers: Option<HashMap<String, String>>,
28
+ pub relative_path: bool,
29
+ #[serde(skip)]
30
+ file_server: OnceLock<StaticFileServer>,
31
+ }
32
+
33
+ #[async_trait]
34
+ impl MiddlewareLayer for StaticAssets {
35
+ async fn initialize(&self) -> Result<()> {
36
+ if let Ok(metadata) = tokio::fs::metadata(&self.root_dir).await {
37
+ if metadata.is_dir() {
38
+ Ok(())
39
+ } else {
40
+ Err(ItsiError::InvalidInput(
41
+ "Root directory exists but is not a directory".to_string(),
42
+ ))
43
+ }
44
+ } else {
45
+ Err(ItsiError::InvalidInput(
46
+ "Root directory exists but is not a directory".to_string(),
47
+ ))
48
+ }?;
49
+ self.file_server
50
+ .set(StaticFileServer::new(StaticFileServerConfig {
51
+ root_dir: self.root_dir.clone(),
52
+ not_found_behavior: self.not_found_behavior.clone(),
53
+ auto_index: self.auto_index,
54
+ max_entries: self.max_files_in_memory,
55
+ try_html_extension: self.try_html_extension,
56
+ max_file_size: self.max_file_size_in_memory,
57
+ recheck_interval: Duration::from_secs(self.file_check_interval),
58
+ }))
59
+ .map_err(ItsiError::default)?;
60
+ Ok(())
61
+ }
62
+
63
+ async fn before(
64
+ &self,
65
+ req: HttpRequest,
66
+ context: &mut RequestContext,
67
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
68
+ // Only handle GET and HEAD requests
69
+ if req.method() != Method::GET && req.method() != Method::HEAD {
70
+ return Ok(Either::Left(req));
71
+ }
72
+ let abs_path = req.uri().path();
73
+ let rel_path = if !self.relative_path {
74
+ abs_path
75
+ } else {
76
+ match context
77
+ .matching_pattern
78
+ .as_ref()
79
+ .and_then(|pattern| pattern.captures(req.uri().path()))
80
+ .and_then(|captures| captures.name("path_suffix"))
81
+ .map(|m| m.as_str())
82
+ {
83
+ Some(suffix) => suffix,
84
+ None => return Ok(Either::Left(req)),
85
+ }
86
+ };
87
+
88
+ // Determine if this is a HEAD request
89
+ let is_head_request = req.method() == Method::HEAD;
90
+
91
+ // Extract range and if-modified-since headers
92
+ let serve_range = parse_range_header(req.headers());
93
+ let if_modified_since = req
94
+ .headers()
95
+ .get(IF_MODIFIED_SINCE)
96
+ .and_then(|ims| ims.to_str().ok())
97
+ .and_then(|ims_str| httpdate::parse_http_date(ims_str).ok());
98
+
99
+ // Let the file server handle everything
100
+ let file_server = self.file_server.get().unwrap();
101
+ let response = file_server
102
+ .serve(
103
+ &req,
104
+ rel_path,
105
+ abs_path,
106
+ serve_range,
107
+ if_modified_since,
108
+ is_head_request,
109
+ )
110
+ .await;
111
+
112
+ if response.is_none() {
113
+ Ok(Either::Left(req))
114
+ } else {
115
+ Ok(Either::Right(response.unwrap()))
116
+ }
117
+ }
118
+ }
119
+
120
+ fn parse_range_header(headers: &HeaderMap) -> ServeRange {
121
+ let range_header = headers.get(RANGE);
122
+ if range_header.is_none() {
123
+ return ServeRange::Full;
124
+ }
125
+ let range_header = range_header.unwrap().to_str().unwrap_or("");
126
+ let bytes_prefix = "bytes=";
127
+ if !range_header.starts_with(bytes_prefix) {
128
+ return ServeRange::Full;
129
+ }
130
+
131
+ let range_str = &range_header[bytes_prefix.len()..];
132
+
133
+ let range_parts: Vec<&str> = range_str
134
+ .split(',')
135
+ .next()
136
+ .unwrap_or("")
137
+ .split('-')
138
+ .collect();
139
+ if range_parts.len() != 2 {
140
+ return ServeRange::Full;
141
+ }
142
+
143
+ let start = if range_parts[0].is_empty() {
144
+ range_parts[1].parse::<u64>().unwrap_or(0)
145
+ } else if let Ok(start) = range_parts[0].parse::<u64>() {
146
+ start
147
+ } else {
148
+ return ServeRange::Full;
149
+ };
150
+
151
+ let end = if range_parts[1].is_empty() {
152
+ u64::MAX // Use u64::MAX as sentinel for open-ended ranges
153
+ } else if let Ok(end) = range_parts[1].parse::<u64>() {
154
+ end // No conversion needed, already u64
155
+ } else {
156
+ return ServeRange::Full;
157
+ };
158
+
159
+ ServeRange::Range(start, end)
160
+ }
161
+
162
+ impl FromValue for StaticAssets {}
@@ -0,0 +1,158 @@
1
+ use crate::server::{
2
+ itsi_service::RequestContext,
3
+ types::{HttpRequest, HttpResponse},
4
+ };
5
+ use serde::Deserialize;
6
+ use std::sync::OnceLock;
7
+
8
+ #[derive(Debug, Clone, Deserialize)]
9
+ #[serde(transparent)]
10
+ pub struct StringRewrite {
11
+ pub template_string: String,
12
+ #[serde(default)]
13
+ pub segments: OnceLock<Vec<Segment>>,
14
+ }
15
+
16
+ #[derive(Debug, Clone, Deserialize)]
17
+ pub enum Segment {
18
+ Literal(String),
19
+ Placeholder(String),
20
+ }
21
+
22
+ pub fn parse_template(template: &str) -> Vec<Segment> {
23
+ let mut segments = Vec::new();
24
+ let mut last_index = 0;
25
+ while let Some(start_index) = template[last_index..].find('{') {
26
+ let start_index = last_index + start_index;
27
+ // Add the literal text before the placeholder.
28
+ if start_index > last_index {
29
+ segments.push(Segment::Literal(
30
+ template[last_index..start_index].to_string(),
31
+ ));
32
+ }
33
+ // Find the corresponding closing brace.
34
+ if let Some(end_index) = template[start_index..].find('}') {
35
+ let end_index = start_index + end_index;
36
+ let placeholder = &template[start_index + 1..end_index];
37
+ segments.push(Segment::Placeholder(placeholder.to_string()));
38
+ last_index = end_index + 1;
39
+ } else {
40
+ // No closing brace found; treat the rest as literal.
41
+ segments.push(Segment::Literal(template[start_index..].to_string()));
42
+ break;
43
+ }
44
+ }
45
+ if last_index < template.len() {
46
+ segments.push(Segment::Literal(template[last_index..].to_string()));
47
+ }
48
+ segments
49
+ }
50
+
51
+ impl StringRewrite {
52
+ pub fn rewrite_request(&self, req: &HttpRequest, context: &RequestContext) -> String {
53
+ let segments = self
54
+ .segments
55
+ .get_or_init(|| parse_template(&self.template_string));
56
+ let captures = context
57
+ .matching_pattern
58
+ .as_ref()
59
+ .and_then(|re| re.captures(req.uri().path()));
60
+
61
+ let mut result = String::with_capacity(self.template_string.len());
62
+
63
+ for segment in segments {
64
+ match segment {
65
+ Segment::Literal(text) => result.push_str(text),
66
+ Segment::Placeholder(placeholder) => {
67
+ let replacement = match placeholder.as_str() {
68
+ "request_id" => context.request_id(),
69
+ "method" => req.method().as_str().to_string(),
70
+ "path" => req.uri().path().to_string(),
71
+ "host" => req.uri().host().unwrap_or("localhost").to_string(),
72
+ "path_and_query" => req
73
+ .uri()
74
+ .path_and_query()
75
+ .map(|pq| pq.to_string())
76
+ .unwrap_or("".to_string()),
77
+ "query" => {
78
+ let query = req.uri().query().unwrap_or("").to_string();
79
+ if query.is_empty() {
80
+ query
81
+ } else {
82
+ format!("?{}", query)
83
+ }
84
+ }
85
+ "port" => req
86
+ .uri()
87
+ .port()
88
+ .map(|p| p.to_string())
89
+ .unwrap_or_else(|| "80".to_string()),
90
+ "start_time" => {
91
+ if let Some(start_time) = context.start_time() {
92
+ start_time.format("%Y-%m-%d:%H:%M:%S:%3f").to_string()
93
+ } else {
94
+ "N/A".to_string()
95
+ }
96
+ }
97
+ other => {
98
+ // Try using the context's matching regex if available.
99
+ if let Some(caps) = &captures {
100
+ if let Some(m) = caps.name(other) {
101
+ m.as_str().to_string()
102
+ } else {
103
+ // Fallback: leave the placeholder as is.
104
+ format!("{{{}}}", other)
105
+ }
106
+ } else {
107
+ format!("{{{}}}", other)
108
+ }
109
+ }
110
+ };
111
+ result.push_str(&replacement);
112
+ }
113
+ }
114
+ }
115
+
116
+ result
117
+ }
118
+
119
+ pub fn rewrite_response(&self, resp: &HttpResponse, context: &RequestContext) -> String {
120
+ let segments = self
121
+ .segments
122
+ .get_or_init(|| parse_template(&self.template_string));
123
+
124
+ let mut result = String::with_capacity(self.template_string.len());
125
+ for segment in segments {
126
+ match segment {
127
+ Segment::Literal(text) => result.push_str(text),
128
+ Segment::Placeholder(placeholder) => {
129
+ let replacement = match placeholder.as_str() {
130
+ "request_id" => context.request_id(),
131
+ "status" => resp.status().as_str().to_string(),
132
+ "response_time" => {
133
+ if let Some(response_time) = context.get_response_time() {
134
+ if let Some(microseconds) = response_time.num_microseconds() {
135
+ format!("{:.3}ms", microseconds as f64 / 1000.0)
136
+ } else {
137
+ format!("{}ms", response_time.num_milliseconds())
138
+ }
139
+ } else {
140
+ "-".to_string()
141
+ }
142
+ }
143
+ other => {
144
+ if let Some(header_value) = resp.headers().get(other) {
145
+ format!("{:?}", header_value)
146
+ } else {
147
+ format!("{{{}}}", other)
148
+ }
149
+ }
150
+ };
151
+ result.push_str(&replacement);
152
+ }
153
+ }
154
+ }
155
+
156
+ result
157
+ }
158
+ }
@@ -0,0 +1,12 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ #[derive(Debug, Clone, Serialize, Deserialize)]
4
+ pub enum TokenSource {
5
+ #[serde(rename(deserialize = "header"))]
6
+ Header {
7
+ name: String,
8
+ prefix: Option<String>,
9
+ },
10
+ #[serde(rename(deserialize = "query"))]
11
+ Query(String),
12
+ }