itsi-server 0.1.1 → 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 (457) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +4487 -0
  3. data/Cargo.toml +7 -0
  4. data/README.md +6 -0
  5. data/Rakefile +7 -4
  6. data/exe/itsi +152 -46
  7. data/ext/itsi_acme/Cargo.toml +86 -0
  8. data/ext/itsi_acme/examples/high_level.rs +63 -0
  9. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  10. data/ext/itsi_acme/examples/low_level.rs +87 -0
  11. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  12. data/ext/itsi_acme/src/acceptor.rs +81 -0
  13. data/ext/itsi_acme/src/acme.rs +354 -0
  14. data/ext/itsi_acme/src/axum.rs +86 -0
  15. data/ext/itsi_acme/src/cache.rs +39 -0
  16. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  17. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  18. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  19. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  20. data/ext/itsi_acme/src/caches/no.rs +78 -0
  21. data/ext/itsi_acme/src/caches/test.rs +136 -0
  22. data/ext/itsi_acme/src/config.rs +172 -0
  23. data/ext/itsi_acme/src/https_helper.rs +69 -0
  24. data/ext/itsi_acme/src/incoming.rs +142 -0
  25. data/ext/itsi_acme/src/jose.rs +161 -0
  26. data/ext/itsi_acme/src/lib.rs +142 -0
  27. data/ext/itsi_acme/src/resolver.rs +59 -0
  28. data/ext/itsi_acme/src/state.rs +424 -0
  29. data/ext/itsi_error/Cargo.toml +3 -0
  30. data/ext/itsi_error/src/lib.rs +98 -24
  31. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  32. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  33. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  34. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  35. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  36. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  37. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  38. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  39. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  40. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  41. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  42. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  43. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  44. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  45. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  46. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  47. data/ext/itsi_rb_helpers/Cargo.toml +3 -0
  48. data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
  49. data/ext/itsi_rb_helpers/src/lib.rs +141 -10
  50. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  51. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  52. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  53. data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  54. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  55. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  56. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  57. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  58. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  59. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  60. data/ext/itsi_scheduler/Cargo.toml +24 -0
  61. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  62. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  63. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  64. data/ext/itsi_scheduler/src/itsi_scheduler.rs +314 -0
  65. data/ext/itsi_scheduler/src/lib.rs +39 -0
  66. data/ext/itsi_server/Cargo.lock +2956 -0
  67. data/ext/itsi_server/Cargo.toml +75 -14
  68. data/ext/itsi_server/extconf.rb +1 -1
  69. data/ext/itsi_server/src/default_responses/html/401.html +68 -0
  70. data/ext/itsi_server/src/default_responses/html/403.html +68 -0
  71. data/ext/itsi_server/src/default_responses/html/404.html +68 -0
  72. data/ext/itsi_server/src/default_responses/html/413.html +71 -0
  73. data/ext/itsi_server/src/default_responses/html/429.html +68 -0
  74. data/ext/itsi_server/src/default_responses/html/500.html +71 -0
  75. data/ext/itsi_server/src/default_responses/html/502.html +71 -0
  76. data/ext/itsi_server/src/default_responses/html/503.html +68 -0
  77. data/ext/itsi_server/src/default_responses/html/504.html +69 -0
  78. data/ext/itsi_server/src/default_responses/html/index.html +238 -0
  79. data/ext/itsi_server/src/default_responses/json/401.json +6 -0
  80. data/ext/itsi_server/src/default_responses/json/403.json +6 -0
  81. data/ext/itsi_server/src/default_responses/json/404.json +6 -0
  82. data/ext/itsi_server/src/default_responses/json/413.json +6 -0
  83. data/ext/itsi_server/src/default_responses/json/429.json +6 -0
  84. data/ext/itsi_server/src/default_responses/json/500.json +6 -0
  85. data/ext/itsi_server/src/default_responses/json/502.json +6 -0
  86. data/ext/itsi_server/src/default_responses/json/503.json +6 -0
  87. data/ext/itsi_server/src/default_responses/json/504.json +6 -0
  88. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  89. data/ext/itsi_server/src/env.rs +43 -0
  90. data/ext/itsi_server/src/lib.rs +133 -40
  91. data/ext/itsi_server/src/prelude.rs +2 -0
  92. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +109 -0
  93. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +143 -0
  94. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  95. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  96. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
  97. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +391 -0
  98. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
  99. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
  100. data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
  101. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  102. data/ext/itsi_server/src/server/binds/bind.rs +204 -0
  103. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  104. data/ext/itsi_server/src/server/binds/listener.rs +444 -0
  105. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  106. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
  107. data/ext/itsi_server/src/server/binds/tls.rs +278 -0
  108. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  109. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  110. data/ext/itsi_server/src/server/io_stream.rs +105 -0
  111. data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
  112. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  113. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  114. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  115. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
  116. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  117. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  118. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
  119. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
  120. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  121. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  122. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
  123. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
  124. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
  125. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  126. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  127. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  128. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  129. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
  130. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
  131. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
  132. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
  133. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  134. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  135. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  136. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
  137. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  138. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
  139. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  140. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  141. data/ext/itsi_server/src/server/mod.rs +13 -5
  142. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  143. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  144. data/ext/itsi_server/src/server/request_job.rs +11 -0
  145. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +354 -0
  146. data/ext/itsi_server/src/server/serve_strategy/mod.rs +30 -0
  147. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +481 -0
  148. data/ext/itsi_server/src/server/signal.rs +77 -0
  149. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  150. data/ext/itsi_server/src/server/thread_worker.rs +479 -0
  151. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  152. data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
  153. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  154. data/ext/itsi_server/src/services/mod.rs +6 -0
  155. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  156. data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
  157. data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
  158. data/ext/itsi_tracing/Cargo.toml +5 -0
  159. data/ext/itsi_tracing/src/lib.rs +366 -7
  160. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  161. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  162. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  163. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  164. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  165. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  166. data/lib/itsi/http_request/response_status_shortcodes.rb +76 -0
  167. data/lib/itsi/http_request.rb +218 -0
  168. data/lib/itsi/http_response.rb +42 -0
  169. data/lib/itsi/passfile.rb +108 -0
  170. data/lib/itsi/server/config/config_helpers.rb +105 -0
  171. data/lib/itsi/server/config/dsl.rb +211 -0
  172. data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
  173. data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
  174. data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
  175. data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
  176. data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
  177. data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
  178. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
  179. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
  180. data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
  181. data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
  182. data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
  183. data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
  184. data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
  185. data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
  186. data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
  187. data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
  188. data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
  189. data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
  190. data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
  191. data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
  192. data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
  193. data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
  194. data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
  195. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
  196. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
  197. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
  198. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
  199. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
  200. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
  201. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
  202. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
  203. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
  204. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
  205. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
  206. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
  207. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
  208. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
  209. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
  210. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
  211. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
  212. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
  213. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
  214. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
  215. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
  216. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
  217. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
  218. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
  219. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
  220. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
  221. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
  222. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
  223. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
  224. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
  225. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
  226. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
  227. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
  228. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
  229. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
  230. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
  231. data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
  232. data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
  233. data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
  234. data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
  235. data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
  236. data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
  237. data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
  238. data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
  239. data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
  240. data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
  241. data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
  242. data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
  243. data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
  244. data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
  245. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
  246. data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
  247. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
  248. data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
  249. data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
  250. data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
  251. data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
  252. data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
  253. data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
  254. data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
  255. data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
  256. data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
  257. data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
  258. data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
  259. data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
  260. data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
  261. data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
  262. data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
  263. data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
  264. data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
  265. data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
  266. data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
  267. data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
  268. data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
  269. data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
  270. data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
  271. data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
  272. data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
  273. data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
  274. data/lib/itsi/server/config/known_paths.rb +20 -0
  275. data/lib/itsi/server/config/middleware/_index.md +56 -0
  276. data/lib/itsi/server/config/middleware/allow_list.md +46 -0
  277. data/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  278. data/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  279. data/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  280. data/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  281. data/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
  282. data/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  283. data/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  284. data/lib/itsi/server/config/middleware/cache_control.md +78 -0
  285. data/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  286. data/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  287. data/lib/itsi/server/config/middleware/compression.md +50 -0
  288. data/lib/itsi/server/config/middleware/compression.rb +37 -0
  289. data/lib/itsi/server/config/middleware/cors.md +93 -0
  290. data/lib/itsi/server/config/middleware/cors.rb +32 -0
  291. data/lib/itsi/server/config/middleware/csp.md +37 -0
  292. data/lib/itsi/server/config/middleware/csp.rb +44 -0
  293. data/lib/itsi/server/config/middleware/deny_list.md +45 -0
  294. data/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  295. data/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
  296. data/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  297. data/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  298. data/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  299. data/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
  300. data/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
  301. data/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  302. data/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
  303. data/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  304. data/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  305. data/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  306. data/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
  307. data/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  308. data/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
  309. data/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  310. data/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
  311. data/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  312. data/lib/itsi/server/config/middleware/error_response.md +61 -0
  313. data/lib/itsi/server/config/middleware/error_response.rb +36 -0
  314. data/lib/itsi/server/config/middleware/etag.md +59 -0
  315. data/lib/itsi/server/config/middleware/etag.rb +27 -0
  316. data/lib/itsi/server/config/middleware/grpc.md +172 -0
  317. data/lib/itsi/server/config/middleware/grpc.rb +54 -0
  318. data/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  319. data/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  320. data/lib/itsi/server/config/middleware/location.md +107 -0
  321. data/lib/itsi/server/config/middleware/location.rb +99 -0
  322. data/lib/itsi/server/config/middleware/log_requests.md +65 -0
  323. data/lib/itsi/server/config/middleware/log_requests.rb +31 -0
  324. data/lib/itsi/server/config/middleware/max_body.md +18 -0
  325. data/lib/itsi/server/config/middleware/max_body.rb +21 -0
  326. data/lib/itsi/server/config/middleware/proxy.md +62 -0
  327. data/lib/itsi/server/config/middleware/proxy.rb +41 -0
  328. data/lib/itsi/server/config/middleware/rackup_file.md +54 -0
  329. data/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
  330. data/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  331. data/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  332. data/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  333. data/lib/itsi/server/config/middleware/redirect.md +55 -0
  334. data/lib/itsi/server/config/middleware/redirect.rb +25 -0
  335. data/lib/itsi/server/config/middleware/request_headers.md +34 -0
  336. data/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  337. data/lib/itsi/server/config/middleware/response_headers.md +33 -0
  338. data/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  339. data/lib/itsi/server/config/middleware/run.md +60 -0
  340. data/lib/itsi/server/config/middleware/run.rb +43 -0
  341. data/lib/itsi/server/config/middleware/static_assets.md +73 -0
  342. data/lib/itsi/server/config/middleware/static_assets.rb +87 -0
  343. data/lib/itsi/server/config/middleware/static_response.md +44 -0
  344. data/lib/itsi/server/config/middleware/static_response.rb +29 -0
  345. data/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
  346. data/lib/itsi/server/config/middleware/token_source.rb +32 -0
  347. data/lib/itsi/server/config/middleware.rb +13 -0
  348. data/lib/itsi/server/config/option.rb +14 -0
  349. data/lib/itsi/server/config/options/_index.md +37 -0
  350. data/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  351. data/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
  352. data/lib/itsi/server/config/options/bind.md +71 -0
  353. data/lib/itsi/server/config/options/bind.rb +26 -0
  354. data/lib/itsi/server/config/options/certificates.md +65 -0
  355. data/lib/itsi/server/config/options/daemonize.md +14 -0
  356. data/lib/itsi/server/config/options/daemonize.rb +19 -0
  357. data/lib/itsi/server/config/options/fiber_scheduler.md +34 -0
  358. data/lib/itsi/server/config/options/fiber_scheduler.rb +21 -0
  359. data/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  360. data/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  361. data/lib/itsi/server/config/options/hooks/_index.md +11 -0
  362. data/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  363. data/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  364. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  365. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  366. data/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  367. data/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  368. data/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  369. data/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  370. data/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  371. data/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  372. data/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  373. data/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  374. data/lib/itsi/server/config/options/include.md +20 -0
  375. data/lib/itsi/server/config/options/include.rb +36 -0
  376. data/lib/itsi/server/config/options/listen_backlog.md +11 -0
  377. data/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  378. data/lib/itsi/server/config/options/log_format.md +18 -0
  379. data/lib/itsi/server/config/options/log_format.rb +19 -0
  380. data/lib/itsi/server/config/options/log_level.md +34 -0
  381. data/lib/itsi/server/config/options/log_level.rb +20 -0
  382. data/lib/itsi/server/config/options/log_target.md +38 -0
  383. data/lib/itsi/server/config/options/log_target.rb +19 -0
  384. data/lib/itsi/server/config/options/log_target_filters.md +17 -0
  385. data/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  386. data/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  387. data/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  388. data/lib/itsi/server/config/options/nodelay.md +16 -0
  389. data/lib/itsi/server/config/options/nodelay.rb +19 -0
  390. data/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  391. data/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  392. data/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  393. data/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  394. data/lib/itsi/server/config/options/preload.md +21 -0
  395. data/lib/itsi/server/config/options/preload.rb +18 -0
  396. data/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  397. data/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  398. data/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  399. data/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  400. data/lib/itsi/server/config/options/request_timeout.md +23 -0
  401. data/lib/itsi/server/config/options/request_timeout.rb +19 -0
  402. data/lib/itsi/server/config/options/reuse_address.md +16 -0
  403. data/lib/itsi/server/config/options/reuse_address.rb +19 -0
  404. data/lib/itsi/server/config/options/reuse_port.md +16 -0
  405. data/lib/itsi/server/config/options/reuse_port.rb +19 -0
  406. data/lib/itsi/server/config/options/scheduler_threads.md +34 -0
  407. data/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  408. data/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  409. data/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  410. data/lib/itsi/server/config/options/stream_body.md +32 -0
  411. data/lib/itsi/server/config/options/stream_body.rb +18 -0
  412. data/lib/itsi/server/config/options/threads.md +44 -0
  413. data/lib/itsi/server/config/options/threads.rb +17 -0
  414. data/lib/itsi/server/config/options/watch.md +16 -0
  415. data/lib/itsi/server/config/options/watch.rb +28 -0
  416. data/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  417. data/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  418. data/lib/itsi/server/config/options/workers.md +42 -0
  419. data/lib/itsi/server/config/options/workers.rb +17 -0
  420. data/lib/itsi/server/config/typed_struct.rb +242 -0
  421. data/lib/itsi/server/config.rb +289 -0
  422. data/lib/itsi/server/default_app/default_app.rb +34 -0
  423. data/lib/itsi/server/default_app/index.html +115 -0
  424. data/lib/itsi/server/default_config/Itsi.rb +107 -0
  425. data/lib/itsi/server/grpc/grpc_call.rb +246 -0
  426. data/lib/itsi/server/grpc/grpc_interface.rb +107 -0
  427. data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  428. data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  429. data/lib/itsi/server/rack/handler/itsi.rb +27 -0
  430. data/lib/itsi/server/rack_interface.rb +94 -0
  431. data/lib/itsi/server/route_tester.rb +157 -0
  432. data/lib/itsi/server/scheduler_interface.rb +21 -0
  433. data/lib/itsi/server/scheduler_mode.rb +10 -0
  434. data/lib/itsi/server/signal_trap.rb +33 -0
  435. data/lib/itsi/server/typed_handlers/param_parser.rb +196 -0
  436. data/lib/itsi/server/typed_handlers/source_parser.rb +56 -0
  437. data/lib/itsi/server/typed_handlers.rb +25 -0
  438. data/lib/itsi/server/version.rb +1 -1
  439. data/lib/itsi/server.rb +265 -9
  440. data/lib/itsi/standard_headers.rb +86 -0
  441. data/lib/ruby_lsp/itsi/addon.rb +129 -0
  442. data/lib/shell_completions/completions.rb +26 -0
  443. metadata +454 -28
  444. data/CHANGELOG.md +0 -5
  445. data/CODE_OF_CONDUCT.md +0 -132
  446. data/LICENSE.txt +0 -21
  447. data/ext/itsi_server/src/request/itsi_request.rs +0 -143
  448. data/ext/itsi_server/src/request/mod.rs +0 -1
  449. data/ext/itsi_server/src/server/bind.rs +0 -138
  450. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -32
  451. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -52
  452. data/ext/itsi_server/src/server/itsi_server.rs +0 -182
  453. data/ext/itsi_server/src/server/listener.rs +0 -218
  454. data/ext/itsi_server/src/server/tls.rs +0 -138
  455. data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  456. data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
  457. data/lib/itsi/request.rb +0 -39
