itsi-server 0.1.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +4487 -0
  3. data/Cargo.toml +7 -0
  4. data/README.md +6 -0
  5. data/Rakefile +7 -4
  6. data/exe/itsi +152 -46
  7. data/ext/itsi_acme/Cargo.toml +86 -0
  8. data/ext/itsi_acme/examples/high_level.rs +63 -0
  9. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  10. data/ext/itsi_acme/examples/low_level.rs +87 -0
  11. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  12. data/ext/itsi_acme/src/acceptor.rs +81 -0
  13. data/ext/itsi_acme/src/acme.rs +354 -0
  14. data/ext/itsi_acme/src/axum.rs +86 -0
  15. data/ext/itsi_acme/src/cache.rs +39 -0
  16. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  17. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  18. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  19. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  20. data/ext/itsi_acme/src/caches/no.rs +78 -0
  21. data/ext/itsi_acme/src/caches/test.rs +136 -0
  22. data/ext/itsi_acme/src/config.rs +172 -0
  23. data/ext/itsi_acme/src/https_helper.rs +69 -0
  24. data/ext/itsi_acme/src/incoming.rs +142 -0
  25. data/ext/itsi_acme/src/jose.rs +161 -0
  26. data/ext/itsi_acme/src/lib.rs +142 -0
  27. data/ext/itsi_acme/src/resolver.rs +59 -0
  28. data/ext/itsi_acme/src/state.rs +424 -0
  29. data/ext/itsi_error/Cargo.toml +3 -0
  30. data/ext/itsi_error/src/lib.rs +98 -24
  31. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  32. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  33. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  34. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  35. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  36. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  37. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  38. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  39. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  40. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  41. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  42. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  43. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  44. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  45. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  46. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  47. data/ext/itsi_rb_helpers/Cargo.toml +3 -0
  48. data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
  49. data/ext/itsi_rb_helpers/src/lib.rs +141 -10
  50. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  51. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  52. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  53. data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  54. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  55. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  56. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  57. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  58. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  59. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  60. data/ext/itsi_scheduler/Cargo.toml +24 -0
  61. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  62. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  63. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  64. data/ext/itsi_scheduler/src/itsi_scheduler.rs +314 -0
  65. data/ext/itsi_scheduler/src/lib.rs +39 -0
  66. data/ext/itsi_server/Cargo.lock +2956 -0
  67. data/ext/itsi_server/Cargo.toml +75 -14
  68. data/ext/itsi_server/extconf.rb +1 -1
  69. data/ext/itsi_server/src/default_responses/html/401.html +68 -0
  70. data/ext/itsi_server/src/default_responses/html/403.html +68 -0
  71. data/ext/itsi_server/src/default_responses/html/404.html +68 -0
  72. data/ext/itsi_server/src/default_responses/html/413.html +71 -0
  73. data/ext/itsi_server/src/default_responses/html/429.html +68 -0
  74. data/ext/itsi_server/src/default_responses/html/500.html +71 -0
  75. data/ext/itsi_server/src/default_responses/html/502.html +71 -0
  76. data/ext/itsi_server/src/default_responses/html/503.html +68 -0
  77. data/ext/itsi_server/src/default_responses/html/504.html +69 -0
  78. data/ext/itsi_server/src/default_responses/html/index.html +238 -0
  79. data/ext/itsi_server/src/default_responses/json/401.json +6 -0
  80. data/ext/itsi_server/src/default_responses/json/403.json +6 -0
  81. data/ext/itsi_server/src/default_responses/json/404.json +6 -0
  82. data/ext/itsi_server/src/default_responses/json/413.json +6 -0
  83. data/ext/itsi_server/src/default_responses/json/429.json +6 -0
  84. data/ext/itsi_server/src/default_responses/json/500.json +6 -0
  85. data/ext/itsi_server/src/default_responses/json/502.json +6 -0
  86. data/ext/itsi_server/src/default_responses/json/503.json +6 -0
  87. data/ext/itsi_server/src/default_responses/json/504.json +6 -0
  88. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  89. data/ext/itsi_server/src/env.rs +43 -0
  90. data/ext/itsi_server/src/lib.rs +133 -40
  91. data/ext/itsi_server/src/prelude.rs +2 -0
  92. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +109 -0
  93. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +143 -0
  94. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  95. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  96. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
  97. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +391 -0
  98. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
  99. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
  100. data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
  101. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  102. data/ext/itsi_server/src/server/binds/bind.rs +204 -0
  103. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  104. data/ext/itsi_server/src/server/binds/listener.rs +444 -0
  105. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  106. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
  107. data/ext/itsi_server/src/server/binds/tls.rs +278 -0
  108. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  109. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  110. data/ext/itsi_server/src/server/io_stream.rs +105 -0
  111. data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
  112. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  113. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  114. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  115. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
  116. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  117. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  118. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
  119. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
  120. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  121. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  122. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
  123. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
  124. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
  125. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  126. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  127. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  128. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  129. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
  130. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
  131. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
  132. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
  133. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  134. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  135. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  136. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
  137. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  138. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
  139. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  140. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  141. data/ext/itsi_server/src/server/mod.rs +13 -5
  142. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  143. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  144. data/ext/itsi_server/src/server/request_job.rs +11 -0
  145. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +354 -0
  146. data/ext/itsi_server/src/server/serve_strategy/mod.rs +30 -0
  147. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +481 -0
  148. data/ext/itsi_server/src/server/signal.rs +77 -0
  149. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  150. data/ext/itsi_server/src/server/thread_worker.rs +479 -0
  151. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  152. data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
  153. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  154. data/ext/itsi_server/src/services/mod.rs +6 -0
  155. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  156. data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
  157. data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
  158. data/ext/itsi_tracing/Cargo.toml +5 -0
  159. data/ext/itsi_tracing/src/lib.rs +366 -7
  160. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  161. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  162. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  163. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  164. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  165. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  166. data/lib/itsi/http_request/response_status_shortcodes.rb +76 -0
  167. data/lib/itsi/http_request.rb +218 -0
  168. data/lib/itsi/http_response.rb +42 -0
  169. data/lib/itsi/passfile.rb +108 -0
  170. data/lib/itsi/server/config/config_helpers.rb +105 -0
  171. data/lib/itsi/server/config/dsl.rb +211 -0
  172. data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
  173. data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
  174. data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
  175. data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
  176. data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
  177. data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
  178. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
  179. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
  180. data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
  181. data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
  182. data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
  183. data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
  184. data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
  185. data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
  186. data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
  187. data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
  188. data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
  189. data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
  190. data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
  191. data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
  192. data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
  193. data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
  194. data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
  195. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
  196. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
  197. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
  198. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
  199. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
  200. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
  201. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
  202. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
  203. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
  204. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
  205. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
  206. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
  207. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
  208. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
  209. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
  210. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
  211. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
  212. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
  213. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
  214. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
  215. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
  216. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
  217. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
  218. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
  219. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
  220. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
  221. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
  222. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
  223. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
  224. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
  225. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
  226. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
  227. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
  228. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
  229. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
  230. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
  231. data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
  232. data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
  233. data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
  234. data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
  235. data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
  236. data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
  237. data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
  238. data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
  239. data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
  240. data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
  241. data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
  242. data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
  243. data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
  244. data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
  245. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
  246. data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
  247. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
  248. data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
  249. data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
  250. data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
  251. data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
  252. data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
  253. data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
  254. data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
  255. data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
  256. data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
  257. data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
  258. data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
  259. data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
  260. data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
  261. data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
  262. data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
  263. data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
  264. data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
  265. data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
  266. data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
  267. data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
  268. data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
  269. data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
  270. data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
  271. data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
  272. data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
  273. data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
  274. data/lib/itsi/server/config/known_paths.rb +20 -0
  275. data/lib/itsi/server/config/middleware/_index.md +56 -0
  276. data/lib/itsi/server/config/middleware/allow_list.md +46 -0
  277. data/lib/itsi/server/config/middleware/allow_list.rb +42 -0
  278. data/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
  279. data/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
  280. data/lib/itsi/server/config/middleware/auth_basic.md +45 -0
  281. data/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
  282. data/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
  283. data/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
  284. data/lib/itsi/server/config/middleware/cache_control.md +78 -0
  285. data/lib/itsi/server/config/middleware/cache_control.rb +45 -0
  286. data/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
  287. data/lib/itsi/server/config/middleware/compression.md +50 -0
  288. data/lib/itsi/server/config/middleware/compression.rb +37 -0
  289. data/lib/itsi/server/config/middleware/cors.md +93 -0
  290. data/lib/itsi/server/config/middleware/cors.rb +32 -0
  291. data/lib/itsi/server/config/middleware/csp.md +37 -0
  292. data/lib/itsi/server/config/middleware/csp.rb +44 -0
  293. data/lib/itsi/server/config/middleware/deny_list.md +45 -0
  294. data/lib/itsi/server/config/middleware/deny_list.rb +42 -0
  295. data/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
  296. data/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
  297. data/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
  298. data/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
  299. data/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
  300. data/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
  301. data/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
  302. data/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
  303. data/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
  304. data/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
  305. data/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
  306. data/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
  307. data/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
  308. data/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
  309. data/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
  310. data/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
  311. data/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
  312. data/lib/itsi/server/config/middleware/error_response.md +61 -0
  313. data/lib/itsi/server/config/middleware/error_response.rb +36 -0
  314. data/lib/itsi/server/config/middleware/etag.md +59 -0
  315. data/lib/itsi/server/config/middleware/etag.rb +27 -0
  316. data/lib/itsi/server/config/middleware/grpc.md +172 -0
  317. data/lib/itsi/server/config/middleware/grpc.rb +54 -0
  318. data/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
  319. data/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
  320. data/lib/itsi/server/config/middleware/location.md +107 -0
  321. data/lib/itsi/server/config/middleware/location.rb +99 -0
  322. data/lib/itsi/server/config/middleware/log_requests.md +65 -0
  323. data/lib/itsi/server/config/middleware/log_requests.rb +31 -0
  324. data/lib/itsi/server/config/middleware/max_body.md +18 -0
  325. data/lib/itsi/server/config/middleware/max_body.rb +21 -0
  326. data/lib/itsi/server/config/middleware/proxy.md +62 -0
  327. data/lib/itsi/server/config/middleware/proxy.rb +41 -0
  328. data/lib/itsi/server/config/middleware/rackup_file.md +54 -0
  329. data/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
  330. data/lib/itsi/server/config/middleware/rate_limit.md +126 -0
  331. data/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
  332. data/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
  333. data/lib/itsi/server/config/middleware/redirect.md +55 -0
  334. data/lib/itsi/server/config/middleware/redirect.rb +25 -0
  335. data/lib/itsi/server/config/middleware/request_headers.md +34 -0
  336. data/lib/itsi/server/config/middleware/request_headers.rb +24 -0
  337. data/lib/itsi/server/config/middleware/response_headers.md +33 -0
  338. data/lib/itsi/server/config/middleware/response_headers.rb +25 -0
  339. data/lib/itsi/server/config/middleware/run.md +60 -0
  340. data/lib/itsi/server/config/middleware/run.rb +43 -0
  341. data/lib/itsi/server/config/middleware/static_assets.md +73 -0
  342. data/lib/itsi/server/config/middleware/static_assets.rb +87 -0
  343. data/lib/itsi/server/config/middleware/static_response.md +44 -0
  344. data/lib/itsi/server/config/middleware/static_response.rb +29 -0
  345. data/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
  346. data/lib/itsi/server/config/middleware/token_source.rb +32 -0
  347. data/lib/itsi/server/config/middleware.rb +13 -0
  348. data/lib/itsi/server/config/option.rb +14 -0
  349. data/lib/itsi/server/config/options/_index.md +37 -0
  350. data/lib/itsi/server/config/options/auto_reload_config.md +13 -0
  351. data/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
  352. data/lib/itsi/server/config/options/bind.md +71 -0
  353. data/lib/itsi/server/config/options/bind.rb +26 -0
  354. data/lib/itsi/server/config/options/certificates.md +65 -0
  355. data/lib/itsi/server/config/options/daemonize.md +14 -0
  356. data/lib/itsi/server/config/options/daemonize.rb +19 -0
  357. data/lib/itsi/server/config/options/fiber_scheduler.md +34 -0
  358. data/lib/itsi/server/config/options/fiber_scheduler.rb +21 -0
  359. data/lib/itsi/server/config/options/header_read_timeout.md +17 -0
  360. data/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
  361. data/lib/itsi/server/config/options/hooks/_index.md +11 -0
  362. data/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
  363. data/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
  364. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
  365. data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
  366. data/lib/itsi/server/config/options/hooks/after_start.md +12 -0
  367. data/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
  368. data/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
  369. data/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
  370. data/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
  371. data/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
  372. data/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
  373. data/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
  374. data/lib/itsi/server/config/options/include.md +20 -0
  375. data/lib/itsi/server/config/options/include.rb +36 -0
  376. data/lib/itsi/server/config/options/listen_backlog.md +11 -0
  377. data/lib/itsi/server/config/options/listen_backlog.rb +19 -0
  378. data/lib/itsi/server/config/options/log_format.md +18 -0
  379. data/lib/itsi/server/config/options/log_format.rb +19 -0
  380. data/lib/itsi/server/config/options/log_level.md +34 -0
  381. data/lib/itsi/server/config/options/log_level.rb +20 -0
  382. data/lib/itsi/server/config/options/log_target.md +38 -0
  383. data/lib/itsi/server/config/options/log_target.rb +19 -0
  384. data/lib/itsi/server/config/options/log_target_filters.md +17 -0
  385. data/lib/itsi/server/config/options/log_target_filters.rb +19 -0
  386. data/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
  387. data/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
  388. data/lib/itsi/server/config/options/nodelay.md +16 -0
  389. data/lib/itsi/server/config/options/nodelay.rb +19 -0
  390. data/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
  391. data/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
  392. data/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
  393. data/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
  394. data/lib/itsi/server/config/options/preload.md +21 -0
  395. data/lib/itsi/server/config/options/preload.rb +18 -0
  396. data/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
  397. data/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
  398. data/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
  399. data/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
  400. data/lib/itsi/server/config/options/request_timeout.md +23 -0
  401. data/lib/itsi/server/config/options/request_timeout.rb +19 -0
  402. data/lib/itsi/server/config/options/reuse_address.md +16 -0
  403. data/lib/itsi/server/config/options/reuse_address.rb +19 -0
  404. data/lib/itsi/server/config/options/reuse_port.md +16 -0
  405. data/lib/itsi/server/config/options/reuse_port.rb +19 -0
  406. data/lib/itsi/server/config/options/scheduler_threads.md +34 -0
  407. data/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
  408. data/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
  409. data/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
  410. data/lib/itsi/server/config/options/stream_body.md +32 -0
  411. data/lib/itsi/server/config/options/stream_body.rb +18 -0
  412. data/lib/itsi/server/config/options/threads.md +44 -0
  413. data/lib/itsi/server/config/options/threads.rb +17 -0
  414. data/lib/itsi/server/config/options/watch.md +16 -0
  415. data/lib/itsi/server/config/options/watch.rb +28 -0
  416. data/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
  417. data/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
  418. data/lib/itsi/server/config/options/workers.md +42 -0
  419. data/lib/itsi/server/config/options/workers.rb +17 -0
  420. data/lib/itsi/server/config/typed_struct.rb +242 -0
  421. data/lib/itsi/server/config.rb +289 -0
  422. data/lib/itsi/server/default_app/default_app.rb +34 -0
  423. data/lib/itsi/server/default_app/index.html +115 -0
  424. data/lib/itsi/server/default_config/Itsi.rb +107 -0
  425. data/lib/itsi/server/grpc/grpc_call.rb +246 -0
  426. data/lib/itsi/server/grpc/grpc_interface.rb +107 -0
  427. data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  428. data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  429. data/lib/itsi/server/rack/handler/itsi.rb +27 -0
  430. data/lib/itsi/server/rack_interface.rb +94 -0
  431. data/lib/itsi/server/route_tester.rb +157 -0
  432. data/lib/itsi/server/scheduler_interface.rb +21 -0
  433. data/lib/itsi/server/scheduler_mode.rb +10 -0
  434. data/lib/itsi/server/signal_trap.rb +33 -0
  435. data/lib/itsi/server/typed_handlers/param_parser.rb +196 -0
  436. data/lib/itsi/server/typed_handlers/source_parser.rb +56 -0
  437. data/lib/itsi/server/typed_handlers.rb +25 -0
  438. data/lib/itsi/server/version.rb +1 -1
  439. data/lib/itsi/server.rb +265 -9
  440. data/lib/itsi/standard_headers.rb +86 -0
  441. data/lib/ruby_lsp/itsi/addon.rb +129 -0
  442. data/lib/shell_completions/completions.rb +26 -0
  443. metadata +454 -28
  444. data/CHANGELOG.md +0 -5
  445. data/CODE_OF_CONDUCT.md +0 -132
  446. data/LICENSE.txt +0 -21
  447. data/ext/itsi_server/src/request/itsi_request.rs +0 -143
  448. data/ext/itsi_server/src/request/mod.rs +0 -1
  449. data/ext/itsi_server/src/server/bind.rs +0 -138
  450. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -32
  451. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -52
  452. data/ext/itsi_server/src/server/itsi_server.rs +0 -182
  453. data/ext/itsi_server/src/server/listener.rs +0 -218
  454. data/ext/itsi_server/src/server/tls.rs +0 -138
  455. data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  456. data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
  457. data/lib/itsi/request.rb +0 -39
