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,55 @@
1
+ use magnus::{value::Lazy, Module, RClass, RModule};
2
+
3
+ pub mod itsi_body_proxy;
4
+ pub mod itsi_grpc_request;
5
+ pub mod itsi_grpc_response;
6
+ pub mod itsi_grpc_stream;
7
+ pub mod itsi_http_request;
8
+ pub mod itsi_http_response;
9
+ pub mod itsi_server;
10
+
11
+ pub static ITSI_MODULE: Lazy<RModule> = Lazy::new(|ruby| ruby.define_module("Itsi").unwrap());
12
+ pub static ITSI_SERVER: Lazy<RClass> = Lazy::new(|ruby| {
13
+ ruby.get_inner(&ITSI_MODULE)
14
+ .define_class("Server", ruby.class_object())
15
+ .unwrap()
16
+ });
17
+
18
+ pub static ITSI_SERVER_CONFIG: Lazy<RModule> =
19
+ Lazy::new(|ruby| ruby.get_inner(&ITSI_SERVER).const_get("Config").unwrap());
20
+
21
+ pub static ITSI_REQUEST: Lazy<RClass> = Lazy::new(|ruby| {
22
+ ruby.get_inner(&ITSI_MODULE)
23
+ .define_class("HttpRequest", ruby.class_object())
24
+ .unwrap()
25
+ });
26
+
27
+ pub static ITSI_RESPONSE: Lazy<RClass> = Lazy::new(|ruby| {
28
+ ruby.get_inner(&ITSI_MODULE)
29
+ .define_class("HttpResponse", ruby.class_object())
30
+ .unwrap()
31
+ });
32
+
33
+ pub static ITSI_BODY_PROXY: Lazy<RClass> = Lazy::new(|ruby| {
34
+ ruby.get_inner(&ITSI_MODULE)
35
+ .define_class("BodyProxy", ruby.class_object())
36
+ .unwrap()
37
+ });
38
+
39
+ pub static ITSI_GRPC_REQUEST: Lazy<RClass> = Lazy::new(|ruby| {
40
+ ruby.get_inner(&ITSI_MODULE)
41
+ .define_class("GrpcRequest", ruby.class_object())
42
+ .unwrap()
43
+ });
44
+
45
+ pub static ITSI_GRPC_STREAM: Lazy<RClass> = Lazy::new(|ruby| {
46
+ ruby.get_inner(&ITSI_MODULE)
47
+ .define_class("GrpcStream", ruby.class_object())
48
+ .unwrap()
49
+ });
50
+
51
+ pub static ITSI_GRPC_RESPONSE: Lazy<RClass> = Lazy::new(|ruby| {
52
+ ruby.get_inner(&ITSI_MODULE)
53
+ .define_class("GrpcResponse", ruby.class_object())
54
+ .unwrap()
55
+ });
@@ -31,13 +31,21 @@ pub struct Bind {
31
31
  pub tls_config: Option<ItsiTlsAcceptor>,
32
32
  }
33
33
 