@@ -0,0 +1,94 @@
1
+ module Itsi
2
+ class Server
3
+ module RackInterface
4
+
5
+ # Builds a handler proc that is compatible with Rack applications.
6
+ def self.for(app)
7
+ require "rack"
8
+ if app.is_a?(String)
9
+ dir = File.expand_path(File.dirname(app))
10
+ Dir.chdir(dir) do
11
+ loaded_app = ::Rack::Builder.parse_file(app)
12
+ app = loaded_app.is_a?(Array) ? loaded_app.first : loaded_app
13
+ end
14
+ end
15
+ lambda do |request|
16
+ Server.respond(request, app.call(request.to_rack_env))
17
+ end
18
+ end
19
+
20
+ # Interface to Rack applications.
21
+ # Here we build the env, and invoke the Rack app's call method.
22
+ # We then turn the Rack response into something Itsi server understands.
23
+ def call(app, request)
24
+ respond request, app.call(request.to_rack_env)
25
+ end
26
+
27
+ # Itsi responses are asynchronous and can be streamed.
28
+ # Response chunks are sent using response.send_frame
29
+ # and the response is finished using response.close_write.
30
+ # If only a single chunk is written, you can use the #send_and_close method.
31
+ def respond(request, (status, headers, body))
32
+ response = request.response
33
+
34
+ # Don't try and respond if we've been hijacked.
35
+ # The hijacker is now responsible for this.
36
+ return if request.hijacked
37
+
38
+ # 1. Set Status
39
+ response.status = status
40
+
41
+ # 2. Set Headers
42
+ body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack")
43
+ headers.each do |key, value|
44
+ unless value.is_a?(Array)
45
+ response[key] = value
46
+ next
47
+ end
48
+
49
+ value.each do |v|
50
+ response[key] = v
51
+ end
52
+ end
53
+
54
+ # 3. Set Body
55
+ # As soon as we start setting the response
56
+ # the server will begin to stream it to the client.
57
+
58
+ # If we're partially hijacked or returned a streaming body,
59
+ # stream this response.
60
+
61
+ if body_streamer
62
+ body_streamer.call(response)
63
+
64
+ # If we're enumerable with more than one chunk
65
+ # also stream, otherwise write in a single chunk
66
+ elsif body.respond_to?(:each) || body.respond_to?(:to_ary)
67
+ unless body.respond_to?(:each)
68
+ body = body.to_ary
69
+ raise "Body #to_ary didn't return an array" unless body.is_a?(Array)
70
+ end
71
+ # We offset this iteration intentionally,
72
+ # to optimize for the case where there's only one chunk.
73
+ buffer = nil
74
+ body.each do |part|
75
+ response << buffer.to_s if buffer
76
+ buffer = part
77
+ end
78
+
79
+ response.send_and_close(buffer.to_s)
80
+ else
81
+ response.send_and_close(body.to_s)
82
+ end
83
+ ensure
84
+ response.close_write
85
+ body.close if body.respond_to?(:close)
86
+ end
87
+
88
+ # A streaming body is one that responds to #call and not #each.
89
+ def streaming_body?(body)
90
+ body.respond_to?(:call) && !body.respond_to?(:each)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,157 @@
1
+ module Itsi
2
+ class Server
3
+ module RouteTester
4
+
5
+ require "set"
6
+ require "strscan"
7
+ require "debug"
8
+ def format_mw(mw)
9
+ mw_name, mw_args = mw
10
+ case mw_name
11
+ when "app"
12
+ "\e[33mapp\e[0m(#{mw_args['app_proc'].inspect.split(' ')[1][0...-1]})"
13
+ when "log_requests"
14
+ if mw_args['before'] && mw_args['after']
15
+ "\e[33mlog_requests\e[0m(before: #{mw_args['before']['format'][0..6]}..., after: #{mw_args['after']['format'][0..6]}...)"
16
+ elsif mw_args['before']
17
+ "\e[33mlog_requests\e[0m(before: #{mw_args['before']['format'][0..6]}...)"
18
+ elsif mw_args['after']
19
+ "\e[33mlog_requests\e[0m(before: nil, after: #{mw_args['after']['format'][0..6]}...)"
20
+ end
21
+ when "compress"
22
+ "\e[33mcompress\e[0m(#{mw_args['algorithms'].join(' ')}, #{mw_args['mime_types']})"
23
+ when "cors"
24
+ "\e[33mcors\e[0m(#{mw_args['allow_origins'].join(' ')}, #{mw_args['allow_methods'].join(' ')})"
25
+ when "etag"
26
+ "\e[33metag\e[0m(#{mw_args['type']}/#{mw_args['algorithm']}, #{mw_args['handle_if_none_match'] ? 'if_none_match' : ''})"
27
+ when "cache_control"
28
+ "\e[33mcache_control\e[0m(max_age: #{mw_args['max_age']}, #{mw_args.select{|_,v| v == true }.keys.join(", ")})"
29
+ when "redirect"
30
+ "\e[33mredirect\e[0m(to: #{mw_args['to']}, type: #{mw_args['type']})"
31
+ when "static_assets"
32
+ "\e[33mstatic_assets\e[0m(path: #{mw_args['root_dir']})"
33
+ when "auth_api_key"
34
+ "\e[33mauth_api_key\e[0m(keys: #{mw_args['valid_keys'].keys}#{mw_args['credentials_file'] ? ", credentials_file: #{mw_args['credentials_file']}" : ""})"
35
+ when "auth_basic"
36
+ "\e[33mbasic_auth\e[0m(keys: #{mw_args['realm']}#{mw_args['credentials_file'] ? ", credentials_file: #{mw_args['credentials_file']}" : ""})"
37
+ when "auth_jwt"
38
+ "\e[33mjwt_auth\e[0m(#{mw_args['verifiers'].keys.join(",")})"
39
+ when "rate_limit"
40
+ key = mw_args['key'].kind_of?(Hash) ? mw_args['key']["parameter"] : mw_args['key']
41
+ "\e[33mrate_limit\e[0m(rps: #{mw_args['requests']}/#{mw_args['seconds']}, key: #{key})"
42
+ when "allow_list"
43
+ "\e[33mallow_list\e[0m(patterns: #{mw_args['allowed_patterns'].join(", ")})"
44
+ when "deny_list"
45
+ "\e[33mdeny_list\e[0m(patterns: #{mw_args['denied_patterns'].join(", ")})"
46
+ when "csp"
47
+ "\e[33mcsp\e[0m(#{mw_args['policy'].map{|k,v| "#{k}: #{v.join(",")}"}.join(", ")})"
48
+ when "intrusion_protection"
49
+ [mw_args].flatten.map do |mw_args|
50
+ "\e[33mintrusion_protection\e[0m(banned_url_patterns: #{mw_args['banned_url_patterns']&.length}, banned_header_patterns: #{mw_args['banned_header_patterns']&.keys&.join(", ")}, #{mw_args['banned_time_seconds']}s)"
51
+ end.join("\n")
52
+ when "request_headers"
53
+ [mw_args].flatten.map do |mw_args|
54
+ "\e[33mrequest_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
55
+ end.join("\n")
56
+ when "response_headers"
57
+ [mw_args].flatten.map do |mw_args|
58
+ "\e[33mresponse_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
59
+ end.join("\n")
60
+ when "static_response"
61
+ "\e[response_headers\e[0m(#{mw_args["code"]} body: #{mw_args["body"][0..10]})"
62
+ else
63
+ "\e[33m#{mw.first}\e[0m"
64
+ end
65
+ end
66
+
67
+ def print_route(route_str, stack)
68
+ filters = %w[methods ports protocols extensions].map do |key|
69
+ val = stack[key]
70
+ val ? "#{key}: #{Array(val).join(",")}" : nil
71
+ end.compact
72
+ filter_str = filters.any? ? filters.join(", ") : "(none)"
73
+
74
+ middlewares = stack["middleware"].to_a
75
+
76
+ puts "─" * 76
77
+ puts "\e[32mRoute:\e[0m \e[33m#{route_str}\e[0m"
78
+ puts "\e[32mConditions:\e[0m \e[34m#{filter_str}\e[0m"
79
+ puts "\e[32mMiddleware:\e[0m • #{format_mw(middlewares.first)}"
80
+ middlewares[1..].each do |mw|
81
+ puts " • #{format_mw(mw)}"
82
+ end
83
+ end
84
+
85
+ def explode_route_pattern(pattern)
86
+ pattern = pattern.gsub(/^\^|\$$/, "")
87
+ pattern = pattern.gsub("\\", "")
88
+ tokens = parse_expression(StringScanner.new(pattern))
89
+ expand_tokens(tokens)
90
+ end
91
+
92
+ # Parses the expression into a nested tree of tokens
93
+ def parse_expression(scanner)
94
+ tokens = []
95
+ buffer = ""
96
+
97
+ until scanner.eos?
98
+ if scanner.scan(/\(\?:/)
99
+ tokens << buffer unless buffer.empty?
100
+ buffer = ""
101
+ tokens << parse_alternation(scanner)
102
+ elsif scanner.peek(1) == ")"
103
+ scanner.getch # consume ')'
104
+ break
105
+ else
106
+ buffer << scanner.getch
107
+ end
108
+ end
109
+
110
+ tokens << buffer unless buffer.empty?
111
+ tokens
112
+ end
113
+
114
+ # Parses inside a non-capturing group (?:A|B|C)
115
+ def parse_alternation(scanner)
116
+ options = []
117
+ current = []
118
+
119
+ until scanner.eos?
120
+ if scanner.scan(/\(\?:/)
121
+ current << parse_alternation(scanner)
122
+ elsif scanner.peek(1) == ")"
123
+ scanner.getch # consume ')'
124
+ break
125
+ elsif scanner.peek(1) == "|"
126
+ scanner.getch # consume '|'
127
+ options << current
128
+ current = []
129
+ else
130
+ current << scanner.getch
131
+ end
132
+ end
133
+
134
+ options << current
135
+ { alt: options }
136
+ end
137
+
138
+ def expand_tokens(tokens)
139
+ parts = tokens.map do |token|
140
+ if token.is_a?(String)
141
+ [token]
142
+ elsif token.is_a?(Hash) && token[:alt]
143
+ # Recurse into each branch of the alternation
144
+ token[:alt].map { |branch| expand_tokens(branch) }.flatten
145
+ else
146
+ raise "Unexpected token: #{token.inspect}"
147
+ end
148
+ end
149
+
150
+ # Cartesian product of all parts
151
+ parts.inject([""]) do |acc, part|
152
+ acc.product(part).map { |a, b| a + b }
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,21 @@
1
+ module Itsi
2
+ class Server
3
+ module SchedulerInterface
4
+ # Simple wrapper to instantiate a scheduler, start it,
5
+ # and immediate have it invoke a scheduler proc
6
+ def start_scheduler_loop(scheduler_class, scheduler_task)
7
+ scheduler = scheduler_class.new
8
+ Fiber.set_scheduler(scheduler)
9
+ [scheduler, Fiber.schedule(&scheduler_task)]
10
+ end
11
+
12
+ # When running in scheduler mode,
13
+ # each request is wrapped in a Fiber.
14
+ def schedule(app, request)
15
+ Fiber.schedule do
16
+ app.call(request)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # Running with a Fiber scheduler enabled but with an ActiveSupport isolation_level set to Thread
2
+ # can be dangerous. A thread isolation level means that all fibers sharing a thread can content
3
+ # for the same resources, which can lead to race conditions.
4
+ # This hook should *only* be disabled if you know there are no such shared resources.
5
+ if defined?(ActiveSupport::IsolatedExecutionState) && !ENV["ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL"]
6
+ Itsi.log_info \
7
+ "ActiveSupport Isolated Execution state detected. Automatically switching to :fiber mode. "\
8
+ "Set ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL to disable this behavior"
9
+ ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
10
+ end
@@ -0,0 +1,33 @@
1
+ module Itsi
2
+ # This trap is necessary for debuggers and similar which intercept certain signals
3
+ # then attempt to restore these to the previous signal when finished.
4
+ # If the previous signal handler was registered in native code, this restoration doesn't
5
+ # work as expected and the native signal handler is lost.
6
+ # We intercept restored signals here and reinstate the Itsi server signal handlers
7
+ # (if the server is still running).
8
+ module SignalTrap
9
+ DEFAULT_SIGNALS = ["DEFAULT", "", nil].freeze
10
+ INTERCEPTED_SIGNALS = ["INT"].freeze
11
+
12
+ def trap(signal, *args, &block)
13
+ unless INTERCEPTED_SIGNALS.include?(signal.to_s) && block.nil? && server_running?
14
+ return super(signal, *args, &block)
15
+ end
16
+
17
+ Itsi::Server.reset_signal_handlers
18
+ nil
19
+ end
20
+
21
+ def server_running?
22
+ Itsi::Server.respond_to?(:running?) && Itsi::Server.running?
23
+ end
24
+ end
25
+ end
26
+
27
+ [Kernel, Signal].each do |receiver|
28
+ receiver.singleton_class.prepend(Itsi::SignalTrap)
29
+ end
30
+
31
+ [Object].each do |receiver|
32
+ receiver.include(Itsi::SignalTrap)
33
+ end
@@ -0,0 +1,196 @@
1
+ module Itsi
2
+ class Server
3
+ module TypedHandlers
4
+ module ParamParser
5
+ require 'date'
6
+
7
+ class ValidationError < StandardError
8
+ attr_reader :errors
9
+ def initialize(errors)
10
+ @errors = errors
11
+ super("Validation failed: #{errors.join('; ')}")
12
+ end
13
+ end
14
+
15
+ # Conversion map for primitive/base type conversions.
16
+ CONVERSION_MAP = {
17
+ String => ->(v){ v.to_s },
18
+ Symbol => ->(v){ v.to_sym },
19
+ Integer => ->(v){ Integer(v) },
20
+ Float => ->(v){ Float(v) },
21
+ :Number => ->(v){ Float(v) },
22
+ TrueClass => ->(v){
23
+ case v
24
+ when true, 'true', '1', 1 then true
25
+ when false, 'false', '0', 0 then false
26
+ else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
27
+ end
28
+ },
29
+ FalseClass => ->(v){
30
+ case v
31
+ when true, 'true', '1', 1 then true
32
+ when false, 'false', '0', 0 then false
33
+ else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
34
+ end
35
+ },
36
+ :Boolean => ->(v){
37
+ case v
38
+ when true, 'true', '1', 1 then true
39
+ when false, 'false', '0', 0 then false
40
+ else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
41
+ end
42
+ },
43
+ Date => ->(v){ Date.parse(v.to_s) },
44
+ Time => ->(v){ Time.parse(v.to_s) },
45
+ DateTime => ->(v){ DateTime.parse(v.to_s) }
46
+ }.compare_by_identity
47
+
48
+ # Preprocess the schema into fixed keys (as symbols) and regex keys.
49
+ # Memoizes the result based on the schema.
50
+ def processed_schema(schema)
51
+ @@schema_cache ||= {}
52
+ @@schema_cache[schema] ||= begin
53
+ fixed = {}
54
+ regex = []
55
+ required_params = schema[:_required] || []
56
+ schema.each do |k, schema_def|
57
+ expected_type, required = schema_def, required_params.include?(k)
58
+ if k.is_a?(Regexp)
59
+ regex << [k, [expected_type, required]]
60
+ else
61
+ fixed[k.to_sym] = [expected_type, required]
62
+ end
63
+ end
64
+ [fixed, regex]
65
+ end
66
+ end
67
+
68
+ # Helper that converts an array of path segments into a string.
69
+ # For example, [:user, "addresses", 0, :street] becomes "user.addresses[0].street".
70
+ def format_path(path)
71
+ result = "".dup
72
+ path.each do |seg|
73
+ if seg.is_a?(Integer)
74
+ result << "[#{seg}]"
75
+ else
76
+ result << (result.empty? ? seg.to_s : ".#{seg}")
77
+ end
78
+ end
79
+ result
80
+ end
81
+
82
+ # In-place casts the value at container[key] according to expected_type.
83
+ # On success, updates container[key] and returns nil.
84
+ # On failure, returns an error message string that uses the formatted path.
85
+ def cast_value!(container, key, expected_type, path)
86
+ if expected_type.is_a?(Array)
87
+ # Only allow homogeneous array types.
88
+ return "Only homogeneous array types are supported at #{format_path(path)}" if expected_type.size != 1
89
+
90
+ # Expect container[key] to be an Array; process each element in place.
91
+ unless container[key].is_a?(Array)
92
+ return "Expected an Array at #{format_path(path)}, got #{container[key].class}"
93
+ end
94
+ container[key].each_with_index do |_, idx|
95
+ err = cast_value!(container[key], idx, expected_type.first, path + [idx])
96
+ return err if err
97
+ end
98
+ return nil
99
+
100
+ elsif expected_type.is_a?(Hash)
101
+ # Nested schema: expect container[key] to be a Hash; process it in place.
102
+ unless container[key].is_a?(Hash)
103
+ return "Expected a Hash at #{format_path(path)}, got #{container[key].class}"
104
+ end
105
+ begin
106
+ apply_schema!(container[key], expected_type, path)
107
+ return nil
108
+ rescue ValidationError => ve
109
+ return ve.errors.join('; ')
110
+ end
111
+
112
+ else
113
+ converter = CONVERSION_MAP[expected_type]
114
+ if converter
115
+ begin
116
+ container[key] = converter.call(container[key])
117
+ return nil
118
+ rescue => e
119
+ return "Invalid value for #{expected_type} at #{format_path(path)}: #{container[key].inspect} (#{e.message})"
120
+ end
121
+ end
122
+
123
+ # Fallbacks.
124
+ if expected_type == Array
125
+ unless container[key].is_a?(Array)
126
+ return "Expected Array at #{format_path(path)}, got #{container[key].class}"
127
+ end
128
+ return nil
129
+ elsif expected_type == Hash
130
+ unless container[key].is_a?(Hash)
131
+ return "Expected Hash at #{format_path(path)}, got #{container[key].class}"
132
+ end
133
+ return nil
134
+ elsif expected_type == File && container[key].is_a?(Hash) && container[key][:tempfile].is_a?(Tempfile)
135
+ return nil
136
+ else
137
+ return "Unsupported type: #{expected_type.inspect} at #{format_path(path)}"
138
+ end
139
+ end
140
+ end
141
+
142
+ # Applies the schema in place to the given params hash.
143
+ # Fixed keys are converted to symbols, and regex-matched keys remain as strings.
144
+ # The current location in the params is tracked as an array of path segments.
145
+ def apply_schema!(params, schema, path = [])
146
+ errors = []
147
+ processed = processed_schema(schema)
148
+ fixed_schema = processed[0]
149
+ regex_schema = processed[1]
150
+
151
+ # Process fixed keys.
152
+ fixed_schema.each do |fixed_key, (expected_type, required)|
153
+ new_path = path + [fixed_key]
154
+ if params.key?(fixed_key)
155
+ # Symbol key present.
156
+ elsif params.key?(fixed_key.to_s)
157
+ params[fixed_key] = params.delete(fixed_key.to_s)
158
+ else
159
+ if required
160
+ errors << "Missing required key: #{format_path(new_path)}"
161
+ else
162
+ params[fixed_key] = nil
163
+ end
164
+ next
165
+ end
166
+
167
+ err = cast_value!(params, fixed_key, expected_type, new_path)
168
+ errors << err if err
169
+ end
170
+
171
+ # Process regex keys (only string keys not already handled as fixed keys).
172
+ params.keys.each do |key|
173
+ if key == :_required
174
+ params.delete(key)
175
+ next
176
+ end
177
+ next if fixed_schema.has_key?(key.to_sym) || fixed_schema.has_key?(key)
178
+ unless regex_schema.find do |regex, (expected_type, _required)|
179
+ if regex.match(key)
180
+ new_path = path + [key]
181
+ err = cast_value!(params, key, expected_type, new_path)
182
+ errors << err if err
183
+ true # only use the first matching regex
184
+ end
185
+ end
186
+ params.delete(key)
187
+ end
188
+ end
189
+
190
+ raise ValidationError.new(errors) unless errors.empty?
191
+ params
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,56 @@
1
+ module Itsi
2
+ class Server
3
+ module TypedHandlers
4
+ module SourceParser
5
+ require 'prism'
6
+
7
+
8
+ def self.extract_expr_from_source_location(proc)
9
+ source_location = proc.source_location
10
+ source_lines = IO.readlines(source_location.first)
11
+
12
+ proc_line = source_location.last - 1
13
+ first_line = source_lines[proc_line]
14
+
15
+ until first_line =~ /(?:lambda|proc|->|def|.*?do\s*|.*?\{.*?\|)/ || proc_line.zero?
16
+ proc_line -= 1
17
+ first_line = source_lines[proc_line]
18
+ end
19
+ lines = source_lines[proc_line..]
20
+ lines[0] = lines[0][/(?:lambda|proc|->|def|.*?do\s+|.*?\{.*?\|).*/]
21
+ src_str = lines.first << "\n"
22
+ intermediate = Prism.parse(src_str)
23
+
24
+ lines[1..-1].each do |line|
25
+ break if intermediate.success?
26
+ token_count = 0
27
+ line.split(/(?=\s|;|\)|\})/).each do |token|
28
+ src_str << token
29
+ token_count += 1
30
+ intermediate = Prism.parse(src_str)
31
+ next unless intermediate.success? && token_count > 1
32
+ break
33
+ end
34
+ end
35
+
36
+ raise 'Source Extraction Failed' unless intermediate.success?
37
+
38
+ src = intermediate.value.statements.body.first.yield_self do |s|
39
+ s.type == :call_node ? s.block : s
40
+ end
41
+ params = src.parameters
42
+ params = params.parameters if params.respond_to?(:parameters)
43
+ requireds = (params&.requireds || []).map(&:name)
44
+ optionals = params&.optionals || []
45
+ keywords = (params&.keywords || []).map do |kw|
46
+ [kw.name, kw.value.slice.gsub(/^_\./, '$.')]
47
+ end.to_h
48
+
49
+ [requireds.length, keywords]
50
+ rescue
51
+ [ proc.parameters.select{|p| p == :req }&.length || 0, {}]
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
1
+ require_relative "typed_handlers/source_parser"
2
+ require_relative "typed_handlers/param_parser"
3
+
4
+ module Itsi
5
+ class Server
6
+ module TypedHandlers
7
+ def self.handler_for(proc, input_schema)
8
+ if input_schema
9
+ input_schema = proc.binding.eval(input_schema)
10
+ lambda do |req|
11
+ req.params(input_schema) do |params|
12
+ proc.call(req, params: params)
13
+ end
14
+ end
15
+ else
16
+ lambda do |req|
17
+ req.params do |params|
18
+ proc.call(req, params)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.1.1"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end