itsi-server 0.1.1 → 0.1.20

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.

Potentially problematic release.


This version of itsi-server might be problematic. Click here for more details.

Files changed (324) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +4487 -0
  3. data/Cargo.toml +7 -0
  4. data/README.md +6 -0
  5. data/Rakefile +8 -1
  6. data/exe/itsi +141 -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 +140 -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 +308 -0
  65. data/ext/itsi_scheduler/src/lib.rs +38 -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 +132 -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 +345 -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 +225 -0
  99. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +506 -0
  100. data/ext/itsi_server/src/ruby_types/itsi_server.rs +84 -0
  101. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  102. data/ext/itsi_server/src/server/binds/bind.rs +201 -0
  103. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  104. data/ext/itsi_server/src/server/binds/listener.rs +437 -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 +270 -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 +56 -0
  114. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +87 -0
  115. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +86 -0
  116. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +338 -0
  117. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +142 -0
  118. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +289 -0
  119. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +292 -0
  120. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +179 -0
  121. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +55 -0
  122. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
  123. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +157 -0
  124. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +195 -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 +201 -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 +110 -0
  130. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +414 -0
  131. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +131 -0
  132. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  133. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +44 -0
  134. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +36 -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 +181 -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 +163 -0
  139. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  140. data/ext/itsi_server/src/server/middleware_stack/mod.rs +345 -0
  141. data/ext/itsi_server/src/server/mod.rs +12 -5
  142. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  143. data/ext/itsi_server/src/server/request_job.rs +11 -0
  144. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +348 -0
  145. data/ext/itsi_server/src/server/serve_strategy/mod.rs +30 -0
  146. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +444 -0
  147. data/ext/itsi_server/src/server/signal.rs +76 -0
  148. data/ext/itsi_server/src/server/size_limited_incoming.rs +101 -0
  149. data/ext/itsi_server/src/server/thread_worker.rs +475 -0
  150. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  151. data/ext/itsi_server/src/services/itsi_http_service.rs +239 -0
  152. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  153. data/ext/itsi_server/src/services/mod.rs +6 -0
  154. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  155. data/ext/itsi_server/src/services/rate_limiter.rs +569 -0
  156. data/ext/itsi_server/src/services/static_file_server.rs +1326 -0
  157. data/ext/itsi_tracing/Cargo.toml +5 -0
  158. data/ext/itsi_tracing/src/lib.rs +346 -7
  159. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  160. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  161. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  162. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  163. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  164. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  165. data/lib/itsi/http_request/response_status_shortcodes.rb +74 -0
  166. data/lib/itsi/http_request.rb +187 -0
  167. data/lib/itsi/http_response.rb +41 -0
  168. data/lib/itsi/passfile.rb +109 -0
  169. data/lib/itsi/server/config/config_helpers.rb +93 -0
  170. data/lib/itsi/server/config/dsl.rb +626 -0
  171. data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
  172. data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
  173. data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
  174. data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
  175. data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
  176. data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
  177. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
  178. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
  179. data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
  180. data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
  181. data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
  182. data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
  183. data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
  184. data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
  185. data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
  186. data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
  187. data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
  188. data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
  189. data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
  190. data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
  191. data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
  192. data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
  193. data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
  194. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
  195. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
  196. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
  197. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
  198. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
  199. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
  200. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
  201. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
  202. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
  203. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
  204. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
  205. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
  206. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
  207. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
  208. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
  209. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
  210. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
  211. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
  212. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
  213. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
  214. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
  215. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
  216. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
  217. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
  218. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
  219. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
  220. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
  221. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
  222. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
  223. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
  224. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
  225. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
  226. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
  227. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
  228. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
  229. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
  230. data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
  231. data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
  232. data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
  233. data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
  234. data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
  235. data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
  236. data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
  237. data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
  238. data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
  239. data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
  240. data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
  241. data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
  242. data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
  243. data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
  244. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
  245. data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
  246. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
  247. data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
  248. data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
  249. data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
  250. data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
  251. data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
  252. data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
  253. data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
  254. data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
  255. data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
  256. data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
  257. data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
  258. data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
  259. data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
  260. data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
  261. data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
  262. data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
  263. data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
  264. data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
  265. data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
  266. data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
  267. data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
  268. data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
  269. data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
  270. data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
  271. data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
  272. data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
  273. data/lib/itsi/server/config/known_paths.rb +17 -0
  274. data/lib/itsi/server/config/middleware/_index.md +54 -0
  275. data/lib/itsi/server/config/middleware/log_requests.md +63 -0
  276. data/lib/itsi/server/config/middleware/log_requests.rb +33 -0
  277. data/lib/itsi/server/config/middleware.rb +9 -0
  278. data/lib/itsi/server/config/option.rb +9 -0
  279. data/lib/itsi/server/config/options/_index.md +36 -0
  280. data/lib/itsi/server/config/options/fiber_scheduler.md +35 -0
  281. data/lib/itsi/server/config/options/fiber_scheduler.rb +18 -0
  282. data/lib/itsi/server/config/options/threads.md +39 -0
  283. data/lib/itsi/server/config/options/threads.rb +17 -0
  284. data/lib/itsi/server/config/options/workers.md +43 -0
  285. data/lib/itsi/server/config/options/workers.rb +17 -0
  286. data/lib/itsi/server/config/typed_struct.rb +203 -0
  287. data/lib/itsi/server/config.rb +260 -0
  288. data/lib/itsi/server/default_app/default_app.rb +34 -0
  289. data/lib/itsi/server/default_app/index.html +115 -0
  290. data/lib/itsi/server/default_config/Itsi-rackup.rb +119 -0
  291. data/lib/itsi/server/default_config/Itsi.rb +107 -0
  292. data/lib/itsi/server/grpc/grpc_call.rb +246 -0
  293. data/lib/itsi/server/grpc/grpc_interface.rb +100 -0
  294. data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  295. data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  296. data/lib/itsi/server/rack/handler/itsi.rb +27 -0
  297. data/lib/itsi/server/rack_interface.rb +94 -0
  298. data/lib/itsi/server/route_tester.rb +107 -0
  299. data/lib/itsi/server/scheduler_interface.rb +21 -0
  300. data/lib/itsi/server/scheduler_mode.rb +10 -0
  301. data/lib/itsi/server/signal_trap.rb +33 -0
  302. data/lib/itsi/server/typed_handlers/param_parser.rb +200 -0
  303. data/lib/itsi/server/typed_handlers/source_parser.rb +55 -0
  304. data/lib/itsi/server/typed_handlers.rb +17 -0
  305. data/lib/itsi/server/version.rb +1 -1
  306. data/lib/itsi/server.rb +181 -9
  307. data/lib/itsi/standard_headers.rb +86 -0
  308. data/lib/ruby_lsp/itsi/addon.rb +127 -0
  309. data/lib/shell_completions/completions.rb +26 -0
  310. metadata +321 -28
  311. data/CHANGELOG.md +0 -5
  312. data/CODE_OF_CONDUCT.md +0 -132
  313. data/LICENSE.txt +0 -21
  314. data/ext/itsi_server/src/request/itsi_request.rs +0 -143
  315. data/ext/itsi_server/src/request/mod.rs +0 -1
  316. data/ext/itsi_server/src/server/bind.rs +0 -138
  317. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -32
  318. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -52
  319. data/ext/itsi_server/src/server/itsi_server.rs +0 -182
  320. data/ext/itsi_server/src/server/listener.rs +0 -218
  321. data/ext/itsi_server/src/server/tls.rs +0 -138
  322. data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  323. data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
  324. data/lib/itsi/request.rb +0 -39