34
+ impl Bind {
35
+ pub fn listener_address_string(&self) -> String {
36
+ match &self.address {
37
+ BindAddress::Ip(ip) => format!("tcp://{}:{}", ip.to_canonical(), self.port.unwrap()),
38
+ BindAddress::UnixSocket(path) => {
39
+ format!("unix://{}", path.as_path().to_str().unwrap())
40
+ }
41
+ }
42
+ }
43
+ }
44
+
34
45
  impl std::fmt::Debug for Bind {
35
46
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36
47
  match &self.address {
37
48
  BindAddress::Ip(ip) => match self.protocol {
38
- BindProtocol::Unix | BindProtocol::Unixs => {
39
- write!(f, "{}://{}", self.protocol, ip)
40
- }
41
49
  BindProtocol::Https if self.port == Some(443) => {
42
50
  write!(f, "{}://{}", self.protocol, ip)
43
51
  }
@@ -158,8 +166,8 @@ fn resolve_hostname(hostname: &str) -> Option<IpAddr> {
158
166
  .to_socket_addrs()
159
167
  .ok()?
160
168
  .find_map(|addr| {
161
- if addr.is_ipv6() {
162
- Some(addr.ip()) // Prefer IPv6
169
+ if addr.is_ipv4() {
170
+ Some(addr.ip()) // Prefer IPv4
163
171
  } else {
164
172
  None
165
173
  }
@@ -0,0 +1,32 @@
1
+ use std::ops::Deref;
2
+
3
+ use bytes::Bytes;
4
+
5
+ #[derive(Debug)]
6
+ pub enum ByteFrame {
7
+ Data(Bytes),
8
+ End(Bytes),
9
+ Empty,
10
+ }
11
+
12
+ impl Deref for ByteFrame {
13
+ type Target = Bytes;
14
+
15
+ fn deref(&self) -> &Self::Target {
16
+ match self {
17
+ ByteFrame::Data(data) => data,
18
+ ByteFrame::End(data) => data,
19
+ ByteFrame::Empty => unreachable!(),
20
+ }
21
+ }
22
+ }
23
+
24
+ impl From<ByteFrame> for Bytes {
25
+ fn from(frame: ByteFrame) -> Self {
26
+ match frame {
27
+ ByteFrame::Data(data) => data,
28
+ ByteFrame::End(data) => data,
29
+ ByteFrame::Empty => unreachable!(),
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,74 @@
1
+ use async_trait::async_trait;
2
+ use redis::aio::ConnectionManager;
3
+ use redis::{Client, RedisError, Script};
4
+ use std::sync::Arc;
5
+ use std::time::Duration;
6
+
7
+ #[derive(Debug)]
8
+ pub enum CacheError {
9
+ RedisError(RedisError),
10
+ // Other error variants as needed.
11
+ }
12
+ /// A general-purpose cache trait with an atomic “increment with timeout” operation.
13
+ #[async_trait]
14
+ pub trait CacheStore: Send + Sync + std::fmt::Debug {
15
+ /// Increments the counter associated with `key` and sets (or extends) its expiration.
16
+ /// Returns the new counter value.
17
+ async fn increment(&self, key: &str, timeout: Duration) -> Result<u64, CacheError>;
18
+ }
19
+
20
+ /// A Redis-backed cache store using an async connection manager.
21
+ /// This uses a TLS-enabled connection when the URL is prefixed with "rediss://".
22
+ #[derive(Clone)]
23
+ pub struct RedisCacheStore {
24
+ connection: Arc<ConnectionManager>,
25
+ }
26
+
27
+ impl std::fmt::Debug for RedisCacheStore {
28
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29
+ f.debug_struct("RedisCacheStore").finish()
30
+ }
31
+ }
32
+
33
+ impl RedisCacheStore {
34
+ /// Constructs a new RedisCacheStore.
35
+ ///
36
+ /// Use a connection URL like "rediss://host:port" to enable TLS (with rustls under the hood).
37
+ /// This constructor is async because it sets up the connection manager.
38
+ pub async fn new(connection_url: &str) -> Result<Self, CacheError> {
39
+ let client = Client::open(connection_url).map_err(CacheError::RedisError)?;
40
+ let connection_manager = ConnectionManager::new(client)
41
+ .await
42
+ .map_err(CacheError::RedisError)?;
43
+ Ok(Self {
44
+ connection: Arc::new(connection_manager),
45
+ })
46
+ }
47
+ }
48
+
49
+ #[async_trait]
50
+ impl CacheStore for RedisCacheStore {
51
+ async fn increment(&self, key: &str, timeout: Duration) -> Result<u64, CacheError> {
52
+ let timeout_secs = timeout.as_secs();
53
+ // Lua script to:
54
+ // 1. INCR the key.
55
+ // 2. If the key doesn't have a TTL, set it.
56
+ let script = r#"
57
+ local current = redis.call('INCR', KEYS[1])
58
+ if redis.call('TTL', KEYS[1]) < 0 then
59
+ redis.call('EXPIRE', KEYS[1], ARGV[1])
60
+ end
61
+ return current
62
+ "#;
63
+ let script = Script::new(script);
64
+ // The ConnectionManager is cloneable and can be used concurrently.
65
+ let mut connection = (*self.connection).clone();
66
+ let value: i64 = script
67
+ .key(key)
68
+ .arg(timeout_secs)
69
+ .invoke_async(&mut connection)
70
+ .await
71
+ .map_err(CacheError::RedisError)?;
72
+ Ok(value as u64)
73
+ }
74
+ }
@@ -0,0 +1,172 @@
1
+ use super::listener::ListenerInfo;
2
+ use super::middleware_stack::CompressionAlgorithm;
3
+ use super::middleware_stack::MiddlewareLayer;
4
+ use super::request_job::RequestJob;
5
+ use super::serve_strategy::single_mode::RunningPhase;
6
+ use super::types::HttpRequest;
7
+ use super::types::HttpResponse;
8
+ use crate::ruby_types::itsi_server::itsi_server_config::ServerParams;
9
+ use chrono;
10
+ use chrono::Local;
11
+ use either::Either;
12
+ use hyper::service::Service;
13
+ use itsi_error::ItsiError;
14
+ use regex::Regex;
15
+ use std::sync::OnceLock;
16
+ use std::{future::Future, ops::Deref, pin::Pin, sync::Arc};
17
+ use tokio::sync::watch::{self};
18
+
19
+ #[derive(Clone)]
20
+ pub struct ItsiService {
21
+ pub inner: Arc<IstiServiceInner>,
22
+ }
23
+
24
+ impl Deref for ItsiService {
25
+ type Target = Arc<IstiServiceInner>;
26
+
27
+ fn deref(&self) -> &Self::Target {
28
+ &self.inner
29
+ }
30
+ }
31
+
32
+ pub struct IstiServiceInner {
33
+ pub sender: async_channel::Sender<RequestJob>,
34
+ pub server_params: Arc<ServerParams>,
35
+ pub listener: Arc<ListenerInfo>,
36
+ pub addr: String,
37
+ pub shutdown_channel: watch::Receiver<RunningPhase>,
38
+ }
39
+
40
+ #[derive(Clone)]
41
+ pub struct RequestContext {
42
+ inner: Arc<RequestContextInner>,
43
+ }
44
+
45
+ impl Deref for RequestContext {
46
+ type Target = Arc<RequestContextInner>;
47
+
48
+ fn deref(&self) -> &Self::Target {
49
+ &self.inner
50
+ }
51
+ }
52
+
53
+ impl Deref for RequestContextInner {
54
+ type Target = ItsiService;
55
+
56
+ fn deref(&self) -> &Self::Target {
57
+ &self.service
58
+ }
59
+ }
60
+
61
+ pub struct RequestContextInner {
62
+ pub request_id: i128,
63
+ pub service: ItsiService,
64
+ pub matching_pattern: Option<Arc<Regex>>,
65
+ pub compression_method: OnceLock<CompressionAlgorithm>,
66
+ pub origin: OnceLock<Option<String>>,
67
+ pub start_time: chrono::DateTime<chrono::Utc>,
68
+ pub request: Option<Arc<HttpRequest>>,
69
+ pub request_start_time: OnceLock<chrono::DateTime<Local>>,
70
+ pub if_none_match: OnceLock<Option<String>>,
71
+ pub etag_value: OnceLock<Option<String>>,
72
+ }
73
+
74
+ impl RequestContext {
75
+ fn new(service: ItsiService, matching_pattern: Option<Arc<Regex>>) -> Self {
76
+ RequestContext {
77
+ inner: Arc::new(RequestContextInner {
78
+ request_id: rand::random::<i128>(),
79
+ service,
80
+ matching_pattern,
81
+ compression_method: OnceLock::new(),
82
+ origin: OnceLock::new(),
83
+ start_time: chrono::Utc::now(),
84
+ request: None,
85
+ request_start_time: OnceLock::new(),
86
+ if_none_match: OnceLock::new(),
87
+ etag_value: OnceLock::new(),
88
+ }),
89
+ }
90
+ }
91
+
92
+ pub fn set_compression_method(&self, method: CompressionAlgorithm) {
93
+ self.inner.compression_method.set(method).unwrap();
94
+ }
95
+
96
+ pub fn set_origin(&self, origin: Option<String>) {
97
+ self.inner.origin.set(origin).unwrap();
98
+ }
99
+
100
+ pub fn set_if_none_match(&self, value: Option<String>) {
101
+ self.inner.if_none_match.set(value).unwrap();
102
+ }
103
+
104
+ pub fn get_if_none_match(&self) -> Option<String> {
105
+ self.inner.if_none_match.get().cloned().flatten()
106
+ }
107
+
108
+ pub fn request_id(&self) -> String {
109
+ self.inner.request_id.to_string()
110
+ }
111
+
112
+ pub fn track_start_time(&self) {
113
+ self.inner
114
+ .request_start_time
115
+ .get_or_init(chrono::Local::now);
116
+ }
117
+
118
+ pub fn start_time(&self) -> Option<chrono::DateTime<Local>> {
119
+ self.inner.request_start_time.get().cloned()
120
+ }
121
+
122
+ pub fn get_response_time(&self) -> Option<chrono::TimeDelta> {
123
+ self.inner
124
+ .request_start_time
125
+ .get()
126
+ .map(|instant| Local::now() - instant)
127
+ }
128
+ }
129
+
130
+ impl Service<HttpRequest> for ItsiService {
131
+ type Response = HttpResponse;
132
+ type Error = ItsiError;
133
+ type Future = Pin<Box<dyn Future<Output = itsi_error::Result<HttpResponse>> + Send>>;
134
+
135
+ // This is called once per incoming Request.
136
+ fn call(&self, req: HttpRequest) -> Self::Future {
137
+ let params = self.server_params.clone();
138
+ let self_clone = self.clone();
139
+ Box::pin(async move {
140
+ let mut req = req;
141
+ let mut resp: Option<HttpResponse> = None;
142
+ let (stack, matching_pattern) = params.middleware.get().unwrap().stack_for(&req);
143
+ let mut context = RequestContext::new(self_clone, matching_pattern);
144
+ let mut depth = 0;
145
+ for (index, elm) in stack.iter().enumerate() {
146
+ match elm.before(req, &mut context).await {
147
+ Ok(Either::Left(r)) => req = r,
148
+ Ok(Either::Right(r)) => {
149
+ resp = Some(r);
150
+ depth = index;
151
+ break;
152
+ }
153
+ Err(e) => return Err(e.into()),
154
+ }
155
+ }
156
+
157
+ let mut resp = match resp {
158
+ Some(r) => r,
159
+ None => {
160
+ return Err(ItsiError::InternalServerError(
161
+ "No response returned from middleware stack".to_string(),
162
+ ))
163
+ }
164
+ };
165
+ for elm in stack.iter().rev().skip(stack.len() - depth - 1) {
166
+ resp = elm.after(resp, &mut context).await;
167
+ }
168
+
169
+ Ok(resp)
170
+ })
171
+ }
172
+ }
@@ -3,7 +3,10 @@ pub enum LifecycleEvent {
3
3
  Start,
4
4
  Shutdown,
5
5
  Restart,
6
+ Reload,
6
7
  IncreaseWorkers,
7
8
  DecreaseWorkers,
8
9
  ForceShutdown,
10
+ PrintInfo,
11
+ ChildTerminated,
9
12
  }
@@ -6,7 +6,9 @@ use super::tls::ItsiTlsAcceptor;
6
6
  use itsi_error::{ItsiError, Result};
7
7
  use itsi_tracing::info;
8
8
  use socket2::{Domain, Protocol, Socket, Type};
9
+ use std::fmt::Display;
9
10
  use std::net::{IpAddr, SocketAddr, TcpListener};
11
+ use std::os::fd::{AsRawFd, FromRawFd, RawFd};
10
12
  use std::sync::Arc;
11
13
  use std::{os::unix::net::UnixListener, path::PathBuf};
12
14
  use tokio::net::TcpListener as TokioTcpListener;
@@ -241,6 +243,32 @@ impl std::fmt::Display for SockAddr {
241
243
  }
242
244
  }
243
245
  }
246
+ impl Display for Listener {
247
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248
+ match self {
249
+ Listener::Tcp(listener) | Listener::TcpTls((listener, _)) => write!(
250
+ f,
251
+ "{}",
252
+ listener
253
+ .local_addr()
254
+ .map(|addr| addr.to_string())
255
+ .unwrap_or_else(|_| "".to_string())
256
+ ),
257
+
258
+ Listener::Unix(listener) | Listener::UnixTls((listener, _)) => write!(
259
+ f,
260
+ "{}",
261
+ listener
262
+ .local_addr()
263
+ .map(|addr| addr
264
+ .as_pathname()
265
+ .map(|path| path.to_str().unwrap_or("").to_owned())
266
+ .unwrap_or_default())
267
+ .unwrap_or_else(|_| "".to_string())
268
+ ),
269
+ }
270
+ }
271
+ }
244
272
 
245
273
  impl Listener {
246
274
  pub fn into_tokio_listener(self) -> TokioListener {
@@ -261,6 +289,58 @@ impl Listener {
261
289
  ),
262
290
  }
263
291
  }
292
+
293
+ /// Handover information when using exec to hand over the listener to a replacement process.
294
+ pub fn handover(&self) -> Result<(String, i32)> {
295
+ match self {
296
+ Listener::Tcp(listener) => {
297
+ let addr = listener.local_addr()?;
298
+ Ok((
299
+ format!("tcp://{}:{}", addr.ip().to_canonical(), addr.port()),
300
+ listener.as_raw_fd(),
301
+ ))
302
+ }
303
+ Listener::TcpTls((listener, _)) => {
304
+ let addr = listener.local_addr()?;
305
+ Ok((
306
+ format!("tcp://{}:{}", addr.ip().to_canonical(), addr.port()),
307
+ listener.as_raw_fd(),
308
+ ))
309
+ }
310
+ Listener::Unix(listener) => {
311
+ let addr = listener.local_addr()?;
312
+ Ok((
313
+ format!("unix://{}", addr.as_pathname().unwrap().to_str().unwrap()),
314
+ listener.as_raw_fd(),
315
+ ))
316
+ }
317
+ Listener::UnixTls((listener, _)) => {
318
+ let addr = listener.local_addr()?;
319
+ Ok((
320
+ format!("unix://{}", addr.as_pathname().unwrap().to_str().unwrap()),
321
+ listener.as_raw_fd(),
322
+ ))
323
+ }
324
+ }
325
+ }
326
+
327
+ pub fn inherit_fd(bind: Bind, fd: RawFd) -> Result<Self> {
328
+ let bound = match bind.address {
329
+ BindAddress::Ip(_) => match bind.protocol {
330
+ BindProtocol::Http => Listener::Tcp(revive_tcp_socket(fd)?),
331
+ BindProtocol::Https => {
332
+ let tcp_listener = revive_tcp_socket(fd)?;
333
+ Listener::TcpTls((tcp_listener, bind.tls_config.unwrap()))
334
+ }
335
+ _ => unreachable!(),
336
+ },
337
+ BindAddress::UnixSocket(_) => match bind.tls_config {
338
+ Some(tls_config) => Listener::UnixTls((revive_unix_socket(fd)?, tls_config)),
339
+ None => Listener::Unix(revive_unix_socket(fd)?),
340
+ },
341
+ };
342
+ Ok(bound)
343
+ }
264
344
  }
265
345
 
266
346
  impl TryFrom<Bind> for Listener {
@@ -285,6 +365,27 @@ impl TryFrom<Bind> for Listener {
285
365
  }
286
366
  }
287
367
 
368
+ fn revive_tcp_socket(fd: RawFd) -> Result<TcpListener> {
369
+ let socket = unsafe { Socket::from_raw_fd(fd) };
370
+ socket.set_reuse_port(true).ok();
371
+ socket.set_reuse_address(true).ok();
372
+ socket.set_nonblocking(true).ok();
373
+ socket.set_nodelay(true).ok();
374
+ socket.set_recv_buffer_size(262_144).ok();
375
+ socket.set_cloexec(true)?;
376
+ socket.listen(1024)?;
377
+ Ok(socket.into())
378
+ }
379
+
380
+ fn revive_unix_socket(fd: RawFd) -> Result<UnixListener> {
381
+ let socket = unsafe { Socket::from_raw_fd(fd) };
382
+ socket.set_nonblocking(true).ok();
383
+ socket.listen(1024)?;
384
+ socket.set_cloexec(true)?;
385
+
386
+ Ok(socket.into())
387
+ }
388
+
288
389
  fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
289
390
  let domain = match addr {
290
391
  IpAddr::V4(_) => Domain::IPV4,
@@ -297,7 +398,7 @@ fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
297
398
  socket.set_nonblocking(true).ok();
298
399
  socket.set_nodelay(true).ok();
299
400
  socket.set_recv_buffer_size(262_144).ok();
300
- info!("Binding to {:?}", socket_address);
401
+ socket.set_only_v6(false).ok();
301
402
  socket.bind(&socket_address.into())?;
302
403
  socket.listen(1024)?;
303
404
  Ok(socket.into())
@@ -310,7 +411,6 @@ fn connect_unix_socket(path: &PathBuf) -> Result<UnixListener> {
310
411
 
311
412
  let socket_address = socket2::SockAddr::unix(path)?;
312
413
 
313
- info!("Binding to {:?}", path);
314
414
  socket.bind(&socket_address)?;
315
415
  socket.listen(1024)?;
316
416
 
@@ -0,0 +1,153 @@
1
+ use super::middlewares::*;
2
+ use crate::server::{
3
+ itsi_service::RequestContext,
4
+ types::{HttpRequest, HttpResponse},
5
+ };
6
+ use async_trait::async_trait;
7
+ use either::Either;
8
+ use magnus::error::Result;
9
+ use std::cmp::Ordering;
10
+
11
+ #[derive(Debug)]
12
+ pub enum Middleware {
13
+ AllowList(AllowList),
14
+ AuthAPIKey(AuthAPIKey),
15
+ AuthBasic(AuthBasic),
16
+ AuthJwt(Box<AuthJwt>),
17
+ CacheControl(CacheControl),
18
+ Compression(Compression),
19
+ Cors(Box<Cors>),
20
+ DenyList(DenyList),
21
+ ETag(ETag),
22
+ IntrusionProtection(IntrusionProtection),
23
+ LogRequests(LogRequests),
24
+ Proxy(Proxy),
25
+ RateLimit(RateLimit),
26
+ Redirect(Redirect),
27
+ RequestHeaders(RequestHeaders),
28
+ ResponseHeaders(ResponseHeaders),
29
+ RubyApp(RubyApp),
30
+ StaticAssets(StaticAssets),
31
+ }
32
+
33
+ #[async_trait]
34
+ impl MiddlewareLayer for Middleware {
35
+ /// Called just once, to initialize the middleware state.
36
+ async fn initialize(&self) -> Result<()> {
37
+ match self {
38
+ Middleware::DenyList(filter) => filter.initialize().await,
39
+ Middleware::AllowList(filter) => filter.initialize().await,
40
+ Middleware::AuthBasic(filter) => filter.initialize().await,
41
+ Middleware::AuthJwt(filter) => filter.initialize().await,
42
+ Middleware::AuthAPIKey(filter) => filter.initialize().await,
43
+ Middleware::IntrusionProtection(filter) => filter.initialize().await,
44
+ Middleware::RateLimit(filter) => filter.initialize().await,
45
+ Middleware::RequestHeaders(filter) => filter.initialize().await,
46
+ Middleware::ResponseHeaders(filter) => filter.initialize().await,
47
+ Middleware::CacheControl(filter) => filter.initialize().await,
48
+ Middleware::Cors(filter) => filter.initialize().await,
49
+ Middleware::ETag(filter) => filter.initialize().await,
50
+ Middleware::StaticAssets(filter) => filter.initialize().await,
51
+ Middleware::Compression(filter) => filter.initialize().await,
52
+ Middleware::LogRequests(filter) => filter.initialize().await,
53
+ Middleware::Redirect(filter) => filter.initialize().await,
54
+ Middleware::Proxy(filter) => filter.initialize().await,
55
+ Middleware::RubyApp(filter) => filter.initialize().await,
56
+ }
57
+ }
58
+
59
+ async fn before(
60
+ &self,
61
+ req: HttpRequest,
62
+ context: &mut RequestContext,
63
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
64
+ match self {
65
+ Middleware::DenyList(filter) => filter.before(req, context).await,
66
+ Middleware::AllowList(filter) => filter.before(req, context).await,
67
+ Middleware::AuthBasic(filter) => filter.before(req, context).await,
68
+ Middleware::AuthJwt(filter) => filter.before(req, context).await,
69
+ Middleware::AuthAPIKey(filter) => filter.before(req, context).await,
70
+ Middleware::IntrusionProtection(filter) => filter.before(req, context).await,
71
+ Middleware::RequestHeaders(filter) => filter.before(req, context).await,
72
+ Middleware::ResponseHeaders(filter) => filter.before(req, context).await,
73
+ Middleware::RateLimit(filter) => filter.before(req, context).await,
74
+ Middleware::CacheControl(filter) => filter.before(req, context).await,
75
+ Middleware::Cors(filter) => filter.before(req, context).await,
76
+ Middleware::ETag(filter) => filter.before(req, context).await,
77
+ Middleware::StaticAssets(filter) => filter.before(req, context).await,
78
+ Middleware::Compression(filter) => filter.before(req, context).await,
79
+ Middleware::LogRequests(filter) => filter.before(req, context).await,
80
+ Middleware::Redirect(filter) => filter.before(req, context).await,
81
+ Middleware::Proxy(filter) => filter.before(req, context).await,
82
+ Middleware::RubyApp(filter) => filter.before(req, context).await,
83
+ }
84
+ }
85
+
86
+ async fn after(&self, res: HttpResponse, context: &mut RequestContext) -> HttpResponse {
87
+ match self {
88
+ Middleware::DenyList(filter) => filter.after(res, context).await,
89
+ Middleware::AllowList(filter) => filter.after(res, context).await,
90
+ Middleware::AuthBasic(filter) => filter.after(res, context).await,
91
+ Middleware::AuthJwt(filter) => filter.after(res, context).await,
92
+ Middleware::AuthAPIKey(filter) => filter.after(res, context).await,
93
+ Middleware::IntrusionProtection(filter) => filter.after(res, context).await,
94
+ Middleware::RateLimit(filter) => filter.after(res, context).await,
95
+ Middleware::RequestHeaders(filter) => filter.after(res, context).await,
96
+ Middleware::ResponseHeaders(filter) => filter.after(res, context).await,
97
+ Middleware::CacheControl(filter) => filter.after(res, context).await,
98
+ Middleware::Cors(filter) => filter.after(res, context).await,
99
+ Middleware::ETag(filter) => filter.after(res, context).await,
100
+ Middleware::StaticAssets(filter) => filter.after(res, context).await,
101
+ Middleware::Compression(filter) => filter.after(res, context).await,
102
+ Middleware::LogRequests(filter) => filter.after(res, context).await,
103
+ Middleware::Redirect(filter) => filter.after(res, context).await,
104
+ Middleware::Proxy(filter) => filter.after(res, context).await,
105
+ Middleware::RubyApp(filter) => filter.after(res, context).await,
106
+ }
107
+ }
108
+ }
109
+
110
+ impl Middleware {
111
+ fn variant_order(&self) -> usize {
112
+ match self {
113
+ Middleware::DenyList(_) => 0,
114
+ Middleware::AllowList(_) => 1,
115
+ Middleware::IntrusionProtection(_) => 2,
116
+ Middleware::Redirect(_) => 3,
117
+ Middleware::LogRequests(_) => 4,
118
+ Middleware::CacheControl(_) => 5,
119
+ Middleware::RequestHeaders(_) => 6,
120
+ Middleware::ResponseHeaders(_) => 7,
121
+ Middleware::AuthBasic(_) => 8,
122
+ Middleware::AuthJwt(_) => 9,
123
+ Middleware::AuthAPIKey(_) => 10,
124
+ Middleware::RateLimit(_) => 11,
125
+ Middleware::ETag(_) => 12,
126
+ Middleware::Compression(_) => 13,
127
+ Middleware::Proxy(_) => 14,
128
+ Middleware::Cors(_) => 15,
129
+ Middleware::StaticAssets(_) => 16,
130
+ Middleware::RubyApp(_) => 17,
131
+ }
132
+ }
133
+ }
134
+
135
+ impl PartialEq for Middleware {
136
+ fn eq(&self, other: &Self) -> bool {
137
+ self.variant_order() == other.variant_order()
138
+ }
139
+ }
140
+
141
+ impl Eq for Middleware {}
142
+
143
+ impl PartialOrd for Middleware {
144
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
145
+ Some(self.variant_order().cmp(&other.variant_order()))
146
+ }
147
+ }
148
+
149
+ impl Ord for Middleware {
150
+ fn cmp(&self, other: &Self) -> Ordering {
151
+ self.variant_order().cmp(&other.variant_order())
152
+ }
153
+ }