itsi 0.2.2 → 0.2.4

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 (498) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/Cargo.lock +29 -30
  4. data/README.md +1 -0
  5. data/Rakefile +2 -2
  6. data/crates/itsi_scheduler/Cargo.toml +1 -1
  7. data/crates/itsi_server/Cargo.toml +1 -1
  8. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +26 -3
  9. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +28 -11
  10. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +1 -1
  11. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +1 -2
  12. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +14 -2
  13. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +86 -41
  14. data/crates/itsi_server/src/services/itsi_http_service.rs +46 -35
  15. data/crates/itsi_server/src/services/static_file_server.rs +31 -3
  16. data/docs/content/_index.md +1 -1
  17. data/docs/content/contact/_index.md +1 -1
  18. data/docs/content/directory_listing.jpg +0 -0
  19. data/docs/content/error_page.jpg +0 -0
  20. data/docs/content/getting_started/local_development.md +9 -2
  21. data/docs/content/getting_started/logging.md +1 -2
  22. data/docs/content/getting_started/signals.md +0 -1
  23. data/docs/hugo.yaml +3 -0
  24. data/examples/api_with_schema_and_controllers/Itsi.rb +35 -0
  25. data/examples/api_with_schema_and_controllers/README.md +10 -0
  26. data/examples/api_with_schema_and_controllers/controllers.rb +66 -0
  27. data/examples/api_with_schema_and_controllers/schemas.rb +25 -0
  28. data/examples/file_server/Itsi.rb +30 -0
  29. data/examples/file_server/README.md +3 -0
  30. data/examples/file_server/about.html +80 -0
  31. data/examples/file_server/admin/secrets.txt +1 -0
  32. data/examples/file_server/fairytale.txt +33 -0
  33. data/examples/file_server/itsi-server-100.png +0 -0
  34. data/examples/file_server/subdirectory/movies.csv +21 -0
  35. data/examples/helpers/datastore.rb +84 -0
  36. data/examples/media_server/Itsi.rb +5 -0
  37. data/examples/media_server/README.md +3 -0
  38. data/examples/media_server/images/itsi-server-100.png +0 -0
  39. data/examples/media_server/index.html +82 -0
  40. data/examples/multi_rack_rails_sinatra/Gemfile +66 -0
  41. data/examples/multi_rack_rails_sinatra/Gemfile.lock +416 -0
  42. data/examples/multi_rack_rails_sinatra/Itsi.rb +44 -0
  43. data/examples/multi_rack_rails_sinatra/README.md +7 -0
  44. data/examples/multi_rack_rails_sinatra/index.html +119 -0
  45. data/examples/multi_rack_rails_sinatra/rails_subapp/.dockerignore +51 -0
  46. data/examples/multi_rack_rails_sinatra/rails_subapp/.gitattributes +9 -0
  47. data/examples/multi_rack_rails_sinatra/rails_subapp/.github/dependabot.yml +12 -0
  48. data/examples/multi_rack_rails_sinatra/rails_subapp/.github/workflows/ci.yml +90 -0
  49. data/examples/multi_rack_rails_sinatra/rails_subapp/.gitignore +34 -0
  50. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/docker-setup.sample +3 -0
  51. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-app-boot.sample +3 -0
  52. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-deploy.sample +14 -0
  53. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-proxy-reboot.sample +3 -0
  54. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-app-boot.sample +3 -0
  55. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-build.sample +51 -0
  56. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-connect.sample +47 -0
  57. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-deploy.sample +109 -0
  58. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  59. data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/secrets +17 -0
  60. data/examples/multi_rack_rails_sinatra/rails_subapp/.rubocop.yml +8 -0
  61. data/examples/multi_rack_rails_sinatra/rails_subapp/.ruby-version +1 -0
  62. data/examples/multi_rack_rails_sinatra/rails_subapp/Dockerfile +72 -0
  63. data/examples/multi_rack_rails_sinatra/rails_subapp/Gemfile +66 -0
  64. data/examples/multi_rack_rails_sinatra/rails_subapp/Gemfile.lock +416 -0
  65. data/examples/multi_rack_rails_sinatra/rails_subapp/README.md +24 -0
  66. data/examples/multi_rack_rails_sinatra/rails_subapp/Rakefile +6 -0
  67. data/examples/multi_rack_rails_sinatra/rails_subapp/app/assets/images/.keep +0 -0
  68. data/examples/multi_rack_rails_sinatra/rails_subapp/app/assets/stylesheets/application.css +161 -0
  69. data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/application_controller.rb +4 -0
  70. data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/articles_controller.rb +70 -0
  71. data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/concerns/.keep +0 -0
  72. data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/home_controller.rb +4 -0
  73. data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/application_helper.rb +2 -0
  74. data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/articles_helper.rb +2 -0
  75. data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/home_helper.rb +2 -0
  76. data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/application.js +3 -0
  77. data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/application.js +9 -0
  78. data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/hello_controller.js +7 -0
  79. data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/index.js +4 -0
  80. data/examples/multi_rack_rails_sinatra/rails_subapp/app/jobs/application_job.rb +7 -0
  81. data/examples/multi_rack_rails_sinatra/rails_subapp/app/mailers/application_mailer.rb +4 -0
  82. data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/application_record.rb +3 -0
  83. data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/article.rb +2 -0
  84. data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/concerns/.keep +0 -0
  85. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_article.html.erb +14 -0
  86. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_article.json.jbuilder +2 -0
  87. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_form.html.erb +30 -0
  88. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/edit.html.erb +12 -0
  89. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/index.html.erb +29 -0
  90. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/index.json.jbuilder +1 -0
  91. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/new.html.erb +11 -0
  92. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/show.html.erb +10 -0
  93. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/show.json.jbuilder +1 -0
  94. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/home/index.html.erb +8 -0
  95. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/application.html.erb +34 -0
  96. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/mailer.html.erb +13 -0
  97. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/mailer.text.erb +1 -0
  98. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/pwa/manifest.json.erb +22 -0
  99. data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/pwa/service-worker.js +26 -0
  100. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/brakeman +7 -0
  101. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/bundle +109 -0
  102. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/dev +2 -0
  103. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/docker-entrypoint +14 -0
  104. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/importmap +4 -0
  105. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/jobs +6 -0
  106. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/kamal +27 -0
  107. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rails +4 -0
  108. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rake +4 -0
  109. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rubocop +8 -0
  110. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/setup +34 -0
  111. data/examples/multi_rack_rails_sinatra/rails_subapp/bin/thrust +5 -0
  112. data/examples/multi_rack_rails_sinatra/rails_subapp/config/application.rb +27 -0
  113. data/examples/multi_rack_rails_sinatra/rails_subapp/config/boot.rb +4 -0
  114. data/examples/multi_rack_rails_sinatra/rails_subapp/config/cable.yml +17 -0
  115. data/examples/multi_rack_rails_sinatra/rails_subapp/config/cache.yml +16 -0
  116. data/examples/multi_rack_rails_sinatra/rails_subapp/config/credentials.yml.enc +1 -0
  117. data/examples/multi_rack_rails_sinatra/rails_subapp/config/database.yml +41 -0
  118. data/examples/multi_rack_rails_sinatra/rails_subapp/config/deploy.yml +116 -0
  119. data/examples/multi_rack_rails_sinatra/rails_subapp/config/environment.rb +5 -0
  120. data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/development.rb +72 -0
  121. data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/production.rb +90 -0
  122. data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/test.rb +53 -0
  123. data/examples/multi_rack_rails_sinatra/rails_subapp/config/importmap.rb +7 -0
  124. data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/assets.rb +7 -0
  125. data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/content_security_policy.rb +25 -0
  126. data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/filter_parameter_logging.rb +8 -0
  127. data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/inflections.rb +16 -0
  128. data/examples/multi_rack_rails_sinatra/rails_subapp/config/locales/en.yml +31 -0
  129. data/examples/multi_rack_rails_sinatra/rails_subapp/config/puma.rb +41 -0
  130. data/examples/multi_rack_rails_sinatra/rails_subapp/config/queue.yml +18 -0
  131. data/examples/multi_rack_rails_sinatra/rails_subapp/config/recurring.yml +10 -0
  132. data/examples/multi_rack_rails_sinatra/rails_subapp/config/routes.rb +17 -0
  133. data/examples/multi_rack_rails_sinatra/rails_subapp/config/storage.yml +34 -0
  134. data/examples/multi_rack_rails_sinatra/rails_subapp/config.ru +6 -0
  135. data/examples/multi_rack_rails_sinatra/rails_subapp/db/cable_schema.rb +11 -0
  136. data/examples/multi_rack_rails_sinatra/rails_subapp/db/cache_schema.rb +14 -0
  137. data/examples/multi_rack_rails_sinatra/rails_subapp/db/migrate/20250422211855_create_articles.rb +10 -0
  138. data/examples/multi_rack_rails_sinatra/rails_subapp/db/queue_schema.rb +129 -0
  139. data/examples/multi_rack_rails_sinatra/rails_subapp/db/schema.rb +20 -0
  140. data/examples/multi_rack_rails_sinatra/rails_subapp/db/seeds.rb +9 -0
  141. data/examples/multi_rack_rails_sinatra/rails_subapp/lib/tasks/.keep +0 -0
  142. data/examples/multi_rack_rails_sinatra/rails_subapp/log/.keep +0 -0
  143. data/examples/multi_rack_rails_sinatra/rails_subapp/public/400.html +114 -0
  144. data/examples/multi_rack_rails_sinatra/rails_subapp/public/404.html +114 -0
  145. data/examples/multi_rack_rails_sinatra/rails_subapp/public/406-unsupported-browser.html +114 -0
  146. data/examples/multi_rack_rails_sinatra/rails_subapp/public/422.html +114 -0
  147. data/examples/multi_rack_rails_sinatra/rails_subapp/public/500.html +114 -0
  148. data/examples/multi_rack_rails_sinatra/rails_subapp/public/icon.png +0 -0
  149. data/examples/multi_rack_rails_sinatra/rails_subapp/public/icon.svg +3 -0
  150. data/examples/multi_rack_rails_sinatra/rails_subapp/public/robots.txt +1 -0
  151. data/examples/multi_rack_rails_sinatra/rails_subapp/script/.keep +0 -0
  152. data/examples/multi_rack_rails_sinatra/rails_subapp/storage/.keep +0 -0
  153. data/examples/multi_rack_rails_sinatra/rails_subapp/test/application_system_test_case.rb +5 -0
  154. data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/.keep +0 -0
  155. data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/articles_controller_test.rb +48 -0
  156. data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/home_controller_test.rb +8 -0
  157. data/examples/multi_rack_rails_sinatra/rails_subapp/test/fixtures/articles.yml +9 -0
  158. data/examples/multi_rack_rails_sinatra/rails_subapp/test/fixtures/files/.keep +0 -0
  159. data/examples/multi_rack_rails_sinatra/rails_subapp/test/helpers/.keep +0 -0
  160. data/examples/multi_rack_rails_sinatra/rails_subapp/test/integration/.keep +0 -0
  161. data/examples/multi_rack_rails_sinatra/rails_subapp/test/mailers/.keep +0 -0
  162. data/examples/multi_rack_rails_sinatra/rails_subapp/test/models/.keep +0 -0
  163. data/examples/multi_rack_rails_sinatra/rails_subapp/test/models/article_test.rb +7 -0
  164. data/examples/multi_rack_rails_sinatra/rails_subapp/test/system/.keep +0 -0
  165. data/examples/multi_rack_rails_sinatra/rails_subapp/test/system/articles_test.rb +43 -0
  166. data/examples/multi_rack_rails_sinatra/rails_subapp/test/test_helper.rb +15 -0
  167. data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/.keep +0 -0
  168. data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/pids/.keep +0 -0
  169. data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/storage/.keep +0 -0
  170. data/examples/multi_rack_rails_sinatra/rails_subapp/vendor/.keep +0 -0
  171. data/examples/multi_rack_rails_sinatra/rails_subapp/vendor/javascript/.keep +0 -0
  172. data/examples/multi_rack_rails_sinatra/sinatra_subapp/config.ru +2 -0
  173. data/examples/multi_rack_rails_sinatra/sinatra_subapp/my_app.rb +96 -0
  174. data/examples/rails_with_static_assets/.dockerignore +51 -0
  175. data/examples/rails_with_static_assets/.gitattributes +9 -0
  176. data/examples/rails_with_static_assets/.github/dependabot.yml +12 -0
  177. data/examples/rails_with_static_assets/.github/workflows/ci.yml +90 -0
  178. data/examples/rails_with_static_assets/.gitignore +34 -0
  179. data/examples/rails_with_static_assets/.kamal/hooks/docker-setup.sample +3 -0
  180. data/examples/rails_with_static_assets/.kamal/hooks/post-app-boot.sample +3 -0
  181. data/examples/rails_with_static_assets/.kamal/hooks/post-deploy.sample +14 -0
  182. data/examples/rails_with_static_assets/.kamal/hooks/post-proxy-reboot.sample +3 -0
  183. data/examples/rails_with_static_assets/.kamal/hooks/pre-app-boot.sample +3 -0
  184. data/examples/rails_with_static_assets/.kamal/hooks/pre-build.sample +51 -0
  185. data/examples/rails_with_static_assets/.kamal/hooks/pre-connect.sample +47 -0
  186. data/examples/rails_with_static_assets/.kamal/hooks/pre-deploy.sample +109 -0
  187. data/examples/rails_with_static_assets/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  188. data/examples/rails_with_static_assets/.kamal/secrets +17 -0
  189. data/examples/rails_with_static_assets/.rubocop.yml +8 -0
  190. data/examples/rails_with_static_assets/.ruby-version +1 -0
  191. data/examples/rails_with_static_assets/Dockerfile +72 -0
  192. data/examples/rails_with_static_assets/Gemfile +66 -0
  193. data/examples/rails_with_static_assets/Gemfile.lock +416 -0
  194. data/examples/rails_with_static_assets/Itsi.rb +10 -0
  195. data/examples/rails_with_static_assets/README.md +14 -0
  196. data/examples/rails_with_static_assets/Rakefile +6 -0
  197. data/examples/rails_with_static_assets/app/assets/images/.keep +0 -0
  198. data/examples/rails_with_static_assets/app/assets/stylesheets/application.css +161 -0
  199. data/examples/rails_with_static_assets/app/controllers/application_controller.rb +4 -0
  200. data/examples/rails_with_static_assets/app/controllers/articles_controller.rb +70 -0
  201. data/examples/rails_with_static_assets/app/controllers/concerns/.keep +0 -0
  202. data/examples/rails_with_static_assets/app/controllers/home_controller.rb +4 -0
  203. data/examples/rails_with_static_assets/app/helpers/application_helper.rb +2 -0
  204. data/examples/rails_with_static_assets/app/helpers/articles_helper.rb +2 -0
  205. data/examples/rails_with_static_assets/app/helpers/home_helper.rb +2 -0
  206. data/examples/rails_with_static_assets/app/javascript/application.js +3 -0
  207. data/examples/rails_with_static_assets/app/javascript/controllers/application.js +9 -0
  208. data/examples/rails_with_static_assets/app/javascript/controllers/hello_controller.js +7 -0
  209. data/examples/rails_with_static_assets/app/javascript/controllers/index.js +4 -0
  210. data/examples/rails_with_static_assets/app/jobs/application_job.rb +7 -0
  211. data/examples/rails_with_static_assets/app/mailers/application_mailer.rb +4 -0
  212. data/examples/rails_with_static_assets/app/models/application_record.rb +3 -0
  213. data/examples/rails_with_static_assets/app/models/article.rb +2 -0
  214. data/examples/rails_with_static_assets/app/models/concerns/.keep +0 -0
  215. data/examples/rails_with_static_assets/app/views/articles/_article.html.erb +14 -0
  216. data/examples/rails_with_static_assets/app/views/articles/_article.json.jbuilder +2 -0
  217. data/examples/rails_with_static_assets/app/views/articles/_form.html.erb +30 -0
  218. data/examples/rails_with_static_assets/app/views/articles/edit.html.erb +12 -0
  219. data/examples/rails_with_static_assets/app/views/articles/index.html.erb +29 -0
  220. data/examples/rails_with_static_assets/app/views/articles/index.json.jbuilder +1 -0
  221. data/examples/rails_with_static_assets/app/views/articles/new.html.erb +11 -0
  222. data/examples/rails_with_static_assets/app/views/articles/show.html.erb +10 -0
  223. data/examples/rails_with_static_assets/app/views/articles/show.json.jbuilder +1 -0
  224. data/examples/rails_with_static_assets/app/views/home/index.html.erb +8 -0
  225. data/examples/rails_with_static_assets/app/views/layouts/application.html.erb +34 -0
  226. data/examples/rails_with_static_assets/app/views/layouts/mailer.html.erb +13 -0
  227. data/examples/rails_with_static_assets/app/views/layouts/mailer.text.erb +1 -0
  228. data/examples/rails_with_static_assets/app/views/pwa/manifest.json.erb +22 -0
  229. data/examples/rails_with_static_assets/app/views/pwa/service-worker.js +26 -0
  230. data/examples/rails_with_static_assets/bin/brakeman +7 -0
  231. data/examples/rails_with_static_assets/bin/bundle +109 -0
  232. data/examples/rails_with_static_assets/bin/dev +2 -0
  233. data/examples/rails_with_static_assets/bin/docker-entrypoint +14 -0
  234. data/examples/rails_with_static_assets/bin/importmap +4 -0
  235. data/examples/rails_with_static_assets/bin/jobs +6 -0
  236. data/examples/rails_with_static_assets/bin/kamal +27 -0
  237. data/examples/rails_with_static_assets/bin/rails +4 -0
  238. data/examples/rails_with_static_assets/bin/rake +4 -0
  239. data/examples/rails_with_static_assets/bin/rubocop +8 -0
  240. data/examples/rails_with_static_assets/bin/setup +34 -0
  241. data/examples/rails_with_static_assets/bin/thrust +5 -0
  242. data/examples/rails_with_static_assets/config/application.rb +26 -0
  243. data/examples/rails_with_static_assets/config/boot.rb +4 -0
  244. data/examples/rails_with_static_assets/config/cable.yml +17 -0
  245. data/examples/rails_with_static_assets/config/cache.yml +16 -0
  246. data/examples/rails_with_static_assets/config/credentials.yml.enc +1 -0
  247. data/examples/rails_with_static_assets/config/database.yml +41 -0
  248. data/examples/rails_with_static_assets/config/deploy.yml +116 -0
  249. data/examples/rails_with_static_assets/config/environment.rb +5 -0
  250. data/examples/rails_with_static_assets/config/environments/development.rb +74 -0
  251. data/examples/rails_with_static_assets/config/environments/production.rb +90 -0
  252. data/examples/rails_with_static_assets/config/environments/test.rb +53 -0
  253. data/examples/rails_with_static_assets/config/importmap.rb +7 -0
  254. data/examples/rails_with_static_assets/config/initializers/assets.rb +7 -0
  255. data/examples/rails_with_static_assets/config/initializers/content_security_policy.rb +25 -0
  256. data/examples/rails_with_static_assets/config/initializers/filter_parameter_logging.rb +8 -0
  257. data/examples/rails_with_static_assets/config/initializers/inflections.rb +16 -0
  258. data/examples/rails_with_static_assets/config/locales/en.yml +31 -0
  259. data/examples/rails_with_static_assets/config/puma.rb +41 -0
  260. data/examples/rails_with_static_assets/config/queue.yml +18 -0
  261. data/examples/rails_with_static_assets/config/recurring.yml +10 -0
  262. data/examples/rails_with_static_assets/config/routes.rb +17 -0
  263. data/examples/rails_with_static_assets/config/storage.yml +34 -0
  264. data/examples/rails_with_static_assets/config.ru +6 -0
  265. data/examples/rails_with_static_assets/db/cable_schema.rb +11 -0
  266. data/examples/rails_with_static_assets/db/cache_schema.rb +14 -0
  267. data/examples/rails_with_static_assets/db/migrate/20250422211855_create_articles.rb +10 -0
  268. data/examples/rails_with_static_assets/db/queue_schema.rb +129 -0
  269. data/examples/rails_with_static_assets/db/schema.rb +20 -0
  270. data/examples/rails_with_static_assets/db/seeds.rb +9 -0
  271. data/examples/rails_with_static_assets/lib/tasks/.keep +0 -0
  272. data/examples/rails_with_static_assets/log/.keep +0 -0
  273. data/examples/rails_with_static_assets/public/400.html +114 -0
  274. data/examples/rails_with_static_assets/public/404.html +114 -0
  275. data/examples/rails_with_static_assets/public/406-unsupported-browser.html +114 -0
  276. data/examples/rails_with_static_assets/public/422.html +114 -0
  277. data/examples/rails_with_static_assets/public/500.html +114 -0
  278. data/examples/rails_with_static_assets/public/icon.png +0 -0
  279. data/examples/rails_with_static_assets/public/icon.svg +3 -0
  280. data/examples/rails_with_static_assets/public/robots.txt +1 -0
  281. data/examples/rails_with_static_assets/script/.keep +0 -0
  282. data/examples/rails_with_static_assets/storage/.keep +0 -0
  283. data/examples/rails_with_static_assets/test/application_system_test_case.rb +5 -0
  284. data/examples/rails_with_static_assets/test/controllers/.keep +0 -0
  285. data/examples/rails_with_static_assets/test/controllers/articles_controller_test.rb +48 -0
  286. data/examples/rails_with_static_assets/test/controllers/home_controller_test.rb +8 -0
  287. data/examples/rails_with_static_assets/test/fixtures/articles.yml +9 -0
  288. data/examples/rails_with_static_assets/test/fixtures/files/.keep +0 -0
  289. data/examples/rails_with_static_assets/test/helpers/.keep +0 -0
  290. data/examples/rails_with_static_assets/test/integration/.keep +0 -0
  291. data/examples/rails_with_static_assets/test/mailers/.keep +0 -0
  292. data/examples/rails_with_static_assets/test/models/.keep +0 -0
  293. data/examples/rails_with_static_assets/test/models/article_test.rb +7 -0
  294. data/examples/rails_with_static_assets/test/system/.keep +0 -0
  295. data/examples/rails_with_static_assets/test/system/articles_test.rb +43 -0
  296. data/examples/rails_with_static_assets/test/test_helper.rb +15 -0
  297. data/examples/rails_with_static_assets/tmp/.keep +0 -0
  298. data/examples/rails_with_static_assets/tmp/pids/.keep +0 -0
  299. data/examples/rails_with_static_assets/tmp/storage/.keep +0 -0
  300. data/examples/rails_with_static_assets/vendor/.keep +0 -0
  301. data/examples/rails_with_static_assets/vendor/javascript/.keep +0 -0
  302. data/examples/reverse_proxy/Itsi.rb +28 -0
  303. data/examples/reverse_proxy/README.md +14 -0
  304. data/examples/reverse_proxy/index.html +119 -0
  305. data/examples/reverse_proxy/rails_subapp/.dockerignore +51 -0
  306. data/examples/reverse_proxy/rails_subapp/.gitattributes +9 -0
  307. data/examples/reverse_proxy/rails_subapp/.github/dependabot.yml +12 -0
  308. data/examples/reverse_proxy/rails_subapp/.github/workflows/ci.yml +90 -0
  309. data/examples/reverse_proxy/rails_subapp/.gitignore +34 -0
  310. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/docker-setup.sample +3 -0
  311. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-app-boot.sample +3 -0
  312. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-deploy.sample +14 -0
  313. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-proxy-reboot.sample +3 -0
  314. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-app-boot.sample +3 -0
  315. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-build.sample +51 -0
  316. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-connect.sample +47 -0
  317. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-deploy.sample +109 -0
  318. data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  319. data/examples/reverse_proxy/rails_subapp/.kamal/secrets +17 -0
  320. data/examples/reverse_proxy/rails_subapp/.rubocop.yml +8 -0
  321. data/examples/reverse_proxy/rails_subapp/.ruby-version +1 -0
  322. data/examples/reverse_proxy/rails_subapp/Dockerfile +72 -0
  323. data/examples/reverse_proxy/rails_subapp/Gemfile +66 -0
  324. data/examples/reverse_proxy/rails_subapp/Gemfile.lock +416 -0
  325. data/examples/reverse_proxy/rails_subapp/README.md +24 -0
  326. data/examples/reverse_proxy/rails_subapp/Rakefile +6 -0
  327. data/examples/reverse_proxy/rails_subapp/app/assets/images/.keep +0 -0
  328. data/examples/reverse_proxy/rails_subapp/app/assets/stylesheets/application.css +161 -0
  329. data/examples/reverse_proxy/rails_subapp/app/controllers/application_controller.rb +4 -0
  330. data/examples/reverse_proxy/rails_subapp/app/controllers/articles_controller.rb +70 -0
  331. data/examples/reverse_proxy/rails_subapp/app/controllers/concerns/.keep +0 -0
  332. data/examples/reverse_proxy/rails_subapp/app/controllers/home_controller.rb +4 -0
  333. data/examples/reverse_proxy/rails_subapp/app/helpers/application_helper.rb +2 -0
  334. data/examples/reverse_proxy/rails_subapp/app/helpers/articles_helper.rb +2 -0
  335. data/examples/reverse_proxy/rails_subapp/app/helpers/home_helper.rb +2 -0
  336. data/examples/reverse_proxy/rails_subapp/app/javascript/application.js +3 -0
  337. data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/application.js +9 -0
  338. data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/hello_controller.js +7 -0
  339. data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/index.js +4 -0
  340. data/examples/reverse_proxy/rails_subapp/app/jobs/application_job.rb +7 -0
  341. data/examples/reverse_proxy/rails_subapp/app/mailers/application_mailer.rb +4 -0
  342. data/examples/reverse_proxy/rails_subapp/app/models/application_record.rb +3 -0
  343. data/examples/reverse_proxy/rails_subapp/app/models/article.rb +2 -0
  344. data/examples/reverse_proxy/rails_subapp/app/models/concerns/.keep +0 -0
  345. data/examples/reverse_proxy/rails_subapp/app/views/articles/_article.html.erb +14 -0
  346. data/examples/reverse_proxy/rails_subapp/app/views/articles/_article.json.jbuilder +2 -0
  347. data/examples/reverse_proxy/rails_subapp/app/views/articles/_form.html.erb +30 -0
  348. data/examples/reverse_proxy/rails_subapp/app/views/articles/edit.html.erb +12 -0
  349. data/examples/reverse_proxy/rails_subapp/app/views/articles/index.html.erb +29 -0
  350. data/examples/reverse_proxy/rails_subapp/app/views/articles/index.json.jbuilder +1 -0
  351. data/examples/reverse_proxy/rails_subapp/app/views/articles/new.html.erb +11 -0
  352. data/examples/reverse_proxy/rails_subapp/app/views/articles/show.html.erb +10 -0
  353. data/examples/reverse_proxy/rails_subapp/app/views/articles/show.json.jbuilder +1 -0
  354. data/examples/reverse_proxy/rails_subapp/app/views/home/index.html.erb +8 -0
  355. data/examples/reverse_proxy/rails_subapp/app/views/layouts/application.html.erb +34 -0
  356. data/examples/reverse_proxy/rails_subapp/app/views/layouts/mailer.html.erb +13 -0
  357. data/examples/reverse_proxy/rails_subapp/app/views/layouts/mailer.text.erb +1 -0
  358. data/examples/reverse_proxy/rails_subapp/app/views/pwa/manifest.json.erb +22 -0
  359. data/examples/reverse_proxy/rails_subapp/app/views/pwa/service-worker.js +26 -0
  360. data/examples/reverse_proxy/rails_subapp/bin/brakeman +7 -0
  361. data/examples/reverse_proxy/rails_subapp/bin/bundle +109 -0
  362. data/examples/reverse_proxy/rails_subapp/bin/dev +2 -0
  363. data/examples/reverse_proxy/rails_subapp/bin/docker-entrypoint +14 -0
  364. data/examples/reverse_proxy/rails_subapp/bin/importmap +4 -0
  365. data/examples/reverse_proxy/rails_subapp/bin/jobs +6 -0
  366. data/examples/reverse_proxy/rails_subapp/bin/kamal +27 -0
  367. data/examples/reverse_proxy/rails_subapp/bin/rails +4 -0
  368. data/examples/reverse_proxy/rails_subapp/bin/rake +4 -0
  369. data/examples/reverse_proxy/rails_subapp/bin/rubocop +8 -0
  370. data/examples/reverse_proxy/rails_subapp/bin/setup +34 -0
  371. data/examples/reverse_proxy/rails_subapp/bin/thrust +5 -0
  372. data/examples/reverse_proxy/rails_subapp/config/application.rb +26 -0
  373. data/examples/reverse_proxy/rails_subapp/config/boot.rb +4 -0
  374. data/examples/reverse_proxy/rails_subapp/config/cable.yml +17 -0
  375. data/examples/reverse_proxy/rails_subapp/config/cache.yml +16 -0
  376. data/examples/reverse_proxy/rails_subapp/config/credentials.yml.enc +1 -0
  377. data/examples/reverse_proxy/rails_subapp/config/database.yml +41 -0
  378. data/examples/reverse_proxy/rails_subapp/config/deploy.yml +116 -0
  379. data/examples/reverse_proxy/rails_subapp/config/environment.rb +5 -0
  380. data/examples/reverse_proxy/rails_subapp/config/environments/development.rb +72 -0
  381. data/examples/reverse_proxy/rails_subapp/config/environments/production.rb +90 -0
  382. data/examples/reverse_proxy/rails_subapp/config/environments/test.rb +53 -0
  383. data/examples/reverse_proxy/rails_subapp/config/importmap.rb +7 -0
  384. data/examples/reverse_proxy/rails_subapp/config/initializers/assets.rb +7 -0
  385. data/examples/reverse_proxy/rails_subapp/config/initializers/content_security_policy.rb +25 -0
  386. data/examples/reverse_proxy/rails_subapp/config/initializers/filter_parameter_logging.rb +8 -0
  387. data/examples/reverse_proxy/rails_subapp/config/initializers/inflections.rb +16 -0
  388. data/examples/reverse_proxy/rails_subapp/config/locales/en.yml +31 -0
  389. data/examples/reverse_proxy/rails_subapp/config/puma.rb +41 -0
  390. data/examples/reverse_proxy/rails_subapp/config/queue.yml +18 -0
  391. data/examples/reverse_proxy/rails_subapp/config/recurring.yml +10 -0
  392. data/examples/reverse_proxy/rails_subapp/config/routes.rb +17 -0
  393. data/examples/reverse_proxy/rails_subapp/config/storage.yml +34 -0
  394. data/examples/reverse_proxy/rails_subapp/config.ru +6 -0
  395. data/examples/reverse_proxy/rails_subapp/db/cable_schema.rb +11 -0
  396. data/examples/reverse_proxy/rails_subapp/db/cache_schema.rb +14 -0
  397. data/examples/reverse_proxy/rails_subapp/db/migrate/20250422211855_create_articles.rb +10 -0
  398. data/examples/reverse_proxy/rails_subapp/db/queue_schema.rb +129 -0
  399. data/examples/reverse_proxy/rails_subapp/db/schema.rb +20 -0
  400. data/examples/reverse_proxy/rails_subapp/db/seeds.rb +9 -0
  401. data/examples/reverse_proxy/rails_subapp/lib/tasks/.keep +0 -0
  402. data/examples/reverse_proxy/rails_subapp/log/.keep +0 -0
  403. data/examples/reverse_proxy/rails_subapp/public/400.html +114 -0
  404. data/examples/reverse_proxy/rails_subapp/public/404.html +114 -0
  405. data/examples/reverse_proxy/rails_subapp/public/406-unsupported-browser.html +114 -0
  406. data/examples/reverse_proxy/rails_subapp/public/422.html +114 -0
  407. data/examples/reverse_proxy/rails_subapp/public/500.html +114 -0
  408. data/examples/reverse_proxy/rails_subapp/public/icon.png +0 -0
  409. data/examples/reverse_proxy/rails_subapp/public/icon.svg +3 -0
  410. data/examples/reverse_proxy/rails_subapp/public/robots.txt +1 -0
  411. data/examples/reverse_proxy/rails_subapp/script/.keep +0 -0
  412. data/examples/reverse_proxy/rails_subapp/storage/.keep +0 -0
  413. data/examples/reverse_proxy/rails_subapp/test/application_system_test_case.rb +5 -0
  414. data/examples/reverse_proxy/rails_subapp/test/controllers/.keep +0 -0
  415. data/examples/reverse_proxy/rails_subapp/test/controllers/articles_controller_test.rb +48 -0
  416. data/examples/reverse_proxy/rails_subapp/test/controllers/home_controller_test.rb +8 -0
  417. data/examples/reverse_proxy/rails_subapp/test/fixtures/articles.yml +9 -0
  418. data/examples/reverse_proxy/rails_subapp/test/fixtures/files/.keep +0 -0
  419. data/examples/reverse_proxy/rails_subapp/test/helpers/.keep +0 -0
  420. data/examples/reverse_proxy/rails_subapp/test/integration/.keep +0 -0
  421. data/examples/reverse_proxy/rails_subapp/test/mailers/.keep +0 -0
  422. data/examples/reverse_proxy/rails_subapp/test/models/.keep +0 -0
  423. data/examples/reverse_proxy/rails_subapp/test/models/article_test.rb +7 -0
  424. data/examples/reverse_proxy/rails_subapp/test/system/.keep +0 -0
  425. data/examples/reverse_proxy/rails_subapp/test/system/articles_test.rb +43 -0
  426. data/examples/reverse_proxy/rails_subapp/test/test_helper.rb +15 -0
  427. data/examples/reverse_proxy/rails_subapp/tmp/.keep +0 -0
  428. data/examples/reverse_proxy/rails_subapp/tmp/pids/.keep +0 -0
  429. data/examples/reverse_proxy/rails_subapp/tmp/storage/.keep +0 -0
  430. data/examples/reverse_proxy/rails_subapp/vendor/.keep +0 -0
  431. data/examples/reverse_proxy/rails_subapp/vendor/javascript/.keep +0 -0
  432. data/examples/reverse_proxy/sinatra_subapp/Gemfile +2 -0
  433. data/examples/reverse_proxy/sinatra_subapp/Gemfile.lock +46 -0
  434. data/examples/reverse_proxy/sinatra_subapp/config.ru +2 -0
  435. data/examples/reverse_proxy/sinatra_subapp/my_app.rb +96 -0
  436. data/examples/simple_api/Itsi.rb +127 -0
  437. data/examples/simple_api_no_schema/Itsi.rb +86 -0
  438. data/examples/spa/Itsi.rb +5 -0
  439. data/examples/spa/README.md +3 -0
  440. data/examples/spa/dist/assets/index-2cf7be43.js +40 -0
  441. data/examples/spa/dist/index.html +13 -0
  442. data/examples/spa/index.html +12 -0
  443. data/examples/spa/package-lock.json +1265 -0
  444. data/examples/spa/package.json +18 -0
  445. data/examples/spa/src/App.jsx +49 -0
  446. data/examples/spa/src/main.jsx +6 -0
  447. data/examples/spa/src/pages/About.jsx +9 -0
  448. data/examples/spa/src/pages/Home.jsx +9 -0
  449. data/examples/spa/vite.config.js +9 -0
  450. data/gems/scheduler/Cargo.lock +74 -17
  451. data/gems/scheduler/itsi-scheduler.gemspec +2 -2
  452. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  453. data/gems/server/Cargo.lock +28 -29
  454. data/gems/server/itsi-server.gemspec +2 -2
  455. data/gems/server/lib/itsi/http_request.rb +31 -34
  456. data/gems/server/lib/itsi/http_response.rb +10 -8
  457. data/gems/server/lib/itsi/passfile.rb +6 -6
  458. data/gems/server/lib/itsi/server/config/config_helpers.rb +33 -33
  459. data/gems/server/lib/itsi/server/config/dsl.rb +16 -21
  460. data/gems/server/lib/itsi/server/config/known_paths.rb +11 -7
  461. data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +0 -4
  462. data/gems/server/lib/itsi/server/config/middleware/error_response.md +13 -0
  463. data/gems/server/lib/itsi/server/config/middleware/location.rb +25 -21
  464. data/gems/server/lib/itsi/server/config/middleware/proxy.rb +15 -14
  465. data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +7 -10
  466. data/gems/server/lib/itsi/server/config/middleware/static_assets.md +40 -0
  467. data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +8 -4
  468. data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +14 -0
  469. data/gems/server/lib/itsi/server/config/option.rb +0 -1
  470. data/gems/server/lib/itsi/server/config/options/include.rb +1 -1
  471. data/gems/server/lib/itsi/server/config/options/nodelay.md +2 -2
  472. data/gems/server/lib/itsi/server/config/options/reuse_address.md +1 -1
  473. data/gems/server/lib/itsi/server/config/typed_struct.rb +32 -35
  474. data/gems/server/lib/itsi/server/config.rb +107 -92
  475. data/gems/server/lib/itsi/server/default_app/default_app.rb +1 -1
  476. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +4 -5
  477. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +6 -7
  478. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +0 -1
  479. data/gems/server/lib/itsi/server/rack_interface.rb +1 -2
  480. data/gems/server/lib/itsi/server/route_tester.rb +26 -24
  481. data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +25 -0
  482. data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +9 -7
  483. data/gems/server/lib/itsi/server/version.rb +1 -1
  484. data/gems/server/lib/itsi/server.rb +22 -22
  485. data/gems/server/lib/itsi/standard_headers.rb +80 -80
  486. data/gems/server/test/helpers/test_helper.rb +17 -16
  487. data/gems/server/test/middleware/static_assets.rb +6 -4
  488. data/gems/server/test/middleware/string_rewrite.rb +54 -0
  489. data/gems/server/test/middleware/test_log_requests.rb +66 -2
  490. data/gems/server/test/options/test_workers.rb +12 -5
  491. data/lib/itsi/version.rb +1 -1
  492. metadata +435 -13
  493. data/examples/static_assets_example.rb +0 -83
  494. data/grpc_test/Itsi.rb +0 -11
  495. data/grpc_test/echo.proto +0 -14
  496. data/grpc_test/echo_pb.rb +0 -16
  497. data/grpc_test/echo_service_impl.rb +0 -8
  498. data/grpc_test/echo_services_pb.rb +0 -22