@@ -0,0 +1,116 @@
1
+ mod allow_list;
2
+ mod auth_api_key;
3
+ mod auth_basic;
4
+ mod auth_jwt;
5
+ mod cache_control;
6
+ mod compression;
7
+ mod cors;
8
+ mod csp;
9
+ mod deny_list;
10
+ mod error_response;
11
+ mod etag;
12
+ mod header_interpretation;
13
+ mod intrusion_protection;
14
+ mod log_requests;
15
+ mod max_body;
16
+ mod proxy;
17
+ mod rate_limit;
18
+ mod redirect;
19
+ mod request_headers;
20
+ mod response_headers;
21
+ mod ruby_app;
22
+ mod static_assets;
23
+ mod static_response;
24
+ mod string_rewrite;
25
+ mod token_source;
26
+
27
+ use std::sync::Arc;
28
+ use std::sync::LazyLock;
29
+
30
+ pub use allow_list::AllowList;
31
+ use async_trait::async_trait;
32
+ pub use auth_api_key::AuthAPIKey;
33
+ pub use auth_basic::AuthBasic;
34
+ pub use auth_jwt::AuthJwt;
35
+ pub use cache_control::CacheControl;
36
+ pub use compression::Compression;
37
+ pub use compression::CompressionAlgorithm;
38
+ pub use cors::Cors;
39
+ pub use csp::Csp;
40
+ pub use deny_list::DenyList;
41
+ use either::Either;
42
+ pub use error_response::ErrorResponse;
43
+ pub use etag::ETag;
44
+ pub use intrusion_protection::IntrusionProtection;
45
+ pub use log_requests::LogRequests;
46
+ use magnus::error::Result;
47
+ use magnus::rb_sys::AsRawValue;
48
+ use magnus::Value;
49
+ pub use max_body::MaxBody;
50
+ pub use proxy::Proxy;
51
+ pub use rate_limit::RateLimit;
52
+ pub use redirect::Redirect;
53
+ pub use request_headers::RequestHeaders;
54
+ pub use response_headers::ResponseHeaders;
55
+ pub use ruby_app::RubyApp;
56
+ use serde::Deserialize;
57
+ use serde_magnus::deserialize;
58
+ pub use static_assets::StaticAssets;
59
+ pub use static_response::StaticResponse;
60
+ pub use string_rewrite::StringRewrite;
61
+
62
+ use crate::server::http_message_types::HttpRequest;
63
+ use crate::server::http_message_types::HttpResponse;
64
+ use crate::services::itsi_http_service::HttpRequestContext;
65
+
66
+ use std::collections::HashMap;
67
+ use std::sync::Mutex;
68
+ static CACHE: LazyLock<Mutex<HashMap<u64, Arc<dyn std::any::Any + Send + Sync>>>> =
69
+ LazyLock::new(|| Mutex::new(HashMap::new()));
70
+
71
+ pub fn clear_value_cache() {
72
+ let mut cache = CACHE.lock().unwrap();
73
+ cache.clear();
74
+ }
75
+
76
+ pub trait FromValue: Sized + Send + Sync + 'static {
77
+ fn from_value(value: Value) -> Result<Arc<Self>>
78
+ where
79
+ Self: Deserialize<'static>,
80
+ {
81
+ let raw = value.as_raw();
82
+
83
+ let mut cache = CACHE.lock().unwrap();
84
+
85
+ if let Some(cached) = cache.get(&raw) {
86
+ if let Some(deserialized) = cached.downcast_ref::<Arc<Self>>() {
87
+ return Ok(deserialized.clone());
88
+ }
89
+ }
90
+
91
+ let deserialized: Arc<Self> = Arc::new(deserialize(value)?);
92
+ cache.insert(raw, deserialized.clone());
93
+ Ok(deserialized)
94
+ }
95
+ }
96
+
97
+ #[async_trait]
98
+ pub trait MiddlewareLayer: Sized + Send + Sync + 'static {
99
+ /// Called just once, to initialize the middleware state.
100
+ async fn initialize(&self) -> Result<()> {
101
+ Ok(())
102
+ }
103
+ /// The "before" hook. By default, it passes through the request.
104
+ async fn before(
105
+ &self,
106
+ req: HttpRequest,
107
+ _context: &mut HttpRequestContext,
108
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
109
+ Ok(Either::Left(req))
110
+ }
111
+
112
+ /// The "after" hook. By default, it passes through the response.
113
+ async fn after(&self, resp: HttpResponse, _context: &mut HttpRequestContext) -> HttpResponse {
114
+ resp
115
+ }
116
+ }
@@ -0,0 +1,411 @@
1
+ use std::{
2
+ collections::HashMap,
3
+ convert::Infallible,
4
+ error::Error,
5
+ net::SocketAddr,
6
+ sync::{
7
+ atomic::{AtomicUsize, Ordering},
8
+ Arc, LazyLock, OnceLock,
9
+ },
10
+ time::Duration,
11
+ };
12
+
13
+ use super::{string_rewrite::StringRewrite, ErrorResponse, FromValue, MiddlewareLayer};
14
+ use crate::{
15
+ server::{
16
+ binds::bind::{Bind, BindAddress},
17
+ http_message_types::{HttpRequest, HttpResponse, RequestExt, ResponseFormat},
18
+ size_limited_incoming::MaxBodySizeReached,
19
+ },
20
+ services::itsi_http_service::HttpRequestContext,
21
+ };
22
+ use async_trait::async_trait;
23
+ use bytes::{Bytes, BytesMut};
24
+ use either::Either;
25
+ use futures::TryStreamExt;
26
+ use http::{HeaderMap, Method, Response, StatusCode};
27
+ use http_body_util::{combinators::BoxBody, BodyExt, Empty, StreamBody};
28
+ use hyper::body::Frame;
29
+ use magnus::error::Result;
30
+ use rand::Rng;
31
+ use reqwest::{
32
+ dns::{Name, Resolve},
33
+ Body, Client, Url,
34
+ };
35
+ use serde::Deserialize;
36
+ use tracing::{debug, info};
37
+
38
+ #[derive(Debug, Clone, Deserialize)]
39
+ pub struct Proxy {
40
+ pub to: StringRewrite,
41
+ pub backends: Vec<String>,
42
+ pub backend_priority: BackendPriority,
43
+ pub headers: HashMap<String, Option<StringRewrite>>,
44
+ pub verify_ssl: bool,
45
+ pub timeout: u64,
46
+ pub tls_sni: bool,
47
+ #[serde(skip_deserializing)]
48
+ pub client: OnceLock<Client>,
49
+ #[serde(default = "bad_gateway_error_response")]
50
+ pub error_response: ErrorResponse,
51
+ }
52
+
53
+ fn bad_gateway_error_response() -> ErrorResponse {
54
+ ErrorResponse::bad_gateway()
55
+ }
56
+
57
+ #[derive(Debug, Clone, Deserialize)]
58
+ pub enum BackendPriority {
59
+ #[serde(rename(deserialize = "round_robin"))]
60
+ RoundRobin,
61
+ #[serde(rename(deserialize = "ordered"))]
62
+ Ordered,
63
+ #[serde(rename(deserialize = "random"))]
64
+ Random,
65
+ }
66
+
67
+ #[derive(Debug, Clone)]
68
+ pub struct Resolver {
69
+ backends: Arc<Vec<SocketAddr>>,
70
+ counter: Arc<AtomicUsize>,
71
+ backend_priority: BackendPriority,
72
+ }
73
+
74
+ pub struct StatefulResolverIter {
75
+ backends: Arc<Vec<SocketAddr>>,
76
+ start_index: usize,
77
+ current: usize,
78
+ }
79
+
80
+ impl Iterator for StatefulResolverIter {
81
+ type Item = SocketAddr;
82
+
83
+ fn next(&mut self) -> Option<Self::Item> {
84
+ if self.current < self.backends.len() {
85
+ let index = (self.start_index + self.current) % self.backends.len();
86
+ self.current += 1;
87
+ Some(self.backends[index])
88
+ } else {
89
+ None
90
+ }
91
+ }
92
+ }
93
+
94
+ impl Resolve for Resolver {
95
+ fn resolve(&self, _name: Name) -> reqwest::dns::Resolving {
96
+ let backends = self.backends.clone();
97
+ let len = backends.len();
98
+
99
+ let start_index = match self.backend_priority {
100
+ BackendPriority::Ordered => 0,
101
+ BackendPriority::Random => rand::rng().random_range(0..len),
102
+ BackendPriority::RoundRobin => self.counter.fetch_add(1, Ordering::Relaxed) % len,
103
+ };
104
+
105
+ let fut = async move {
106
+ let iter = StatefulResolverIter {
107
+ backends,
108
+ start_index,
109
+ current: 0,
110
+ };
111
+ Ok(Box::new(iter) as Box<dyn Iterator<Item = SocketAddr> + Send>)
112
+ };
113
+
114
+ Box::pin(fut)
115
+ }
116
+ }
117
+
118
+ static BAD_GATEWAY_RESPONSE: LazyLock<ErrorResponse> = LazyLock::new(ErrorResponse::bad_gateway);
119
+ static GATEWAY_TIMEOUT_RESPONSE: LazyLock<ErrorResponse> =
120
+ LazyLock::new(ErrorResponse::gateway_timeout);
121
+ static SERVICE_UNAVAILABLE_RESPONSE: LazyLock<ErrorResponse> =
122
+ LazyLock::new(ErrorResponse::service_unavailable);
123
+ static INTERNAL_SERVER_ERROR_RESPONSE: LazyLock<ErrorResponse> =
124
+ LazyLock::new(ErrorResponse::internal_server_error);
125
+
126
+ fn is_idempotent(method: &Method) -> bool {
127
+ matches!(
128
+ *method,
129
+ Method::GET | Method::HEAD | Method::PUT | Method::DELETE | Method::OPTIONS
130
+ )
131
+ }
132
+
133
+ /// A helper that stores the immutable parts of the incoming request.
134
+ struct RequestInfo {
135
+ method: Method,
136
+ headers: HeaderMap,
137
+ }
138
+
139
+ impl Proxy {
140
+ /// Build a header map of overriding headers based on the configured values.
141
+ /// This uses the full HttpRequest and context to compute each header value.
142
+ fn build_overriding_headers(
143
+ &self,
144
+ req: &HttpRequest,
145
+ context: &mut HttpRequestContext,
146
+ ) -> http::HeaderMap {
147
+ let mut headers = http::HeaderMap::new();
148
+ for (name, header_opt) in self.headers.iter() {
149
+ if let Some(header_value) = header_opt {
150
+ // Compute the header value using the full HttpRequest.
151
+ let value_str = header_value.rewrite_request(req, context);
152
+ if let Ok(header_val) = http::HeaderValue::from_str(&value_str) {
153
+ if let Ok(header_name) = name.parse::<http::header::HeaderName>() {
154
+ headers.insert(header_name, header_val);
155
+ }
156
+ }
157
+ }
158
+ }
159
+ headers
160
+ }
161
+
162
+ /// Build a reqwest::RequestBuilder by merging the original request headers
163
+ /// (unless overridden) with the precomputed overriding headers.
164
+ fn build_reqwest_request_info(
165
+ &self,
166
+ req_info: &RequestInfo,
167
+ url: &str,
168
+ host_str: &str,
169
+ body: Body,
170
+ overriding_headers: &http::HeaderMap,
171
+ ) -> reqwest::RequestBuilder {
172
+ let mut builder = self
173
+ .client
174
+ .get()
175
+ .unwrap()
176
+ .request(req_info.method.clone(), url);
177
+
178
+ // Forward headers from the original request unless they are overridden.
179
+ for (name, value) in req_info.headers.iter() {
180
+ if overriding_headers.contains_key(name) {
181
+ continue;
182
+ }
183
+ builder = builder.header(name, value);
184
+ }
185
+
186
+ // Add a Host header if not overridden.
187
+ if !overriding_headers.contains_key("host") && !host_str.is_empty() {
188
+ debug!("Adding Host header: {}", host_str);
189
+ builder = builder.header("Host", host_str);
190
+ }
191
+
192
+ for (name, value) in overriding_headers.iter() {
193
+ builder = builder.header(name, value);
194
+ }
195
+
196
+ builder.body(body)
197
+ }
198
+
199
+ /// Sends an idempotent request using a replayable (buffered) body.
200
+ async fn send_request_idempotent(
201
+ &self,
202
+ req_info: &RequestInfo,
203
+ url: &str,
204
+ host_str: &str,
205
+ max_attempts: usize,
206
+ replayable_bytes: Bytes,
207
+ overriding_headers: &http::HeaderMap,
208
+ ) -> std::result::Result<reqwest::Response, reqwest::Error> {
209
+ let mut last_err = None;
210
+ for attempt in 0..max_attempts {
211
+ let body = Body::from(replayable_bytes.clone());
212
+ let builder =
213
+ self.build_reqwest_request_info(req_info, url, host_str, body, overriding_headers);
214
+ match builder.send().await {
215
+ Ok(response) => return Ok(response),
216
+ Err(e) => {
217
+ // Retry for connectivity-related errors.
218
+ if e.is_connect() {
219
+ debug!(target: "middleware::proxy", "Connection error, retrying");
220
+ last_err = Some(e);
221
+ if attempt + 1 < max_attempts {
222
+ continue;
223
+ } else {
224
+ break;
225
+ }
226
+ } else {
227
+ return Err(e);
228
+ }
229
+ }
230
+ }
231
+ }
232
+ Err(last_err.expect("At least one attempt should have set last_err"))
233
+ }
234
+
235
+ /// Sends a non-idempotent request once using its streaming body.
236
+ async fn send_request_non_idempotent(
237
+ &self,
238
+ req: HttpRequest,
239
+ req_info: &RequestInfo,
240
+ url: &str,
241
+ host_str: &str,
242
+ overriding_headers: &http::HeaderMap,
243
+ ) -> std::result::Result<reqwest::Response, reqwest::Error> {
244
+ let body = Body::wrap_stream(req.into_data_stream());
245
+ let builder =
246
+ self.build_reqwest_request_info(req_info, url, host_str, body, overriding_headers);
247
+ builder.send().await
248
+ }
249
+ }
250
+
251
+ #[async_trait]
252
+ impl MiddlewareLayer for Proxy {
253
+ async fn initialize(&self) -> Result<()> {
254
+ let backends = self
255
+ .backends
256
+ .iter()
257
+ .filter_map(|be| {
258
+ let bind: Bind = be.parse().ok()?;
259
+ match (bind.address, bind.port) {
260
+ (BindAddress::Ip(ip_addr), port) => {
261
+ Some(SocketAddr::new(ip_addr, port.unwrap()))
262
+ }
263
+ (BindAddress::UnixSocket(_), _) => None,
264
+ }
265
+ })
266
+ .collect::<Vec<_>>();
267
+ debug!(target: "middleware::proxy", "backends: {:?}", backends);
268
+
269
+ self.client
270
+ .set(
271
+ Client::builder()
272
+ .timeout(Duration::from_secs(self.timeout))
273
+ .danger_accept_invalid_certs(!self.verify_ssl)
274
+ .danger_accept_invalid_hostnames(!self.verify_ssl)
275
+ .dns_resolver(Arc::new(Resolver {
276
+ backends: Arc::new(backends),
277
+ counter: Arc::new(AtomicUsize::new(0)),
278
+ backend_priority: self.backend_priority.clone(),
279
+ }))
280
+ .tls_sni(self.tls_sni)
281
+ .build()
282
+ .map_err(|e| {
283
+ magnus::Error::new(
284
+ magnus::exception::runtime_error(),
285
+ format!("Failed to build Reqwest client: {}", e),
286
+ )
287
+ })?,
288
+ )
289
+ .map_err(|_e| {
290
+ magnus::Error::new(
291
+ magnus::exception::standard_error(),
292
+ "Failed to save resolver backends",
293
+ )
294
+ })?;
295
+ Ok(())
296
+ }
297
+
298
+ async fn before(
299
+ &self,
300
+ req: HttpRequest,
301
+ context: &mut HttpRequestContext,
302
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
303
+ let url = self.to.rewrite_request(&req, context);
304
+
305
+ let accept: ResponseFormat = req.accept().into();
306
+ let error_response = self.error_response.to_http_response(accept.clone()).await;
307
+
308
+ let destination = match Url::parse(&url) {
309
+ Ok(dest) => dest,
310
+ Err(_) => {
311
+ debug!(target: "middleware::proxy", "Failed to parse URL: {}", url);
312
+ return Ok(Either::Right(error_response));
313
+ }
314
+ };
315
+
316
+ debug!(target: "middleware::proxy", "Proxying to: {:?}", destination);
317
+
318
+ // Clone the headers before consuming the request.
319
+ let req_headers = req.headers().clone();
320
+ let host_str = destination.host_str().unwrap_or_else(|| {
321
+ req_headers
322
+ .get("Host")
323
+ .and_then(|h| h.to_str().ok())
324
+ .unwrap_or("")
325
+ });
326
+
327
+ info!("Extracted host str is {}", host_str);
328
+ let req_info = RequestInfo {
329
+ method: req.method().clone(),
330
+ headers: req_headers.clone(),
331
+ };
332
+
333
+ // Precompute the overriding headers from the full request.
334
+ let overriding_headers = self.build_overriding_headers(&req, context);
335
+
336
+ // Determine max_attempts based on the number of backends.
337
+ let max_attempts = self.backends.len();
338
+
339
+ let reqwest_response_result = if is_idempotent(&req_info.method) {
340
+ let (_parts, body) = req.into_parts();
341
+ let replayable_bytes = match body.into_data_stream().try_collect::<Vec<Bytes>>().await {
342
+ Ok(chunks) => {
343
+ let mut buf = BytesMut::new();
344
+ for chunk in chunks {
345
+ buf.extend_from_slice(&chunk);
346
+ }
347
+ buf.freeze()
348
+ }
349
+ Err(e) => {
350
+ tracing::error!("Error buffering request body: {}", e);
351
+ return Ok(Either::Right(error_response));
352
+ }
353
+ };
354
+ self.send_request_idempotent(
355
+ &req_info,
356
+ &url,
357
+ host_str,
358
+ max_attempts,
359
+ replayable_bytes,
360
+ &overriding_headers,
361
+ )
362
+ .await
363
+ } else {
364
+ self.send_request_non_idempotent(req, &req_info, &url, host_str, &overriding_headers)
365
+ .await
366
+ };
367
+
368
+ let response = match reqwest_response_result {
369
+ Ok(response) => {
370
+ debug!(target: "middleware::proxy", "Response {} received", response.status());
371
+
372
+ let status = response.status();
373
+ let mut builder = Response::builder().status(status);
374
+ for (hn, hv) in response.headers() {
375
+ builder = builder.header(hn, hv);
376
+ }
377
+ let response = builder.body(BoxBody::new(StreamBody::new(
378
+ response
379
+ .bytes_stream()
380
+ .map_ok(Frame::data)
381
+ .map_err(|_| -> Infallible { unreachable!("We handle IO errors above") }),
382
+ )));
383
+ response.unwrap_or(error_response)
384
+ }
385
+ Err(e) => {
386
+ debug!(target: "middleware::proxy", "Error {:?} received", e);
387
+ if let Some(inner) = e.source() {
388
+ if inner.downcast_ref::<MaxBodySizeReached>().is_some() {
389
+ let mut max_body_response = Response::new(BoxBody::new(Empty::new()));
390
+ *max_body_response.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
391
+ return Ok(Either::Right(max_body_response));
392
+ }
393
+ }
394
+ if e.is_timeout() {
395
+ GATEWAY_TIMEOUT_RESPONSE.to_http_response(accept).await
396
+ } else if e.is_connect() {
397
+ BAD_GATEWAY_RESPONSE.to_http_response(accept).await
398
+ } else if e.is_status() {
399
+ SERVICE_UNAVAILABLE_RESPONSE.to_http_response(accept).await
400
+ } else {
401
+ INTERNAL_SERVER_ERROR_RESPONSE
402
+ .to_http_response(accept)
403
+ .await
404
+ }
405
+ }
406
+ };
407
+
408
+ Ok(Either::Right(response))
409
+ }
410
+ }
411
+ impl FromValue for Proxy {}
@@ -0,0 +1,142 @@
1
+ use super::{token_source::TokenSource, ErrorResponse, FromValue, MiddlewareLayer};
2
+ use crate::server::http_message_types::{HttpRequest, HttpResponse, RequestExt};
3
+ use crate::services::itsi_http_service::HttpRequestContext;
4
+ use crate::services::rate_limiter::{
5
+ create_rate_limit_key, get_rate_limiter, RateLimitError, RateLimiter, RateLimiterConfig,
6
+ };
7
+ use async_trait::async_trait;
8
+ use either::Either;
9
+ use magnus::error::Result;
10
+ use serde::Deserialize;
11
+ use std::collections::HashMap;
12
+ use std::sync::{Arc, OnceLock};
13
+ use std::time::Duration;
14
+ use tracing::{debug, error, warn};
15
+
16
+ #[derive(Debug, Clone, Deserialize)]
17
+ pub struct RateLimit {
18
+ pub requests: u64,
19
+ pub seconds: u64,
20
+ pub key: RateLimitKey,
21
+ #[serde(skip_deserializing)]
22
+ pub rate_limiter: OnceLock<Arc<dyn RateLimiter>>,
23
+ pub store_config: RateLimiterConfig,
24
+ pub trusted_proxies: HashMap<String, TokenSource>,
25
+ #[serde(default = "too_many_requests_error_response")]
26
+ pub error_response: ErrorResponse,
27
+ }
28
+
29
+ fn too_many_requests_error_response() -> ErrorResponse {
30
+ ErrorResponse::too_many_requests()
31
+ }
32
+
33
+ #[derive(Debug, Clone, Deserialize)]
34
+ pub enum RateLimitKey {
35
+ #[serde(rename(deserialize = "address"))]
36
+ SocketAddress,
37
+ #[serde(rename(deserialize = "parameter"))]
38
+ Parameter(TokenSource),
39
+ }
40
+
41
+ #[async_trait]
42
+ impl MiddlewareLayer for RateLimit {
43
+ async fn initialize(&self) -> Result<()> {
44
+ // Instantiate our rate limiter based on the rate limit config here.
45
+ // This will automatically fall back to in-memory if Redis fails
46
+ if let Ok(limiter) = get_rate_limiter(&self.store_config).await {
47
+ let _ = self.rate_limiter.set(limiter);
48
+ }
49
+ Ok(())
50
+ }
51
+
52
+ async fn before(
53
+ &self,
54
+ req: HttpRequest,
55
+ context: &mut HttpRequestContext,
56
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
57
+ // Get the key to rate limit on
58
+ let key_value = match &self.key {
59
+ RateLimitKey::SocketAddress => {
60
+ // Use the socket address from the context
61
+ if self.trusted_proxies.contains_key(&context.addr) {
62
+ let source = self.trusted_proxies.get(&context.addr).unwrap();
63
+ source.extract_token(&req).unwrap_or(&context.addr)
64
+ } else {
65
+ &context.addr
66
+ }
67
+ }
68
+ RateLimitKey::Parameter(token_source) => {
69
+ match token_source {
70
+ TokenSource::Header { name, prefix } => {
71
+ if let Some(header) = req.header(name) {
72
+ if let Some(prefix) = prefix {
73
+ header.strip_prefix(prefix).unwrap_or("").trim_ascii()
74
+ } else {
75
+ header.trim_ascii()
76
+ }
77
+ } else {
78
+ // If no token is found, skip rate limiting
79
+ warn!("No token found in header for rate limiting");
80
+ return Ok(Either::Left(req));
81
+ }
82
+ }
83
+ TokenSource::Query(query_name) => {
84
+ if let Some(value) = req.query_param(query_name) {
85
+ value
86
+ } else {
87
+ // If no token is found, skip rate limiting
88
+ warn!("No token found in query for rate limiting");
89
+ return Ok(Either::Left(req));
90
+ }
91
+ }
92
+ }
93
+ }
94
+ };
95
+
96
+ // Create a rate limit key
97
+ let rate_limit_key = create_rate_limit_key(key_value, req.uri().path());
98
+
99
+ debug!(target: "middleware::rate_limit", "Rate limit key: {}", rate_limit_key);
100
+ // Get the rate limiter
101
+ if let Some(limiter) = self.rate_limiter.get() {
102
+ // Check if rate limit is exceeded
103
+ let timeout = Duration::from_secs(self.seconds);
104
+ let limit = self.requests;
105
+
106
+ match limiter.check_limit(&rate_limit_key, limit, timeout).await {
107
+ Ok(_) => {
108
+ debug!(target: "middleware::rate_limit", "Rate limit not exceeded");
109
+ Ok(Either::Left(req))
110
+ }
111
+ Err(RateLimitError::RateLimitExceeded { limit, ttl, .. }) => {
112
+ debug!(target: "middleware::rate_limit", "Rate limit exceeded. Limit: {}, ttl: {}", limit, ttl);
113
+ let mut response = self
114
+ .error_response
115
+ .to_http_response(req.accept().into())
116
+ .await;
117
+ response
118
+ .headers_mut()
119
+ .insert("X-RateLimit-Limit", limit.to_string().parse().unwrap());
120
+ response
121
+ .headers_mut()
122
+ .insert("X-RateLimit-Remaining", "0".parse().unwrap());
123
+ response
124
+ .headers_mut()
125
+ .insert("X-RateLimit-Reset", ttl.to_string().parse().unwrap());
126
+ response
127
+ .headers_mut()
128
+ .insert("Retry-After", ttl.to_string().parse().unwrap());
129
+ Ok(Either::Right(response))
130
+ }
131
+ Err(e) => {
132
+ error!("Rate limiter error: {:?}", e);
133
+ Ok(Either::Left(req))
134
+ }
135
+ }
136
+ } else {
137
+ warn!("Rate limiter not initialized");
138
+ Ok(Either::Left(req))
139
+ }
140
+ }
141
+ }
142
+ impl FromValue for RateLimit {}