itsi 0.1.20 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -8
  3. data/Cargo.lock +2 -2
  4. data/LICENSE.txt +698 -0
  5. data/README.md +15 -4
  6. data/Rakefile +9 -5
  7. data/crates/itsi_acme/.gitignore +4 -0
  8. data/crates/itsi_acme/Cargo.toml +86 -0
  9. data/crates/itsi_acme/LICENSE-APACHE +201 -0
  10. data/crates/itsi_acme/LICENSE-MIT +23 -0
  11. data/crates/itsi_acme/README.md +9 -0
  12. data/crates/itsi_acme/examples/high_level.rs +63 -0
  13. data/crates/itsi_acme/examples/high_level_warp.rs +52 -0
  14. data/crates/itsi_acme/examples/low_level.rs +87 -0
  15. data/crates/itsi_acme/examples/low_level_axum.rs +66 -0
  16. data/crates/itsi_acme/src/acceptor.rs +81 -0
  17. data/crates/itsi_acme/src/acme.rs +354 -0
  18. data/crates/itsi_acme/src/axum.rs +86 -0
  19. data/crates/itsi_acme/src/cache.rs +39 -0
  20. data/crates/itsi_acme/src/caches/boxed.rs +80 -0
  21. data/crates/itsi_acme/src/caches/composite.rs +69 -0
  22. data/crates/itsi_acme/src/caches/dir.rs +106 -0
  23. data/crates/itsi_acme/src/caches/mod.rs +11 -0
  24. data/crates/itsi_acme/src/caches/no.rs +78 -0
  25. data/crates/itsi_acme/src/caches/test.rs +136 -0
  26. data/crates/itsi_acme/src/config.rs +172 -0
  27. data/crates/itsi_acme/src/https_helper.rs +69 -0
  28. data/crates/itsi_acme/src/incoming.rs +142 -0
  29. data/crates/itsi_acme/src/jose.rs +161 -0
  30. data/crates/itsi_acme/src/lib.rs +142 -0
  31. data/crates/itsi_acme/src/resolver.rs +59 -0
  32. data/crates/itsi_acme/src/state.rs +424 -0
  33. data/crates/itsi_rb_helpers/src/lib.rs +4 -3
  34. data/crates/itsi_scheduler/Cargo.toml +1 -1
  35. data/crates/itsi_scheduler/src/itsi_scheduler.rs +8 -2
  36. data/crates/itsi_scheduler/src/lib.rs +1 -0
  37. data/crates/itsi_server/Cargo.toml +1 -1
  38. data/crates/itsi_server/src/lib.rs +2 -1
  39. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +18 -1
  40. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +11 -3
  41. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +122 -63
  42. data/crates/itsi_server/src/ruby_types/itsi_server.rs +2 -0
  43. data/crates/itsi_server/src/server/binds/bind.rs +3 -0
  44. data/crates/itsi_server/src/server/binds/listener.rs +12 -5
  45. data/crates/itsi_server/src/server/binds/tls.rs +13 -5
  46. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +12 -5
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +8 -1
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +9 -1
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +48 -43
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +11 -2
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +39 -12
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +36 -27
  53. data/crates/itsi_server/src/server/middleware_stack/middlewares/csp.rs +25 -11
  54. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +12 -3
  55. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +74 -72
  56. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +15 -1
  57. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +11 -8
  58. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +19 -11
  59. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +5 -5
  60. data/crates/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +2 -2
  61. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +11 -5
  62. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +17 -20
  63. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +19 -8
  64. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +16 -37
  65. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +22 -12
  66. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +26 -11
  67. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +7 -1
  68. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +14 -4
  69. data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +19 -0
  70. data/crates/itsi_server/src/server/middleware_stack/mod.rs +49 -13
  71. data/crates/itsi_server/src/server/mod.rs +1 -0
  72. data/crates/itsi_server/src/server/redirect_type.rs +26 -0
  73. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +22 -16
  74. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +49 -12
  75. data/crates/itsi_server/src/server/signal.rs +1 -0
  76. data/crates/itsi_server/src/server/size_limited_incoming.rs +6 -0
  77. data/crates/itsi_server/src/server/thread_worker.rs +5 -1
  78. data/crates/itsi_server/src/services/itsi_http_service.rs +20 -2
  79. data/crates/itsi_server/src/services/rate_limiter.rs +15 -4
  80. data/crates/itsi_server/src/services/static_file_server.rs +33 -19
  81. data/crates/itsi_tracing/src/lib.rs +42 -22
  82. data/docs/content/_index.md +1 -2
  83. data/docs/content/acknowledgements/_index.md +5 -2
  84. data/docs/content/configuration/_index.md +8 -5
  85. data/docs/content/contact/_index.md +8 -1
  86. data/docs/content/faqs/_index.md +5 -3
  87. data/docs/content/features/_index.md +56 -50
  88. data/docs/content/getting_started/_index.md +8 -5
  89. data/docs/content/getting_started/local_development.md +68 -8
  90. data/docs/content/getting_started/logging.md +16 -9
  91. data/docs/content/getting_started/running_itsi_in_production.md +5 -3
  92. data/docs/content/getting_started/signals.md +38 -0
  93. data/docs/content/itsi_scheduler/_index.md +8 -7
  94. data/docs/content/utilities/_index.md +13 -0
  95. data/docs/content/utilities/config_file_testing.md +17 -0
  96. data/docs/content/utilities/passfile_generator.md +41 -0
  97. data/docs/content/utilities/route_testing.md +27 -0
  98. data/docs/content/utilities/secrets_management.md +30 -0
  99. data/docs/hugo.yaml +1 -1
  100. data/fairytale.txt +3 -4
  101. data/gems/scheduler/Cargo.lock +1 -1
  102. data/gems/scheduler/README.md +4 -5
  103. data/gems/scheduler/Rakefile +0 -4
  104. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  105. data/gems/scheduler/lib/itsi/scheduler.rb +9 -4
  106. data/gems/scheduler/test/test_active_record.rb +12 -7
  107. data/gems/server/Cargo.lock +1 -1
  108. data/gems/server/Rakefile +0 -4
  109. data/gems/server/exe/itsi +13 -2
  110. data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +2 -0
  111. data/gems/server/lib/itsi/http_request.rb +40 -9
  112. data/gems/server/lib/itsi/http_response.rb +2 -1
  113. data/gems/server/lib/itsi/passfile.rb +0 -1
  114. data/gems/server/lib/itsi/server/config/config_helpers.rb +20 -8
  115. data/gems/server/lib/itsi/server/config/dsl.rb +20 -435
  116. data/gems/server/lib/itsi/server/config/known_paths.rb +4 -1
  117. data/gems/server/lib/itsi/server/config/middleware/_index.md +6 -4
  118. data/gems/server/lib/itsi/server/config/middleware/allow_list.md +46 -0
  119. data/gems/server/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  120. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  121. data/gems/server/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  122. data/gems/server/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  123. data/gems/server/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
  124. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  125. data/gems/server/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  126. data/gems/server/lib/itsi/server/config/middleware/cache_control.md +78 -0
  127. data/gems/server/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  128. data/gems/server/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  129. data/gems/server/lib/itsi/server/config/middleware/compression.md +50 -0
  130. data/gems/server/lib/itsi/server/config/middleware/compression.rb +37 -0
  131. data/gems/server/lib/itsi/server/config/middleware/cors.md +93 -0
  132. data/gems/server/lib/itsi/server/config/middleware/cors.rb +32 -0
  133. data/gems/server/lib/itsi/server/config/middleware/csp.md +37 -0
  134. data/gems/server/lib/itsi/server/config/middleware/csp.rb +44 -0
  135. data/gems/server/lib/itsi/server/config/middleware/deny_list.md +45 -0
  136. data/gems/server/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  137. data/gems/server/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
  138. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  139. data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  140. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  141. data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
  142. data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
  143. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  144. data/gems/server/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
  145. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  146. data/gems/server/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  147. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  148. data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
  149. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  150. data/gems/server/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
  151. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  152. data/gems/server/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
  153. data/gems/server/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  154. data/gems/server/lib/itsi/server/config/middleware/error_response.md +61 -0
  155. data/gems/server/lib/itsi/server/config/middleware/error_response.rb +36 -0
  156. data/gems/server/lib/itsi/server/config/middleware/etag.md +59 -0
  157. data/gems/server/lib/itsi/server/config/middleware/etag.rb +27 -0
  158. data/gems/server/lib/itsi/server/config/middleware/grpc.md +172 -0
  159. data/gems/server/lib/itsi/server/config/middleware/grpc.rb +54 -0
  160. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  161. data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  162. data/gems/server/lib/itsi/server/config/middleware/location.md +107 -0
  163. data/gems/server/lib/itsi/server/config/middleware/location.rb +99 -0
  164. data/gems/server/lib/itsi/server/config/middleware/log_requests.md +13 -11
  165. data/gems/server/lib/itsi/server/config/middleware/log_requests.rb +1 -3
  166. data/gems/server/lib/itsi/server/config/middleware/max_body.md +18 -0
  167. data/gems/server/lib/itsi/server/config/middleware/max_body.rb +21 -0
  168. data/gems/server/lib/itsi/server/config/middleware/proxy.md +62 -0
  169. data/gems/server/lib/itsi/server/config/middleware/proxy.rb +41 -0
  170. data/gems/server/lib/itsi/server/config/middleware/rackup_file.md +54 -0
  171. data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
  172. data/gems/server/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  173. data/gems/server/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  174. data/gems/server/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  175. data/gems/server/lib/itsi/server/config/middleware/redirect.md +55 -0
  176. data/gems/server/lib/itsi/server/config/middleware/redirect.rb +25 -0
  177. data/gems/server/lib/itsi/server/config/middleware/request_headers.md +34 -0
  178. data/gems/server/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  179. data/gems/server/lib/itsi/server/config/middleware/response_headers.md +33 -0
  180. data/gems/server/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  181. data/gems/server/lib/itsi/server/config/middleware/run.md +60 -0
  182. data/gems/server/lib/itsi/server/config/middleware/run.rb +43 -0
  183. data/gems/server/lib/itsi/server/config/middleware/static_assets.md +73 -0
  184. data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +87 -0
  185. data/gems/server/lib/itsi/server/config/middleware/static_response.md +44 -0
  186. data/gems/server/lib/itsi/server/config/middleware/static_response.rb +29 -0
  187. data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
  188. data/gems/server/lib/itsi/server/config/middleware/token_source.rb +32 -0
  189. data/gems/server/lib/itsi/server/config/middleware.rb +4 -0
  190. data/gems/server/lib/itsi/server/config/option.rb +5 -0
  191. data/gems/server/lib/itsi/server/config/options/_index.md +3 -2
  192. data/gems/server/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  193. data/gems/server/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
  194. data/gems/server/lib/itsi/server/config/options/bind.md +71 -0
  195. data/gems/server/lib/itsi/server/config/options/bind.rb +26 -0
  196. data/gems/server/lib/itsi/server/config/options/certificates.md +65 -0
  197. data/gems/server/lib/itsi/server/config/options/daemonize.md +14 -0
  198. data/gems/server/lib/itsi/server/config/options/daemonize.rb +19 -0
  199. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.md +1 -2
  200. data/gems/server/lib/itsi/server/config/options/fiber_scheduler.rb +6 -3
  201. data/gems/server/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  202. data/gems/server/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  203. data/gems/server/lib/itsi/server/config/options/hooks/_index.md +11 -0
  204. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  205. data/gems/server/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  206. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  207. data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  208. data/gems/server/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  209. data/gems/server/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  210. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  211. data/gems/server/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  212. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  213. data/gems/server/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  214. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  215. data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  216. data/gems/server/lib/itsi/server/config/options/include.md +20 -0
  217. data/gems/server/lib/itsi/server/config/options/include.rb +36 -0
  218. data/gems/server/lib/itsi/server/config/options/listen_backlog.md +11 -0
  219. data/gems/server/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  220. data/gems/server/lib/itsi/server/config/options/log_format.md +18 -0
  221. data/gems/server/lib/itsi/server/config/options/log_format.rb +19 -0
  222. data/gems/server/lib/itsi/server/config/options/log_level.md +34 -0
  223. data/gems/server/lib/itsi/server/config/options/log_level.rb +20 -0
  224. data/gems/server/lib/itsi/server/config/options/log_target.md +38 -0
  225. data/gems/server/lib/itsi/server/config/options/log_target.rb +19 -0
  226. data/gems/server/lib/itsi/server/config/options/log_target_filters.md +17 -0
  227. data/gems/server/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  228. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  229. data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  230. data/gems/server/lib/itsi/server/config/options/nodelay.md +16 -0
  231. data/gems/server/lib/itsi/server/config/options/nodelay.rb +19 -0
  232. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  233. data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  234. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  235. data/gems/server/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  236. data/gems/server/lib/itsi/server/config/options/preload.md +21 -0
  237. data/gems/server/lib/itsi/server/config/options/preload.rb +18 -0
  238. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  239. data/gems/server/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  240. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  241. data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  242. data/gems/server/lib/itsi/server/config/options/request_timeout.md +23 -0
  243. data/gems/server/lib/itsi/server/config/options/request_timeout.rb +19 -0
  244. data/gems/server/lib/itsi/server/config/options/reuse_address.md +16 -0
  245. data/gems/server/lib/itsi/server/config/options/reuse_address.rb +19 -0
  246. data/gems/server/lib/itsi/server/config/options/reuse_port.md +16 -0
  247. data/gems/server/lib/itsi/server/config/options/reuse_port.rb +19 -0
  248. data/gems/server/lib/itsi/server/config/options/scheduler_threads.md +34 -0
  249. data/gems/server/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  250. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  251. data/gems/server/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  252. data/gems/server/lib/itsi/server/config/options/stream_body.md +32 -0
  253. data/gems/server/lib/itsi/server/config/options/stream_body.rb +18 -0
  254. data/gems/server/lib/itsi/server/config/options/threads.md +7 -2
  255. data/gems/server/lib/itsi/server/config/options/threads.rb +1 -1
  256. data/gems/server/lib/itsi/server/config/options/watch.md +16 -0
  257. data/gems/server/lib/itsi/server/config/options/watch.rb +28 -0
  258. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  259. data/gems/server/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  260. data/gems/server/lib/itsi/server/config/options/workers.md +1 -2
  261. data/gems/server/lib/itsi/server/config/options/workers.rb +1 -1
  262. data/gems/server/lib/itsi/server/config/typed_struct.rb +59 -20
  263. data/gems/server/lib/itsi/server/config.rb +77 -48
  264. data/gems/server/lib/itsi/server/default_config/Itsi.rb +3 -3
  265. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +1 -1
  266. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +11 -4
  267. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +3 -3
  268. data/gems/server/lib/itsi/server/route_tester.rb +58 -8
  269. data/gems/server/lib/itsi/server/signal_trap.rb +1 -1
  270. data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +14 -18
  271. data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +5 -4
  272. data/gems/server/lib/itsi/server/typed_handlers.rb +12 -4
  273. data/gems/server/lib/itsi/server/version.rb +1 -1
  274. data/gems/server/lib/itsi/server.rb +98 -14
  275. data/gems/server/lib/ruby_lsp/itsi/addon.rb +20 -18
  276. data/gems/server/test/helpers/test_helper.rb +89 -29
  277. data/gems/server/test/middleware/allow_list.rb +128 -0
  278. data/gems/server/test/middleware/auth_api_key.rb +141 -0
  279. data/gems/server/test/middleware/auth_basic.rb +91 -0
  280. data/gems/server/test/middleware/auth_jwt.rb +214 -0
  281. data/gems/server/test/middleware/cache_control.rb +82 -0
  282. data/gems/server/test/middleware/cidr_to_regex.rb +46 -0
  283. data/gems/server/test/middleware/compression.rb +89 -0
  284. data/gems/server/test/middleware/cors.rb +113 -0
  285. data/gems/server/test/middleware/csp.rb +62 -0
  286. data/gems/server/test/middleware/deny_list.rb +131 -0
  287. data/gems/server/test/middleware/endpoint.rb +300 -0
  288. data/gems/server/test/middleware/etag.rb +75 -0
  289. data/gems/server/test/middleware/grpc/grpc.rb +158 -0
  290. data/gems/server/test/middleware/grpc/test_service.proto +32 -0
  291. data/gems/server/test/middleware/grpc/test_service_impl.rb +28 -0
  292. data/gems/server/test/middleware/grpc/test_service_pb.rb +18 -0
  293. data/gems/server/test/middleware/grpc/test_service_services_pb.rb +30 -0
  294. data/gems/server/test/middleware/header_interpolation.rb +35 -0
  295. data/gems/server/test/middleware/intrusion_protection.rb +259 -0
  296. data/gems/server/test/middleware/location.rb +220 -0
  297. data/gems/server/test/middleware/max_body.rb +20 -0
  298. data/gems/server/test/middleware/proxy.rb +415 -0
  299. data/gems/server/test/middleware/rate_limit.rb +211 -0
  300. data/gems/server/test/middleware/redirect.rb +85 -0
  301. data/gems/server/test/middleware/request_headers.rb +50 -0
  302. data/gems/server/test/middleware/response_headers.rb +50 -0
  303. data/gems/server/test/middleware/static_assets.rb +374 -0
  304. data/gems/server/test/middleware/static_response.rb +56 -0
  305. data/gems/server/test/middleware/string_rewrite.rb +112 -0
  306. data/gems/server/test/options/bind.rb +47 -0
  307. data/gems/server/test/options/header_read_timeout.rb +23 -0
  308. data/gems/server/test/options/test_request_timeout.rb +16 -0
  309. data/gems/server/test/options/test_workers.rb +2 -4
  310. data/gems/server/test/{test_itsi_server.rb → rack/test_rack_server.rb} +2 -2
  311. data/grpc_test/Itsi.rb +11 -0
  312. data/grpc_test/echo.proto +14 -0
  313. data/grpc_test/echo_pb.rb +16 -0
  314. data/grpc_test/echo_service_impl.rb +8 -0
  315. data/grpc_test/echo_services_pb.rb +22 -0
  316. data/lib/itsi/version.rb +1 -1
  317. data/tasks.txt +15 -72
  318. metadata +210 -7
  319. data/gems/server/lib/itsi/server/default_config/Itsi-rackup.rb +0 -119