@@ -2,9 +2,10 @@ module Itsi
2
2
  class Server
3
3
  module TypedHandlers
4
4
  module SourceParser
5
- require 'prism'
6
-
5
+ require "prism"
7
6
 
7
+ # Source Parser interprets endpoint handlers
8
+ # and extracts arity and schema information.
8
9
  def self.extract_expr_from_source_location(proc)
9
10
  source_location = proc.source_location
10
11
  source_lines = IO.readlines(source_location.first)
@@ -23,17 +24,19 @@ module Itsi
23
24
 
24
25
  lines[1..-1].each do |line|
25
26
  break if intermediate.success?
27
+
26
28
  token_count = 0
27
29
  line.split(/(?=\s|;|\)|\})/).each do |token|
28
30
  src_str << token
29
31
  token_count += 1
30
32
  intermediate = Prism.parse(src_str)
31
33
  next unless intermediate.success? && token_count > 1
34
+
32
35
  break
33
36
  end
34
37
  end
35
38
 
36
- raise 'Source Extraction Failed' unless intermediate.success?
39
+ raise "Source Extraction Failed" unless intermediate.success?
37
40
 
38
41
  src = intermediate.value.statements.body.first.yield_self do |s|
39
42
  s.type == :call_node ? s.block : s
@@ -41,14 +44,13 @@ module Itsi
41
44
  params = src.parameters
