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,76 @@
1
+ use crate::{
2
+ server::http_message_types::{HttpRequest, HttpResponse},
3
+ services::itsi_http_service::HttpRequestContext,
4
+ };
5
+
6
+ use super::{string_rewrite::StringRewrite, FromValue, MiddlewareLayer};
7
+
8
+ use async_trait::async_trait;
9
+ use either::Either;
10
+ use http::{Response, StatusCode};
11
+ use http_body_util::{combinators::BoxBody, Empty};
12
+ use magnus::error::Result;
13
+ use serde::Deserialize;
14
+
15
+ /// A simple API key filter.
16
+ /// The API key can be given inside the header or a query string
17
+ /// Keys are validated against a list of allowed key values (Changing these requires a restart)
18
+ ///
19
+ #[derive(Debug, Clone, Deserialize)]
20
+ pub struct Redirect {
21
+ pub to: StringRewrite,
22
+ #[serde(default)]
23
+ #[serde(rename(deserialize = "type"))]
24
+ pub redirect_type: RedirectType,
25
+ }
26
+
27
+ #[derive(Debug, Clone, Deserialize, Default)]
28
+ pub enum RedirectType {
29
+ #[serde(rename(deserialize = "permanent"))]
30
+ #[default]
31
+ Permanent,
32
+ #[serde(rename(deserialize = "temporary"))]
33
+ Temporary,
34
+ #[serde(rename(deserialize = "found"))]
35
+ Found,
36
+ #[serde(rename(deserialize = "moved_permanently"))]
37
+ MovedPermanently,
38
+ }
39
+
40
+ #[async_trait]
41
+ impl MiddlewareLayer for Redirect {
42
+ async fn before(
43
+ &self,
44
+ req: HttpRequest,
45
+ context: &mut HttpRequestContext,
46
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
47
+ Ok(Either::Right(self.redirect_response(&req, context)?))
48
+ }
49
+ }
50
+
51
+ impl Redirect {
52
+ pub fn redirect_response(
53
+ &self,
54
+ req: &HttpRequest,
55
+ context: &mut HttpRequestContext,
56
+ ) -> Result<HttpResponse> {
57
+ let mut response = Response::new(BoxBody::new(Empty::new()));
58
+ *response.status_mut() = match self.redirect_type {
59
+ RedirectType::Permanent => StatusCode::PERMANENT_REDIRECT,
60
+ RedirectType::Temporary => StatusCode::TEMPORARY_REDIRECT,
61
+ RedirectType::MovedPermanently => StatusCode::MOVED_PERMANENTLY,
62
+ RedirectType::Found => StatusCode::FOUND,
63
+ };
64
+ response.headers_mut().append(
65
+ "Location",
66
+ self.to.rewrite_request(req, context).parse().map_err(|e| {
67
+ magnus::Error::new(
68
+ magnus::exception::standard_error(),
69
+ format!("Invalid Rewrite String: {:?}: {}", self.to, e),
70
+ )
71
+ })?,
72
+ );
73
+ Ok(response)
74
+ }
75
+ }
76
+ impl FromValue for Redirect {}
@@ -0,0 +1,44 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::{
4
+ server::http_message_types::{HttpRequest, HttpResponse},
5
+ services::itsi_http_service::HttpRequestContext,
6
+ };
7
+
8
+ use super::{FromValue, MiddlewareLayer};
9
+ use async_trait::async_trait;
10
+ use either::Either;
11
+ use http::HeaderName;
12
+ use magnus::error::Result;
13
+ use serde::Deserialize;
14
+
15
+ #[derive(Debug, Clone, Deserialize)]
16
+ pub struct RequestHeaders {
17
+ pub additions: HashMap<String, Vec<String>>,
18
+ pub removals: Vec<String>,
19
+ }
20
+
21
+ #[async_trait]
22
+ impl MiddlewareLayer for RequestHeaders {
23
+ async fn before(
24
+ &self,
25
+ mut req: HttpRequest,
26
+ _: &mut HttpRequestContext,
27
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
28
+ let headers = req.headers_mut();
29
+ for removal in &self.removals {
30
+ headers.remove(removal);
31
+ }
32
+ for (header_name, header_values) in &self.additions {
33
+ for header_value in header_values {
34
+ if let Ok(parsed_header_name) = header_name.parse::<HeaderName>() {
35
+ if let Ok(parsed_header_value) = header_value.parse() {
36
+ headers.append(parsed_header_name, parsed_header_value);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ Ok(Either::Left(req))
42
+ }
43
+ }
44
+ impl FromValue for RequestHeaders {}
@@ -0,0 +1,36 @@
1
+ use std::collections::HashMap;
2
+
3
+ use super::{FromValue, MiddlewareLayer};
4
+ use crate::{
5
+ server::http_message_types::HttpResponse, services::itsi_http_service::HttpRequestContext,
6
+ };
7
+ use async_trait::async_trait;
8
+ use http::HeaderName;
9
+ use serde::Deserialize;
10
+
11
+ #[derive(Debug, Clone, Deserialize)]
12
+ pub struct ResponseHeaders {
13
+ pub additions: HashMap<String, Vec<String>>,
14
+ pub removals: Vec<String>,
15
+ }
16
+
17
+ #[async_trait]
18
+ impl MiddlewareLayer for ResponseHeaders {
19
+ async fn after(&self, mut resp: HttpResponse, _: &mut HttpRequestContext) -> HttpResponse {
20
+ let headers = resp.headers_mut();
21
+ for removal in &self.removals {
22
+ headers.remove(removal);
23
+ }
24
+ for (header_name, header_values) in &self.additions {
25
+ for header_value in header_values {
26
+ if let Ok(parsed_header_name) = header_name.parse::<HeaderName>() {
27
+ if let Ok(parsed_header_value) = header_value.parse() {
28
+ headers.append(parsed_header_name, parsed_header_value);
29
+ }
30
+ }
31
+ }
32
+ }
33
+ resp
34
+ }
35
+ }
36
+ impl FromValue for ResponseHeaders {}
@@ -0,0 +1,126 @@
1
+ use super::MiddlewareLayer;
2
+ use crate::ruby_types::itsi_grpc_call::ItsiGrpcCall;
3
+ use crate::ruby_types::itsi_http_request::ItsiHttpRequest;
4
+ use crate::server::http_message_types::{HttpRequest, HttpResponse};
5
+ use crate::services::itsi_http_service::HttpRequestContext;
6
+ use crate::services::static_file_server::ROOT_STATIC_FILE_SERVER;
7
+ use async_trait::async_trait;
8
+ use derive_more::Debug;
9
+ use either::Either;
10
+ use itsi_rb_helpers::{HeapVal, HeapValue};
11
+ use magnus::{block::Proc, error::Result, value::ReprValue, Symbol};
12
+ use regex::Regex;
13
+ use std::str::FromStr;
14
+ use std::sync::atomic::Ordering;
15
+ use std::sync::Arc;
16
+
17
+ #[derive(Debug)]
18
+ pub struct RubyApp {
19
+ app: Arc<HeapValue<Proc>>,
20
+ request_type: RequestType,
21
+ sendfile: bool,
22
+ nonblocking: bool,
23
+ base_path: Regex,
24
+ }
25
+
26
+ #[derive(Debug)]
27
+ pub enum RequestType {
28
+ Http,
29
+ Grpc,
30
+ }
31
+
32
+ impl FromStr for RequestType {
33
+ type Err = &'static str;
34
+
35
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
36
+ match s {
37
+ "http" => Ok(RequestType::Http),
38
+ "grpc" => Ok(RequestType::Grpc),
39
+ _ => Err("Invalid request type"),
40
+ }
41
+ }
42
+ }
43
+
44
+ impl RubyApp {
45
+ pub fn from_value(params: HeapVal) -> magnus::error::Result<Arc<Self>> {
46
+ let app = params.funcall::<_, _, Proc>(Symbol::new("[]"), ("app_proc",))?;
47
+ let sendfile = params
48
+ .funcall::<_, _, bool>(Symbol::new("[]"), ("sendfile",))
49
+ .unwrap_or(true);
50
+ let nonblocking = params
51
+ .funcall::<_, _, bool>(Symbol::new("[]"), ("nonblocking",))
52
+ .unwrap_or(false);
53
+ let base_path_src = params
54
+ .funcall::<_, _, String>(Symbol::new("[]"), ("base_path",))
55
+ .unwrap_or("".to_owned());
56
+ let base_path = Regex::new(&base_path_src).unwrap();
57
+
58
+ let request_type: RequestType = params
59
+ .funcall::<_, _, String>(Symbol::new("[]"), ("request_type",))
60
+ .unwrap_or("http".to_string())
61
+ .parse()
62
+ .unwrap_or(RequestType::Http);
63
+
64
+ Ok(Arc::new(RubyApp {
65
+ app: Arc::new(app.into()),
66
+ sendfile,
67
+ nonblocking,
68
+ request_type,
69
+ base_path,
70
+ }))
71
+ }
72
+ }
73
+
74
+ #[async_trait]
75
+ impl MiddlewareLayer for RubyApp {
76
+ async fn before(
77
+ &self,
78
+ req: HttpRequest,
79
+ context: &mut HttpRequestContext,
80
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
81
+ context.is_ruby_request.store(true, Ordering::SeqCst);
82
+ match self.request_type {
83
+ RequestType::Http => {
84
+ let uri = req.uri().path();
85
+ let script_name = self
86
+ .base_path
87
+ .captures(uri)
88
+ .and_then(|caps| caps.name("base_path"))
89
+ .map(|m| m.as_str())
90
+ .unwrap_or("/")
91
+ .to_owned();
92
+ ItsiHttpRequest::process_request(
93
+ self.app.clone(),
94
+ req,
95
+ context,
96
+ script_name,
97
+ self.nonblocking,
98
+ )
99
+ .await
100
+ .map_err(|e| e.into())
101
+ .map(Either::Right)
102
+ }
103
+ RequestType::Grpc => {
104
+ ItsiGrpcCall::process_request(self.app.clone(), req, context, self.nonblocking)
105
+ .await
106
+ .map_err(|e| e.into())
107
+ .map(Either::Right)
108
+ }
109
+ }
110
+ }
111
+
112
+ async fn after(&self, resp: HttpResponse, context: &mut HttpRequestContext) -> HttpResponse {
113
+ if self.sendfile {
114
+ if let Some(sendfile_header) = resp.headers().get("X-Sendfile") {
115
+ return ROOT_STATIC_FILE_SERVER
116
+ .serve_single_abs(
117
+ sendfile_header.to_str().unwrap(),
118
+ context.accept.clone(),
119
+ &[],
120
+ )
121
+ .await;
122
+ }
123
+ }
124
+ resp
125
+ }
126
+ }
@@ -0,0 +1,181 @@
1
+ use super::{FromValue, MiddlewareLayer};
2
+ use crate::{
3
+ server::http_message_types::{HttpRequest, HttpResponse},
4
+ services::{
5
+ itsi_http_service::HttpRequestContext,
6
+ static_file_server::{
7
+ NotFoundBehavior, ServeRange, StaticFileServer, StaticFileServerConfig,
8
+ },
9
+ },
10
+ };
11
+ use async_trait::async_trait;
12
+ use either::Either;
13
+ use http::{
14
+ header::{IF_MODIFIED_SINCE, RANGE},
15
+ HeaderMap, Method,
16
+ };
17
+ use itsi_error::ItsiError;
18
+ use magnus::error::Result;
19
+ use regex::Regex;
20
+ use serde::Deserialize;
21
+ use std::{collections::HashMap, path::PathBuf, sync::OnceLock, time::Duration};
22
+
23
+ #[derive(Debug, Deserialize)]
24
+ pub struct StaticAssets {
25
+ pub root_dir: PathBuf,
26
+ pub not_found_behavior: NotFoundBehavior,
27
+ pub auto_index: bool,
28
+ pub try_html_extension: bool,
29
+ pub max_file_size_in_memory: u64,
30
+ pub max_files_in_memory: u64,
31
+ pub file_check_interval: u64,
32
+ pub headers: Option<HashMap<String, String>>,
33
+ pub allowed_extensions: Vec<String>,
34
+ pub relative_path: bool,
35
+ pub serve_hidden_files: bool,
36
+ pub base_path: String,
37
+ #[serde(skip)]
38
+ pub base_path_regex: OnceLock<Regex>,
39
+ #[serde(skip)]
40
+ file_server: OnceLock<StaticFileServer>,
41
+ }
42
+
43
+ #[async_trait]
44
+ impl MiddlewareLayer for StaticAssets {
45
+ async fn initialize(&self) -> Result<()> {
46
+ if let Ok(metadata) = tokio::fs::metadata(&self.root_dir).await {
47
+ if metadata.is_dir() {
48
+ Ok(())
49
+ } else {
50
+ Err(ItsiError::InvalidInput(
51
+ "Root directory exists but is not a directory".to_string(),
52
+ ))
53
+ }
54
+ } else {
55
+ Err(ItsiError::InvalidInput(
56
+ "Root directory exists but is not a directory".to_string(),
57
+ ))
58
+ }?;
59
+ self.base_path_regex
60
+ .set(Regex::new(&self.base_path).map_err(ItsiError::new)?)
61
+ .map_err(ItsiError::new)?;
62
+
63
+ self.file_server
64
+ .set(StaticFileServer::new(StaticFileServerConfig {
65
+ root_dir: self.root_dir.clone(),
66
+ not_found_behavior: self.not_found_behavior.clone(),
67
+ auto_index: self.auto_index,
68
+ max_entries: self.max_files_in_memory,
69
+ try_html_extension: self.try_html_extension,
70
+ max_file_size: self.max_file_size_in_memory,
71
+ recheck_interval: Duration::from_secs(self.file_check_interval),
72
+ serve_hidden_files: self.serve_hidden_files,
73
+ allowed_extensions: self.allowed_extensions.clone(),
74
+ })?)
75
+ .map_err(ItsiError::new)?;
76
+ Ok(())
77
+ }
78
+
79
+ async fn before(
80
+ &self,
81
+ req: HttpRequest,
82
+ context: &mut HttpRequestContext,
83
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
84
+ // Only handle GET and HEAD requests
85
+ if req.method() != Method::GET && req.method() != Method::HEAD {
86
+ return Ok(Either::Left(req));
87
+ }
88
+ let abs_path = req.uri().path();
89
+ let rel_path = if !self.relative_path {
90
+ abs_path
91
+ } else {
92
+ let base_path = self
93
+ .base_path_regex
94
+ .get()
95
+ .unwrap()
96
+ .captures(abs_path)
97
+ .and_then(|caps| caps.name("base_path"))
98
+ .map(|m| m.as_str())
99
+ .unwrap_or("/");
100
+
101
+ match abs_path.strip_prefix(base_path) {
102
+ Some(suffix) => suffix,
103
+ None => return Ok(Either::Left(req)),
104
+ }
105
+ };
106
+
107
+ // Determine if this is a HEAD request
108
+ let is_head_request = req.method() == Method::HEAD;
109
+
110
+ // Extract range and if-modified-since headers
111
+ let serve_range = parse_range_header(req.headers());
112
+ let if_modified_since = req
113
+ .headers()
114
+ .get(IF_MODIFIED_SINCE)
115
+ .and_then(|ims| ims.to_str().ok())
116
+ .and_then(|ims_str| httpdate::parse_http_date(ims_str).ok());
117
+
118
+ // Let the file server handle everything
119
+ let file_server = self.file_server.get().unwrap();
120
+ let response = file_server
121
+ .serve(
122
+ &req,
123
+ rel_path,
124
+ abs_path,
125
+ serve_range,
126
+ if_modified_since,
127
+ is_head_request,
128
+ &context.supported_encoding_set,
129
+ )
130
+ .await;
131
+ if response.is_none() {
132
+ Ok(Either::Left(req))
133
+ } else {
134
+ Ok(Either::Right(response.unwrap()))
135
+ }
136
+ }
137
+ }
138
+
139
+ fn parse_range_header(headers: &HeaderMap) -> ServeRange {
140
+ let range_header = headers.get(RANGE);
141
+ if range_header.is_none() {
142
+ return ServeRange::Full;
143
+ }
144
+ let range_header = range_header.unwrap().to_str().unwrap_or("");
145
+ let bytes_prefix = "bytes=";
146
+ if !range_header.starts_with(bytes_prefix) {
147
+ return ServeRange::Full;
148
+ }
149
+
150
+ let range_str = &range_header[bytes_prefix.len()..];
151
+
152
+ let range_parts: Vec<&str> = range_str
153
+ .split(',')
154
+ .next()
155
+ .unwrap_or("")
156
+ .split('-')
157
+ .collect();
158
+ if range_parts.len() != 2 {
159
+ return ServeRange::Full;
160
+ }
161
+
162
+ let start = if range_parts[0].is_empty() {
163
+ range_parts[1].parse::<u64>().unwrap_or(0)
164
+ } else if let Ok(start) = range_parts[0].parse::<u64>() {
165
+ start
166
+ } else {
167
+ return ServeRange::Full;
168
+ };
169
+
170
+ let end = if range_parts[1].is_empty() {
171
+ u64::MAX // Use u64::MAX as sentinel for open-ended ranges
172
+ } else if let Ok(end) = range_parts[1].parse::<u64>() {
173
+ end // No conversion needed, already u64
174
+ } else {
175
+ return ServeRange::Full;
176
+ };
177
+
178
+ ServeRange::Range(start, end)
179
+ }
180
+
181
+ impl FromValue for StaticAssets {}
@@ -0,0 +1,55 @@
1
+ use std::sync::OnceLock;
2
+
3
+ use super::{FromValue, MiddlewareLayer};
4
+ use crate::server::http_message_types::{HttpRequest, HttpResponse};
5
+ use crate::services::itsi_http_service::HttpRequestContext;
6
+ use async_trait::async_trait;
7
+ use bytes::Bytes;
8
+ use derive_more::Debug;
9
+ use either::Either;
10
+ use http::{HeaderMap, HeaderName, HeaderValue, Response, StatusCode};
11
+ use http_body_util::combinators::BoxBody;
12
+ use http_body_util::Full;
13
+ use itsi_error::ItsiError;
14
+ use magnus::error::Result;
15
+ use serde::Deserialize;
16
+
17
+ #[derive(Debug, Deserialize)]
18
+ pub struct StaticResponse {
19
+ code: u16,
20
+ headers: Vec<(String, String)>,
21
+ body: Vec<u8>,
22
+ #[serde(skip)]
23
+ header_map: OnceLock<HeaderMap>,
24
+ }
25
+
26
+ #[async_trait]
27
+ impl MiddlewareLayer for StaticResponse {
28
+ async fn initialize(&self) -> Result<()> {
29
+ let mut header_map = HeaderMap::new();
30
+ for (key, value) in self.headers.iter() {
31
+ if let (Ok(hn), Ok(hv)) = (key.parse::<HeaderName>(), value.parse::<HeaderValue>()) {
32
+ header_map.insert(hn, hv);
33
+ }
34
+ }
35
+ self.header_map
36
+ .set(header_map)
37
+ .map_err(|_| ItsiError::new("Failed to set headers"))?;
38
+ Ok(())
39
+ }
40
+
41
+ async fn before(
42
+ &self,
43
+ _req: HttpRequest,
44
+ _context: &mut HttpRequestContext,
45
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
46
+ let mut resp = Response::new(BoxBody::new(Full::new(Bytes::from(self.body.clone()))));
47
+ let status = StatusCode::from_u16(self.code).unwrap_or(StatusCode::OK);
48
+ *resp.status_mut() = status;
49
+ *resp.headers_mut() = self.header_map.get().unwrap().clone();
50
+
51
+ Ok(Either::Right(resp))
52
+ }
53
+ }
54
+
55
+ impl FromValue for StaticResponse {}
@@ -0,0 +1,163 @@
1
+ use serde::Deserialize;
2
+ use std::sync::OnceLock;
3
+
4
+ use crate::{
5
+ server::http_message_types::{HttpRequest, HttpResponse},
6
+ services::itsi_http_service::HttpRequestContext,
7
+ };
8
+
9
+ #[derive(Debug, Clone, Deserialize)]
10
+ #[serde(transparent)]
11
+ pub struct StringRewrite {
12
+ pub template_string: String,
13
+ #[serde(default)]
14
+ pub segments: OnceLock<Vec<Segment>>,
15
+ }
16
+
17
+ #[derive(Debug, Clone, Deserialize)]
18
+ pub enum Segment {
19
+ Literal(String),
20
+ Placeholder(String),
21
+ }
22
+
23
+ pub fn parse_template(template: &str) -> Vec<Segment> {
24
+ let mut segments = Vec::new();
25
+ let mut last_index = 0;
26
+ while let Some(start_index) = template[last_index..].find('{') {
27
+ let start_index = last_index + start_index;
28
+ // Add the literal text before the placeholder.
29
+ if start_index > last_index {
30
+ segments.push(Segment::Literal(
31
+ template[last_index..start_index].to_string(),
32
+ ));
33
+ }
34
+ // Find the corresponding closing brace.
35
+ if let Some(end_index) = template[start_index..].find('}') {
36
+ let end_index = start_index + end_index;
37
+ let placeholder = &template[start_index + 1..end_index];
38
+ segments.push(Segment::Placeholder(placeholder.to_string()));
39
+ last_index = end_index + 1;
40
+ } else {
41
+ // No closing brace found; treat the rest as literal.
42
+ segments.push(Segment::Literal(template[start_index..].to_string()));
43
+ break;
44
+ }
45
+ }
46
+ if last_index < template.len() {
47
+ segments.push(Segment::Literal(template[last_index..].to_string()));
48
+ }
49
+ segments
50
+ }
51
+
52
+ impl StringRewrite {
53
+ pub fn rewrite_request(&self, req: &HttpRequest, context: &HttpRequestContext) -> String {
54
+ let segments = self
55
+ .segments
56
+ .get_or_init(|| parse_template(&self.template_string));
57
+ let captures = context
58
+ .matching_pattern
59
+ .as_ref()
60
+ .and_then(|re| re.captures(req.uri().path()));
61
+
62
+ let mut result = String::with_capacity(self.template_string.len());
63
+
64
+ for segment in segments {
65
+ match segment {
66
+ Segment::Literal(text) => result.push_str(text),
67
+ Segment::Placeholder(placeholder) => {
68
+ let replacement = match placeholder.as_str() {
69
+ "request_id" => context.short_request_id(),
70
+ "request_id_full" => context.request_id(),
71
+ "method" => req.method().as_str().to_string(),
72
+ "path" => req.uri().path().to_string(),
73
+ "addr" => context.addr.to_owned(),
74
+ "host" => req.uri().host().unwrap_or("localhost").to_string(),
75
+ "path_and_query" => req
76
+ .uri()
77
+ .path_and_query()
78
+ .map(|pq| pq.to_string())
79
+ .unwrap_or("".to_string()),
80
+ "query" => {
81
+ let query = req.uri().query().unwrap_or("").to_string();
82
+ if query.is_empty() {
83
+ query
84
+ } else {
85
+ format!("?{}", query)
86
+ }
87
+ }
88
+ "port" => req
89
+ .uri()
90
+ .port()
91
+ .map(|p| p.to_string())
92
+ .unwrap_or_else(|| "80".to_string()),
93
+ "start_time" => {
94
+ if let Some(start_time) = context.start_time() {
95
+ start_time.format("%Y-%m-%d:%H:%M:%S:%3f").to_string()
96
+ } else {
97
+ "N/A".to_string()
98
+ }
99
+ }
100
+ other => {
101
+ // Try using the context's matching regex if available.
102
+ if let Some(caps) = &captures {
103
+ if let Some(m) = caps.name(other) {
104
+ m.as_str().to_string()
105
+ } else {
106
+ // Fallback: leave the placeholder as is.
107
+ format!("{{{}}}", other)
108
+ }
109
+ } else {
110
+ format!("{{{}}}", other)
111
+ }
112
+ }
113
+ };
114
+ result.push_str(&replacement);
115
+ }
116
+ }
117
+ }
118
+
119
+ result
120
+ }
121
+
122
+ pub fn rewrite_response(&self, resp: &HttpResponse, context: &HttpRequestContext) -> String {
123
+ let segments = self
124
+ .segments
125
+ .get_or_init(|| parse_template(&self.template_string));
126
+
127
+ let mut result = String::with_capacity(self.template_string.len());
128
+ for segment in segments {
129
+ match segment {
130
+ Segment::Literal(text) => result.push_str(text),
131
+ Segment::Placeholder(placeholder) => {
132
+ let replacement = match placeholder.as_str() {
133
+ "request_id" => context.short_request_id(),
134
+ "request_id_full" => context.request_id(),
135
+ "status" => resp.status().as_str().to_string(),
136
+ "addr" => context.addr.to_owned(),
137
+ "response_time" => {
138
+ if let Some(response_time) = context.get_response_time() {
139
+ if let Some(microseconds) = response_time.num_microseconds() {
140
+ format!("{:.3}ms", microseconds as f64 / 1000.0)
141
+ } else {
142
+ format!("{}ms", response_time.num_milliseconds())
143
+ }
144
+ } else {
145
+ "-".to_string()
146
+ }
147
+ }
148
+ other => {
149
+ if let Some(header_value) = resp.headers().get(other) {
150
+ format!("{:?}", header_value)
151
+ } else {
152
+ format!("{{{}}}", other)
153
+ }
154
+ }
155
+ };
156
+ result.push_str(&replacement);
157
+ }
158
+ }
159
+ }
160
+
161
+ result
162
+ }
163
+ }
@@ -0,0 +1,12 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ #[derive(Debug, Clone, Serialize, Deserialize)]
4
+ pub enum TokenSource {
5
+ #[serde(rename(deserialize = "header"))]
6
+ Header {
7
+ name: String,
8
+ prefix: Option<String>,
9
+ },
10
+ #[serde(rename(deserialize = "query"))]
11
+ Query(String),
12
+ }