@@ -0,0 +1,186 @@
1
+ ---
2
+ title: Controller
3
+ url: /middleware/controller
4
+ prev: endpoint/
5
+ ---
6
+
7
+
8
+ Instead of supplying an [endpoint](/middleware/endpoint) body inline, you can also reference a method by name (as a `:symbol`).
9
+ Itsi will attach the method, resolved by name within the current controller scope, to the endpoint.
10
+
11
+ E.g.
12
+ ```ruby {filename=Itsi.rb}
13
+ controller UserController.new
14
+ get "", :index
15
+ ```
16
+
17
+ The default controller scope is the parent `Itsi.rb` config file.
18
+ However you can use the `controller` middleware to explicitly set a controller scope per [location](/middleware/location) block. All named endpoints will then be satisfied by the current controller.
19
+
20
+ {{< callout >}}
21
+ Itsi will check for the presence and structure of all:
22
+ * Controller methods
23
+ * [Schemas](/middleware/schemas)
24
+
25
+ at **boot time** ensuring that you can't be caught out by naming mismatches at runtime, or during a hot-reload.
26
+ If Itsi boots successfully, the controller methods exist and accept the correct parameters.
27
+ {{</ callout >}}
28
+
29
+ ## Basic Example
30
+ ```ruby {filename=Itsi.rb}
31
+ controller UserController.new
32
+ ```
33
+
34
+ {{< callout >}}
35
+ There are no special requirements for a controller in Itsi, it can be *any* ruby object, so long as it responds to the methods attached to the endpoint and accepts the request object as the first argument. This could be a singleton module, an instance, a struct etc.
36
+ {{< /callout >}}.
37
+
38
+ ### Detailed Example
39
+
40
+ ```ruby {filename=Itsi.rb}
41
+
42
+ require_relative "schemas"
43
+ require_relative "user_controller"
44
+
45
+ location "/users*" do
46
+ controller UserController.new
47
+ post "/", :create
48
+ end
49
+
50
+ def home(req)
51
+ req.respond "I'm home"
52
+ end
53
+ # Default controller is just the top-level Itsi scope
54
+ get "/", :home
55
+ ```
56
+
57
+
58
+ ```ruby {filename=user_controller.rb}
59
+ class UserController
60
+
61
+ def initialize()
62
+ # One time controller set-up here
63
+ end
64
+
65
+ def create(request, params: UserInputSchema, response_format: UserResponseSchema)
66
+ user = User.create!(params)
67
+ request.created \
68
+ json: {
69
+ id: user.id,
70
+ email: user.email,
71
+ full_name: "#{user.first_name} #{user.last_name}",
72
+ created_at: user.created_at.iso8601,
73
+ address: {
74
+ street: user.address.street,
75
+ city: user.address.city,
76
+ postcode: user.address.postcode
77
+ }
78
+ },
79
+ as: response_format
80
+ end
81
+ end
82
+
83
+ # Dummy data model.
84
+ Address = Struct.new(:street, :city, :postcode, :country, keyword_init: true)
85
+
86
+ class User < Struct.new(
87
+ :id, :email, :first_name, :last_name, :created_at,
88
+ :address, :age, :active, :roles, keyword_init: true)
89
+ def self.create!(params)
90
+ self.new(
91
+ id: Random.rand(1000000...99999999),
92
+ address: Address.new(params.delete :address),
93
+ **params,
94
+ created_at: Time.now
95
+ )
96
+ end
97
+ end
98
+
99
+ ```
100
+
101
+ ```ruby {filename=schemas.rb}
102
+ AddressSchema = {
103
+ _required: %i[street city postcode],
104
+ street: String,
105
+ city: String,
106
+ postcode: String,
107
+ country: String # Optional
108
+ }
109
+
110
+ UserInputSchema = {
111
+ _required: %i[first_name last_name email address],
112
+ first_name: String,
113
+ last_name: String,
114
+ email: String,
115
+ age: Integer,
116
+ active: :Boolean,
117
+ roles: Array[String],
118
+ address: AddressSchema
119
+ }
120
+
121
+ UserResponseSchema = {
122
+ _required: %i[id email full_name],
123
+ id: Integer,
124
+ email: String,
125
+ full_name: String,
126
+ created_at: String,
127
+ address: AddressSchema
128
+ }
129
+ ```
130
+
131
+ ```bash
132
+ curl http://0.0.0.0:3000/users -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{"id": 3, "age": "nine", "first_name":8,"last_name":"test","email":"test", "address": {"street":"1 Main Street","city":"Wellington","postcode":1234}}'
133
+
134
+ {"error":"Validation failed: Invalid value for Integer at age: \"nine\" (invalid value for Integer(): \"nine\")"}%
135
+ ```
136
+
137
+
138
+ ```bash
139
+ curl http://0.0.0.0:3000/users \
140
+ -H 'Accept: application/json' \
141
+ -H 'Content-Type: application/json' \
142
+ -d '{"id": 3, "age": "ninety-nine", "first_name":"John","last_name":"Smith","email":"test", "address": {"street":"1 Main Street","city":"Wellington","postcode":1234}}'
143
+ ```
144
+ ```json
145
+ {
146
+ "error":"Validation failed: Invalid value for Integer at age: \"ninety-nine\" (invalid value for Integer(): \"nine\")"}%
147
+ ```
148
+
149
+ ```bash
150
+ curl http://0.0.0.0:3000/users \
151
+ -H 'Accept: application/json' \
152
+ -H 'Content-Type: application/json' \
153
+ -d '{"id": 3, "age": 99, "first_name":"John","last_name":"Smith","email":"test", "address": {"street":"1 Main Street","city":"Wellington","postcode":1234}}'
154
+ ```
155
+ ```json
156
+ {
157
+ "id":46895213,
158
+ "email":"test",
159
+ "full_name":"John Smith",
160
+ "created_at":"2025-04-20T08:47:28+12:00",
161
+ "address":{
162
+ "street":"1 Main Street",
163
+ "city":"Wellington",
164
+ "postcode":"1234",
165
+ "country":null
166
+ }
167
+ }
168
+ ```
169
+
170
+ ```bash
171
+ curl http://0.0.0.0:3000/
172
+ I'm home
173
+ ```
174
+
175
+ ### Module as a Controller
176
+ ```ruby {filename=Itsi.rb}
177
+ module UserController
178
+ module_function
179
+ def create(req, params)
180
+ req.ok json: User.create(params)
181
+ end
182
+ end
183
+
184
+ controller User
185
+ post "/", :create
186
+ ```
@@ -0,0 +1,33 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Controller < Middleware
5
+
6
+ insert_text <<~SNIPPET
7
+ controller ${1:MyControllerClass.new}
8
+ SNIPPET
9
+
10
+ detail "Sets the controller scope for named endpoints"
11
+
12
+ schema do
13
+ Type(Object) & Required()
14
+ end
15
+
16
+ def initialize(location, controller=nil)
17
+ super
18
+
19
+ if controller
20
+ location.instance_eval{ @controller = controller}
21
+ end
22
+ end
23
+
24
+ def build!
25
+ if !@params
26
+ location.instance_eval{ @controller }
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Delete
3
+ url: /middleware/delete
4
+ ---
5
+
6
+ The `delete` middleware is an [endpoint](/middleware/endpoint) restricted to DELETE requests.
7
+
8
+ Endpoints are light-weight inline middleware that can be used to handle requests without the need for a fully fledged Rack-based application framework.
9
+ Endpoints can optionally be directed to a controller, and use request and response schema enforcement.
10
+
11
+ You can use endpoints and rack-apps simultaneously.
12
+ See [endpoint](/middleware/endpoint).
@@ -0,0 +1,42 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Delete < Middleware
5
+
6
+ insert_text [
7
+ <<~SNIPPET,
8
+ delete "${1:/path}", :${2:handler}
9
+ SNIPPET
10
+ <<~SNIPPET,
11
+ delete "${1:/path}" do |req|
12
+ $2
13
+ end
14
+ SNIPPET
15
+ <<~SNIPPET,
16
+ delete "${1:/path}" do |req, params|
17
+ $2
18
+ end
19
+ SNIPPET
20
+ ]
21
+
22
+ detail ["A light-weight DELETE endpoint (controller)", "A light-weight DELETE endpoint (inline block)", "A light-weight DELETE endpoint (inline params)"]
23
+
24
+ schema do
25
+ {
26
+ paths: Array(Or(Type(String), Type(Regexp))),
27
+ handler: Type(Proc) & Required(),
28
+ http_methods: Array(Type(String)),
29
+ nonblocking: Bool()
30
+ }
31
+ end
32
+
33
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
34
+ location.endpoint(path, handler, http_methods: ["DELETE"], nonblocking: nonblocking, &handler_proc)
35
+ end
36
+
37
+ def build!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,99 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Endpoint < Middleware
5
+
6
+ InvalidHandlerException = Class.new(StandardError)
7
+
8
+ insert_text [
9
+ <<~SNIPPET,
10
+ endpoint "${1:/path}", :${2:handler}
11
+ SNIPPET
12
+ <<~SNIPPET,
13
+ endpoint "${1:/path}" do |req|
14
+ $2
15
+ end
16
+ SNIPPET
17
+ <<~SNIPPET,
18
+ endpoint "${1:/path}" do |req, params|
19
+ $2
20
+ end
21
+ SNIPPET
22
+ ]
23
+
24
+ detail ["A light-weight HTTP endpoint (controller)", "A light-weight HTTP endpoint (inline block)", "A light-weight HTTP endpoint (inline params)"]
25
+
26
+ schema do
27
+ {
28
+ paths: Array(Or(Type(String), Type(Regexp))),
29
+ handler: Type(Proc) & Required(),
30
+ http_methods: Array(Type(String)),
31
+ nonblocking: Bool()
32
+ }
33
+ end
34
+
35
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
36
+ raise "Can not combine a controller method and inline handler" if handler && handler_proc
37
+ handler_proc = location.controller.method(handler).to_proc if handler.is_a?(Symbol) || handler.is_a?(String)
38
+
39
+ super(
40
+ location,
41
+ { paths: Array(path), handler: handler_proc, http_methods: http_methods, nonblocking: nonblocking }
42
+ )
43
+
44
+ num_required, keywords = Itsi::Server::TypedHandlers::SourceParser.extract_expr_from_source_location(handler_proc)
45
+ params_schema = keywords[:params]
46
+ response_schema = keywords[:response_format]
47
+ exception = nil
48
+ if params_schema && num_required > 1
49
+ exception = InvalidHandlerException.new("Cannot accept multiple required parameters in a single endpoint. A single typed or untyped params argument is supported")
50
+ end
51
+ if num_required > 2
52
+ exception = InvalidHandlerException.new("Cannot accept more than two required parameters in a single endpoint. An can either accept a single request argument, or a request and a params argument (which may be typed or untyped). You can also use keyword arguments to anchor response types")
53
+ end
54
+ if num_required == 0
55
+ exception = InvalidHandlerException.new("Cannot accept zero required parameters in a single endpoint. Endpoint must accept a request parameter")
56
+ end
57
+ if response_schema && !(handler_proc.binding.eval(response_schema) rescue false)
58
+ exception = InvalidHandlerException.new("Response Schema by name `#{response_schema}` not found.")
59
+ end
60
+ if params_schema && !(handler_proc.binding.eval(params_schema) rescue false)
61
+ exception = InvalidHandlerException.new("Params Schema by name `#{params_schema}` not found.")
62
+ end
63
+
64
+ if exception
65
+ exception.set_backtrace([handler_proc.source_location.join(":")] + caller)
66
+ raise exception
67
+ end
68
+
69
+ accepts_params = !params_schema.nil? || num_required > 1
70
+
71
+ if accepts_params
72
+ @params[:handler] = Itsi::Server::TypedHandlers.handler_for(@params[:handler], params_schema)
73
+ end
74
+ end
75
+
76
+ def build!
77
+ params = @params
78
+ app = { preloader: -> { params[:handler] }, nonblocking: @params[:nonblocking] }
79
+
80
+ if @params[:paths] == [""] && @params[:http_methods].empty?
81
+ location.middleware[:app] = app
82
+ location.location("*") do
83
+ @middleware[:app] = app
84
+ end
85
+ else
86
+ @params[:paths] << "" if @params[:paths].empty?
87
+ @params[:paths] = @params[:paths].flat_map do |p|
88
+ stripped_trailing = p[/(.*)\/?$/, 1]
89
+ [stripped_trailing, stripped_trailing + "/"]
90
+ end.uniq
91
+ location.location(*@params[:paths], methods: @params[:http_methods]) do
92
+ @middleware[:app] = app
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Get
3
+ url: /middleware/get
4
+ ---
5
+
6
+ The `get` middleware is an [endpoint](/middleware/endpoint) restricted to GET requests.
7
+
8
+ Endpoints are light-weight inline middleware that can be used to handle requests without the need for a fully fledged Rack-based application framework.
9
+ Endpoints can optionally be directed to a controller, and use request and response schema enforcement.
10
+
11
+ You can use endpoints and rack-apps simultaneously.
12
+ See [endpoint](/middleware/endpoint).
@@ -0,0 +1,42 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Get < Middleware
5
+
6
+ insert_text [
7
+ <<~SNIPPET,
8
+ get "${1:/path}", :${2:handler}
9
+ SNIPPET
10
+ <<~SNIPPET,
11
+ get "${1:/path}" do |req|
12
+ $2
13
+ end
14
+ SNIPPET
15
+ <<~SNIPPET,
16
+ get "${1:/path}" do |req, params|
17
+ $2
18
+ end
19
+ SNIPPET
20
+ ]
21
+
22
+ detail ["A light-weight GET endpoint (controller)", "A light-weight GET endpoint (inline block)", "A light-weight HTTP endpoint (inline params)"]
23
+
24
+ schema do
25
+ {
26
+ paths: Array(Or(Type(String), Type(Regexp))),
27
+ handler: Type(Proc) & Required(),
28
+ http_methods: Array(Type(String)),
29
+ nonblocking: Bool()
30
+ }
31
+ end
32
+
33
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
34
+ location.endpoint(path, handler, http_methods: ["GET", "HEAD"], nonblocking: nonblocking, &handler_proc)
35
+ end
36
+
37
+ def build!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: HTTP Request
3
+ url: /middleware/http_request
4
+ ---
5
+
6
+ An [endpoint](/middleware/endpoint), always accepts a `request` object as the first parameter.
7
+ E.g.
8
+
9
+ ```ruby {filename=Itsi.rb}
10
+ get "/" do |req|
11
+ end
12
+ ```
13
+
14
+
15
+ end
16
+
17
+ | Method | Description |
18
+ |------------------|-----------------------------------------------------------------------------|
19
+ | `path` | Retrieves the path of the HTTP request. |
20
+ | `script_name` | Retrieves the script name of the HTTP request. |
21
+ | `query_string` | Retrieves the query string from the HTTP request. |
22
+ | `content_type` | Retrieves the content type of the HTTP request. |
23
+ | `content_length` | Retrieves the content length of the HTTP request. |
24
+ | `request_method` | Retrieves the HTTP method (e.g., GET, POST) of the request. |
25
+ | `version` | Retrieves the HTTP version of the request. |
26
+ | `rack_protocol` | Retrieves the Rack protocol version used in the request. |
27
+ | `host` | Retrieves the host of the HTTP request. |
28
+ | `headers` | Retrieves all headers from the HTTP request. |
29
+ | `uri` | Retrieves the full URI of the HTTP request. |
30
+ | `header` | Retrieves the value of a specific header from the HTTP request. |
31
+ | `[]` | Alias for `header`, retrieves the value of a specific header. |
32
+ | `scheme` | Retrieves the scheme (e.g., http, https) of the HTTP request. |
33
+ | `remote_addr` | Retrieves the remote address of the client making the request. |
34
+ | `port` | Retrieves the port number of the HTTP request. |
35
+ | `body` | Retrieves the body of the HTTP request (As an IO). |
36
+ | `response` | Retrieves the [response](/middleware/http_response) object associated with the HTTP request. |
37
+ | `json?` | Checks if the request content type is JSON. |
38
+ | `html?` | Checks if the request content type is HTML. |
39
+ | `url_encoded?` | Checks if the request content type is URL-encoded. |
40
+ | `multipart?` | Checks if the request content type is multipart. |
41
+ | `url_params` | Retrieves the URL parameters from the HTTP request. |
42
+ | `#<status_name>` | Writes a response with the specified status code and closes the response. |
43
+ | `respond` | Writes a response with the specified status code and closes the response. |
44
+ | `query_params` | Retrieves the query parameters from the HTTP request. |
@@ -0,0 +1,39 @@
1
+ ---
2
+ title: HTTP Response
3
+ url: /middleware/http_response
4
+ ---
5
+
6
+ Within the body of an [endpoint](/middleware/endpoint), you can access the `#response` object on the incoming request for more fine-grained control over the response body.
7
+
8
+
9
+ {{< callout >}}
10
+ Itsi allows you to efficiently keep long-running responses open, and write to these asynchronously.
11
+ Just remember to close them eventually...
12
+
13
+ {{< /callout >}}
14
+
15
+
16
+ E.g.
17
+
18
+ ```ruby {filename=Itsi.rb}
19
+
20
+ get "/" do |req|
21
+ resp = req.response
22
+ resp << "Stream some content"
23
+
24
+ # Eventually... (This does not have to occur within the body of this method.)
25
+ resp.close
26
+ end
27
+ ```
28
+
29
+
30
+ | Method | Description |
31
+ |------------------|-----------------------------------------------------------------------------|
32
+ | `#<<` | Appends content to the response body (allows you to stream content). |
33
+ | `#send_and_close`| Sends a single response chunk and closes the connection. |
34
+ | `status=` | Sets the HTTP status code for the response. |
35
+ | `add_header` | Adds a header to the response. |
36
+ | `accept` | Retrieves the accepted content types from the request. |
37
+ | `close` | Closes the response stream. |
38
+ | `json?` | Checks if the response content type is JSON. |
39
+ | `html?` | Checks if the response content type is HTML. |
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Patch
3
+ url: /middleware/patch
4
+ ---
5
+
6
+ The `patch` middleware is an [endpoint](/middleware/endpoint) restricted to PATCH requests.
7
+
8
+ Endpoints are light-weight inline middleware that can be used to handle requests without the need for a fully fledged Rack-based application framework.
9
+ Endpoints can optionally be directed to a controller, and use request and response schema enforcement.
10
+
11
+ You can use endpoints and rack-apps simultaneously.
12
+ See [endpoint](/middleware/endpoint).
@@ -0,0 +1,42 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Patch < Middleware
5
+
6
+ insert_text [
7
+ <<~SNIPPET,
8
+ patch "${1:/path}", :${2:handler}
9
+ SNIPPET
10
+ <<~SNIPPET,
11
+ patch "${1:/path}" do |req|
12
+ $2
13
+ end
14
+ SNIPPET
15
+ <<~SNIPPET,
16
+ patch "${1:/path}" do |req, params|
17
+ $2
18
+ end
19
+ SNIPPET
20
+ ]
21
+
22
+ detail ["A light-weight PATCH endpoint (controller)", "A light-weight PATCH endpoint (inline block)", "A light-weight PATCH endpoint (inline params)"]
23
+
24
+ schema do
25
+ {
26
+ paths: Array(Or(Type(String), Type(Regexp))),
27
+ handler: Type(Proc) & Required(),
28
+ http_methods: Array(Type(String)),
29
+ nonblocking: Bool()
30
+ }
31
+ end
32
+
33
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
34
+ location.endpoint(path, handler, http_methods: ["PATCH"], nonblocking: nonblocking, &handler_proc)
35
+ end
36
+
37
+ def build!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Post
3
+ url: /middleware/post
4
+ ---
5
+
6
+ The `post` middleware is an [endpoint](/middleware/endpoint) restricted to POST requests.
7
+
8
+ Endpoints are light-weight inline middleware that can be used to handle requests without the need for a fully fledged Rack-based application framework.
9
+ Endpoints can optionally be directed to a controller, and use request and response schema enforcement.
10
+
11
+ You can use endpoints and rack-apps simultaneously.
12
+ See [endpoint](/middleware/endpoint).
@@ -0,0 +1,42 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Post < Middleware
5
+
6
+ insert_text [
7
+ <<~SNIPPET,
8
+ post "${1:/path}", :${2:handler}
9
+ SNIPPET
10
+ <<~SNIPPET,
11
+ post "${1:/path}" do |req|
12
+ $2
13
+ end
14
+ SNIPPET
15
+ <<~SNIPPET,
16
+ post "${1:/path}" do |req, params|
17
+ $2
18
+ end
19
+ SNIPPET
20
+ ]
21
+
22
+ detail ["A light-weight POST endpoint (controller)", "A light-weight POST endpoint (inline block)", "A light-weight POST endpoint (inline params)"]
23
+
24
+ schema do
25
+ {
26
+ paths: Array(Or(Type(String), Type(Regexp))),
27
+ handler: Type(Proc) & Required(),
28
+ http_methods: Array(Type(String)),
29
+ nonblocking: Bool()
30
+ }
31
+ end
32
+
33
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
34
+ location.endpoint(path, handler, http_methods: ["POST"], nonblocking: nonblocking, &handler_proc)
35
+ end
36
+
37
+ def build!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Put
3
+ url: /middleware/put
4
+ ---
5
+
6
+ The `put` middleware is an [endpoint](/middleware/endpoint) restricted to PUT requests.
7
+
8
+ Endpoints are light-weight inline middleware that can be used to handle requests without the need for a fully fledged Rack-based application framework.
9
+ Endpoints can optionally be directed to a controller, and use request and response schema enforcement.
10
+
11
+ You can use endpoints and rack-apps simultaneously.
12
+ See [endpoint](/middleware/endpoint).
@@ -0,0 +1,42 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Put < Middleware
5
+
6
+ insert_text [
7
+ <<~SNIPPET,
8
+ put "${1:/path}", :${2:handler}
9
+ SNIPPET
10
+ <<~SNIPPET,
11
+ put "${1:/path}" do |req|
12
+ $2
13
+ end
14
+ SNIPPET
15
+ <<~SNIPPET,
16
+ put "${1:/path}" do |req, params|
17
+ $2
18
+ end
19
+ SNIPPET
20
+ ]
21
+
22
+ detail ["A light-weight PUT endpoint (controller)", "A light-weight PUT endpoint (inline block)", "A light-weight PUT endpoint (inline params)"]
23
+
24
+ schema do
25
+ {
26
+ paths: Array(Or(Type(String), Type(Regexp))),
27
+ handler: Type(Proc) & Required(),
28
+ http_methods: Array(Type(String)),
29
+ nonblocking: Bool()
30
+ }
31
+ end
32
+
33
+ def initialize(location, path="", handler=nil, http_methods: [], nonblocking: false, &handler_proc)
34
+ location.endpoint(path, handler, http_methods: ["PUT"], nonblocking: nonblocking, &handler_proc)
35
+ end
36
+
37
+ def build!
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end