42
45
  params = params.parameters if params.respond_to?(:parameters)
43
46
  requireds = (params&.requireds || []).map(&:name)
44
- optionals = params&.optionals || []
45
47
  keywords = (params&.keywords || []).map do |kw|
46
- [kw.name, kw.value.slice.gsub(/^_\./, '$.')]
48
+ [kw.name, kw.value.slice.gsub(/^_\./, "$.")]
47
49
  end.to_h
48
50
 
49
51
  [requireds.length, keywords]
50
- rescue
51
- [ proc.parameters.select{|p| p == :req }&.length || 0, {}]
52
+ rescue StandardError
53
+ [proc.parameters.select { |p| p == :req }&.length || 0, {}]
52
54
  end
53
55
  end
54
56
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.2.2"
5
+ VERSION = "0.2.4"
6
6
  end
7
7
  end
@@ -27,7 +27,6 @@ module Itsi
27
27
  extend RouteTester
28
28
 
29
29
  class << self
30
-
31
30
  def running?
32
31
  @running && !@running.empty?
33
32
  end
@@ -62,9 +61,8 @@ module Itsi
62
61
  server
63
62
  end
64
63
  background ? [server, Thread.new(&run)] : run[]
65
- rescue Exception => e
64
+ rescue Exception => e # rubocop:disable Lint/RescueException
66
65
  Itsi.log_error e.message
