itsi-server 0.1.1 → 0.2.3

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 +4486 -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 +588 -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 +215 -0
  168. data/lib/itsi/http_response.rb +44 -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 +206 -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 +24 -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 +74 -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 +113 -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 +13 -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 +239 -0
  421. data/lib/itsi/server/config.rb +304 -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 +245 -0
  426. data/lib/itsi/server/grpc/grpc_interface.rb +106 -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 +26 -0
  430. data/lib/itsi/server/rack_interface.rb +93 -0
  431. data/lib/itsi/server/route_tester.rb +159 -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 +58 -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 +456 -30
  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,122 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: reflection.proto for package 'grpc.reflection.v1'
3
+ # Original file comments:
4
+ # Copyright 2016 The gRPC Authors
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ # Service exported by server reflection. A more complete description of how
19
+ # server reflection works can be found at
20
+ # https://github.com/grpc/grpc/blob/master/doc/server-reflection.md
21
+ #
22
+ # The canonical version of this proto can be found at
23
+ # https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto
24
+ #
25
+
26
+ require "grpc"
27
+ require_relative "reflection_pb"
28
+
29
+ module Grpc
30
+ module Reflection
31
+ module V1
32
+ module ServerReflection
33
+ class Service
34
+ include ::GRPC::GenericService
35
+
36
+ self.marshal_class_method = :encode
37
+ self.unmarshal_class_method = :decode
38
+ self.service_name = "grpc.reflection.v1.ServerReflection"
39
+
40
+ # The reflection service is structured as a bidirectional stream, ensuring
41
+ # all related requests go to a single server.
42
+ rpc :ServerReflectionInfo, stream(::Grpc::Reflection::V1::ServerReflectionRequest),
43
+ stream(::Grpc::Reflection::V1::ServerReflectionResponse)
44
+
45
+ def initialize(handlers)
46
+ @handlers = handlers
47
+ super()
48
+ end
49
+
50
+ def server_reflection_info(req, _unused_call)
51
+ req.each do |request|
52
+ res = Grpc::Reflection::V1::ServerReflectionResponse.new
53
+
54
+ if !request.list_services.empty?
55
+ res.list_services_response = Grpc::Reflection::V1::ListServiceResponse.new(service: list_services_response)
56
+ elsif !request.file_containing_symbol.empty?
57
+ res.file_descriptor_response = Grpc::Reflection::V1::FileDescriptorResponse.new(
58
+ file_descriptor_proto: [
59
+ Google::Protobuf::FileDescriptorProto.encode(Google::Protobuf::DescriptorPool.generated_pool.lookup(request.file_containing_symbol).file_descriptor.to_proto)
60
+ ]
61
+ )
62
+ elsif !request.file_by_filename.empty?
63
+ # Handle file_by_filename requests
64
+ file_descriptor = find_file_descriptor_by_filename(request.file_by_filename)
65
+ if file_descriptor
66
+ res.file_descriptor_response = Grpc::Reflection::V1::FileDescriptorResponse.new(
67
+ file_descriptor_proto: [Google::Protobuf::FileDescriptorProto.encode(file_descriptor)]
68
+ )
69
+ else
70
+ res.error_response = Grpc::Reflection::V1::ErrorResponse.new(
71
+ error_code: 5, # NOT_FOUND
72
+ error_message: "File not found: #{request.file_by_filename}"
73
+ )
74
+ end
75
+ end
76
+ yield res
77
+ # We can loop here if running in Fiber mode, but for best compatibility with blocking IO modes
78
+ # we'll close the connection and force the client to reconnect force
79
+ # subsequent reflection requests
80
+ break
81
+ end
82
+ end
83
+
84
+ def find_file_descriptor_by_filename(filename)
85
+ # First try direct lookup in the pool
86
+
87
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(filename)&.file_descriptor
88
+ return descriptor.to_proto if descriptor
89
+
90
+ proto_name = convert_file_path_to_proto_name(filename)
91
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(proto_name)&.file_descriptor
92
+ return descriptor.to_proto if descriptor
93
+
94
+ nil
95
+ end
96
+
97
+ def convert_file_path_to_proto_name(file_path)
98
+ # Remove .proto extension
99
+ file_path = file_path.sub(/\.proto$/, "")
100
+
101
+ # Split path into parts
102
+ parts = file_path.split("/")
103
+
104
+ # Convert last part to PascalCase (e.g., money -> Money)
105
+ parts[-1] = parts[-1].split("_").map(&:capitalize).join
106
+
107
+ # Join with dots
108
+ parts.join(".")
109
+ end
110
+
111
+ def list_services_response
112
+ @list_services_response ||= @handlers.map(&:class).map(&:service_name).map do |name|
113
+ Grpc::Reflection::V1::ServiceResponse.new(name: name)
114
+ end
115
+ end
116
+ end
117
+
118
+ Stub = Service.rpc_stub_class
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,26 @@
1
+ return unless defined?(::Rackup::Handler) || defined?(Rack::Handler)
2
+
3
+ module Rack
4
+ module Handler
5
+ module Itsi
6
+ def self.run(app, options = {})
7
+ host = options.fetch(:host, "127.0.0.1")
8
+ port = options.fetch(:Port, 3001)
9
+ ::Itsi::Server.start(
10
+ {
11
+ app: app,
12
+ binds: ["http://#{host}:#{port}"]
13
+ }
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ if defined?(Rackup)
21
+ ::Rackup::Handler.register("itsi", Rack::Handler::Itsi)
22
+ ::Rackup::Handler.register("Itsi", Rack::Handler::Itsi)
23
+ elsif defined?(Rack)
24
+ ::Rack::Handler.register("itsi", Rack::Handler::Itsi)
25
+ ::Rack::Handler.register("Itsi", Rack::Handler::Itsi)
26
+ end
@@ -0,0 +1,93 @@
1
+ module Itsi
2
+ class Server
3
+ module RackInterface
4
+ # Builds a handler proc that is compatible with Rack applications.
5
+ def self.for(app)
6
+ require "rack"
7
+ if app.is_a?(String)
8
+ dir = File.expand_path(File.dirname(app))
9
+ Dir.chdir(dir) do
10
+ loaded_app = ::Rack::Builder.parse_file(app)
11
+ app = loaded_app.is_a?(Array) ? loaded_app.first : loaded_app
12
+ end
13
+ end
14
+ lambda do |request|
15
+ Server.respond(request, app.call(request.to_rack_env))
16
+ end
17
+ end
18
+
19
+ # Interface to Rack applications.
20
+ # Here we build the env, and invoke the Rack app's call method.
21
+ # We then turn the Rack response into something Itsi server understands.
22
+ def call(app, request)
23
+ respond request, app.call(request.to_rack_env)
24
+ end
25
+
26
+ # Itsi responses are asynchronous and can be streamed.
27
+ # Response chunks are sent using response.send_frame
28
+ # and the response is finished using response.close_write.
29
+ # If only a single chunk is written, you can use the #send_and_close method.
30
+ def respond(request, (status, headers, body))
31
+ response = request.response
32
+
33
+ # Don't try and respond if we've been hijacked.
34
+ # The hijacker is now responsible for this.
35
+ return if request.hijacked
36
+
37
+ # 1. Set Status
38
+ response.status = status
39
+
40
+ # 2. Set Headers
41
+ body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack")
42
+ headers.each do |key, value|
43
+ unless value.is_a?(Array)
44
+ response[key] = value
45
+ next
46
+ end
47
+
48
+ value.each do |v|
49
+ response[key] = v
50
+ end
51
+ end
52
+
53
+ # 3. Set Body
54
+ # As soon as we start setting the response
55
+ # the server will begin to stream it to the client.
56
+
57
+ # If we're partially hijacked or returned a streaming body,
58
+ # stream this response.
59
+
60
+ if body_streamer
61
+ body_streamer.call(response)
62
+
63
+ # If we're enumerable with more than one chunk
64
+ # also stream, otherwise write in a single chunk
65
+ elsif body.respond_to?(:each) || body.respond_to?(:to_ary)
66
+ unless body.respond_to?(:each)
67
+ body = body.to_ary
68
+ raise "Body #to_ary didn't return an array" unless body.is_a?(Array)
69
+ end
70
+ # We offset this iteration intentionally,
71
+ # to optimize for the case where there's only one chunk.
72
+ buffer = nil
73
+ body.each do |part|
74
+ response << buffer.to_s if buffer
75
+ buffer = part
76
+ end
77
+
78
+ response.send_and_close(buffer.to_s)
79
+ else
80
+ response.send_and_close(body.to_s)
81
+ end
82
+ ensure
83
+ response.close_write
84
+ body.close if body.respond_to?(:close)
85
+ end
86
+
87
+ # A streaming body is one that responds to #call and not #each.
88
+ def streaming_body?(body)
89
+ body.respond_to?(:call) && !body.respond_to?(:each)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,159 @@
1
+ module Itsi
2
+ class Server
3
+ # Utility module for printing Itsi route information
4
+ module RouteTester
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 do |_, v|
29
+ v == true
30
+ end.keys.join(", ")})"
31
+ when "redirect"
32
+ "\e[33mredirect\e[0m(to: #{mw_args["to"]}, type: #{mw_args["type"]})"
33
+ when "static_assets"
34
+ "\e[33mstatic_assets\e[0m(path: #{mw_args["root_dir"]})"
35
+ when "auth_api_key"
36
+ "\e[33mauth_api_key\e[0m(keys: #{mw_args["valid_keys"].keys}#{mw_args["credentials_file"] ? ", credentials_file: #{mw_args["credentials_file"]}" : ""})"
37
+ when "auth_basic"
38
+ "\e[33mbasic_auth\e[0m(keys: #{mw_args["realm"]}#{mw_args["credentials_file"] ? ", credentials_file: #{mw_args["credentials_file"]}" : ""})"
39
+ when "auth_jwt"
40
+ "\e[33mjwt_auth\e[0m(#{mw_args["verifiers"].keys.join(",")})"
41
+ when "rate_limit"
42
+ key = mw_args["key"].is_a?(Hash) ? mw_args["key"]["parameter"] : mw_args["key"]
43
+ "\e[33mrate_limit\e[0m(rps: #{mw_args["requests"]}/#{mw_args["seconds"]}, key: #{key})"
44
+ when "allow_list"
45
+ "\e[33mallow_list\e[0m(patterns: #{mw_args["allowed_patterns"].join(", ")})"
46
+ when "deny_list"
47
+ "\e[33mdeny_list\e[0m(patterns: #{mw_args["denied_patterns"].join(", ")})"
48
+ when "csp"
49
+ "\e[33mcsp\e[0m(#{mw_args["policy"].map { |k, v| "#{k}: #{v.join(",")}" }.join(", ")})"
50
+ when "intrusion_protection"
51
+ [mw_args].flatten.map do |mw_args|
52
+ "\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)"
53
+ end.join("\n")
54
+ when "request_headers"
55
+ [mw_args].flatten.map do |mw_args|
56
+ "\e[33mrequest_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
57
+ end.join("\n")
58
+ when "response_headers"
59
+ [mw_args].flatten.map do |mw_args|
60
+ "\e[33mresponse_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
61
+ end.join("\n")
62
+ when "static_response"
63
+ "\e[response_headers\e[0m(#{mw_args["code"]} body: #{mw_args["body"][0..10]})"
64
+ else
65
+ "\e[33m#{mw.first}\e[0m"
66
+ end
67
+ end
68
+
69
+ def print_route(route_str, stack)
70
+ filters = %w[methods ports protocols extensions].map do |key|
71
+ val = stack[key]
72
+ val ? "#{key}: #{Array(val).join(",")}" : nil
73
+ end.compact
74
+ filter_str = filters.any? ? filters.join(", ") : "(none)"
75
+
76
+ middlewares = stack["middleware"].to_a
77
+
78
+ puts "─" * 76
79
+ puts "\e[32mRoute:\e[0m \e[33m#{route_str}\e[0m"
80
+ puts "\e[32mConditions:\e[0m \e[34m#{filter_str}\e[0m"
81
+ puts "\e[32mMiddleware:\e[0m • #{format_mw(middlewares.first)}"
82
+ middlewares[1..].each do |mw|
83
+ puts " • #{format_mw(mw)}"
84
+ end
85
+ end
86
+
87
+ def explode_route_pattern(pattern)
88
+ pattern = pattern.gsub(/^\^|\$$/, "")
89
+ pattern = pattern.gsub("\\", "")
90
+ tokens = parse_expression(StringScanner.new(pattern))
91
+ expand_tokens(tokens)
92
+ end
93
+
94
+ # Parses the expression into a nested tree of tokens
95
+ def parse_expression(scanner)
96
+ tokens = []
97
+ buffer = ""
98
+
99
+ until scanner.eos?
100
+ if scanner.scan(/\(\?:/)
101
+ tokens << buffer unless buffer.empty?
102
+ buffer = ""
103
+ tokens << parse_alternation(scanner)
104
+ elsif scanner.peek(1) == ")"
105
+ scanner.getch # consume ')'
106
+ break
107
+ else
108
+ buffer << scanner.getch
109
+ end
110
+ end
111
+
112
+ tokens << buffer unless buffer.empty?
113
+ tokens
114
+ end
115
+
116
+ # Parses inside a non-capturing group (?:A|B|C)
117
+ def parse_alternation(scanner)
118
+ options = []
119
+ current = []
120
+
121
+ until scanner.eos?
122
+ if scanner.scan(/\(\?:/)
123
+ current << parse_alternation(scanner)
124
+ elsif scanner.peek(1) == ")"
125
+ scanner.getch # consume ')'
126
+ break
127
+ elsif scanner.peek(1) == "|"
128
+ scanner.getch # consume '|'
129
+ options << current
130
+ current = []
131
+ else
132
+ current << scanner.getch
133
+ end
134
+ end
135
+
136
+ options << current
137
+ { alt: options }
138
+ end
139
+
140
+ def expand_tokens(tokens)
141
+ parts = tokens.map do |token|
142
+ if token.is_a?(String)
143
+ [token]
144
+ elsif token.is_a?(Hash) && token[:alt]
145
+ # Recurse into each branch of the alternation
146
+ token[:alt].map { |branch| expand_tokens(branch) }.flatten
147
+ else
148
+ raise "Unexpected token: #{token.inspect}"
149
+ end
150
+ end
151
+
152
+ # Cartesian product of all parts
153
+ parts.inject([""]) do |acc, part|
154
+ acc.product(part).map { |a, b| a + b }
155
+ end
156
+ end
157
+ end
158
+ end
159
+ 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