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
@@ -9,4 +9,9 @@ tracing-subscriber = { version = "0.3.19", features = [
9
9
  "env-filter",
10
10
  "std",
11
11
  "fmt",
12
+ "json",
13
+ "ansi",
12
14
  ] }
15
+ tracing-attributes = "0.1"
16
+ atty = "0.2.14"
17
+ tracing-appender = "0.2.3"
@@ -1,11 +1,350 @@
1
+ use atty::{Stream, is};
2
+ use std::{
3
+ env,
4
+ sync::{Mutex, OnceLock},
5
+ };
6
+ use tracing::Level;
1
7
  pub use tracing::{debug, error, info, trace, warn};
2
- use tracing_subscriber::{EnvFilter, fmt};
8
+ use tracing_appender::rolling;
9
+ use tracing_subscriber::fmt::writer::BoxMakeWriter;
10
+ use tracing_subscriber::{EnvFilter, fmt, prelude::*, reload};
11
+ use tracing_subscriber::{Layer, Registry, layer::Layered};
3
12
 
13
+ // Global reload handle for changing the level at runtime.
14
+ static RELOAD_HANDLE: OnceLock<
15
+ Mutex<Option<reload::Handle<EnvFilter, tracing_subscriber::Registry>>>,
16
+ > = OnceLock::new();
17
+
18
+ // Global reload handle for changing the formatting layer (log target/format) at runtime.
19
+ type ReloadFmtHandle = reload::Handle<
20
+ Box<
21
+ dyn Layer<
22
+ tracing_subscriber::layer::Layered<
23
+ reload::Layer<EnvFilter, tracing_subscriber::Registry>,
24
+ tracing_subscriber::Registry,
25
+ >,
26
+ > + Send
27
+ + Sync,
28
+ >,
29
+ Layered<tracing_subscriber::reload::Layer<EnvFilter, Registry>, Registry>,
30
+ >;
31
+
32
+ static RELOAD_FMT_HANDLE: OnceLock<Mutex<Option<ReloadFmtHandle>>> = OnceLock::new();
33
+
34
+ // Global current log configuration for formatting options.
35
+ static CURRENT_CONFIG: OnceLock<Mutex<LogConfig>> = OnceLock::new();
36
+
37
+ /// Log format: Plain or JSON.
38
+ #[derive(Debug, Clone)]
39
+ pub enum LogFormat {
40
+ Plain,
41
+ Json,
42
+ }
43
+
44
+ /// Log target: STDOUT, File, or Both.
45
+ #[derive(Debug, Clone)]
46
+ pub enum LogTarget {
47
+ Stdout,
48
+ File(String), // file name (rotated daily)
49
+ Both(String), // file name (rotated daily) plus STDOUT
50
+ }
51
+
52
+ /// Logger configuration.
53
+ #[derive(Debug, Clone)]
54
+ pub struct LogConfig {
55
+ /// Log level as a string (e.g. "info", "debug").
56
+ pub level: String,
57
+ /// Format: Plain (with optional ANSI) or JSON.
58
+ pub format: LogFormat,
59
+ /// Target: STDOUT, File, or Both.
60
+ pub target: LogTarget,
61
+ /// Whether to enable ANSI coloring (for plain text).
62
+ pub use_ansi: bool,
63
+ }
64
+
65
+ impl Default for LogConfig {
66
+ fn default() -> Self {
67
+ let level = env::var("ITSI_LOG").unwrap_or_else(|_| "info".into());
68
+ let format = match env::var("ITSI_LOG_FORMAT").as_deref() {
69
+ Ok("json") => LogFormat::Json,
70
+ _ => LogFormat::Plain,
71
+ };
72
+ let target = match env::var("ITSI_LOG_TARGET").as_deref() {
73
+ Ok("file") => {
74
+ let file = env::var("ITSI_LOG_FILE").unwrap_or_else(|_| "app.log".into());
75
+ LogTarget::File(file)
76
+ }
77
+ Ok("both") => {
78
+ let file = env::var("ITSI_LOG_FILE").unwrap_or_else(|_| "app.log".into());
79
+ LogTarget::Both(file)
80
+ }
81
+ _ => LogTarget::Stdout,
82
+ };
83
+ // If ITSI_LOG_ANSI is set, use that; otherwise, use ANSI if stdout is a TTY.
84
+ let use_ansi = env::var("ITSI_LOG_ANSI")
85
+ .map(|s| s == "true")
86
+ .unwrap_or_else(|_| is(Stream::Stdout));
87
+ Self {
88
+ level,
89
+ format,
90
+ target,
91
+ use_ansi,
92
+ }
93
+ }
94
+ }
95
+
96
+ /// Build the formatting layer based on the provided configuration.
97
+ fn build_fmt_layer(
98
+ config: &LogConfig,
99
+ ) -> Box<
100
+ dyn Layer<
101
+ tracing_subscriber::layer::Layered<
102
+ reload::Layer<EnvFilter, tracing_subscriber::Registry>,
103
+ tracing_subscriber::Registry,
104
+ >,
105
+ > + Send
106
+ + Sync,
107
+ > {
108
+ match &config.target {
109
+ LogTarget::Stdout => match config.format {
110
+ LogFormat::Plain => fmt::layer()
111
+ .compact()
112
+ .with_file(false)
113
+ .with_line_number(false)
114
+ .with_target(true)
115
+ .with_thread_ids(false)
116
+ .with_writer(BoxMakeWriter::new(std::io::stdout))
117
+ .with_ansi(config.use_ansi)
118
+ .boxed(),
119
+ LogFormat::Json => fmt::layer()
120
+ .compact()
121
+ .with_file(false)
122
+ .with_line_number(false)
123
+ .with_target(true)
124
+ .with_thread_ids(false)
125
+ .with_writer(BoxMakeWriter::new(std::io::stdout))
126
+ .with_ansi(config.use_ansi)
127
+ .json()
128
+ .boxed(),
129
+ },
130
+ LogTarget::File(file) => {
131
+ let file_clone = file.clone();
132
+ match config.format {
133
+ LogFormat::Plain => fmt::layer()
134
+ .compact()
135
+ .with_file(false)
136
+ .with_line_number(false)
137
+ .with_target(true)
138
+ .with_thread_ids(false)
139
+ .with_writer(BoxMakeWriter::new(move || {
140
+ rolling::daily(".", file_clone.clone())
141
+ }))
142
+ .with_ansi(false)
143
+ .boxed(),
144
+ LogFormat::Json => {
145
+ let file_clone = file.clone();
146
+ fmt::layer()
147
+ .compact()
148
+ .with_file(false)
149
+ .with_line_number(false)
150
+ .with_target(true)
151
+ .with_thread_ids(false)
152
+ .with_writer(BoxMakeWriter::new(move || {
153
+ rolling::daily(".", file_clone.clone())
154
+ }))
155
+ .with_ansi(false)
156
+ .json()
157
+ .boxed()
158
+ }
159
+ }
160
+ }
161
+ LogTarget::Both(file) => {
162
+ let file_clone = file.clone();
163
+ match config.format {
164
+ LogFormat::Plain => {
165
+ let stdout_layer = fmt::layer()
166
+ .compact()
167
+ .with_file(false)
168
+ .with_line_number(false)
169
+ .with_target(true)
170
+ .with_thread_ids(false)
171
+ .with_writer(BoxMakeWriter::new(std::io::stdout))
172
+ .with_ansi(config.use_ansi);
173
+ let file_layer = fmt::layer()
174
+ .compact()
175
+ .with_file(false)
176
+ .with_line_number(false)
177
+ .with_target(true)
178
+ .with_thread_ids(false)
179
+ .with_writer(BoxMakeWriter::new(move || {
180
+ rolling::daily(".", file_clone.clone())
181
+ }))
182
+ .with_ansi(false);
183
+ stdout_layer.and_then(file_layer).boxed()
184
+ }
185
+ LogFormat::Json => {
186
+ let stdout_layer = fmt::layer()
187
+ .compact()
188
+ .with_file(false)
189
+ .with_line_number(false)
190
+ .with_target(true)
191
+ .with_thread_ids(false)
192
+ .with_writer(BoxMakeWriter::new(std::io::stdout))
193
+ .with_ansi(config.use_ansi)
194
+ .json();
195
+ let file_layer = fmt::layer()
196
+ .compact()
197
+ .with_file(false)
198
+ .with_line_number(false)
199
+ .with_target(true)
200
+ .with_thread_ids(false)
201
+ .with_writer(BoxMakeWriter::new(move || {
202
+ rolling::daily(".", file_clone.clone())
203
+ }))
204
+ .with_ansi(false)
205
+ .json();
206
+ stdout_layer.and_then(file_layer).boxed()
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+
213
+ /// Update the formatting layer using the current configuration.
214
+ fn update_fmt_layer(config: &LogConfig) {
215
+ if let Some(handle) = RELOAD_FMT_HANDLE.get().unwrap().lock().unwrap().as_ref() {
216
+ let new_layer = build_fmt_layer(config);
217
+ handle
218
+ .modify(|layer| {
219
+ *layer = new_layer;
220
+ })
221
+ .expect("Failed to update formatting layer");
222
+ } else {
223
+ eprintln!("Reload handle for formatting layer not initialized; call init() first.");
224
+ }
225
+ }
226
+
227
+ /// Initialize the global tracing subscriber with the default configuration.
4
228
  pub fn init() {
5
- let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
6
- let format = fmt::format().with_level(true).with_target(false).compact();
7
- tracing_subscriber::fmt()
8
- .with_env_filter(env_filter)
9
- .event_format(format)
10
- .init();
229
+ init_with_config(LogConfig::default());
230
+ }
231
+
232
+ /// Initialize the global tracing subscriber with a given configuration.
233
+ pub fn init_with_config(config: LogConfig) {
234
+ // Store the current config in a global for future updates.
235
+ CURRENT_CONFIG.set(Mutex::new(config.clone())).ok();
236
+
237
+ // Build an EnvFilter from the configured level.
238
+ let env_filter = EnvFilter::new(config.clone().level);
239
+
240
+ // Build the formatting layer based on the configuration.
241
+ let fmt_layer = build_fmt_layer(&config);
242
+
243
+ // Create a reloadable filter layer so we can update the level at runtime.
244
+ let (filter_layer, filter_handle) = reload::Layer::new(env_filter);
245
+
246
+ // Create a reloadable formatting layer so we can update the target/format at runtime.
247
+ let (fmt_layer, fmt_handle) = reload::Layer::new(fmt_layer);
248
+
249
+ // Build the subscriber registry.
250
+ let subscriber = tracing_subscriber::registry()
251
+ .with(filter_layer)
252
+ .with(fmt_layer);
253
+
254
+ tracing::subscriber::set_global_default(subscriber)
255
+ .expect("Unable to set global tracing subscriber");
256
+
257
+ RELOAD_HANDLE.set(Mutex::new(Some(filter_handle))).unwrap();
258
+ RELOAD_FMT_HANDLE.set(Mutex::new(Some(fmt_handle))).ok();
259
+ }
260
+
261
+ /// Change the log level at runtime.
262
+ pub fn set_level(new_level: &str) {
263
+ if let Some(handle) = RELOAD_HANDLE.get().unwrap().lock().unwrap().as_ref() {
264
+ handle
265
+ .modify(|filter| *filter = EnvFilter::new(new_level))
266
+ .expect("Failed to update log level");
267
+
268
+ // Also update the stored config.
269
+ if let Some(config_mutex) = CURRENT_CONFIG.get() {
270
+ let mut config = config_mutex.lock().unwrap();
271
+ config.level = new_level.to_string();
272
+ }
273
+ } else {
274
+ eprintln!("Reload handle not initialized; call init() first.");
275
+ }
276
+ }
277
+
278
+ /// Change the log target at runtime.
279
+ pub fn set_target(new_target: &str) {
280
+ let target: LogTarget = match new_target {
281
+ "stdout" => LogTarget::Stdout,
282
+ path => LogTarget::File(path.to_string()),
283
+ };
284
+ if let Some(config_mutex) = CURRENT_CONFIG.get() {
285
+ let mut config = config_mutex.lock().unwrap();
286
+ config.target = target;
287
+ update_fmt_layer(&config);
288
+ } else {
289
+ eprintln!("Current configuration not initialized; call init() first.");
290
+ }
291
+ }
292
+
293
+ /// Change the log format at runtime.
294
+ pub fn set_format(new_format: &str) {
295
+ let format = match new_format {
296
+ "json" => LogFormat::Json,
297
+ "plain" => LogFormat::Plain,
298
+ _ => LogFormat::Json,
299
+ };
300
+ if let Some(config_mutex) = CURRENT_CONFIG.get() {
301
+ let mut config = config_mutex.lock().unwrap();
302
+ config.format = format;
303
+ update_fmt_layer(&config);
304
+ } else {
305
+ eprintln!("Current configuration not initialized; call init() first.");
306
+ }
307
+ }
308
+ pub fn set_target_filters(targets: Vec<(&str, Level)>) {
309
+ if let Some(reload_handle_mutex) = RELOAD_HANDLE.get() {
310
+ if let Ok(handle_guard) = reload_handle_mutex.lock() {
311
+ if let Some(handle) = handle_guard.as_ref() {
312
+ let mut new_filter = EnvFilter::new("");
313
+
314
+ if let Some(config_mutex) = CURRENT_CONFIG.get() {
315
+ if let Ok(config) = config_mutex.lock() {
316
+ if let Ok(directive) = config.level.parse() {
317
+ new_filter = new_filter.add_directive(directive);
318
+ }
319
+ }
320
+ }
321
+
322
+ for (target, level) in targets {
323
+ let directive_str = format!("{}={}", target, level);
324
+ if let Ok(directive) = directive_str.parse() {
325
+ new_filter = new_filter.add_directive(directive);
326
+ }
327
+ }
328
+
329
+ if let Err(e) = handle.modify(|filter| *filter = new_filter) {
330
+ eprintln!("Failed to update filter with target directives: {}", e);
331
+ }
332
+ }
333
+ }
334
+ } else {
335
+ eprintln!("Reload handle for filter not initialized; call init() first.");
336
+ }
337
+ }
338
+
339
+ /// Run a function silently by temporarily setting a no-op subscriber.
340
+ pub fn run_silently<F, R>(f: F) -> R
341
+ where
342
+ F: FnOnce() -> R,
343
+ {
344
+ let no_op_subscriber = tracing_subscriber::fmt()
345
+ .with_writer(std::io::sink)
346
+ .with_max_level(tracing_subscriber::filter::LevelFilter::OFF)
347
+ .finish();
348
+ let dispatch = tracing::Dispatch::new(no_op_subscriber);
349
+ tracing::dispatcher::with_default(&dispatch, f)
11
350
  }
@@ -0,0 +1,74 @@
1
+ module Itsi
2
+ class HttpRequest
3
+ module ResponseStatusShortcodes
4
+
5
+ HTTP_STATUS_CODES = {
6
+ 100 => :continue,
7
+ 101 => :switching_protocols,
8
+ 102 => :processing,
9
+ 200 => :ok,
10
+ 201 => :created,
11
+ 202 => :accepted,
12
+ 203 => :non_authoritative_information,
13
+ 204 => :no_content,
14
+ 205 => :reset_content,
15
+ 206 => :partial_content,
16
+ 207 => :multi_status,
17
+ 208 => :already_reported,
18
+ 226 => :im_used,
19
+ 300 => :multiple_choices,
20
+ 301 => :moved_permanently,
21
+ 302 => :found,
22
+ 303 => :see_other,
23
+ 304 => :not_modified,
24
+ 305 => :use_proxy,
25
+ 307 => :temporary_redirect,
26
+ 308 => :permanent_redirect,
27
+ 400 => :bad_request,
28
+ 401 => :unauthorized,
29
+ 402 => :payment_required,
30
+ 403 => :forbidden,
31
+ 404 => :not_found,
32
+ 405 => :method_not_allowed,
33
+ 406 => :not_acceptable,
34
+ 407 => :proxy_authentication_required,
35
+ 408 => :request_timeout,
36
+ 409 => :conflict,
37
+ 410 => :gone,
38
+ 411 => :length_required,
39
+ 412 => :precondition_failed,
40
+ 413 => :payload_too_large,
41
+ 414 => :uri_too_long,
42
+ 415 => :unsupported_media_type,
43
+ 416 => :range_not_satisfiable,
44
+ 417 => :expectation_failed,
45
+ 418 => :im_a_teapot,
46
+ 421 => :misdirected_request,
47
+ 422 => :unprocessable_entity,
48
+ 423 => :locked,
49
+ 424 => :failed_dependency,
50
+ 425 => :too_early,
51
+ 426 => :upgrade_required,
52
+ 428 => :precondition_required,
53
+ 429 => :too_many_requests,
54
+ 431 => :request_header_fields_too_large,
55
+ 451 => :unavailable_for_legal_reasons,
56
+ 500 => :internal_server_error,
57
+ 501 => :not_implemented,
58
+ 502 => :bad_gateway,
59
+ 503 => :service_unavailable,
60
+ 504 => :gateway_timeout,
61
+ 505 => :http_version_not_supported,
62
+ 506 => :variant_also_negotiates,
63
+ 507 => :insufficient_storage,
64
+ 508 => :loop_detected,
65
+ 510 => :not_extended,
66
+ 511 => :network_authentication_required
67
+ }.freeze
68
+
69
+ HTTP_STATUS_CODES.each do |code, name|
70
+ define_method(name) {|*args, **kwargs| respond(*args, **kwargs, status: code) }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require "socket"
5
+ require "uri"
6
+ require_relative 'http_request/response_status_shortcodes'
7
+
8
+ module Itsi
9
+ class HttpRequest
10
+ include Server::TypedHandlers::ParamParser
11
+ include ResponseStatusShortcodes
12
+ attr_accessor :hijacked
13
+
14
+ EMPTY_IO = StringIO.new("")
15
+ RACK_HEADER_MAP = StandardHeaders::ALL.map do |header|
16
+ rack_form = if header == "content-type"
17
+ "CONTENT_TYPE"
18
+ elsif header == "content-length"
19
+ "CONTENT_LENGTH"
20
+ else
21
+ "HTTP_#{header.upcase.gsub(/-/, "_")}"
22
+ end
23
+ [header, rack_form]
24
+ end.to_h.tap do |hm|
25
+ hm.default_proc = proc { |hsh, key| "HTTP_#{key.upcase.gsub(/-/, "_")}" }
26
+ end
27
+
28
+ def to_rack_env
29
+ path = self.path
30
+ host = self.host
31
+ version = self.version
32
+
33
+ {
34
+ "SERVER_SOFTWARE" => "Itsi",
35
+ "SCRIPT_NAME" => script_name,
36
+ "REQUEST_METHOD" => request_method,
37
+ "PATH_INFO" => path,
38
+ "REQUEST_PATH" => path,
39
+ "QUERY_STRING" => query_string,
40
+ "REMOTE_ADDR" => remote_addr,
41
+ "SERVER_PORT" => port.to_s,
42
+ "SERVER_NAME" => host,
43
+ "SERVER_PROTOCOL" => version,
44
+ "HTTP_HOST" => host,
45
+ "HTTP_VERSION" => version,
46
+ "itsi.request" => self,
47
+ "itsi.response" => response,
48
+ "rack.version" => [version],
49
+ "rack.url_scheme" => scheme,
50
+ "rack.input" => build_input_io,
51
+ "rack.errors" => $stderr,
52
+ "rack.multithread" => true,
53
+ "rack.multiprocess" => true,
54
+ "rack.run_once" => false,
55
+ "rack.hijack?" => true,
56
+ "rack.multipart.buffer_size" => 16_384,
57
+ "rack.hijack" => method(:hijack)
58
+ }.tap do |r|
59
+ headers.each do |(k, v)|
60
+ r[case k
61
+ when "content-type" then "CONTENT_TYPE"
62
+ when "content-length" then "CONTENT_LENGTH"
63
+ when "accept" then "HTTP_ACCEPT"
64
+ when "accept-encoding" then "HTTP_ACCEPT_ENCODING"
65
+ when "accept-language" then "HTTP_ACCEPT_LANGUAGE"
66
+ when "user-agent" then "HTTP_USER_AGENT"
67
+ when "referer" then "HTTP_REFERER"
68
+ when "origin" then "HTTP_ORIGIN"
69
+ when "cookie" then "HTTP_COOKIE"
70
+ when "authorization" then "HTTP_AUTHORIZATION"
71
+ when "x-forwarded-for" then "HTTP_X_FORWARDED_FOR"
72
+ when "x-forwarded-proto" then "HTTP_X_FORWARDED_PROTO"
73
+ else RACK_HEADER_MAP[k]
74
+ end
75
+ ] = v
76
+ end
77
+ end
78
+ end
79
+
80
+ def respond(
81
+ _body = nil, _status = 200, _headers = nil,
82
+ json: nil,
83
+ html: nil,
84
+ text: nil,
85
+ xml: nil,
86
+ hijack: false,
87
+ as: nil,
88
+ status: _status,
89
+ headers: _headers,
90
+ body: _body,
91
+ &blk
92
+ )
93
+
94
+ if json
95
+ validate!(json, as: as) if as
96
+ body = json.to_json
97
+ headers ||= {}
98
+ headers["Content-Type"] ||= "application/json"
99
+ elsif html
100
+ body = html
101
+ headers ||= {}
102
+ headers["Content-Type"] ||= "text/html"
103
+ elsif xml
104
+ body = xml
105
+ headers ||= {}
106
+ headers["Content-Type"] ||= "application/xml"
107
+ elsif text
108
+ body = text
109
+ headers ||= {}
110
+ headers["Content-Type"] ||= "text/plain"
111
+ end
112
+
113
+ response.respond(status: status, headers: headers, body: body, hijack: hijack, &blk)
114
+ end
115
+
116
+ def hijack
117
+ self.hijacked = true
118
+ UNIXSocket.pair.yield_self do |(server_sock, app_sock)|
119
+ server_sock.autoclose = false
120
+ self.response.hijack(server_sock.fileno)
121
+ server_sock.sync = true
122
+ app_sock.sync = true
123
+ app_sock
124
+ end
125
+ end
126
+
127
+ def build_input_io
128
+ case body
129
+ when nil then EMPTY_IO
130
+ when String then StringIO.new(body)
131
+ when Array then File.open(body.first, "rb")
132
+ else body
133
+ end
134
+ end
135
+
136
+ def validate!(params, as: nil)
137
+ as ? apply_schema!(params, as) : params
138
+ end
139
+
140
+ def params(schema=nil)
141
+ params = case
142
+ when url_encoded? then URI.decode_www_form(build_input_io.read).to_h
143
+ when json? then JSON.parse(build_input_io.read)
144
+ when multipart?
145
+ Rack::Multipart::Parser.parse(
146
+ build_input_io,
147
+ content_length,
148
+ content_type,
149
+ Rack::Multipart::Parser::TEMPFILE_FACTORY,
150
+ Rack::Multipart::Parser::BUFSIZE,
151
+ Rack::Utils.default_query_parser
152
+ ).params
153
+ else
154
+ {}
155
+ end
156
+
157
+ params.merge!(query_params).merge!(url_params)
158
+
159
+ yield schema ? apply_schema!(params, schema) : params
160
+
161
+ rescue StandardError => e
162
+ if response.json?
163
+ respond(json: {error: e.message}, status: 400)
164
+ else
165
+ respond(e.message, 400)
166
+ end
167
+ ensure
168
+ clean_temp_files(params)
169
+ end
170
+
171
+ def clean_temp_files(params)
172
+ case params
173
+ when Hash
174
+ if params.key?(:tempfile)
175
+ params[:tempfile].unlink
176
+ else
177
+ params.each_value { |v| clean_temp_files(v) }
178
+ end
179
+ when Array then params.each { |v| clean_temp_files(v) }
180
+ end
181
+ end
182
+
183
+ def query_params
184
+ URI.decode_www_form(query_string).to_h
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ require 'forwardable'
3
+ require "stringio"
4
+ require "socket"
5
+
6
+ module Itsi
7
+
8
+ class HttpResponse
9
+
10
+ def respond _body=nil, _status=200, _header=nil, status: _status, headers: _header, body: _body, hijack: false, &blk
11
+ self.status = status
12
+
13
+ body = body.to_s unless body.is_a?(String)
14
+
15
+ if headers
16
+ headers.each do |key, value|
17
+ if value.is_a?(Array)
18
+ value.each { |v| add_header(key, v) }
19
+ else
20
+ add_header(key, value)
21
+ end
22
+ end
23
+ end
24
+
25
+ if body
26
+ # Common case. Write a single string body.
27
+ send_and_close(body)
28
+ elsif block_given?
29
+
30
+ # If you call respond with a block, you get a handle to a stream that you can write to.
31
+ yield self
32
+
33
+ # If you hijack the connection, you are responsible for closing it.
34
+ # Otherwise, the response will be closed automatically.
35
+ self.close unless hijack
36
+ else
37
+ self.close
38
+ end
39
+ end
40
+ end
41
+ end