67
- raise e
68
66
  end
69
67
 
70
68
  def static(cli_params)
@@ -72,7 +70,8 @@ module Itsi
72
70
  end
73
71
 
74
72
  def stop
75
- return unless pid = get_pid
73
+ return unless (pid = get_pid)
74
+
76
75
  Process.kill(:INT, pid)
77
76
  i = 0
78
77
  while i < 10
@@ -96,7 +95,7 @@ module Itsi
96
95
  File.write(Itsi::Server::Config.pid_file_path, Process.pid)
97
96
  end
98
97
 
99
- def get_pid(warn=true)
98
+ def get_pid(warn = true)
100
99
  pid = File.read(Itsi::Server::Config.pid_file_path).to_i
101
100
  if Process.kill(0, pid)
102
101
  pid
@@ -110,7 +109,7 @@ module Itsi
110
109
  end
111
110
 
112
111
  def test
113
- Itsi::Server::Config.test!(cli_params = {})
112
+ Itsi::Server::Config.test!({})
114
113
  end
115
114
 
116
115
  def init
@@ -118,25 +117,25 @@ module Itsi
118
117
  end
119
118
 
120
119
  def reload
121
- return unless pid = get_pid
120
+ return unless (pid = get_pid)
122
121
 
123
122
  Process.kill(:HUP, pid)