@@ -0,0 +1,626 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class DSL
5
+ require_relative "config_helpers"
6
+ require_relative "option"
7
+ require_relative "middleware"
8
+
9
+ attr_reader :parent, :children, :middleware, :controller_class, :routes, :http_methods, :protocols,
10
+ :hosts, :ports, :extensions, :content_types, :accepts, :options
11
+
12
+ def self.evaluate(config = Itsi::Server::Config.config_file_path, &blk)
13
+ config = new(routes: ["/"]) do
14
+ if blk
15
+ instance_exec(&blk)
16
+ else
17
+ code = IO.read(config)
18
+ instance_eval(code, config.to_s, 1)
19
+ end
20
+ end
21
+ [config.options, config.errors]
22
+ rescue Exception => e
23
+ [{}, [[e, e.backtrace[0]]]]
24
+ end
25
+
26
+ def initialize(
27
+ parent = nil,
28
+ routes: [],
29
+ methods: [],
30
+ protocols: [],
31
+ hosts: [],
32
+ ports: [],
33
+ extensions: [],
34
+ content_types: [],
35
+ accepts: [],
36
+ controller: self,
37
+ &block
38
+ )
39
+ @parent = parent
40
+ @children = []
41
+ @middleware = {}
42
+ @controller_class = nil
43
+
44
+ @controller = controller
45
+ @routes = Array(routes).flatten
46
+ @http_methods = methods.map { |s| s.is_a?(Regexp) ? s : s.to_s }
47
+ @protocols = protocols.map { |s| s.is_a?(Regexp) ? s : s.to_s }
48
+ @hosts = hosts.map { |s| s.is_a?(Regexp) ? s : s.to_s }
49
+ @ports = ports.map { |s| s.is_a?(Regexp) ? s : s.to_s }
50
+ @extensions = extensions.map { |s| s.is_a?(Regexp) ? s : s.to_s }
51
+ @content_types = content_types.map { |s| s.is_a?(Regexp) ? s : s.to_s }
52
+ @accepts = accepts.map { |s| s.is_a?(Regexp) ? s : s.to_s }
53
+
54
+ @options = {
55
+ middleware_loaders: [],
56
+ middleware_loader: lambda do
57
+ @options[:middleware_loaders].each(&:call)
58
+ @middleware[:app] ||= {}
59
+ @middleware[:app][:app_proc] = @middleware[:app]&.[](:preloader)&.call || DEFAULT_APP[]
60
+ flatten_routes
61
+ end
62
+ }
63
+
64
+ @errors = []
65
+ instance_exec(&block)
66
+ end
67
+
68
+ def errors
69
+ @children.map(&:errors).flatten + @errors
70
+ end
71
+
72
+ Option.subclasses.each do |option|
73
+ option_name = option.option_name
74
+ define_method(option_name) do |*args, **kwargs, &blk|
75
+ @options[option_name] = option.new(self, *args, **kwargs, &blk).build!
76
+ rescue => e
77
+ @errors << [e, caller[1]]
78
+ end
79
+ end
80
+
81
+ Middleware.subclasses.each do |middleware|
82
+ middleware_name = middleware.middleware_name
83
+ define_method(middleware_name) do |*args, **kwargs, &blk|
84
+ @middleware[middleware_name] = middleware.new(@parent, *args, **kwargs, &blk).build!
85
+ rescue => e
86
+ @errors << [e, caller[1]]
87
+ end
88
+ end
89
+
90
+ def oob_gc_responses_threshold(threshold)
91
+ raise "OOB GC responses threshold must be set at the root" unless @parent.nil?
92
+
93
+ @options[:oob_gc_responses_threshold] = threshold.to_i
94
+ end
95
+
96
+ def log_level(level)
97
+ raise "Log level must be set at the root" unless @parent.nil?
98
+
99
+ @options[:log_level] = level.to_s
100
+ end
101
+
102
+ def log_target(target)
103
+ raise "Log target must be set at the root" unless @parent.nil?
104
+
105
+ @options[:log_target] = target.to_s
106
+ end
107
+
108
+ def log_target_filters(target_filters)
109
+ raise "Log target filters must be set at the root" unless @parent.nil?
110
+
111
+ @options[:log_target_filters] = target_filters
112
+ end
113
+
114
+ def log_format(target)
115
+ raise "Log format must be set at the root" unless @parent.nil?
116
+
117
+ @options[:log_format] = target.to_s
118
+ end
119
+
120
+ def get(route, app_proc = nil, nonblocking: false, &blk)
121
+ endpoint(route, [:get], app_proc, nonblocking: nonblocking, &blk)
122
+ end
123
+
124
+ def post(route, app_proc = nil, nonblocking: false, &blk)
125
+ endpoint(route, [:post], app_proc, nonblocking: nonblocking, &blk)
126
+ end
127
+
128
+ def put(route, app_proc = nil, nonblocking: false, &blk)
129
+ endpoint(route, [:put], app_proc, nonblocking: nonblocking, &blk)
130
+ end
131
+
132
+ def delete(route, app_proc = nil, nonblocking: false, &blk)
133
+ endpoint(route, [:delete], app_proc, nonblocking: nonblocking, &blk)
134
+ end
135
+
136
+ def patch(route, app_proc = nil, nonblocking: false, &blk)
137
+ endpoint(route, [:patch], app_proc, nonblocking: nonblocking, &blk)
138
+ end
139
+
140
+ def endpoint(route=nil, methods=[], app_proc = nil, nonblocking: false, &blk)
141
+ raise "You must provide either a block or an explicit handler for the endpoint" if app_proc.nil? && blk.nil?
142
+
143
+ app_proc = @controller.method(app_proc).to_proc if app_proc.is_a?(Symbol)
144
+
145
+ app_proc ||= blk
146
+ num_required, keywords = Itsi::Server::TypedHandlers::SourceParser.extract_expr_from_source_location(app_proc)
147
+ params_schema = keywords[:params]
148
+
149
+ if params_schema && num_required > 1
150
+ raise "Cannot accept multiple required parameters in a single endpoint. A single typed or untyped params argument is supported"
151
+ end
152
+ if num_required > 2
153
+ raise "Cannot accept more than two required parameters in a single endpoint. An can either accept a single request argument, or a request and a params argument (which may be typed or untyped)"
154
+ end
155
+ if num_required == 0
156
+ raise "Cannot accept zero required parameters in a single endpoint. Endpoint must accept a request parameter"
157
+ end
158
+
159
+ accepts_params = !params_schema.nil? || num_required > 1
160
+
161
+ if accepts_params
162
+ app_proc = Itsi::Server::TypedHandlers.handler_for(app_proc, params_schema)
163
+ end
164
+
165
+ if route || http_methods.any?
166
+ # For endpoints, it's usually assumed trailing slash and non-trailing slash behaviour is the same
167
+ routes = route == "/" ? ["", "/"] : [route]
168
+ location(*routes, methods: http_methods) do
169
+ @middleware[:app] = { preloader: -> { app_proc }, nonblocking: nonblocking }
170
+ end
171
+ else
172
+ app = { preloader: -> { app_proc }, nonblocking: nonblocking }
173
+ @middleware[:app] = app
174
+ location("*") do
175
+ @middleware[:app] = app
176
+ end
177
+ end
178
+ end
179
+
180
+ def grpc(*handlers, reflection: true, nonblocking: false, **, &blk)
181
+ if @middleware[:app] && @middleware[:app][:request_type].to_s != "grpc"
182
+ raise "App has already been set. You can use only one of `run` and `rackup_file` or `grpc` per location"
183
+ end
184
+
185
+ grpc_reflection(handlers) if reflection
186
+
187
+ handlers.each do |handler|
188
+ location(Regexp.new("#{Regexp.escape(handler.class.service_name)}/(?:#{handler.class.rpc_descs.keys.map(&:to_s).join("|")})")) do
189
+ @middleware[:app] = { preloader: -> { Itsi::Server::GrpcInterface.for(handler) }, request_type: "grpc", nonblocking: nonblocking }
190
+ instance_exec(&blk)
191
+ end
192
+ end
193
+ end
194
+
195
+ def grpc_reflection(handlers)
196
+ @grpc_reflected_services ||= []
197
+ @grpc_reflected_services.concat(handlers)
198
+
199
+ location(["grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo",
200
+ "grpc.reflection.v1.ServerReflection/ServerReflectionInfo"]) do
201
+ @middleware[:app] = { preloader: lambda {
202
+ Itsi::Server::GrpcInterface.reflection_for(handlers)
203
+ }, request_type: "grpc" }
204
+ end
205
+ end
206
+
207
+ def run(app, sendfile: true, nonblocking: false, path_info: "/")
208
+ app_args = { preloader: -> { Itsi::Server::RackInterface.for(app) }, sendfile: sendfile, base_path: "^(?<base_path>#{paths_from_parent.gsub(/\.\*\)$/, ')')}).*$", path_info: path_info, nonblocking: nonblocking }
209
+ base_path = "^(?<base_path>#{paths_from_parent.gsub(/\.\*\)$/, ')')}).*$"
210
+ @middleware[:app] = app_args
211
+ location("*") do
212
+ @middleware[:app] = app_args
213
+ end
214
+ end
215
+
216
+ def rackup_file(rackup_file, nonblocking: false, sendfile: true, path_info: "/")
217
+ raise "Rackup file #{rackup_file} doesn't exist" unless File.exist?(rackup_file)
218
+ app_args = { preloader: -> { Itsi::Server::RackInterface.for(rackup_file) }, sendfile: sendfile, base_path: "^(?<base_path>#{paths_from_parent.gsub(/\.\*\)$/, ')')}).*$", path_info: path_info, nonblocking: nonblocking }
219
+ @middleware[:app] = app_args
220
+ location("*") do
221
+ @middleware[:app] = app_args
222
+ end
223
+ end
224
+
225
+ def include(path)
226
+ code = IO.read("#{path}.rb")
227
+ instance_eval(code, "#{path}.rb", 1)
228
+ end
229
+
230
+ def reuse_address(reuse_address)
231
+ raise "reuse_address must be set at the root" unless @parent.nil?
232
+ @options[:reuse_address] = reuse_address
233
+ end
234
+
235
+ def reuse_port(reuse_port)
236
+ raise "reuse_port must be set at the root" unless @parent.nil?
237
+ @options[:reuse_port] = reuse_port
238
+ end
239
+
240
+ def listen_backlog(listen_backlog)
241
+ raise "listen_backlog must be set at the root" unless @parent.nil?
242
+ @options[:listen_backlog] = listen_backlog
243
+ end
244
+
245
+ def nodelay(nodelay)
246
+ raise "nodelay must be set at the root" unless @parent.nil?
247
+ @options[:nodelay] = nodelay
248
+ end
249
+
250
+ def recv_buffer_size(recv_buffer_size)
251
+ raise "recv_buffer_size must be set at the root" unless @parent.nil?
252
+ @options[:recv_buffer_size] = recv_buffer_size
253
+ end
254
+
255
+ def bind(bind_str)
256
+ raise "Bind must be set at the root" unless @parent.nil?
257
+
258
+ @options[:binds] ||= []
259
+ @options[:binds] << bind_str.to_s
260
+ end
261
+
262
+ def after_fork(&block)
263
+ raise "After fork must be set at the root" unless @parent.nil?
264
+
265
+ @options[:hooks] ||= {}
266
+ @options[:hooks][:after_fork] = block
267
+ end
268
+
269
+ def before_fork(&block)
270
+ raise "Before fork must be set at the root" unless @parent.nil?
271
+
272
+ @options[:hooks] ||= {}
273
+ @options[:hooks][:before_fork] = block
274
+ end
275
+
276
+ def after_memory_threshold_reached(&block)
277
+ raise "Before fork must be set at the root" unless @parent.nil?
278
+
279
+ @options[:hooks] ||= {}
280
+ @options[:hooks][:after_memory_threshold_reached] = block
281
+ end
282
+
283
+ def worker_memory_limit(memory_limit)
284
+ raise "Worker memory limit must be set at the root" unless @parent.nil?
285
+
286
+ @options[:worker_memory_limit] = memory_limit
287
+ end
288
+
289
+ def multithreaded_reactor(multithreaded)
290
+ raise "Multithreaded reactor must be set at the root" unless @parent.nil?
291
+
292
+ @options[:multithreaded_reactor] = !!multithreaded
293
+ end
294
+
295
+ def pin_worker_cores(pin_worker_cores)
296
+ raise "Pin worker cores must be set at the root" unless @parent.nil?
297
+
298
+ @options[:pin_worker_cores] = !!pin_worker_cores
299
+ end
300
+
301
+ def auto_reload_config!
302
+ if ENV["BUNDLE_BIN_PATH"]
303
+ watch "Itsi.rb", [%w[bundle exec itsi restart]]
304
+ else
305
+ watch "Itsi.rb", [%w[itsi restart]]
306
+ end
307
+ end
308
+
309
+ def watch(path, commands)
310
+ raise "Watch be set at the root" unless @parent.nil?
311
+
312
+ @options[:notify_watchers] ||= []
313
+ @options[:notify_watchers] << [path, commands]
314
+ end
315
+
316
+ def fiber_scheduler(klass_name = true)
317
+ raise "Fiber scheduler must be set at the root" unless @parent.nil?
318
+
319
+ klass_name = "Itsi::Scheduler" if klass_name == true
320
+ @options[:scheduler_class] = klass_name if klass_name
321
+ end
322
+
323
+ def scheduler_threads(threads = 1)
324
+ raise "Scheduler threads must be set at the root" unless @parent.nil?
325
+
326
+ @options[:scheduler_threads] = threads
327
+ end
328
+
329
+ def request_timeout(request_timeout)
330
+ raise "Request timeout must be set at the root" unless @parent.nil?
331
+
332
+ @options[:request_timeout] = request_timeout
333
+ end
334
+
335
+ def preload(preload)
336
+ raise "Preload must be set at the root" unless @parent.nil?
337
+
338
+ @options[:preload] = preload
339
+ end
340
+
341
+ def shutdown_timeout(shutdown_timeout)
342
+ raise "Shutdown timeout must be set at the root" unless @parent.nil?
343
+
344
+ @options[:shutdown_timeout] = shutdown_timeout.to_f
345
+ end
346
+
347
+ def header_read_timeout(header_read_timeout)
348
+ raise "Header read timeout must be set at the root" unless @parent.nil?
349
+
350
+ @options[:header_read_timeout] = header_read_timeout.to_f
351
+ end
352
+
353
+ def stream_body(stream_body)
354
+ raise "Stream body must be set at the root" unless @parent.nil?
355
+
356
+ @options[:stream_body] = !!stream_body
357
+ end
358
+
359
+ def location(*routes, methods: [], protocols: [], hosts: [], ports: [], extensions: [], content_types: [],
360
+ accepts: [], &block)
361
+ build_child = lambda {
362
+ @children << DSL.new(
363
+ self,
364
+ routes: routes,
365
+ methods: Array(methods) | self.http_methods,
366
+ protocols: Array(protocols) | self.protocols,
367
+ hosts: Array(hosts) | self.hosts,
368
+ ports: Array(ports) | self.ports,
369
+ extensions: Array(extensions) | self.extensions,
370
+ content_types: Array(content_types) | self.content_types,
371
+ accepts: Array(accepts) | self.accepts,
372
+ controller: @controller,
373
+ &block
374
+ )
375
+ }
376
+ if @parent.nil?
377
+ @options[:middleware_loaders] << build_child
378
+ else
379
+ build_child[]
380
+ end
381
+ end
382
+
383
+
384
+ def allow_list(**args)
385
+ args[:allowed_patterns] = Array(args[:allowed_patterns]).map do |pattern|
386
+ if pattern.is_a?(Regexp)
387
+ pattern.source
388
+ else
389
+ pattern
390
+ end
391
+ end
392
+ @middleware[:allow_list] = args
393
+ end
394
+
395
+ def deny_list(**args)
396
+ args[:denied_patterns] = Array(args[:denied_patterns]).map do |pattern|
397
+ if pattern.is_a?(Regexp)
398
+ pattern.source
399
+ else
400
+ pattern
401
+ end
402
+ end
403
+ @middleware[:deny_list] = args
404
+ end
405
+
406
+ def controller(controller)
407
+ @controller = controller
408
+ end
409
+
410
+ def auth_basic(**args)
411
+ if File.exist?(".itsi-credentials") && !args[:credential_file]
412
+ args[:credential_file] = ".itsi-credentials"
413
+ end
414
+
415
+ if args[:credential_file] && File.exist?(args[:credential_file])
416
+ args[:credential_pairs] = Passfile.load(args[:credential_file])
417
+ end
418
+
419
+ @middleware[:auth_basic] = args
420
+ end
421
+
422
+ def redirect(**args)
423
+ @middleware[:redirect] = args
424
+ end
425
+
426
+ def proxy(**args)
427
+ @middleware[:proxy] = args
428
+ end
429
+
430
+ def static_response(**args)
431
+ args[:body] = args[:body].bytes
432
+ @middleware[:static_response] = args
433
+ end
434
+
435
+ def auth_jwt(**args)
436
+ @middleware[:auth_jwt] = args
437
+ end
438
+
439
+ def auth_api_key(**args)
440
+ if args[:valid_keys] && args[:valid_keys].is_a?(Array)
441
+ args[:valid_keys] = args[:valid_keys].each_with_index.map { |key, index| [index, key] }.to_h
442
+ args[:key_id_source] = nil
443
+ end
444
+
445
+ if File.exist?(".itsi-credentials") && !args[:credential_file]
446
+ args[:credential_file] = ".itsi-credentials"
447
+ end
448
+
449
+ if args[:credential_file] && File.exist?(args[:credential_file])
450
+ args[:valid_keys] = Passfile.load(args[:credential_file])
451
+ end
452
+
453
+ @middleware[:auth_api_key] = args
454
+ end
455
+
456
+ def compress(**args)
457
+ @middleware[:compression] = args
458
+ end
459
+
460
+ def request_headers(**args)
461
+ @middleware[:request_headers] = args
462
+ end
463
+
464
+ def max_body(**args)
465
+ @middleware[:max_body] = args
466
+ end
467
+
468
+ def response_headers(**args)
469
+ @middleware[:response_headers] = args
470
+ end
471
+
472
+ def rate_limit(**args)
473
+ @middleware[:rate_limit] = args
474
+ end
475
+
476
+ def cache_control(**args)
477
+ @middleware[:cache_control] = args
478
+ end
479
+
480
+ def etag(**args)
481
+ @middleware[:etag] = args
482
+ end
483
+
484
+ def csp(**args)
485
+ @middleware[:csp] = args
486
+ end
487
+
488
+ def intrusion_protection(**args)
489
+ args[:banned_url_patterns] = Array(args[:banned_url_patterns]).flatten.map do |pattern|
490
+ if pattern.is_a?(Regexp)
491
+ pattern.source
492
+ else
493
+ pattern
494
+ end
495
+ end
496
+ @middleware[:intrusion_protection] = args
497
+ end
498
+
499
+ def cors(**args)
500
+ @middleware[:cors] = args
501
+ end
502
+
503
+ def static_assets(**args)
504
+ root_dir = args[:root_dir] || "."
505
+
506
+ if !File.exist?(root_dir)
507
+ warn "Warning: static_assets root_dir '#{root_dir}' does not exist!"
508
+ elsif !File.directory?(root_dir)
509
+ warn "Warning: static_assets root_dir '#{root_dir}' is not a directory!"
510
+ end
511
+
512
+ args[:relative_path] = true unless args.key?(:relative_path)
513
+
514
+ args[:allowed_extensions] ||= []
515
+
516
+ if (args[:allowed_extensions].include?("html") || args[:allowed_extensions].include?(:html)) && args[:try_html_extension]
517
+ args[:allowed_extensions] << ""
518
+ end
519
+
520
+ args[:base_path] = "^(?<base_path>#{paths_from_parent}).*$"
521
+
522
+ location("*", extensions: args[:allowed_extensions]) do
523
+ @middleware[:static_assets] = args
524
+ end
525
+ end
526
+
527
+ def file_server(**args)
528
+ # Forward to static_assets for implementation
529
+ puts "Note: file_server is an alias for static_assets"
530
+ static_assets(**args)
531
+ end
532
+
533
+ def flatten_routes
534
+ result = []
535
+ result.concat(@children.flat_map(&:flatten_routes))
536
+ route_options = paths_from_parent
537
+ if route_options
538
+ result << deep_stringify_keys(
539
+ {
540
+ route: Regexp.new("^#{route_options}/?$"),
541
+ methods: @http_methods.any? ? @http_methods : nil,
542
+ protocols: @protocols.any? ? @protocols : nil,
543
+ hosts: @hosts.any? ? @hosts : nil,
544
+ ports: @ports.any? ? @ports : nil,
545
+ extensions: @extensions.any? ? @extensions : nil,
546
+ content_types: @content_types.any? ? @content_types : nil,
547
+ accepts: @accepts.any? ? @accepts : nil,
548
+ middleware: effective_middleware
549
+ }
550
+ )
551
+ end
552
+ result
553
+ end
554
+
555
+ def paths_from_parent
556
+ return nil unless @routes.any?
557
+
558
+ route_or_str = @routes.map do |seg|
559
+ case seg
560
+ when Regexp
561
+ seg.source
562
+ else
563
+ parts = seg.split('/')
564
+ parts.map do |part|
565
+ case part
566
+ when /^:([A-Za-z_]\w*)(?:\(([^)]*)\))?$/
567
+ param_name = Regexp.last_match(1)
568
+ custom = Regexp.last_match(2)
569
+ if custom && !custom.empty?
570
+ "(?<#{param_name}>#{custom})"
571
+ else
572
+ "(?<#{param_name}>[^/]+)"
573
+ end
574
+ when /\*/
575
+ part.gsub(/\*/, ".*")
576
+ else
577
+ Regexp.escape(part)
578
+ end
579
+ end.join("/")
580
+ end
581
+ end.join("|")
582
+ if parent && parent.paths_from_parent && parent.paths_from_parent != "(?:/)"
583
+ "#{parent.paths_from_parent}#{route_or_str != "" ? "(?:#{route_or_str})" : ""}"
584
+ else
585
+ route_or_str = "/#{route_or_str}" unless route_or_str.start_with?("/")
586
+ "(?:#{route_or_str})"
587
+ end
588
+ end
589
+
590
+ def effective_middleware
591
+ chain = []
592
+ node = self
593
+ while node
594
+ if node.middleware[:app]&.[](:preloader)
595
+ node.middleware[:app][:app_proc] = node.middleware[:app].delete(:preloader).call
596
+ end
597
+ chain << node
598
+ node = node.parent
599
+ end
600
+ chain.reverse!
601
+
602
+ merged = {}
603
+
604
+ chain.each do |n|
605
+ n.middleware.each do |k, v|
606
+ merged[k] = v
607
+ end
608
+ end
609
+ deep_stringify_keys(merged)
610
+ end
611
+
612
+ def deep_stringify_keys(obj)
613
+ case obj
614
+ when Hash
615
+ obj.transform_keys!(&:to_s)
616
+ obj.transform_values! { |v| deep_stringify_keys(v) }
617
+ when Array
618
+ obj.map { |v| deep_stringify_keys(v) }
619
+ else
620
+ obj
621
+ end
622
+ end
623
+ end
624
+ end
625
+ end
626
+ end