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,195 @@
1
+ use crate::{
2
+ server::http_message_types::{HttpRequest, HttpResponse},
3
+ services::itsi_http_service::HttpRequestContext,
4
+ };
5
+
6
+ use super::{FromValue, MiddlewareLayer};
7
+ use async_trait::async_trait;
8
+ use base64::{engine::general_purpose, Engine as _};
9
+ use bytes::{Bytes, BytesMut};
10
+ use either::Either;
11
+ use futures::TryStreamExt;
12
+ use http::{header, HeaderValue, Response, StatusCode};
13
+ use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
14
+ use hyper::body::Body;
15
+ use magnus::error::Result;
16
+ use serde::Deserialize;
17
+ use sha2::{Digest, Sha256};
18
+
19
+ #[derive(Debug, Clone, Copy, Deserialize, Default)]
20
+ pub enum ETagType {
21
+ #[serde(rename = "strong")]
22
+ #[default]
23
+ Strong,
24
+ #[serde(rename = "weak")]
25
+ Weak,
26
+ }
27
+
28
+ #[derive(Debug, Clone, Copy, Deserialize, Default)]
29
+ pub enum HashAlgorithm {
30
+ #[serde(rename = "sha256")]
31
+ #[default]
32
+ Sha256,
33
+ #[serde(rename = "md5")]
34
+ Md5,
35
+ }
36
+
37
+ #[derive(Debug, Clone, Deserialize)]
38
+ pub struct ETag {
39
+ #[serde(default)]
40
+ pub r#type: ETagType,
41
+ #[serde(default)]
42
+ pub algorithm: HashAlgorithm,
43
+ #[serde(default)]
44
+ pub min_body_size: usize,
45
+ #[serde(default = "default_true")]
46
+ pub handle_if_none_match: bool,
47
+ }
48
+
49
+ fn default_true() -> bool {
50
+ true
51
+ }
52
+
53
+ #[async_trait]
54
+ impl MiddlewareLayer for ETag {
55
+ async fn before(
56
+ &self,
57
+ req: HttpRequest,
58
+ context: &mut HttpRequestContext,
59
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
60
+ // Store if-none-match header in context if present for later use in after hook
61
+ if self.handle_if_none_match {
62
+ if let Some(if_none_match) = req.headers().get(header::IF_NONE_MATCH) {
63
+ if let Ok(etag_value) = if_none_match.to_str() {
64
+ context.set_if_none_match(Some(etag_value.to_string()));
65
+ }
66
+ }
67
+ }
68
+ Ok(Either::Left(req))
69
+ }
70
+
71
+ async fn after(&self, resp: HttpResponse, context: &mut HttpRequestContext) -> HttpResponse {
72
+ // Skip for error responses or responses that shouldn't have ETags
73
+ match resp.status() {
74
+ StatusCode::OK
75
+ | StatusCode::CREATED
76
+ | StatusCode::ACCEPTED
77
+ | StatusCode::NON_AUTHORITATIVE_INFORMATION
78
+ | StatusCode::NO_CONTENT
79
+ | StatusCode::PARTIAL_CONTENT => {}
80
+ _ => return resp,
81
+ }
82
+
83
+ // Skip if already has an ETag
84
+ if resp.headers().contains_key(header::ETAG) {
85
+ return resp;
86
+ }
87
+
88
+ // Skip if Cache-Control: no-store is present
89
+ if let Some(cache_control) = resp.headers().get(header::CACHE_CONTROL) {
90
+ if let Ok(cache_control_str) = cache_control.to_str() {
91
+ if cache_control_str.contains("no-store") {
92
+ return resp;
93
+ }
94
+ }
95
+ }
96
+
97
+ // Check if body is a stream or fixed size using size_hint (similar to compression.rs)
98
+ let body_size = resp.size_hint().exact();
99
+
100
+ // Skip streaming bodies
101
+ if body_size.is_none() {
102
+ return resp;
103
+ }
104
+
105
+ // Skip if body is too small
106
+ if body_size.unwrap_or(0) < self.min_body_size as u64 {
107
+ return resp;
108
+ }
109
+
110
+ let (mut parts, mut body) = resp.into_parts();
111
+ let etag_value = if let Some(existing_etag) = parts.headers.get(header::ETAG) {
112
+ existing_etag.to_str().unwrap_or("").to_string()
113
+ } else {
114
+ // Get the full bytes from the body
115
+ let full_bytes: Bytes = match body
116
+ .into_data_stream()
117
+ .try_fold(BytesMut::new(), |mut acc, chunk| async move {
118
+ acc.extend_from_slice(&chunk);
119
+ Ok(acc)
120
+ })
121
+ .await
122
+ {
123
+ Ok(bytes_mut) => bytes_mut.freeze(),
124
+ Err(_) => return Response::from_parts(parts, BoxBody::new(Empty::new())),
125
+ };
126
+
127
+ let computed_etag = match self.algorithm {
128
+ HashAlgorithm::Sha256 => {
129
+ let mut hasher = Sha256::new();
130
+ hasher.update(&full_bytes);
131
+ let result = hasher.finalize();
132
+ general_purpose::STANDARD.encode(result)
133
+ }
134
+ HashAlgorithm::Md5 => {
135
+ let digest = md5::compute(&full_bytes);
136
+ format!("{:x}", digest)
137
+ }
138
+ };
139
+
140
+ let formatted_etag = match self.r#type {
141
+ ETagType::Strong => format!("\"{}\"", computed_etag),
142
+ ETagType::Weak => format!("W/\"{}\"", computed_etag),
143
+ };
144
+
145
+ if let Ok(value) = HeaderValue::from_str(&formatted_etag) {
146
+ parts.headers.insert(header::ETAG, value);
147
+ }
148
+
149
+ body = Full::new(full_bytes).boxed();
150
+ formatted_etag
151
+ };
152
+
153
+ // Handle 304 Not Modified if we have an If-None-Match header and it matches
154
+ if self.handle_if_none_match {
155
+ if let Some(if_none_match) = context.get_if_none_match() {
156
+ if if_none_match == etag_value || if_none_match == "*" {
157
+ // Return 304 Not Modified without the body
158
+ let mut not_modified = Response::new(BoxBody::new(Empty::new()));
159
+ *not_modified.status_mut() = StatusCode::NOT_MODIFIED;
160
+ // Copy headers we want to preserve
161
+ for (name, value) in parts.headers.iter() {
162
+ if matches!(
163
+ name,
164
+ &header::CACHE_CONTROL
165
+ | &header::CONTENT_LOCATION
166
+ | &header::DATE
167
+ | &header::ETAG
168
+ | &header::EXPIRES
169
+ | &header::VARY
170
+ ) {
171
+ not_modified.headers_mut().insert(name, value.clone());
172
+ }
173
+ }
174
+ return not_modified;
175
+ }
176
+ }
177
+ }
178
+
179
+ // Recreate response with the original body and the ETag header
180
+ Response::from_parts(parts, body)
181
+ }
182
+ }
183
+
184
+ impl Default for ETag {
185
+ fn default() -> Self {
186
+ Self {
187
+ r#type: ETagType::Strong,
188
+ algorithm: HashAlgorithm::Sha256,
189
+ min_body_size: 0,
190
+ handle_if_none_match: true,
191
+ }
192
+ }
193
+ }
194
+
195
+ impl FromValue for ETag {}
@@ -0,0 +1,82 @@
1
+ use http::{header::GetAll, HeaderValue};
2
+
3
+ /// Given a list of header values (which may be comma-separated and may have quality parameters)
4
+ /// and a list of supported items (each supported item is a full value or a prefix ending with '*'),
5
+ /// return Some(supported_item) for the first supported item that matches any header value, or None.
6
+ pub fn find_first_supported<'a, I>(header_values: &[HeaderValue], supported: I) -> Option<&'a str>
7
+ where
8
+ I: IntoIterator<Item = &'a str> + Clone,
9
+ {
10
+ // best candidate: (quality, supported_index, candidate)
11
+ let mut best: Option<(f32, usize, &'a str)> = None;
12
+
13
+ for value in header_values.iter() {
14
+ if let Ok(s) = value.to_str() {
15
+ for token in s.split(',') {
16
+ let token = token.trim();
17
+ if token.is_empty() {
18
+ continue;
19
+ }
20
+ let mut parts = token.split(';');
21
+ let enc = parts.next()?.trim();
22
+ if enc.is_empty() {
23
+ continue;
24
+ }
25
+ let quality = parts
26
+ .find_map(|p| {
27
+ let p = p.trim();
28
+ if let Some(q_str) = p.strip_prefix("q=") {
29
+ q_str.parse::<f32>().ok()
30
+ } else {
31
+ None
32
+ }
33
+ })
34
+ .unwrap_or(1.0);
35
+
36
+ // For each supported encoding, iterate over a clone of the iterable.
37
+ for (i, supp) in supported.clone().into_iter().enumerate() {
38
+ let is_match = if supp == "*" {
39
+ true
40
+ } else if let Some(prefix) = supp.strip_suffix('*') {
41
+ enc.starts_with(prefix)
42
+ } else {
43
+ enc.eq_ignore_ascii_case(supp)
44
+ };
45
+
46
+ if is_match {
47
+ best = match best {
48
+ Some((best_q, best_idx, _))
49
+ if quality > best_q || (quality == best_q && i < best_idx) =>
50
+ {
51
+ Some((quality, i, supp))
52
+ }
53
+ None => Some((quality, i, supp)),
54
+ _ => best,
55
+ };
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ best.map(|(_, _, candidate)| candidate)
63
+ }
64
+
65
+ pub fn header_contains(header_values: &GetAll<HeaderValue>, needle: &str) -> bool {
66
+ if needle == "*" {
67
+ return true;
68
+ }
69
+ let mut headers = header_values
70
+ .iter()
71
+ .flat_map(|value| value.to_str().unwrap_or("").split(','))
72
+ .map(|s| s.trim().split(';').next().unwrap_or(""))
73
+ .filter(|s| !s.is_empty());
74
+
75
+ let needle_lower = needle;
76
+ if needle.ends_with('*') {
77
+ let prefix = &needle_lower[..needle_lower.len() - 1];
78
+ headers.any(|h| h.starts_with(prefix))
79
+ } else {
80
+ headers.any(|h| h == needle_lower)
81
+ }
82
+ }
@@ -0,0 +1,201 @@
1
+ use crate::server::http_message_types::{HttpRequest, HttpResponse, RequestExt};
2
+ use crate::services::itsi_http_service::HttpRequestContext;
3
+ use crate::services::rate_limiter::{
4
+ get_ban_manager, get_rate_limiter, BanManager, RateLimiter, RateLimiterConfig,
5
+ };
6
+
7
+ use super::{ErrorResponse, FromValue, MiddlewareLayer};
8
+
9
+ use async_trait::async_trait;
10
+ use either::Either;
11
+ use itsi_tracing::*;
12
+ use magnus::error::Result;
13
+ use regex::RegexSet;
14
+ use serde::Deserialize;
15
+ use std::time::Duration;
16
+ use std::{
17
+ collections::HashMap,
18
+ sync::{Arc, OnceLock},
19
+ };
20
+
21
+ #[derive(Debug, Clone, Deserialize)]
22
+ pub struct IntrusionProtection {
23
+ #[serde(skip_deserializing)]
24
+ pub banned_url_pattern_matcher: OnceLock<RegexSet>,
25
+ #[serde(default)]
26
+ pub banned_url_patterns: Vec<String>,
27
+ #[serde(skip_deserializing)]
28
+ pub banned_header_pattern_matchers: OnceLock<HashMap<String, RegexSet>>,
29
+ #[serde(default)]
30
+ pub banned_header_patterns: HashMap<String, Vec<String>>,
31
+ pub banned_time_seconds: u64,
32
+ #[serde(skip_deserializing)]
33
+ pub rate_limiter: OnceLock<Arc<dyn RateLimiter>>,
34
+ #[serde(skip_deserializing)]
35
+ pub ban_manager: OnceLock<BanManager>,
36
+ pub store_config: RateLimiterConfig,
37
+ #[serde(default = "forbidden_error_response")]
38
+ pub error_response: ErrorResponse,
39
+ }
40
+
41
+ fn forbidden_error_response() -> ErrorResponse {
42
+ ErrorResponse::forbidden()
43
+ }
44
+
45
+ #[async_trait]
46
+ impl MiddlewareLayer for IntrusionProtection {
47
+ async fn initialize(&self) -> Result<()> {
48
+ // Initialize regex matchers for URL patterns
49
+ if !self.banned_url_patterns.is_empty() {
50
+ match RegexSet::new(&self.banned_url_patterns) {
51
+ Ok(regex_set) => {
52
+ let _ = self.banned_url_pattern_matcher.set(regex_set);
53
+ }
54
+ Err(e) => {
55
+ error!("Failed to compile URL regex patterns: {:?}", e);
56
+ }
57
+ }
58
+ }
59
+
60
+ // Initialize regex matchers for header patterns
61
+ if !self.banned_header_patterns.is_empty() {
62
+ let mut header_matchers = HashMap::new();
63
+ for (header_name, patterns) in &self.banned_header_patterns {
64
+ if !patterns.is_empty() {
65
+ match RegexSet::new(patterns) {
66
+ Ok(regex_set) => {
67
+ header_matchers.insert(header_name.clone(), regex_set);
68
+ }
69
+ Err(e) => {
70
+ error!(
71
+ "Failed to compile header regex patterns for {}: {:?}",
72
+ header_name, e
73
+ );
74
+ }
75
+ }
76
+ }
77
+ }
78
+ let _ = self.banned_header_pattern_matchers.set(header_matchers);
79
+ }
80
+
81
+ // Initialize rate limiter (used for tracking bans)
82
+ // This will automatically fall back to in-memory if Redis fails
83
+ if let Ok(limiter) = get_rate_limiter(&self.store_config).await {
84
+ let _ = self.rate_limiter.set(limiter);
85
+ }
86
+
87
+ // Initialize ban manager
88
+ // This will automatically fall back to in-memory if Redis fails
89
+ if let Ok(manager) = get_ban_manager(&self.store_config).await {
90
+ let _ = self.ban_manager.set(manager);
91
+ }
92
+
93
+ Ok(())
94
+ }
95
+
96
+ async fn before(
97
+ &self,
98
+ req: HttpRequest,
99
+ context: &mut HttpRequestContext,
100
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
101
+ // Get client IP address from context's service
102
+ let client_ip = &context.addr;
103
+
104
+ // Check if the IP is already banned
105
+ if let Some(ban_manager) = self.ban_manager.get() {
106
+ match ban_manager.is_banned(client_ip).await {
107
+ Ok(Some(_)) => {
108
+ return Ok(Either::Right(
109
+ self.error_response
110
+ .to_http_response(req.accept().into())
111
+ .await,
112
+ ));
113
+ }
114
+ Err(e) => {
115
+ error!("Error checking IP ban status: {:?}", e);
116
+ // Continue processing - fail open
117
+ }
118
+ _ => {
119
+ // Not banned, continue with intrusion checks
120
+ }
121
+ }
122
+ } else {
123
+ warn!("No ban manager available for intrusion protection");
124
+ }
125
+
126
+ // Check for banned URL patterns
127
+ if let Some(url_matcher) = self.banned_url_pattern_matcher.get() {
128
+ let path = req.uri().path_and_query().map(|p| p.as_str()).unwrap_or("");
129
+
130
+ if url_matcher.is_match(path) {
131
+ if let Some(ban_manager) = self.ban_manager.get() {
132
+ match ban_manager
133
+ .ban_ip(
134
+ client_ip,
135
+ &format!("Banned URL pattern detected: {}", path),
136
+ Duration::from_secs(self.banned_time_seconds),
137
+ )
138
+ .await
139
+ {
140
+ Ok(_) => {}
141
+ Err(e) => error!("Failed to ban IP {}: {:?}", client_ip, e),
142
+ }
143
+ }
144
+
145
+ // Always return the error response even if banning failed
146
+ return Ok(Either::Right(
147
+ self.error_response
148
+ .to_http_response(req.accept().into())
149
+ .await,
150
+ ));
151
+ }
152
+ }
153
+
154
+ // Check for banned header patterns
155
+ if let Some(header_matchers) = self.banned_header_pattern_matchers.get() {
156
+ for (header_name, pattern_set) in header_matchers {
157
+ if let Some(header_value) = req.header(header_name) {
158
+ if pattern_set.is_match(header_value) {
159
+ info!(
160
+ "Intrusion detected: Header pattern match for {} in header {}",
161
+ header_value, header_name
162
+ );
163
+
164
+ // Ban the IP address if possible
165
+ if let Some(ban_manager) = self.ban_manager.get() {
166
+ match ban_manager
167
+ .ban_ip(
168
+ client_ip,
169
+ &format!(
170
+ "Banned header pattern detected: {} in {}",
171
+ header_value, header_name
172
+ ),
173
+ Duration::from_secs(self.banned_time_seconds),
174
+ )
175
+ .await
176
+ {
177
+ Ok(_) => info!(
178
+ "Successfully banned IP {} for {} seconds",
179
+ client_ip, self.banned_time_seconds
180
+ ),
181
+ Err(e) => error!("Failed to ban IP {}: {:?}", client_ip, e),
182
+ }
183
+ }
184
+
185
+ // Always return the error response even if banning failed
186
+ return Ok(Either::Right(
187
+ self.error_response
188
+ .to_http_response(req.accept().into())
189
+ .await,
190
+ ));
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ // No intrusion detected
197
+ Ok(Either::Left(req))
198
+ }
199
+ }
200
+
201
+ impl FromValue for IntrusionProtection {}
@@ -0,0 +1,82 @@
1
+ use async_trait::async_trait;
2
+ use either::Either;
3
+ use itsi_tracing::*;
4
+ use magnus::error::Result;
5
+ use serde::Deserialize;
6
+
7
+ use crate::server::http_message_types::{HttpRequest, HttpResponse};
8
+ use crate::services::itsi_http_service::HttpRequestContext;
9
+
10
+ use super::string_rewrite::StringRewrite;
11
+ use super::{FromValue, MiddlewareLayer};
12
+
13
+ /// Logging middleware for HTTP requests and responses
14
+ ///
15
+ /// Supports customizable log formats with placeholders
16
+ #[derive(Debug, Clone, Deserialize)]
17
+ pub struct LogRequests {
18
+ pub before: Option<LogConfig>,
19
+ pub after: Option<LogConfig>,
20
+ }
21
+
22
+ #[derive(Debug, Clone, Deserialize)]
23
+ pub struct LogConfig {
24
+ level: LogMiddlewareLevel,
25
+ format: StringRewrite,
26
+ }
27
+
28
+ #[derive(Debug, Clone, Deserialize)]
29
+ pub enum LogMiddlewareLevel {
30
+ #[serde(rename(deserialize = "INFO"))]
31
+ Info,
32
+ #[serde(rename(deserialize = "TRACE"))]
33
+ Trace,
34
+ #[serde(rename(deserialize = "DEBUG"))]
35
+ Debug,
36
+ #[serde(rename(deserialize = "WARN"))]
37
+ Warn,
38
+ #[serde(rename(deserialize = "ERROR"))]
39
+ Error,
40
+ }
41
+
42
+ impl LogMiddlewareLevel {
43
+ pub fn log(&self, message: String) {
44
+ match self {
45
+ LogMiddlewareLevel::Trace => trace!(message),
46
+ LogMiddlewareLevel::Debug => debug!(message),
47
+ LogMiddlewareLevel::Info => info!(message),
48
+ LogMiddlewareLevel::Warn => warn!(message),
49
+ LogMiddlewareLevel::Error => error!(message),
50
+ }
51
+ }
52
+ }
53
+
54
+ #[async_trait]
55
+ impl MiddlewareLayer for LogRequests {
56
+ async fn initialize(&self) -> Result<()> {
57
+ Ok(())
58
+ }
59
+
60
+ async fn before(
61
+ &self,
62
+ req: HttpRequest,
63
+ context: &mut HttpRequestContext,
64
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
65
+ context.track_start_time();
66
+ if let Some(LogConfig { level, format }) = self.before.as_ref() {
67
+ level.log(format.rewrite_request(&req, context));
68
+ }
69
+
70
+ Ok(Either::Left(req))
71
+ }
72
+
73
+ async fn after(&self, resp: HttpResponse, context: &mut HttpRequestContext) -> HttpResponse {
74
+ if let Some(LogConfig { level, format }) = self.after.as_ref() {
75
+ level.log(format.rewrite_response(&resp, context));
76
+ }
77
+
78
+ resp
79
+ }
80
+ }
81
+
82
+ impl FromValue for LogRequests {}
@@ -0,0 +1,47 @@
1
+ use crate::{
2
+ server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
3
+ services::itsi_http_service::HttpRequestContext,
4
+ };
5
+
6
+ use super::{ErrorResponse, FromValue, MiddlewareLayer};
7
+ use async_trait::async_trait;
8
+ use either::Either;
9
+ use http::StatusCode;
10
+ use magnus::error::Result;
11
+ use serde::Deserialize;
12
+ use std::sync::atomic::Ordering;
13
+
14
+ #[derive(Debug, Clone, Deserialize)]
15
+ pub struct MaxBody {
16
+ pub max_size: usize,
17
+ #[serde(default = "payload_too_large_error_response")]
18
+ pub error_response: ErrorResponse,
19
+ }
20
+
21
+ fn payload_too_large_error_response() -> ErrorResponse {
22
+ ErrorResponse::payload_too_large()
23
+ }
24
+
25
+ #[async_trait]
26
+ impl MiddlewareLayer for MaxBody {
27
+ async fn before(
28
+ &self,
29
+ req: HttpRequest,
30
+ context: &mut HttpRequestContext,
31
+ ) -> Result<Either<HttpRequest, HttpResponse>> {
32
+ req.body().limit.store(self.max_size, Ordering::Relaxed);
33
+ context.set_response_format(req.accept().into());
34
+ Ok(Either::Left(req))
35
+ }
36
+
37
+ async fn after(&self, resp: HttpResponse, context: &mut HttpRequestContext) -> HttpResponse {
38
+ if resp.status() == StatusCode::PAYLOAD_TOO_LARGE {
39
+ self.error_response
40
+ .to_http_response(context.response_format().clone())
41
+ .await
42
+ } else {
43
+ resp
44
+ }
45
+ }
46
+ }
47
+ impl FromValue for MaxBody {}