124
123
  end
125
124
 
126
125
  def restart
127
- return unless pid = get_pid
126
+ return unless (pid = get_pid)
128
127
 
129
128
  Process.kill(:USR1, pid)
130
129
  end
131
130
 
132
131
  def passfile(options, subcmd)
133
132
  filename = options[:passfile]
134
- unless filename || subcmd == 'echo'
133
+ unless filename || subcmd == "echo"
135
134
  puts "Error: passfile not set. Use --passfile option to provide a path to a file containing hashed credentials."
136
135
  puts "This file contains hashed credentials and should not be included in source control without additional protection."
137
136
  exit(1)
138
137
  end
139
- algorithm = options.fetch(:algorithm, 'sha256')
138
+ algorithm = options.fetch(:algorithm, "sha256")
140
139
 
141
140
  unless %w[sha256 sha512 bcrypt argon2 none].include?(algorithm)
142
141
  puts "Invalid algorithm"
@@ -144,9 +143,9 @@ module Itsi
144
143
  end
145
144
 
146
145
  case subcmd
147
- when 'add', 'echo'
146
+ when "add", "echo"
148
147
  Passfile.send(subcmd, filename, algorithm)
149
- when 'remove', 'list'
148
+ when "remove", "list"
150
149
  Passfile.send(subcmd, filename)
