itsi-server 0.2.22-aarch64-linux

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 (451) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +8 -0
  3. data/Cargo.lock +4452 -0
  4. data/Cargo.toml +11 -0
  5. data/Rakefile +57 -0
  6. data/exe/itsi +193 -0
  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.lock +368 -0
  30. data/ext/itsi_error/Cargo.toml +12 -0
  31. data/ext/itsi_error/src/lib.rs +140 -0
  32. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  33. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  34. data/ext/itsi_rb_helpers/Cargo.lock +355 -0
  35. data/ext/itsi_rb_helpers/Cargo.toml +11 -0
  36. data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
  37. data/ext/itsi_rb_helpers/src/lib.rs +232 -0
  38. data/ext/itsi_scheduler/Cargo.toml +24 -0
  39. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  40. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  41. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  42. data/ext/itsi_scheduler/src/itsi_scheduler.rs +320 -0
  43. data/ext/itsi_scheduler/src/lib.rs +39 -0
  44. data/ext/itsi_server/Cargo.lock +2956 -0
  45. data/ext/itsi_server/Cargo.toml +94 -0
  46. data/ext/itsi_server/extconf.rb +11 -0
  47. data/ext/itsi_server/src/default_responses/html/401.html +68 -0
  48. data/ext/itsi_server/src/default_responses/html/403.html +68 -0
  49. data/ext/itsi_server/src/default_responses/html/404.html +68 -0
  50. data/ext/itsi_server/src/default_responses/html/413.html +71 -0
  51. data/ext/itsi_server/src/default_responses/html/429.html +68 -0
  52. data/ext/itsi_server/src/default_responses/html/500.html +71 -0
  53. data/ext/itsi_server/src/default_responses/html/502.html +71 -0
  54. data/ext/itsi_server/src/default_responses/html/503.html +68 -0
  55. data/ext/itsi_server/src/default_responses/html/504.html +69 -0
  56. data/ext/itsi_server/src/default_responses/html/index.html +238 -0
  57. data/ext/itsi_server/src/default_responses/json/401.json +6 -0
  58. data/ext/itsi_server/src/default_responses/json/403.json +6 -0
  59. data/ext/itsi_server/src/default_responses/json/404.json +6 -0
  60. data/ext/itsi_server/src/default_responses/json/413.json +6 -0
  61. data/ext/itsi_server/src/default_responses/json/429.json +6 -0
  62. data/ext/itsi_server/src/default_responses/json/500.json +6 -0
  63. data/ext/itsi_server/src/default_responses/json/502.json +6 -0
  64. data/ext/itsi_server/src/default_responses/json/503.json +6 -0
  65. data/ext/itsi_server/src/default_responses/json/504.json +6 -0
  66. data/ext/itsi_server/src/default_responses/mod.rs +14 -0
  67. data/ext/itsi_server/src/env.rs +43 -0
  68. data/ext/itsi_server/src/lib.rs +154 -0
  69. data/ext/itsi_server/src/prelude.rs +2 -0
  70. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +116 -0
  71. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +149 -0
  72. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +346 -0
  73. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +265 -0
  74. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +399 -0
  75. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +447 -0
  76. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +545 -0
  77. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +650 -0
  78. data/ext/itsi_server/src/ruby_types/itsi_server.rs +102 -0
  79. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  80. data/ext/itsi_server/src/server/binds/bind.rs +204 -0
  81. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  82. data/ext/itsi_server/src/server/binds/listener.rs +485 -0
  83. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  84. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
  85. data/ext/itsi_server/src/server/binds/tls.rs +278 -0
  86. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  87. data/ext/itsi_server/src/server/frame_stream.rs +143 -0
  88. data/ext/itsi_server/src/server/http_message_types.rs +230 -0
  89. data/ext/itsi_server/src/server/io_stream.rs +128 -0
  90. data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
  91. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  92. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +93 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +329 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +300 -0
  99. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  100. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  101. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +188 -0
  102. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +168 -0
  103. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +183 -0
  104. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  105. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  106. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +133 -0
  107. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  108. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +122 -0
  109. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +407 -0
  110. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +155 -0
  111. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +54 -0
  112. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  113. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  114. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +138 -0
  115. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +269 -0
  116. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +62 -0
  117. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +218 -0
  118. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  119. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  120. data/ext/itsi_server/src/server/mod.rs +14 -0
  121. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  122. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  123. data/ext/itsi_server/src/server/request_job.rs +11 -0
  124. data/ext/itsi_server/src/server/serve_strategy/acceptor.rs +100 -0
  125. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +411 -0
  126. data/ext/itsi_server/src/server/serve_strategy/mod.rs +31 -0
  127. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +449 -0
  128. data/ext/itsi_server/src/server/signal.rs +129 -0
  129. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  130. data/ext/itsi_server/src/server/thread_worker.rs +504 -0
  131. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  132. data/ext/itsi_server/src/services/itsi_http_service.rs +270 -0
  133. data/ext/itsi_server/src/services/mime_types.rs +2896 -0
  134. data/ext/itsi_server/src/services/mod.rs +6 -0
  135. data/ext/itsi_server/src/services/password_hasher.rs +89 -0
  136. data/ext/itsi_server/src/services/rate_limiter.rs +609 -0
  137. data/ext/itsi_server/src/services/static_file_server.rs +1400 -0
  138. data/ext/itsi_tracing/Cargo.lock +274 -0
  139. data/ext/itsi_tracing/Cargo.toml +17 -0
  140. data/ext/itsi_tracing/src/lib.rs +370 -0
  141. data/lib/itsi/http_request/response_status_shortcodes.rb +76 -0
  142. data/lib/itsi/http_request.rb +228 -0
  143. data/lib/itsi/http_response.rb +49 -0
  144. data/lib/itsi/passfile.rb +108 -0
  145. data/lib/itsi/rack_env_pool.rb +49 -0
  146. data/lib/itsi/server/3.1/itsi_server.so +0 -0
  147. data/lib/itsi/server/3.2/itsi_server.so +0 -0
  148. data/lib/itsi/server/3.3/itsi_server.so +0 -0
  149. data/lib/itsi/server/3.4/itsi_server.so +0 -0
  150. data/lib/itsi/server/4.0/itsi_server.so +0 -0
  151. data/lib/itsi/server/config/config_helpers.rb +116 -0
  152. data/lib/itsi/server/config/dsl.rb +208 -0
  153. data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
  154. data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
  155. data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
  156. data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
  157. data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
  158. data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
  159. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
  160. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
  161. data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
  162. data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
  163. data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
  164. data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
  165. data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
  166. data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
  167. data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
  168. data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
  169. data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
  170. data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
  171. data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
  172. data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
  173. data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
  174. data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
  175. data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
  176. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
  177. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
  178. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
  179. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
  180. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
  181. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
  182. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
  183. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
  184. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
  185. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
  186. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
  187. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
  188. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
  189. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
  190. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
  191. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
  192. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
  193. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
  194. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
  195. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
  196. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
  197. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
  198. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
  199. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
  200. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
  201. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
  202. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
  203. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
  204. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
  205. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
  206. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
  207. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
  208. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
  209. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
  210. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
  211. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
  212. data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
  213. data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
  214. data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
  215. data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
  216. data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
  217. data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
  218. data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
  219. data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
  220. data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
  221. data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
  222. data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
  223. data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
  224. data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
  225. data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
  226. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
  227. data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
  228. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
  229. data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
  230. data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
  231. data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
  232. data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
  233. data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
  234. data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
  235. data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
  236. data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
  237. data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
  238. data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
  239. data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
  240. data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
  241. data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
  242. data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
  243. data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
  244. data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
  245. data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
  246. data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
  247. data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
  248. data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
  249. data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
  250. data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
  251. data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
  252. data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
  253. data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
  254. data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
  255. data/lib/itsi/server/config/known_paths.rb +24 -0
  256. data/lib/itsi/server/config/middleware/_index.md +56 -0
  257. data/lib/itsi/server/config/middleware/allow_list.md +46 -0
  258. data/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  259. data/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  260. data/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  261. data/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  262. data/lib/itsi/server/config/middleware/auth_basic.rb +46 -0
  263. data/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  264. data/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  265. data/lib/itsi/server/config/middleware/cache_control.md +78 -0
  266. data/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  267. data/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  268. data/lib/itsi/server/config/middleware/compression.md +50 -0
  269. data/lib/itsi/server/config/middleware/compression.rb +37 -0
  270. data/lib/itsi/server/config/middleware/cors.md +93 -0
  271. data/lib/itsi/server/config/middleware/cors.rb +32 -0
  272. data/lib/itsi/server/config/middleware/csp.md +37 -0
  273. data/lib/itsi/server/config/middleware/csp.rb +44 -0
  274. data/lib/itsi/server/config/middleware/deny_list.md +45 -0
  275. data/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  276. data/lib/itsi/server/config/middleware/endpoint/_index.md +160 -0
  277. data/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  278. data/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  279. data/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  280. data/lib/itsi/server/config/middleware/endpoint/delete.rb +43 -0
  281. data/lib/itsi/server/config/middleware/endpoint/endpoint.rb +106 -0
  282. data/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  283. data/lib/itsi/server/config/middleware/endpoint/get.rb +43 -0
  284. data/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  285. data/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  286. data/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  287. data/lib/itsi/server/config/middleware/endpoint/patch.rb +43 -0
  288. data/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  289. data/lib/itsi/server/config/middleware/endpoint/post.rb +43 -0
  290. data/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  291. data/lib/itsi/server/config/middleware/endpoint/put.rb +43 -0
  292. data/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  293. data/lib/itsi/server/config/middleware/error_response.md +74 -0
  294. data/lib/itsi/server/config/middleware/error_response.rb +36 -0
  295. data/lib/itsi/server/config/middleware/etag.md +55 -0
  296. data/lib/itsi/server/config/middleware/etag.rb +25 -0
  297. data/lib/itsi/server/config/middleware/grpc.md +170 -0
  298. data/lib/itsi/server/config/middleware/grpc.rb +54 -0
  299. data/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  300. data/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  301. data/lib/itsi/server/config/middleware/location.md +107 -0
  302. data/lib/itsi/server/config/middleware/location.rb +103 -0
  303. data/lib/itsi/server/config/middleware/log_requests.md +67 -0
  304. data/lib/itsi/server/config/middleware/log_requests.rb +31 -0
  305. data/lib/itsi/server/config/middleware/max_body.md +18 -0
  306. data/lib/itsi/server/config/middleware/max_body.rb +21 -0
  307. data/lib/itsi/server/config/middleware/proxy.md +62 -0
  308. data/lib/itsi/server/config/middleware/proxy.rb +42 -0
  309. data/lib/itsi/server/config/middleware/rackup_file.md +72 -0
  310. data/lib/itsi/server/config/middleware/rackup_file.rb +43 -0
  311. data/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  312. data/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  313. data/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  314. data/lib/itsi/server/config/middleware/redirect.md +55 -0
  315. data/lib/itsi/server/config/middleware/redirect.rb +25 -0
  316. data/lib/itsi/server/config/middleware/request_headers.md +34 -0
  317. data/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  318. data/lib/itsi/server/config/middleware/response_headers.md +33 -0
  319. data/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  320. data/lib/itsi/server/config/middleware/run.md +79 -0
  321. data/lib/itsi/server/config/middleware/run.rb +45 -0
  322. data/lib/itsi/server/config/middleware/static_assets.md +113 -0
  323. data/lib/itsi/server/config/middleware/static_assets.rb +99 -0
  324. data/lib/itsi/server/config/middleware/static_response.md +44 -0
  325. data/lib/itsi/server/config/middleware/static_response.rb +30 -0
  326. data/lib/itsi/server/config/middleware/string_rewrite.md +81 -0
  327. data/lib/itsi/server/config/middleware/token_source.rb +32 -0
  328. data/lib/itsi/server/config/middleware.rb +13 -0
  329. data/lib/itsi/server/config/option.rb +13 -0
  330. data/lib/itsi/server/config/options/_index.md +41 -0
  331. data/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  332. data/lib/itsi/server/config/options/auto_reload_config.rb +46 -0
  333. data/lib/itsi/server/config/options/bind.md +71 -0
  334. data/lib/itsi/server/config/options/bind.rb +26 -0
  335. data/lib/itsi/server/config/options/certificates.md +65 -0
  336. data/lib/itsi/server/config/options/daemonize.md +14 -0
  337. data/lib/itsi/server/config/options/daemonize.rb +19 -0
  338. data/lib/itsi/server/config/options/fiber_scheduler.md +34 -0
  339. data/lib/itsi/server/config/options/fiber_scheduler.rb +21 -0
  340. data/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  341. data/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  342. data/lib/itsi/server/config/options/hooks/_index.md +11 -0
  343. data/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  344. data/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  345. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  346. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  347. data/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  348. data/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  349. data/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  350. data/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  351. data/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  352. data/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  353. data/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  354. data/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  355. data/lib/itsi/server/config/options/include.md +21 -0
  356. data/lib/itsi/server/config/options/include.rb +41 -0
  357. data/lib/itsi/server/config/options/listen_backlog.md +11 -0
  358. data/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  359. data/lib/itsi/server/config/options/log_format.md +18 -0
  360. data/lib/itsi/server/config/options/log_format.rb +19 -0
  361. data/lib/itsi/server/config/options/log_level.md +34 -0
  362. data/lib/itsi/server/config/options/log_level.rb +20 -0
  363. data/lib/itsi/server/config/options/log_target.md +38 -0
  364. data/lib/itsi/server/config/options/log_target.rb +19 -0
  365. data/lib/itsi/server/config/options/log_target_filters.md +17 -0
  366. data/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  367. data/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  368. data/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  369. data/lib/itsi/server/config/options/nodelay.md +16 -0
  370. data/lib/itsi/server/config/options/nodelay.rb +19 -0
  371. data/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  372. data/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  373. data/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  374. data/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  375. data/lib/itsi/server/config/options/pipeline_flush.md +16 -0
  376. data/lib/itsi/server/config/options/pipeline_flush.rb +19 -0
  377. data/lib/itsi/server/config/options/preload.md +21 -0
  378. data/lib/itsi/server/config/options/preload.rb +18 -0
  379. data/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  380. data/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  381. data/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  382. data/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  383. data/lib/itsi/server/config/options/request_timeout.md +23 -0
  384. data/lib/itsi/server/config/options/request_timeout.rb +19 -0
  385. data/lib/itsi/server/config/options/reuse_address.md +18 -0
  386. data/lib/itsi/server/config/options/reuse_address.rb +19 -0
  387. data/lib/itsi/server/config/options/reuse_port.md +18 -0
  388. data/lib/itsi/server/config/options/reuse_port.rb +17 -0
  389. data/lib/itsi/server/config/options/ruby_thread_request_backlog_size.md +18 -0
  390. data/lib/itsi/server/config/options/ruby_thread_request_backlog_size.rb +19 -0
  391. data/lib/itsi/server/config/options/scheduler_threads.md +41 -0
  392. data/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  393. data/lib/itsi/server/config/options/send_buffer_size.md +15 -0
  394. data/lib/itsi/server/config/options/send_buffer_size.rb +19 -0
  395. data/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  396. data/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  397. data/lib/itsi/server/config/options/stream_body.md +32 -0
  398. data/lib/itsi/server/config/options/stream_body.rb +18 -0
  399. data/lib/itsi/server/config/options/threads.md +44 -0
  400. data/lib/itsi/server/config/options/threads.rb +17 -0
  401. data/lib/itsi/server/config/options/watch.md +16 -0
  402. data/lib/itsi/server/config/options/watch.rb +28 -0
  403. data/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  404. data/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  405. data/lib/itsi/server/config/options/workers.md +42 -0
  406. data/lib/itsi/server/config/options/workers.rb +17 -0
  407. data/lib/itsi/server/config/options/writev.md +25 -0
  408. data/lib/itsi/server/config/options/writev.rb +19 -0
  409. data/lib/itsi/server/config/typed_struct.rb +239 -0
  410. data/lib/itsi/server/config.rb +321 -0
  411. data/lib/itsi/server/default_app/default_app.rb +34 -0
  412. data/lib/itsi/server/default_app/index.html +115 -0
  413. data/lib/itsi/server/default_config/Itsi.rb +108 -0
  414. data/lib/itsi/server/grpc/grpc_call.rb +247 -0
  415. data/lib/itsi/server/grpc/grpc_interface.rb +106 -0
  416. data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  417. data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  418. data/lib/itsi/server/native_extension.rb +34 -0
  419. data/lib/itsi/server/rack/handler/itsi.rb +29 -0
  420. data/lib/itsi/server/rack_interface.rb +109 -0
  421. data/lib/itsi/server/route_tester.rb +159 -0
  422. data/lib/itsi/server/scheduler_interface.rb +23 -0
  423. data/lib/itsi/server/scheduler_mode.rb +10 -0
  424. data/lib/itsi/server/signal_trap.rb +33 -0
  425. data/lib/itsi/server/typed_handlers/param_parser.rb +221 -0
  426. data/lib/itsi/server/typed_handlers/source_parser.rb +58 -0
  427. data/lib/itsi/server/typed_handlers.rb +25 -0
  428. data/lib/itsi/server/version.rb +7 -0
  429. data/lib/itsi/server.rb +288 -0
  430. data/lib/itsi/standard_headers.rb +86 -0
  431. data/lib/ruby_lsp/itsi/addon.rb +128 -0
  432. data/lib/shell_completions/completions.rb +26 -0
  433. data/vendor/rb-sys-build/.cargo-ok +1 -0
  434. data/vendor/rb-sys-build/.cargo_vcs_info.json +6 -0
  435. data/vendor/rb-sys-build/Cargo.lock +294 -0
  436. data/vendor/rb-sys-build/Cargo.toml +71 -0
  437. data/vendor/rb-sys-build/Cargo.toml.orig +32 -0
  438. data/vendor/rb-sys-build/LICENSE-APACHE +190 -0
  439. data/vendor/rb-sys-build/LICENSE-MIT +21 -0
  440. data/vendor/rb-sys-build/src/bindings/sanitizer.rs +185 -0
  441. data/vendor/rb-sys-build/src/bindings/stable_api.rs +247 -0
  442. data/vendor/rb-sys-build/src/bindings/wrapper.h +71 -0
  443. data/vendor/rb-sys-build/src/bindings.rs +280 -0
  444. data/vendor/rb-sys-build/src/cc.rs +421 -0
  445. data/vendor/rb-sys-build/src/lib.rs +12 -0
  446. data/vendor/rb-sys-build/src/rb_config/flags.rs +101 -0
  447. data/vendor/rb-sys-build/src/rb_config/library.rs +132 -0
  448. data/vendor/rb-sys-build/src/rb_config/search_path.rs +57 -0
  449. data/vendor/rb-sys-build/src/rb_config.rs +906 -0
  450. data/vendor/rb-sys-build/src/utils.rs +53 -0
  451. metadata +569 -0