151
150
  else
152
151
  puts "Valid subcommands are: add | remove | list"
@@ -165,6 +164,7 @@ module Itsi
165
164
  new_name = "#{base}_#{i}#{ext}"
166
165
  candidate = File.join(dir, new_name)
167
166
  return candidate unless File.exist?(candidate)
167
+
168
168
  i += 1
169
169
  end
170
170
  end
@@ -189,11 +189,11 @@ module Itsi
189
189
 
190
190
  case alg
191
191
  when /^HS(\d+)$/
192
- bits = $1.to_i
192
+ bits = ::Regexp.last_match(1).to_i
193
193
  bytes = bits / 8
194
194
  key = SecureRandom.random_bytes(bytes)
195
195
  pem = Base64.strict_encode64(key)
196
- content = "=== HMAC #{bits}-bit Secret (base64) ===\n#{pem}\n"
196
+ content = "=== HMAC #{bits}-bit Secret (base64) ===\n#{pem}\n"
197
197
  save_or_print("hmac_#{bits}_secret.txt", content, options)
198
198
 
199
199
  when /^RS/, /^PS/
@@ -215,32 +215,33 @@ module Itsi
215
215
  save_or_print("ecdsa_public.pem", "=== ECDSA Public Key ===\n#{pub}", options)
216
216
 
217
217
  else
218
- STDERR.puts "Unsupported algorithm: #{alg}"
218
+ warn "Unsupported algorithm: #{alg}"
219
219
  exit 1
220
220
  end
221
221
  end
222
222
 
223
-
224
223
  def add_worker
225
- return unless pid = get_pid
224
+ return unless (pid = get_pid)
226
225
 
227
226
  Process.kill(:TTIN, pid)
228
227
  end
229
228
 
230
229
  def remove_worker
231
- return unless pid = get_pid
230
+ return unless (pid = get_pid)
232
231
 
233
232
  Process.kill(:TTOU, pid)
234
233
  end
235
234
 
236
235
  def status
237
- return unless pid = get_pid
236
+ return unless (pid = get_pid)
237
+
238
238
  Itsi.log_info("Itsi running on #{pid}")
239
239
  Process.kill(:USR2, pid)
240
240
  end
241
241
 
242
242
  def load_route_middleware_stack(cli_params)
243
- middleware, errors = Config.build_config(cli_params, Itsi::Server::Config.config_file_path(cli_params[:config_file_path]))
243
+ middleware, errors = Config.build_config(cli_params,
244
+ Itsi::Server::Config.config_file_path(cli_params[:config_file_path]))
244
245
  if errors.any?
245
246
  puts errors
246
247
  []
@@ -261,7 +262,7 @@ module Itsi
261
262
  end
262
263
 
263
264
  def routes(cli_params = {})
264
- load_route_middleware_stack(cli_params).each do |stack|
265
+ load_route_middleware_stack(cli_params).first.each do |stack|
265
266
  routes = explode_route_pattern(stack["route"].source)
266
267
  routes.each do |route|
267
268
  print_route(route, stack)
@@ -271,7 +272,6 @@ module Itsi
271
272
  end
272
273
 
273
274
  alias serve start
274
-
275
275
  end
276
276
  end
277
277
  end
@@ -1,86 +1,86 @@
1
1
  module Itsi
2
2
  module StandardHeaders
3
3
  ALL = [
4
- ACCEPT = "accept",
5
- ACCEPT_CHARSET = "accept-charset",
6
- ACCEPT_ENCODING = "accept-encoding",
7
- ACCEPT_LANGUAGE = "accept-language",
8
- ACCEPT_RANGES = "accept-ranges",
9
- ACCESS_CONTROL_ALLOW_CREDENTIALS = "access-control-allow-credentials",
10
- ACCESS_CONTROL_ALLOW_HEADERS = "access-control-allow-headers",
11
- ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods",
12
- ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin",
13
- ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers",
14
- ACCESS_CONTROL_MAX_AGE = "access-control-max-age",
15
- ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers",
16
- ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method",
17
- AGE = "age",
18
- ALLOW = "allow",
19
- ALT_SVC = "alt-svc",
20
- AUTHORIZATION = "authorization",
21
- CACHE_CONTROL = "cache-control",
22
- CACHE_STATUS = "cache-status",
23
- CDN_CACHE_CONTROL = "cdn-cache-control",
24
- CONNECTION = "connection",
25
- CONTENT_DISPOSITION = "content-disposition",
26
- CONTENT_ENCODING = "content-encoding",
27
- CONTENT_LANGUAGE = "content-language",
28
- CONTENT_LENGTH = "content-length",
29
- CONTENT_LOCATION = "content-location",
30
- CONTENT_RANGE = "content-range",
31
- CONTENT_SECURITY_POLICY_REPORT_ONLY = "content-security-policy-report-only",
32
- CONTENT_TYPE = "content-type",
33
- COOKIE = "cookie",
34
- DNT = "dnt",
35
- DATE = "date",
36
- ETAG = "etag",
37
- EXPECT = "expect",
38
- EXPIRES = "expires",
39
- FORWARDED = "forwarded",
40
- FROM = "from",
41
- HOST = "host",
42
- IF_MATCH = "if-match",
43
- IF_MODIFIED_SINCE = "if-modified-since",
44
- IF_NONE_MATCH = "if-none-match",
45
- IF_RANGE = "if-range",
46
- IF_UNMODIFIED_SINCE = "if-unmodified-since",
47
- LAST_MODIFIED = "last-modified",
48
- LINK = "link",
49
- LOCATION = "location",
50
- MAX_FORWARDS = "max-forwards",
51
- ORIGIN = "origin",
52
- PRAGMA = "pragma",
53
- PROXY_AUTHENTICATE = "proxy-authenticate",
54
- PROXY_AUTHORIZATION = "proxy-authorization",
55
- PUBLIC_KEY_PINS = "public-key-pins",
56
- PUBLIC_KEY_PINS_REPORT_ONLY = "public-key-pins-report-only",
57
- RANGE = "range",
58
- REFERER = "referer",
59
- REFERRER_POLICY = "referrer-policy",
60
- REFRESH = "refresh",
61
- RETRY_AFTER = "retry-after",
62
- SEC_WEBSOCKET_ACCEPT = "sec-websocket-accept",
63
- SEC_WEBSOCKET_EXTENSIONS = "sec-websocket-extensions",
64
- SEC_WEBSOCKET_KEY = "sec-websocket-key",
65
- SEC_WEBSOCKET_PROTOCOL = "sec-websocket-protocol",
66
- SEC_WEBSOCKET_VERSION = "sec-websocket-version",
67
- SERVER = "server",
68
- SET_COOKIE = "set-cookie",
69
- STRICT_TRANSPORT_SECURITY = "strict-transport-security",
70
- TE = "te",
71
- TRAILER = "trailer",
72
- TRANSFER_ENCODING = "transfer-encoding",
73
- USER_AGENT = "user-agent",
74
- UPGRADE = "upgrade",
75
- UPGRADE_INSECURE_REQUESTS = "upgrade-insecure-requests",
76
- VARY = "vary",
77
- VIA = "via",
78
- WARNING = "warning",
79
- WWW_AUTHENTICATE = "www-authenticate",
80
- X_CONTENT_TYPE_OPTIONS = "x-content-type-options",
81
- X_DNS_PREFETCH_CONTROL = "x-dns-prefetch-control",
82
- X_FRAME_OPTIONS = "x-frame-options",
83
- X_XSS_PROTECTION = "x-xss-protection",
4
+ ACCEPT = "accept".freeze,
5
+ ACCEPT_CHARSET = "accept-charset".freeze,
6
+ ACCEPT_ENCODING = "accept-encoding".freeze,
7
+ ACCEPT_LANGUAGE = "accept-language".freeze,
8
+ ACCEPT_RANGES = "accept-ranges".freeze,
9
+ ACCESS_CONTROL_ALLOW_CREDENTIALS = "access-control-allow-credentials".freeze,
10
+ ACCESS_CONTROL_ALLOW_HEADERS = "access-control-allow-headers".freeze,
11
+ ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods".freeze,
12
+ ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin".freeze,
13
+ ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers".freeze,
14
+ ACCESS_CONTROL_MAX_AGE = "access-control-max-age".freeze,
15
+ ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers".freeze,
16
+ ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method".freeze,
17
+ AGE = "age".freeze,
18
+ ALLOW = "allow".freeze,
19
+ ALT_SVC = "alt-svc".freeze,
20
+ AUTHORIZATION = "authorization".freeze,
21
+ CACHE_CONTROL = "cache-control".freeze,
22
+ CACHE_STATUS = "cache-status".freeze,
23
+ CDN_CACHE_CONTROL = "cdn-cache-control".freeze,
24
+ CONNECTION = "connection".freeze,
25
+ CONTENT_DISPOSITION = "content-disposition".freeze,
26
+ CONTENT_ENCODING = "content-encoding".freeze,
27
+ CONTENT_LANGUAGE = "content-language".freeze,
28
+ CONTENT_LENGTH = "content-length".freeze,
29
+ CONTENT_LOCATION = "content-location".freeze,
30
+ CONTENT_RANGE = "content-range".freeze,
31
+ CONTENT_SECURITY_POLICY_REPORT_ONLY = "content-security-policy-report-only".freeze,
32
+ CONTENT_TYPE = "content-type".freeze,
33
+ COOKIE = "cookie".freeze,
34
+ DNT = "dnt".freeze,
35
+ DATE = "date".freeze,
36
+ ETAG = "etag".freeze,
37
+ EXPECT = "expect".freeze,
38
+ EXPIRES = "expires".freeze,
39
+ FORWARDED = "forwarded".freeze,
40
+ FROM = "from".freeze,
41
+ HOST = "host".freeze,
42
+ IF_MATCH = "if-match".freeze,
43
+ IF_MODIFIED_SINCE = "if-modified-since".freeze,
44
+ IF_NONE_MATCH = "if-none-match".freeze,
45
+ IF_RANGE = "if-range".freeze,
46
+ IF_UNMODIFIED_SINCE = "if-unmodified-since".freeze,
47
+ LAST_MODIFIED = "last-modified".freeze,
48
+ LINK = "link".freeze,
49
+ LOCATION = "location".freeze,
50
+ MAX_FORWARDS = "max-forwards".freeze,
51
+ ORIGIN = "origin".freeze,
52
+ PRAGMA = "pragma".freeze,
53
+ PROXY_AUTHENTICATE = "proxy-authenticate".freeze,
54
+ PROXY_AUTHORIZATION = "proxy-authorization".freeze,
55
+ PUBLIC_KEY_PINS = "public-key-pins".freeze,
56
+ PUBLIC_KEY_PINS_REPORT_ONLY = "public-key-pins-report-only".freeze,
57
+ RANGE = "range".freeze,
58
+ REFERER = "referer".freeze,
59
+ REFERRER_POLICY = "referrer-policy".freeze,
60
+ REFRESH = "refresh".freeze,
61
+ RETRY_AFTER = "retry-after".freeze,
62
+ SEC_WEBSOCKET_ACCEPT = "sec-websocket-accept".freeze,
63
+ SEC_WEBSOCKET_EXTENSIONS = "sec-websocket-extensions".freeze,
64
+ SEC_WEBSOCKET_KEY = "sec-websocket-key".freeze,
65
+ SEC_WEBSOCKET_PROTOCOL = "sec-websocket-protocol".freeze,
66
+ SEC_WEBSOCKET_VERSION = "sec-websocket-version".freeze,
67
+ SERVER = "server".freeze,
68
+ SET_COOKIE = "set-cookie".freeze,
69
+ STRICT_TRANSPORT_SECURITY = "strict-transport-security".freeze,
70
+ TE = "te".freeze,
71
+ TRAILER = "trailer".freeze,
72
+ TRANSFER_ENCODING = "transfer-encoding".freeze,
73
+ USER_AGENT = "user-agent".freeze,
74
+ UPGRADE = "upgrade".freeze,
75
+ UPGRADE_INSECURE_REQUESTS = "upgrade-insecure-requests".freeze,
76
+ VARY = "vary".freeze,
77
+ VIA = "via".freeze,
78
+ WARNING = "warning".freeze,
79
+ WWW_AUTHENTICATE = "www-authenticate".freeze,
80
+ X_CONTENT_TYPE_OPTIONS = "x-content-type-options".freeze,
81
+ X_DNS_PREFETCH_CONTROL = "x-dns-prefetch-control".freeze,
82
+ X_FRAME_OPTIONS = "x-frame-options".freeze,
83
+ X_XSS_PROTECTION = "x-xss-protection".freeze
84
84
  ]
85
85
  end
86
86
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  ENV["ITSI_LOG"] = "off"
3
4
 
4
5
  require "minitest/reporters"