@@ -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
+
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"]})"
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,23 @@
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
+ rescue StandardError => e
18
+ request.server_error(e.message)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ 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,221 @@
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
+ # Support top-level array schema: homogeneous arrays.
147
+ if schema.is_a?(Array)
148
+ # Only allow homogeneous array types
149
+ unless schema.size == 1
150
+ raise ValidationError.new(["Schema Array must contain exactly one type. Got #{schema.size}"])
151
+ end
152
+ expected_type = schema.first
153
+ # Expect params to be an Array
154
+ unless params.is_a?(Array)
155
+ raise ValidationError.new(["Expected Array at #{format_path(path)}, got #{params.class}"])
156
+ end
157
+ errors = []
158
+ params.each_with_index do |_, idx|
159
+ err = cast_value!(params, idx, expected_type, path + [idx])
160
+ errors << err if err
161
+ end
162
+ raise ValidationError.new(errors) unless errors.empty?
163
+ return params
164
+ end
165
+
166
+ # Ensure schema is a Hash
167
+ unless schema.is_a?(Hash)
168
+ raise ValidationError.new(["Unsupported schema type: #{schema.class} at #{format_path(path)}"])
169
+ end
170
+
171
+ errors = []
172
+ processed = processed_schema(schema)
173
+ fixed_schema = processed[0]
174
+ regex_schema = processed[1]
175
+
176
+ # Process fixed keys.
177
+ fixed_schema.each do |fixed_key, (expected_type, required)|
178
+ new_path = path + [fixed_key]
179
+ if params.key?(fixed_key)
180
+ # Symbol key present.
181
+ elsif params.key?(fixed_key.to_s)
182
+ params[fixed_key] = params.delete(fixed_key.to_s)
183
+ else
184
+ if required
185
+ errors << "Missing required key: #{format_path(new_path)}"
186
+ else
187
+ params[fixed_key] = nil
188
+ end
189
+ next
190
+ end
191
+
192
+ err = cast_value!(params, fixed_key, expected_type, new_path)
193
+ errors << err if err
194
+ end
195
+
196
+ # Process regex keys (only string keys not already handled as fixed keys).
197
+ params.keys.each do |key|
198
+ if key == :_required
199
+ params.delete(key)
200
+ next
201
+ end
202
+ next if fixed_schema.has_key?(key.to_sym) || fixed_schema.has_key?(key)
203
+ unless regex_schema.find do |regex, (expected_type, _required)|
204
+ if regex.match(key)
205
+ new_path = path + [key]
206
+ err = cast_value!(params, key, expected_type, new_path)
207
+ errors << err if err
208
+ true # only use the first matching regex
209
+ end
210
+ end
211
+ params.delete(key)
212
+ end
213
+ end
214
+
215
+ raise ValidationError.new(errors) unless errors.empty?
216
+ params
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,58 @@
1
+ module Itsi
2
+ class Server
3
+ module TypedHandlers
4
+ module SourceParser
5
+ require "prism"
6
+
7
+ # Source Parser interprets endpoint handlers
8
+ # and extracts arity and schema information.
9
+ def self.extract_expr_from_source_location(proc)
10
+ source_location = proc.source_location
11
+ source_lines = IO.readlines(source_location.first)
12
+
13
+ proc_line = source_location.last - 1
14
+ first_line = source_lines[proc_line]
15
+
16
+ until first_line =~ /(?:lambda|proc|->|def|.*?do\s*|.*?\{.*?\|)/ || proc_line.zero?
17
+ proc_line -= 1
18
+ first_line = source_lines[proc_line]
19
+ end
20
+ lines = source_lines[proc_line..]
21
+ lines[0] = lines[0][/(?:lambda|proc|->|def|.*?do\s+|.*?\{.*?\|).*/]
22
+ src_str = lines.first << "\n"
23
+ intermediate = Prism.parse(src_str)
24
+
25
+ lines[1..-1].each do |line|
26
+ break if intermediate.success?
27
+
28
+ token_count = 0
29
+ line.split(/(?=\s|;|\)|\})/).each do |token|
30
+ src_str << token
31
+ token_count += 1
32
+ intermediate = Prism.parse(src_str)
33
+ next unless intermediate.success? && token_count > 1
34
+
35
+ break
36
+ end
37
+ end
38
+
39
+ raise "Source Extraction Failed" unless intermediate.success?
40
+
41
+ src = intermediate.value.statements.body.first.yield_self do |s|
42
+ s.type == :call_node ? s.block : s
43
+ end
44
+ params = src.parameters
45
+ params = params.parameters if params.respond_to?(:parameters)
46
+ requireds = (params&.requireds || []).map(&:name)
47
+ keywords = (params&.keywords || []).map do |kw|
48
+ [kw.name, kw.value.slice.gsub(/^_\./, "$.")]
49
+ end.to_h
50
+
51
+ [requireds.length, keywords]
52
+ rescue StandardError
53
+ [proc.parameters.select { |p| p == :req }&.length || 0, {}]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ 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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Itsi
4
+ class Server
5
+ VERSION = "0.2.22"
6
+ end
7
+ end