@@ -8,14 +9,13 @@ require "socket"
8
9
  require "net/http"
9
10
  require "minitest/autorun"
10
11
 
11
-
12
12
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
13
13
 
14
- def free_bind(protocol="http", unix_socket: false)
14
+ def free_bind(protocol = "http", unix_socket: false)
15
15
  if unix_socket
16
16
  socket_path = "/tmp/itsi_socket_#{Process.pid}_#{rand(1000)}.sock"
17
17
  UNIXServer.new(socket_path).close
18
- protocol == 'https' ? "tls://#{socket_path}" : "unix://#{socket_path}"
18
+ protocol == "https" ? "tls://#{socket_path}" : "unix://#{socket_path}"
19
19
  else
20
20
  server = TCPServer.new("0.0.0.0", 0)
21
21
  port = server.addr[1]
@@ -24,7 +24,6 @@ def free_bind(protocol="http", unix_socket: false)
24
24
  end
25
25
  end
26
26
 
27
-
28
27
  def server(app: nil, protocol: "http", bind: free_bind(protocol), itsi_rb: nil, cleanup: true, timeout: 5, &blk)
29
28
  itsi_rb ||= lambda do
30
29
  # Inline Itsi.rb
@@ -49,7 +48,7 @@ def server(app: nil, protocol: "http", bind: free_bind(protocol), itsi_rb: nil,
49
48
  sync.pop
50
49
  uri = URI(bind)
51
50
  # Timeout.timeout(timeout) do
52
- RequestContext.new(uri, self).instance_exec(uri, &blk)
51
+ RequestContext.new(uri, self).instance_exec(uri, &blk)
53
52
  # end
54
53
  rescue StandardError => e
55
54
  puts e
@@ -60,9 +59,9 @@ ensure
60
59
  Itsi::Server.stop_background_threads if cleanup
61
60
  end
62
61
 
63
- require 'net/http'
64
- require 'net_http_unix'
65
- require 'uri'
62
+ require "net/http"
63
+ require "net_http_unix"
64
+ require "uri"
66
65
 
67
66
  class RequestContext
68
67
  def initialize(uri, binding)
@@ -74,7 +73,7 @@ class RequestContext
74
73
  @binding.send(method_name, *args, &block)
75
74
  end
76
75
 
77
- def post(path, data="", headers = {})
76
+ def post(path, data = "", headers = {})
78
77
  client.post(uri_for(path), data, headers)
79
78
  end
80
79
 
@@ -101,7 +100,7 @@ class RequestContext
101
100
  client.request(request)
102
101
  end
103
102
 
104
- def put(path, data="", headers = {})
103
+ def put(path, data = "", headers = {})
105
104
  request = Net::HTTP::Put.new(uri_for(path))
106
105
  request.body = data
107
106
  headers.each { |k, v| request[k] = v }
@@ -114,7 +113,7 @@ class RequestContext
114
113
  client.request(request)
115
114
  end
116
115
 
117
- def patch(path, data="", headers = {})
116
+ def patch(path, data = "", headers = {})
118
117
  request = Net::HTTP::Patch.new(uri_for(path))
119
118
  request.body = data
120
119
  client.request(request)
@@ -127,21 +126,23 @@ class RequestContext
127
126
  read_timeout: 1,
128
127
  open_timeout: 1
129
128
  }
130
- if @uri.scheme == 'unix'
129
+ if @uri.scheme == "unix"
131
130
  NetX::HTTPUnix.new(
132
131
  @uri.to_s,
133
- **opts)
132
+ **opts
133
+ )
134
134
  else
135
135
  Net::HTTP.start(
136
136
  @uri.host,
137
137
  @uri.port,
138
- use_ssl: @uri.scheme == 'https',
139
- **opts)
138
+ use_ssl: @uri.scheme == "https",
139
+ **opts
140
+ )
140
141
  end
141
142
  end
142
143
 
143
144
  def uri_for(path)
144
- if @uri.scheme == 'unix'
145
+ if @uri.scheme == "unix"
145
146
  URI::HTTP.build(path: path, host: "localhost")
146
147
  else
147
148
  URI.join(@uri.to_s, path)
@@ -133,6 +133,7 @@ class TestStaticAssets < Minitest::Test
133
133
  end
134
134
  end
135
135
  end
136
+
136
137
  def test_relative_path_true
137
138
  Dir.mktmpdir do |dir|
138
139
  # Create file "test.txt" in root_dir.
@@ -141,18 +142,19 @@ class TestStaticAssets < Minitest::Test
141
142
  File.write(file_path, "relative true")
142
143
  server(
143
144
  itsi_rb: lambda do
144
- location "foo/bar/baz" do
145
+ location "foo/bar/baz/*" do
145
146
  static_assets \
146
147
  root_dir: "#{dir}",
147
148
  not_found_behavior: "fallthrough",
148
149
  allowed_extensions: ["txt"],
149
150
  relative_path: true
150
151
 
151
- get("/foo/bar/baz/test.txt") { |r| r.ok "fallback" }
152
+ get("/test.txt") { |r| r.not_found }
152
153
  end
153
154
  end
154
155
  ) do
155
156
  res = get_resp("/foo/bar/baz/test.txt")
157
+
156
158
  assert_equal "200", res.code, "Expected 200 OK with relative_path: true"
157
159
  assert_equal "relative true", res.body
158
160
  end
@@ -169,14 +171,14 @@ class TestStaticAssets < Minitest::Test
169
171
  server(
170
172
  itsi_rb: lambda do
171
173
 
172
- location "/foo/bar/baz/" do
174
+ location "/foo/bar/baz/*" do
173
175
  static_assets \
174
176
  root_dir: "#{dir}",
175
177
  not_found_behavior: "fallthrough",
176
178
  allowed_extensions: ["txt"],
177
179
  relative_path: false
178
180
 
179
- get("/foo/bar/baz/test.txt") { |r| r.ok "fallback" }
181
+ get("/test.txt") { |r| r.ok "fallback" }
180
182
  end
181
183
  end
182
184
  ) do
@@ -109,4 +109,58 @@ class TestStringRewrite < Minitest::Test
109
109
  assert_equal "https://example.com/{unknown}", res["Location"]
110
110
  end
111
111
  end
112
+
113
+ def test_strip_prefix
114
+ server(
115
+ itsi_rb: lambda do
116
+ redirect to: "https://example.com{path|strip_prefix:/rails}", type: "temporary"
117
+ get("/rails/foo") { |r| r.ok }
118
+ end
119
+ ) do
120
+ res = get_resp("/rails/foo")
121
+ assert_equal "307", res.code
122
+ assert_equal "https://example.com/foo", res["Location"]
123
+ end
124
+ end
125
+
126
+ def test_strip_suffix
127
+ server(
128
+ itsi_rb: lambda do
129
+ redirect to: "{path_and_query|strip_suffix:.json}", type: "found"
130
+ get("/data.json") { |r| r.ok }
131
+ end
132
+ ) do
133
+ res = get_resp("/data.json")
134
+ assert_equal "302", res.code
135
+ # .json is removed from end of "/data.json"
136
+ assert_equal "/data", res["Location"]
137
+ end
138
+ end
139
+
140
+ def test_replace
141
+ server(
142
+ itsi_rb: lambda do
143
+ redirect to: "https://{host|replace:localhost,api.example.com}", type: "permanent"
144
+ get("/foo") { |r| r.ok }
145
+ end
146
+ ) do
147
+ res = get_resp("/foo")
148
+ assert_equal "308", res.code
149
+ assert_equal "https://api.example.com", res["Location"]
150
+ end
151
+ end
152
+
153
+ def test_chain_modifiers
154
+ server(
155
+ itsi_rb: lambda do
156
+ redirect to: "https://example.com{path|strip_prefix:/v1|replace:api,service}", type: "temporary"
157
+ get("/v1/api/users") { |r| r.ok }
158
+ end
159
+ ) do
160
+ res = get_resp("/v1/api/users")
161
+ assert_equal "307", res.code
162
+ # after strip_prefix: "/api/users", then replace "api"→"service"
163
+ assert_equal "https://example.com/service/users", res["Location"]
164
+ end
165
+ end
112
166
  end