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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/Cargo.lock +29 -30
- data/README.md +1 -0
- data/Rakefile +2 -2
- data/crates/itsi_scheduler/Cargo.toml +1 -1
- data/crates/itsi_server/Cargo.toml +1 -1
- data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +26 -3
- data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +28 -11
- data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +1 -1
- data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +1 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +14 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +86 -41
- data/crates/itsi_server/src/services/itsi_http_service.rs +46 -35
- data/crates/itsi_server/src/services/static_file_server.rs +31 -3
- data/docs/content/_index.md +1 -1
- data/docs/content/contact/_index.md +1 -1
- data/docs/content/directory_listing.jpg +0 -0
- data/docs/content/error_page.jpg +0 -0
- data/docs/content/getting_started/local_development.md +9 -2
- data/docs/content/getting_started/logging.md +1 -2
- data/docs/content/getting_started/signals.md +0 -1
- data/docs/hugo.yaml +3 -0
- data/examples/api_with_schema_and_controllers/Itsi.rb +35 -0
- data/examples/api_with_schema_and_controllers/README.md +10 -0
- data/examples/api_with_schema_and_controllers/controllers.rb +66 -0
- data/examples/api_with_schema_and_controllers/schemas.rb +25 -0
- data/examples/file_server/Itsi.rb +30 -0
- data/examples/file_server/README.md +3 -0
- data/examples/file_server/about.html +80 -0
- data/examples/file_server/admin/secrets.txt +1 -0
- data/examples/file_server/fairytale.txt +33 -0
- data/examples/file_server/itsi-server-100.png +0 -0
- data/examples/file_server/subdirectory/movies.csv +21 -0
- data/examples/helpers/datastore.rb +84 -0
- data/examples/media_server/Itsi.rb +5 -0
- data/examples/media_server/README.md +3 -0
- data/examples/media_server/images/itsi-server-100.png +0 -0
- data/examples/media_server/index.html +82 -0
- data/examples/multi_rack_rails_sinatra/Gemfile +66 -0
- data/examples/multi_rack_rails_sinatra/Gemfile.lock +416 -0
- data/examples/multi_rack_rails_sinatra/Itsi.rb +44 -0
- data/examples/multi_rack_rails_sinatra/README.md +7 -0
- data/examples/multi_rack_rails_sinatra/index.html +119 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.dockerignore +51 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.gitattributes +9 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.github/dependabot.yml +12 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.github/workflows/ci.yml +90 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.gitignore +34 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/docker-setup.sample +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-app-boot.sample +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-deploy.sample +14 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-app-boot.sample +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-build.sample +51 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-connect.sample +47 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-deploy.sample +109 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.kamal/secrets +17 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.rubocop.yml +8 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/.ruby-version +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/Dockerfile +72 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/Gemfile +66 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/Gemfile.lock +416 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/README.md +24 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/Rakefile +6 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/assets/images/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/assets/stylesheets/application.css +161 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/application_controller.rb +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/articles_controller.rb +70 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/concerns/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/controllers/home_controller.rb +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/application_helper.rb +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/articles_helper.rb +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/helpers/home_helper.rb +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/application.js +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/application.js +9 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/hello_controller.js +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/javascript/controllers/index.js +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/jobs/application_job.rb +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/mailers/application_mailer.rb +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/application_record.rb +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/article.rb +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/models/concerns/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_article.html.erb +14 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_article.json.jbuilder +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/_form.html.erb +30 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/edit.html.erb +12 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/index.html.erb +29 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/index.json.jbuilder +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/new.html.erb +11 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/show.html.erb +10 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/articles/show.json.jbuilder +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/home/index.html.erb +8 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/application.html.erb +34 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/mailer.html.erb +13 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/layouts/mailer.text.erb +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/pwa/manifest.json.erb +22 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/app/views/pwa/service-worker.js +26 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/brakeman +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/bundle +109 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/dev +2 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/docker-entrypoint +14 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/importmap +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/jobs +6 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/kamal +27 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rails +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rake +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/rubocop +8 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/setup +34 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/bin/thrust +5 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/application.rb +27 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/boot.rb +4 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/cable.yml +17 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/cache.yml +16 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/credentials.yml.enc +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/database.yml +41 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/deploy.yml +116 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/environment.rb +5 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/development.rb +72 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/production.rb +90 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/environments/test.rb +53 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/importmap.rb +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/assets.rb +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/content_security_policy.rb +25 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/initializers/inflections.rb +16 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/locales/en.yml +31 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/puma.rb +41 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/queue.yml +18 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/recurring.yml +10 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/routes.rb +17 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config/storage.yml +34 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/config.ru +6 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/cable_schema.rb +11 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/cache_schema.rb +14 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/migrate/20250422211855_create_articles.rb +10 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/queue_schema.rb +129 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/schema.rb +20 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/db/seeds.rb +9 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/lib/tasks/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/log/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/400.html +114 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/404.html +114 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/406-unsupported-browser.html +114 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/422.html +114 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/500.html +114 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/icon.png +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/icon.svg +3 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/public/robots.txt +1 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/script/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/storage/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/application_system_test_case.rb +5 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/articles_controller_test.rb +48 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/controllers/home_controller_test.rb +8 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/fixtures/articles.yml +9 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/fixtures/files/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/helpers/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/integration/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/mailers/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/models/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/models/article_test.rb +7 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/system/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/system/articles_test.rb +43 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/test/test_helper.rb +15 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/pids/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/tmp/storage/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/vendor/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/rails_subapp/vendor/javascript/.keep +0 -0
- data/examples/multi_rack_rails_sinatra/sinatra_subapp/config.ru +2 -0
- data/examples/multi_rack_rails_sinatra/sinatra_subapp/my_app.rb +96 -0
- data/examples/rails_with_static_assets/.dockerignore +51 -0
- data/examples/rails_with_static_assets/.gitattributes +9 -0
- data/examples/rails_with_static_assets/.github/dependabot.yml +12 -0
- data/examples/rails_with_static_assets/.github/workflows/ci.yml +90 -0
- data/examples/rails_with_static_assets/.gitignore +34 -0
- data/examples/rails_with_static_assets/.kamal/hooks/docker-setup.sample +3 -0
- data/examples/rails_with_static_assets/.kamal/hooks/post-app-boot.sample +3 -0
- data/examples/rails_with_static_assets/.kamal/hooks/post-deploy.sample +14 -0
- data/examples/rails_with_static_assets/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/examples/rails_with_static_assets/.kamal/hooks/pre-app-boot.sample +3 -0
- data/examples/rails_with_static_assets/.kamal/hooks/pre-build.sample +51 -0
- data/examples/rails_with_static_assets/.kamal/hooks/pre-connect.sample +47 -0
- data/examples/rails_with_static_assets/.kamal/hooks/pre-deploy.sample +109 -0
- data/examples/rails_with_static_assets/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/examples/rails_with_static_assets/.kamal/secrets +17 -0
- data/examples/rails_with_static_assets/.rubocop.yml +8 -0
- data/examples/rails_with_static_assets/.ruby-version +1 -0
- data/examples/rails_with_static_assets/Dockerfile +72 -0
- data/examples/rails_with_static_assets/Gemfile +66 -0
- data/examples/rails_with_static_assets/Gemfile.lock +416 -0
- data/examples/rails_with_static_assets/Itsi.rb +10 -0
- data/examples/rails_with_static_assets/README.md +14 -0
- data/examples/rails_with_static_assets/Rakefile +6 -0
- data/examples/rails_with_static_assets/app/assets/images/.keep +0 -0
- data/examples/rails_with_static_assets/app/assets/stylesheets/application.css +161 -0
- data/examples/rails_with_static_assets/app/controllers/application_controller.rb +4 -0
- data/examples/rails_with_static_assets/app/controllers/articles_controller.rb +70 -0
- data/examples/rails_with_static_assets/app/controllers/concerns/.keep +0 -0
- data/examples/rails_with_static_assets/app/controllers/home_controller.rb +4 -0
- data/examples/rails_with_static_assets/app/helpers/application_helper.rb +2 -0
- data/examples/rails_with_static_assets/app/helpers/articles_helper.rb +2 -0
- data/examples/rails_with_static_assets/app/helpers/home_helper.rb +2 -0
- data/examples/rails_with_static_assets/app/javascript/application.js +3 -0
- data/examples/rails_with_static_assets/app/javascript/controllers/application.js +9 -0
- data/examples/rails_with_static_assets/app/javascript/controllers/hello_controller.js +7 -0
- data/examples/rails_with_static_assets/app/javascript/controllers/index.js +4 -0
- data/examples/rails_with_static_assets/app/jobs/application_job.rb +7 -0
- data/examples/rails_with_static_assets/app/mailers/application_mailer.rb +4 -0
- data/examples/rails_with_static_assets/app/models/application_record.rb +3 -0
- data/examples/rails_with_static_assets/app/models/article.rb +2 -0
- data/examples/rails_with_static_assets/app/models/concerns/.keep +0 -0
- data/examples/rails_with_static_assets/app/views/articles/_article.html.erb +14 -0
- data/examples/rails_with_static_assets/app/views/articles/_article.json.jbuilder +2 -0
- data/examples/rails_with_static_assets/app/views/articles/_form.html.erb +30 -0
- data/examples/rails_with_static_assets/app/views/articles/edit.html.erb +12 -0
- data/examples/rails_with_static_assets/app/views/articles/index.html.erb +29 -0
- data/examples/rails_with_static_assets/app/views/articles/index.json.jbuilder +1 -0
- data/examples/rails_with_static_assets/app/views/articles/new.html.erb +11 -0
- data/examples/rails_with_static_assets/app/views/articles/show.html.erb +10 -0
- data/examples/rails_with_static_assets/app/views/articles/show.json.jbuilder +1 -0
- data/examples/rails_with_static_assets/app/views/home/index.html.erb +8 -0
- data/examples/rails_with_static_assets/app/views/layouts/application.html.erb +34 -0
- data/examples/rails_with_static_assets/app/views/layouts/mailer.html.erb +13 -0
- data/examples/rails_with_static_assets/app/views/layouts/mailer.text.erb +1 -0
- data/examples/rails_with_static_assets/app/views/pwa/manifest.json.erb +22 -0
- data/examples/rails_with_static_assets/app/views/pwa/service-worker.js +26 -0
- data/examples/rails_with_static_assets/bin/brakeman +7 -0
- data/examples/rails_with_static_assets/bin/bundle +109 -0
- data/examples/rails_with_static_assets/bin/dev +2 -0
- data/examples/rails_with_static_assets/bin/docker-entrypoint +14 -0
- data/examples/rails_with_static_assets/bin/importmap +4 -0
- data/examples/rails_with_static_assets/bin/jobs +6 -0
- data/examples/rails_with_static_assets/bin/kamal +27 -0
- data/examples/rails_with_static_assets/bin/rails +4 -0
- data/examples/rails_with_static_assets/bin/rake +4 -0
- data/examples/rails_with_static_assets/bin/rubocop +8 -0
- data/examples/rails_with_static_assets/bin/setup +34 -0
- data/examples/rails_with_static_assets/bin/thrust +5 -0
- data/examples/rails_with_static_assets/config/application.rb +26 -0
- data/examples/rails_with_static_assets/config/boot.rb +4 -0
- data/examples/rails_with_static_assets/config/cable.yml +17 -0
- data/examples/rails_with_static_assets/config/cache.yml +16 -0
- data/examples/rails_with_static_assets/config/credentials.yml.enc +1 -0
- data/examples/rails_with_static_assets/config/database.yml +41 -0
- data/examples/rails_with_static_assets/config/deploy.yml +116 -0
- data/examples/rails_with_static_assets/config/environment.rb +5 -0
- data/examples/rails_with_static_assets/config/environments/development.rb +74 -0
- data/examples/rails_with_static_assets/config/environments/production.rb +90 -0
- data/examples/rails_with_static_assets/config/environments/test.rb +53 -0
- data/examples/rails_with_static_assets/config/importmap.rb +7 -0
- data/examples/rails_with_static_assets/config/initializers/assets.rb +7 -0
- data/examples/rails_with_static_assets/config/initializers/content_security_policy.rb +25 -0
- data/examples/rails_with_static_assets/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/rails_with_static_assets/config/initializers/inflections.rb +16 -0
- data/examples/rails_with_static_assets/config/locales/en.yml +31 -0
- data/examples/rails_with_static_assets/config/puma.rb +41 -0
- data/examples/rails_with_static_assets/config/queue.yml +18 -0
- data/examples/rails_with_static_assets/config/recurring.yml +10 -0
- data/examples/rails_with_static_assets/config/routes.rb +17 -0
- data/examples/rails_with_static_assets/config/storage.yml +34 -0
- data/examples/rails_with_static_assets/config.ru +6 -0
- data/examples/rails_with_static_assets/db/cable_schema.rb +11 -0
- data/examples/rails_with_static_assets/db/cache_schema.rb +14 -0
- data/examples/rails_with_static_assets/db/migrate/20250422211855_create_articles.rb +10 -0
- data/examples/rails_with_static_assets/db/queue_schema.rb +129 -0
- data/examples/rails_with_static_assets/db/schema.rb +20 -0
- data/examples/rails_with_static_assets/db/seeds.rb +9 -0
- data/examples/rails_with_static_assets/lib/tasks/.keep +0 -0
- data/examples/rails_with_static_assets/log/.keep +0 -0
- data/examples/rails_with_static_assets/public/400.html +114 -0
- data/examples/rails_with_static_assets/public/404.html +114 -0
- data/examples/rails_with_static_assets/public/406-unsupported-browser.html +114 -0
- data/examples/rails_with_static_assets/public/422.html +114 -0
- data/examples/rails_with_static_assets/public/500.html +114 -0
- data/examples/rails_with_static_assets/public/icon.png +0 -0
- data/examples/rails_with_static_assets/public/icon.svg +3 -0
- data/examples/rails_with_static_assets/public/robots.txt +1 -0
- data/examples/rails_with_static_assets/script/.keep +0 -0
- data/examples/rails_with_static_assets/storage/.keep +0 -0
- data/examples/rails_with_static_assets/test/application_system_test_case.rb +5 -0
- data/examples/rails_with_static_assets/test/controllers/.keep +0 -0
- data/examples/rails_with_static_assets/test/controllers/articles_controller_test.rb +48 -0
- data/examples/rails_with_static_assets/test/controllers/home_controller_test.rb +8 -0
- data/examples/rails_with_static_assets/test/fixtures/articles.yml +9 -0
- data/examples/rails_with_static_assets/test/fixtures/files/.keep +0 -0
- data/examples/rails_with_static_assets/test/helpers/.keep +0 -0
- data/examples/rails_with_static_assets/test/integration/.keep +0 -0
- data/examples/rails_with_static_assets/test/mailers/.keep +0 -0
- data/examples/rails_with_static_assets/test/models/.keep +0 -0
- data/examples/rails_with_static_assets/test/models/article_test.rb +7 -0
- data/examples/rails_with_static_assets/test/system/.keep +0 -0
- data/examples/rails_with_static_assets/test/system/articles_test.rb +43 -0
- data/examples/rails_with_static_assets/test/test_helper.rb +15 -0
- data/examples/rails_with_static_assets/tmp/.keep +0 -0
- data/examples/rails_with_static_assets/tmp/pids/.keep +0 -0
- data/examples/rails_with_static_assets/tmp/storage/.keep +0 -0
- data/examples/rails_with_static_assets/vendor/.keep +0 -0
- data/examples/rails_with_static_assets/vendor/javascript/.keep +0 -0
- data/examples/reverse_proxy/Itsi.rb +28 -0
- data/examples/reverse_proxy/README.md +14 -0
- data/examples/reverse_proxy/index.html +119 -0
- data/examples/reverse_proxy/rails_subapp/.dockerignore +51 -0
- data/examples/reverse_proxy/rails_subapp/.gitattributes +9 -0
- data/examples/reverse_proxy/rails_subapp/.github/dependabot.yml +12 -0
- data/examples/reverse_proxy/rails_subapp/.github/workflows/ci.yml +90 -0
- data/examples/reverse_proxy/rails_subapp/.gitignore +34 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/docker-setup.sample +3 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-app-boot.sample +3 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-deploy.sample +14 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/post-proxy-reboot.sample +3 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-app-boot.sample +3 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-build.sample +51 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-connect.sample +47 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-deploy.sample +109 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/hooks/pre-proxy-reboot.sample +3 -0
- data/examples/reverse_proxy/rails_subapp/.kamal/secrets +17 -0
- data/examples/reverse_proxy/rails_subapp/.rubocop.yml +8 -0
- data/examples/reverse_proxy/rails_subapp/.ruby-version +1 -0
- data/examples/reverse_proxy/rails_subapp/Dockerfile +72 -0
- data/examples/reverse_proxy/rails_subapp/Gemfile +66 -0
- data/examples/reverse_proxy/rails_subapp/Gemfile.lock +416 -0
- data/examples/reverse_proxy/rails_subapp/README.md +24 -0
- data/examples/reverse_proxy/rails_subapp/Rakefile +6 -0
- data/examples/reverse_proxy/rails_subapp/app/assets/images/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/app/assets/stylesheets/application.css +161 -0
- data/examples/reverse_proxy/rails_subapp/app/controllers/application_controller.rb +4 -0
- data/examples/reverse_proxy/rails_subapp/app/controllers/articles_controller.rb +70 -0
- data/examples/reverse_proxy/rails_subapp/app/controllers/concerns/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/app/controllers/home_controller.rb +4 -0
- data/examples/reverse_proxy/rails_subapp/app/helpers/application_helper.rb +2 -0
- data/examples/reverse_proxy/rails_subapp/app/helpers/articles_helper.rb +2 -0
- data/examples/reverse_proxy/rails_subapp/app/helpers/home_helper.rb +2 -0
- data/examples/reverse_proxy/rails_subapp/app/javascript/application.js +3 -0
- data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/application.js +9 -0
- data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/hello_controller.js +7 -0
- data/examples/reverse_proxy/rails_subapp/app/javascript/controllers/index.js +4 -0
- data/examples/reverse_proxy/rails_subapp/app/jobs/application_job.rb +7 -0
- data/examples/reverse_proxy/rails_subapp/app/mailers/application_mailer.rb +4 -0
- data/examples/reverse_proxy/rails_subapp/app/models/application_record.rb +3 -0
- data/examples/reverse_proxy/rails_subapp/app/models/article.rb +2 -0
- data/examples/reverse_proxy/rails_subapp/app/models/concerns/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/_article.html.erb +14 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/_article.json.jbuilder +2 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/_form.html.erb +30 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/edit.html.erb +12 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/index.html.erb +29 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/index.json.jbuilder +1 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/new.html.erb +11 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/show.html.erb +10 -0
- data/examples/reverse_proxy/rails_subapp/app/views/articles/show.json.jbuilder +1 -0
- data/examples/reverse_proxy/rails_subapp/app/views/home/index.html.erb +8 -0
- data/examples/reverse_proxy/rails_subapp/app/views/layouts/application.html.erb +34 -0
- data/examples/reverse_proxy/rails_subapp/app/views/layouts/mailer.html.erb +13 -0
- data/examples/reverse_proxy/rails_subapp/app/views/layouts/mailer.text.erb +1 -0
- data/examples/reverse_proxy/rails_subapp/app/views/pwa/manifest.json.erb +22 -0
- data/examples/reverse_proxy/rails_subapp/app/views/pwa/service-worker.js +26 -0
- data/examples/reverse_proxy/rails_subapp/bin/brakeman +7 -0
- data/examples/reverse_proxy/rails_subapp/bin/bundle +109 -0
- data/examples/reverse_proxy/rails_subapp/bin/dev +2 -0
- data/examples/reverse_proxy/rails_subapp/bin/docker-entrypoint +14 -0
- data/examples/reverse_proxy/rails_subapp/bin/importmap +4 -0
- data/examples/reverse_proxy/rails_subapp/bin/jobs +6 -0
- data/examples/reverse_proxy/rails_subapp/bin/kamal +27 -0
- data/examples/reverse_proxy/rails_subapp/bin/rails +4 -0
- data/examples/reverse_proxy/rails_subapp/bin/rake +4 -0
- data/examples/reverse_proxy/rails_subapp/bin/rubocop +8 -0
- data/examples/reverse_proxy/rails_subapp/bin/setup +34 -0
- data/examples/reverse_proxy/rails_subapp/bin/thrust +5 -0
- data/examples/reverse_proxy/rails_subapp/config/application.rb +26 -0
- data/examples/reverse_proxy/rails_subapp/config/boot.rb +4 -0
- data/examples/reverse_proxy/rails_subapp/config/cable.yml +17 -0
- data/examples/reverse_proxy/rails_subapp/config/cache.yml +16 -0
- data/examples/reverse_proxy/rails_subapp/config/credentials.yml.enc +1 -0
- data/examples/reverse_proxy/rails_subapp/config/database.yml +41 -0
- data/examples/reverse_proxy/rails_subapp/config/deploy.yml +116 -0
- data/examples/reverse_proxy/rails_subapp/config/environment.rb +5 -0
- data/examples/reverse_proxy/rails_subapp/config/environments/development.rb +72 -0
- data/examples/reverse_proxy/rails_subapp/config/environments/production.rb +90 -0
- data/examples/reverse_proxy/rails_subapp/config/environments/test.rb +53 -0
- data/examples/reverse_proxy/rails_subapp/config/importmap.rb +7 -0
- data/examples/reverse_proxy/rails_subapp/config/initializers/assets.rb +7 -0
- data/examples/reverse_proxy/rails_subapp/config/initializers/content_security_policy.rb +25 -0
- data/examples/reverse_proxy/rails_subapp/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/reverse_proxy/rails_subapp/config/initializers/inflections.rb +16 -0
- data/examples/reverse_proxy/rails_subapp/config/locales/en.yml +31 -0
- data/examples/reverse_proxy/rails_subapp/config/puma.rb +41 -0
- data/examples/reverse_proxy/rails_subapp/config/queue.yml +18 -0
- data/examples/reverse_proxy/rails_subapp/config/recurring.yml +10 -0
- data/examples/reverse_proxy/rails_subapp/config/routes.rb +17 -0
- data/examples/reverse_proxy/rails_subapp/config/storage.yml +34 -0
- data/examples/reverse_proxy/rails_subapp/config.ru +6 -0
- data/examples/reverse_proxy/rails_subapp/db/cable_schema.rb +11 -0
- data/examples/reverse_proxy/rails_subapp/db/cache_schema.rb +14 -0
- data/examples/reverse_proxy/rails_subapp/db/migrate/20250422211855_create_articles.rb +10 -0
- data/examples/reverse_proxy/rails_subapp/db/queue_schema.rb +129 -0
- data/examples/reverse_proxy/rails_subapp/db/schema.rb +20 -0
- data/examples/reverse_proxy/rails_subapp/db/seeds.rb +9 -0
- data/examples/reverse_proxy/rails_subapp/lib/tasks/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/log/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/public/400.html +114 -0
- data/examples/reverse_proxy/rails_subapp/public/404.html +114 -0
- data/examples/reverse_proxy/rails_subapp/public/406-unsupported-browser.html +114 -0
- data/examples/reverse_proxy/rails_subapp/public/422.html +114 -0
- data/examples/reverse_proxy/rails_subapp/public/500.html +114 -0
- data/examples/reverse_proxy/rails_subapp/public/icon.png +0 -0
- data/examples/reverse_proxy/rails_subapp/public/icon.svg +3 -0
- data/examples/reverse_proxy/rails_subapp/public/robots.txt +1 -0
- data/examples/reverse_proxy/rails_subapp/script/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/storage/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/application_system_test_case.rb +5 -0
- data/examples/reverse_proxy/rails_subapp/test/controllers/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/controllers/articles_controller_test.rb +48 -0
- data/examples/reverse_proxy/rails_subapp/test/controllers/home_controller_test.rb +8 -0
- data/examples/reverse_proxy/rails_subapp/test/fixtures/articles.yml +9 -0
- data/examples/reverse_proxy/rails_subapp/test/fixtures/files/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/helpers/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/integration/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/mailers/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/models/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/models/article_test.rb +7 -0
- data/examples/reverse_proxy/rails_subapp/test/system/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/test/system/articles_test.rb +43 -0
- data/examples/reverse_proxy/rails_subapp/test/test_helper.rb +15 -0
- data/examples/reverse_proxy/rails_subapp/tmp/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/tmp/pids/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/tmp/storage/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/vendor/.keep +0 -0
- data/examples/reverse_proxy/rails_subapp/vendor/javascript/.keep +0 -0
- data/examples/reverse_proxy/sinatra_subapp/Gemfile +2 -0
- data/examples/reverse_proxy/sinatra_subapp/Gemfile.lock +46 -0
- data/examples/reverse_proxy/sinatra_subapp/config.ru +2 -0
- data/examples/reverse_proxy/sinatra_subapp/my_app.rb +96 -0
- data/examples/simple_api/Itsi.rb +127 -0
- data/examples/simple_api_no_schema/Itsi.rb +86 -0
- data/examples/spa/Itsi.rb +5 -0
- data/examples/spa/README.md +3 -0
- data/examples/spa/dist/assets/index-2cf7be43.js +40 -0
- data/examples/spa/dist/index.html +13 -0
- data/examples/spa/index.html +12 -0
- data/examples/spa/package-lock.json +1265 -0
- data/examples/spa/package.json +18 -0
- data/examples/spa/src/App.jsx +49 -0
- data/examples/spa/src/main.jsx +6 -0
- data/examples/spa/src/pages/About.jsx +9 -0
- data/examples/spa/src/pages/Home.jsx +9 -0
- data/examples/spa/vite.config.js +9 -0
- data/gems/scheduler/Cargo.lock +74 -17
- data/gems/scheduler/itsi-scheduler.gemspec +2 -2
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/server/Cargo.lock +28 -29
- data/gems/server/itsi-server.gemspec +2 -2
- data/gems/server/lib/itsi/http_request.rb +31 -34
- data/gems/server/lib/itsi/http_response.rb +10 -8
- data/gems/server/lib/itsi/passfile.rb +6 -6
- data/gems/server/lib/itsi/server/config/config_helpers.rb +33 -33
- data/gems/server/lib/itsi/server/config/dsl.rb +16 -21
- data/gems/server/lib/itsi/server/config/known_paths.rb +11 -7
- data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +0 -4
- data/gems/server/lib/itsi/server/config/middleware/error_response.md +13 -0
- data/gems/server/lib/itsi/server/config/middleware/location.rb +25 -21
- data/gems/server/lib/itsi/server/config/middleware/proxy.rb +15 -14
- data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +7 -10
- data/gems/server/lib/itsi/server/config/middleware/static_assets.md +40 -0
- data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +8 -4
- data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +14 -0
- data/gems/server/lib/itsi/server/config/option.rb +0 -1
- data/gems/server/lib/itsi/server/config/options/include.rb +1 -1
- data/gems/server/lib/itsi/server/config/options/nodelay.md +2 -2
- data/gems/server/lib/itsi/server/config/options/reuse_address.md +1 -1
- data/gems/server/lib/itsi/server/config/typed_struct.rb +32 -35
- data/gems/server/lib/itsi/server/config.rb +107 -92
- data/gems/server/lib/itsi/server/default_app/default_app.rb +1 -1
- data/gems/server/lib/itsi/server/grpc/grpc_call.rb +4 -5
- data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +6 -7
- data/gems/server/lib/itsi/server/rack/handler/itsi.rb +0 -1
- data/gems/server/lib/itsi/server/rack_interface.rb +1 -2
- data/gems/server/lib/itsi/server/route_tester.rb +26 -24
- data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +25 -0
- data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +9 -7
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/gems/server/lib/itsi/server.rb +22 -22
- data/gems/server/lib/itsi/standard_headers.rb +80 -80
- data/gems/server/test/helpers/test_helper.rb +17 -16
- data/gems/server/test/middleware/static_assets.rb +6 -4
- data/gems/server/test/middleware/string_rewrite.rb +54 -0
- data/gems/server/test/middleware/test_log_requests.rb +66 -2
- data/gems/server/test/options/test_workers.rb +12 -5
- data/lib/itsi/version.rb +1 -1
- metadata +435 -13
- data/examples/static_assets_example.rb +0 -83
- data/grpc_test/Itsi.rb +0 -11
- data/grpc_test/echo.proto +0 -14
- data/grpc_test/echo_pb.rb +0 -16
- data/grpc_test/echo_service_impl.rb +0 -8
- data/grpc_test/echo_services_pb.rb +0 -22
@@ -4,7 +4,7 @@ url: /options/reuse_address
|
|
4
4
|
---
|
5
5
|
|
6
6
|
Configures whether the server should bind to the underlying socket using the `SO_REUSEADDR` option.
|
7
|
-
This
|
7
|
+
This option determines whether the server allows the reuse of local addresses during binding. This can be useful in scenarios where a socket needs to be quickly rebound without waiting for the operating system to release the address.
|
8
8
|
|
9
9
|
## Configuration
|
10
10
|
```ruby {filename=Itsi.rb}
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "time"
|
3
5
|
|
4
6
|
module Itsi
|
5
7
|
class Server
|
@@ -10,25 +12,19 @@ module Itsi
|
|
10
12
|
|
11
13
|
def self.new(defaults = nil, &defaults_blk)
|
12
14
|
defaults = TypedStruct.module_eval(&defaults_blk) if defaults_blk
|
13
|
-
unless defaults.is_a?(Hash)
|
14
|
-
|
15
|
-
end
|
15
|
+
return defaults unless defaults.is_a?(Hash)
|
16
|
+
|
16
17
|
defaults.transform_values! { _1.is_a?(Validation) ? _1.default(nil) : _1 }
|
17
18
|
Struct.new(*defaults.keys, keyword_init: true) do
|
18
19
|
define_method(:initialize) do |*input, validate: true, **raw_input|
|
20
|
+
raise "─ Invalid input to #{self}: #{input.last}" if input.last && !input.last.is_a?(Hash)
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
raw_input.transform_keys!{|k| k.to_s.downcase.to_sym }
|
24
|
-
raw_input.merge!(input.pop.transform_keys!{|k| k.to_s.downcase.to_sym}) if input.last.is_a?(Hash)
|
22
|
+
raw_input.transform_keys! { |k| k.to_s.downcase.to_sym }
|
23
|
+
raw_input.merge!(input.pop.transform_keys! { |k| k.to_s.downcase.to_sym }) if input.last.is_a?(Hash)
|
25
24
|
|
26
25
|
excess_keys = raw_input.keys - defaults.keys
|
27
26
|
|
28
|
-
if excess_keys.any?
|
29
|
-
raise "─ Unsupported keys #{excess_keys}"
|
30
|
-
|
31
|
-
end
|
27
|
+
raise "─ Unsupported keys #{excess_keys}" if excess_keys.any?
|
32
28
|
|
33
29
|
initial_values = defaults.each_with_object({}) do |(k, default_config), inputs|
|
34
30
|
value = raw_input.key?(k) ? raw_input[k] : default_config[VALUE].dup
|
@@ -106,9 +102,7 @@ module Itsi
|
|
106
102
|
|
107
103
|
def &(other)
|
108
104
|
tail = self
|
109
|
-
while tail.next
|
110
|
-
tail = tail.next
|
111
|
-
end
|
105
|
+
tail = tail.next while tail.next
|
112
106
|
tail.next = other
|
113
107
|
self
|
114
108
|
end
|
@@ -148,10 +142,14 @@ module Itsi
|
|
148
142
|
elsif validation.eql?(::Date) then Date.parse(value.to_s)
|
149
143
|
elsif validation.eql?(Float) then Float(value)
|
150
144
|
elsif validation.eql?(Integer) then Integer(value)
|
151
|
-
elsif validation.eql?(Proc)
|
145
|
+
elsif validation.eql?(Proc)
|
152
146
|
raise ArgumentError, "Invalid #{validation} value: #{value.inspect}" unless value.is_a?(Proc)
|
153
147
|
elsif validation.eql?(String) || validation.eql?(Symbol)
|
154
|
-
|
148
|
+
unless value.is_a?(String) || value.is_a?(Symbol)
|
149
|
+
raise ArgumentError,
|
150
|
+
"Invalid #{validation} value: #{value.inspect}"
|
151
|
+
end
|
152
|
+
|
155
153
|
if validation.eql?(String)
|
156
154
|
value.to_s
|
157
155
|
elsif validation.eql?(Symbol)
|
@@ -178,33 +176,32 @@ module Itsi
|
|
178
176
|
{
|
179
177
|
Bool: Validation.new(:Bool, [[true, false]]),
|
180
178
|
Required: Validation.new(:Required, ->(value) { !value.nil? }),
|
181
|
-
Or:
|
182
|
-
Validation.new(:Or,
|
183
|
-
|
179
|
+
Or: lambda { |*validations|
|
180
|
+
Validation.new(:Or, lambda { |v|
|
184
181
|
return true if v.nil?
|
182
|
+
|
185
183
|
errs = []
|
186
184
|
validations.each do |validation|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
errs << e.message
|
192
|
-
end
|
185
|
+
v = validation.validate!(v)
|
186
|
+
return v
|
187
|
+
rescue StandardError => e
|
188
|
+
errs << e.message
|
193
189
|
end
|
194
190
|
raise StandardError.new("─ Validation failed (None match:) \n └#{errs.join("\n └")}")
|
195
191
|
})
|
196
192
|
},
|
197
|
-
Range:
|
193
|
+
Range: lambda { |input_range|
|
198
194
|
Validation.new(:Range, [input_range])
|
199
195
|
},
|
200
196
|
Length: lambda { |input_length|
|
201
197
|
Validation.new(:Length, ->(value) { input_length === value.length })
|
202
198
|
},
|
203
|
-
Hash:
|
204
|
-
Validation.new(:Hash,
|
205
|
-
return true if
|
206
|
-
raise StandardError.new("Expected hash got #{
|
207
|
-
|
199
|
+
Hash: lambda { |key_type, value_type|
|
200
|
+
Validation.new(:Hash, lambda { |hash|
|
201
|
+
return true if hash.nil?
|
202
|
+
raise StandardError.new("Expected hash got #{hash.class}") unless hash.is_a?(Hash)
|
203
|
+
|
204
|
+
hash.map do |k, v|
|
208
205
|
[
|
209
206
|
key_type.validate!(k),
|
210
207
|
value_type.validate!(v)
|
@@ -213,7 +210,7 @@ module Itsi
|
|
213
210
|
})
|
214
211
|
},
|
215
212
|
Type: ->(input_type) { Validation.new(:Type, input_type) },
|
216
|
-
Enum: ->(allowed_values) { Validation.new(:Enum, [allowed_values.map{|v| v.
|
213
|
+
Enum: ->(allowed_values) { Validation.new(:Enum, [allowed_values.map { |v| v.is_a?(Symbol) ? v.to_s : v }]) },
|
217
214
|
Array: lambda { |*value_validations|
|
218
215
|
Validation.new(:Array, [::Array, lambda { |value|
|
219
216
|
return true unless value
|
@@ -41,15 +41,18 @@ module Itsi
|
|
41
41
|
elsif args[:static]
|
42
42
|
DSL.evaluate do
|
43
43
|
location "/" do
|
44
|
-
rate_limit key:
|
45
|
-
etag type:
|
46
|
-
compress min_size: 1024 * 1024, level:
|
47
|
-
|
44
|
+
rate_limit key: "address", store_config: "in_memory", requests: 2, seconds: 5
|
45
|
+
etag type: "strong", algorithm: "md5", min_body_size: 1024 * 1024
|
46
|
+
compress min_size: 1024 * 1024, level: "fastest", algorithms: %w[zstd gzip br deflate],
|
47
|
+
mime_types: %w[all], compress_streams: true
|
48
|
+
log_requests before: { level: "INFO", format: "[{request_id}] {method} {path_and_query} - {addr} " },
|
49
|
+
after: { level: "INFO",
|
50
|
+
format: "[{request_id}] └─ {status} in {response_time}" }
|
48
51
|
static_assets \
|
49
52
|
relative_path: true,
|
50
53
|
allowed_extensions: [],
|
51
|
-
root_dir:
|
52
|
-
not_found_behavior: {error:
|
54
|
+
root_dir: ".",
|
55
|
+
not_found_behavior: { error: "not_found" },
|
53
56
|
auto_index: true,
|
54
57
|
try_html_extension: true,
|
55
58
|
max_file_size_in_memory: 1024 * 1024, # 1MB
|
@@ -57,7 +60,7 @@ module Itsi
|
|
57
60
|
file_check_interval: 1,
|
58
61
|
serve_hidden_files: false,
|
59
62
|
headers: {
|
60
|
-
|
63
|
+
"X-Content-Type-Options" => "nosniff"
|
61
64
|
}
|
62
65
|
end
|
63
66
|
end
|
@@ -69,7 +72,7 @@ module Itsi
|
|
69
72
|
rackup_file args.fetch(:rackup_file, "./config.ru")
|
70
73
|
end
|
71
74
|
else
|
72
|
-
DSL.evaluate{}
|
75
|
+
DSL.evaluate {}
|
73
76
|
end
|
74
77
|
|
75
78
|
itsifile_config.transform_keys!(&:to_sym)
|
@@ -85,7 +88,7 @@ module Itsi
|
|
85
88
|
Itsi.log_debug("Preloading middleware and default rack app")
|
86
89
|
preloaded_middleware = middleware_loader.call
|
87
90
|
middleware_loader = -> { preloaded_middleware }
|
88
|
-
rescue
|
91
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
89
92
|
errors << [e, e.backtrace[0]]
|
90
93
|
end
|
91
94
|
# If we're just preloading a specific gem group, we'll do that here too
|
@@ -107,7 +110,13 @@ module Itsi
|
|
107
110
|
worker_memory_limit: args.fetch(:worker_memory_limit) { itsifile_config.fetch(:worker_memory_limit, nil) },
|
108
111
|
silence: args.fetch(:silence) { itsifile_config.fetch(:silence, false) },
|
109
112
|
shutdown_timeout: args.fetch(:shutdown_timeout) { itsifile_config.fetch(:shutdown_timeout, 5) },
|
110
|
-
hooks: args[:hooks] && itsifile_config[:hooks]
|
113
|
+
hooks: if args[:hooks] && itsifile_config[:hooks]
|
114
|
+
args[:hooks].merge(itsifile_config[:hooks])
|
115
|
+
else
|
116
|
+
itsifile_config.fetch(
|
117
|
+
:hooks, args[:hooks]
|
118
|
+
)
|
119
|
+
end,
|
111
120
|
preload: !!preload,
|
112
121
|
request_timeout: itsifile_config.fetch(:request_timeout, nil),
|
113
122
|
header_read_timeout: args.fetch(:header_read_timeout) { itsifile_config.fetch(:header_read_timeout, nil) },
|
@@ -132,53 +141,23 @@ module Itsi
|
|
132
141
|
listeners: args.fetch(:listeners) { nil },
|
133
142
|
reuse_address: itsifile_config.fetch(:reuse_address, true),
|
134
143
|
reuse_port: itsifile_config.fetch(:reuse_port, true),
|
135
|
-
listen_backlog: itsifile_config.fetch(:listen_backlog, 1024
|
144
|
+
listen_backlog: itsifile_config.fetch(:listen_backlog, 1024),
|
136
145
|
nodelay: itsifile_config.fetch(:nodelay, true),
|
137
146
|
recv_buffer_size: itsifile_config.fetch(:recv_buffer_size, 262_144)
|
138
147
|
}.transform_keys(&:to_s)
|
139
148
|
|
140
|
-
|
141
|
-
|
142
|
-
file, lineno = location.split(":")
|
143
|
-
lineno = lineno.to_i
|
144
|
-
err_message = error.kind_of?(NoMethodError) ? error.detailed_message : error.message
|
145
|
-
file_lines = IO.readlines(file)
|
146
|
-
info_lines = if error.kind_of?(SyntaxError)
|
147
|
-
[]
|
148
|
-
else
|
149
|
-
([lineno-2, 0].max...[file_lines.length, lineno.succ.succ].min).map do |currline|
|
150
|
-
if currline == lineno-1
|
151
|
-
line = file_lines[currline][0...-1]
|
152
|
-
padding = line[/^\s+/]&.length || 0
|
153
|
-
|
154
|
-
[
|
155
|
-
" \e[31m#{currline.succ.to_s.rjust(3)} | #{line}\e[0m",
|
156
|
-
" | #{' ' * padding}\e[33m^^^\e[0m "
|
157
|
-
]
|
158
|
-
else
|
159
|
-
" #{currline.succ.to_s.rjust(3)} | #{file_lines[currline][0...-1]}"
|
160
|
-
end
|
161
|
-
end.flatten
|
162
|
-
end
|
163
|
-
[
|
164
|
-
err_message,
|
165
|
-
" --> #{File.expand_path(file)}:#{lineno}",
|
166
|
-
*info_lines
|
167
|
-
]
|
168
|
-
end
|
169
|
-
|
170
|
-
return srv_config, error_lines
|
171
|
-
rescue
|
149
|
+
[srv_config, errors_to_error_lines(errors)]
|
150
|
+
rescue StandardError
|
172
151
|
Itsi.log_error e.message
|
173
152
|
puts e.backtrace
|
174
153
|
end
|
175
154
|
|
176
155
|
def self.test!(cli_params)
|
177
|
-
|
156
|
+
config, errors = build_config(cli_params, Itsi::Server::Config.config_file_path(cli_params[:config_file]))
|
178
157
|
unless errors.any?
|
179
158
|
begin
|
180
|
-
|
181
|
-
rescue Exception => e
|
159
|
+
config["middleware_loader"][]
|
160
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
182
161
|
errors = [e]
|
183
162
|
end
|
184
163
|
end
|
@@ -191,6 +170,42 @@ module Itsi
|
|
191
170
|
end
|
192
171
|
end
|
193
172
|
|
173
|
+
def self.errors_to_error_lines(errors)
|
174
|
+
return unless errors
|
175
|
+
|
176
|
+
errors.flat_map do |(error, message)|
|
177
|
+
location = message[/(.*?):in/, 1]
|
178
|
+
file, lineno = location.split(":")
|
179
|
+
lineno = lineno.to_i
|
180
|
+
err_message = error.is_a?(NoMethodError) ? error.detailed_message : error.message
|
181
|
+
file_lines = IO.readlines(file)
|
182
|
+
info_lines = \
|
183
|
+
if error.is_a?(SyntaxError)
|
184
|
+
[]
|
185
|
+
else
|
186
|
+
|
187
|
+
([lineno - 2, 0].max...[file_lines.length, lineno.succ.succ].min).map do |currline|
|
188
|
+
if currline == lineno - 1
|
189
|
+
line = file_lines[currline][0...-1]
|
190
|
+
padding = line[/^\s+/]&.length || 0
|
191
|
+
|
192
|
+
[
|
193
|
+
" \e[31m#{currline.succ.to_s.rjust(3)} | #{line}\e[0m",
|
194
|
+
" | #{" " * padding}\e[33m^^^\e[0m "
|
195
|
+
]
|
196
|
+
else
|
197
|
+
" #{currline.succ.to_s.rjust(3)} | #{file_lines[currline][0...-1]}"
|
198
|
+
end
|
199
|
+
end.flatten
|
200
|
+
end
|
201
|
+
[
|
202
|
+
err_message,
|
203
|
+
" --> #{File.expand_path(file)}:#{lineno}",
|
204
|
+
*info_lines
|
205
|
+
]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
194
209
|
# Reloads the entire process
|
195
210
|
# using exec, passing in any active file descriptors
|
196
211
|
# and previous invocation arguments
|
@@ -233,56 +248,56 @@ module Itsi
|
|
233
248
|
|
234
249
|
default_config = IO.read("#{__dir__}/default_config/Itsi.rb")
|
235
250
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
251
|
+
default_config << \
|
252
|
+
if File.exist?("./config.ru")
|
253
|
+
<<~RUBY
|
254
|
+
# You can mount several Ruby apps as either
|
255
|
+
# 1. rackup files
|
256
|
+
# 2. inline rack apps
|
257
|
+
# 3. inline Ruby endpoints
|
258
|
+
#
|
259
|
+
# 1. rackup_file
|
260
|
+
rackup_file "./config.ru"
|
261
|
+
#
|
262
|
+
# 2. inline rack app
|
263
|
+
# require 'rack'
|
264
|
+
# run(Rack::Builder.app do
|
265
|
+
# use Rack::CommonLogger
|
266
|
+
# run ->(env) { [200, { 'content-type' => 'text/plain' }, ['OK']] }
|
267
|
+
# end)
|
268
|
+
#
|
269
|
+
# 3. Endpoints
|
270
|
+
# endpoint "/" do |req|
|
271
|
+
# req.ok "Hello from Itsi"
|
272
|
+
# end
|
273
|
+
RUBY
|
274
|
+
else
|
275
|
+
<<~RUBY
|
276
|
+
# You can mount several Ruby apps as either
|
277
|
+
# 1. rackup files
|
278
|
+
# 2. inline rack apps
|
279
|
+
# 3. inline Ruby endpoints
|
280
|
+
#
|
281
|
+
# 1. rackup_file
|
282
|
+
# Use `rackup_file` to specify the Rack app file name.
|
283
|
+
#
|
284
|
+
# 2. inline rack app
|
285
|
+
# require 'rack'
|
286
|
+
# run(Rack::Builder.app do
|
287
|
+
# use Rack::CommonLogger
|
288
|
+
# run ->(env) { [200, { 'content-type' => 'text/plain' }, ['OK']] }
|
289
|
+
# end)
|
290
|
+
#
|
291
|
+
# 3. Endpoint
|
292
|
+
endpoint "/" do |req|
|
293
|
+
req.ok "Hello from Itsi"
|
294
|
+
end
|
295
|
+
RUBY
|
296
|
+
end
|
281
297
|
|
282
298
|
File.open(ITSI_DEFAULT_CONFIG_FILE, "w") do |file|
|
283
299
|
file.write(default_config)
|
284
300
|
end
|
285
|
-
|
286
301
|
end
|
287
302
|
end
|
288
303
|
end
|
@@ -7,11 +7,11 @@ module Itsi
|
|
7
7
|
attr_accessor :rpc_desc
|
8
8
|
|
9
9
|
def input_stream?
|
10
|
-
@input_stream ||= @rpc_desc&.input
|
10
|
+
@input_stream ||= @rpc_desc&.input.is_a?(GRPC::RpcDesc::Stream) || false
|
11
11
|
end
|
12
12
|
|
13
13
|
def output_stream?
|
14
|
-
@output_stream ||= @rpc_desc&.output
|
14
|
+
@output_stream ||= @rpc_desc&.output.is_a?(GRPC::RpcDesc::Stream) || false
|
15
15
|
end
|
16
16
|
|
17
17
|
def input_type
|
@@ -64,7 +64,7 @@ module Itsi
|
|
64
64
|
return nil if first_char.nil?
|
65
65
|
|
66
66
|
# Step 2: Process objects until we hit the end of the JSON stream or array.
|
67
|
-
loop do
|
67
|
+
loop do # rubocop:disable Lint/UnreachableLoop,Metrics/BlockLength
|
68
68
|
# Skip any whitespace or commas preceding an object.
|
69
69
|
char = nil
|
70
70
|
loop do
|
@@ -89,7 +89,6 @@ module Itsi
|
|
89
89
|
|
90
90
|
buffer << ch
|
91
91
|
|
92
|
-
|
93
92
|
if in_string
|
94
93
|
if escape
|
95
94
|
escape = false
|
@@ -120,7 +119,7 @@ module Itsi
|
|
120
119
|
def remote_read
|
121
120
|
if content_type == "application/json"
|
122
121
|
if input_stream?
|
123
|
-
if next_item = parse_from_json_stream(reader)
|
122
|
+
if (next_item = parse_from_json_stream(reader))
|
124
123
|
input_type.decode_json(next_item)
|
125
124
|
end
|
126
125
|
else
|
@@ -29,7 +29,6 @@ module Itsi
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def handle_request(active_call)
|
32
|
-
puts "Handling active call"
|
33
32
|
unless (active_call.rpc_desc = @rpc_descs[active_call.method_name])
|
34
33
|
active_call.stream.write("\n")
|
35
34
|
active_call.send_status(13, "Method not found")
|
@@ -89,18 +88,18 @@ module Itsi
|
|
89
88
|
result = service.send(active_call.method_name, message, active_call) do |response|
|
90
89
|
active_call.remote_send(response)
|
91
90
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
return unless result.is_a?(Enumerator)
|
92
|
+
|
93
|
+
result.each { |response| active_call.remote_send(response) }
|
95
94
|
end
|
96
95
|
|
97
96
|
def handle_bidi_streaming(active_call)
|
98
97
|
result = service.send(active_call.method_name, active_call.each_remote_read, active_call) do |response|
|
99
98
|
active_call.remote_send(response)
|
100
99
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
return unless result.is_a?(Enumerator)
|
101
|
+
|
102
|
+
result.each { |response| active_call.remote_send(response) }
|
104
103
|
end
|
105
104
|
end
|
106
105
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Itsi
|
2
2
|
class Server
|
3
3
|
module RackInterface
|
4
|
-
|
5
4
|
# Builds a handler proc that is compatible with Rack applications.
|
6
5
|
def self.for(app)
|
7
6
|
require "rack"
|
8
7
|
if app.is_a?(String)
|
9
8
|
dir = File.expand_path(File.dirname(app))
|
10
9
|
Dir.chdir(dir) do
|
11
|
-
loaded_app = ::Rack::Builder.parse_file(app)
|
10
|
+
loaded_app = ::Rack::Builder.parse_file(File.basename(app))
|
12
11
|
app = loaded_app.is_a?(Array) ? loaded_app.first : loaded_app
|
13
12
|
end
|
14
13
|
end
|
@@ -1,53 +1,55 @@
|
|
1
1
|
module Itsi
|
2
2
|
class Server
|
3
|
+
# Utility module for printing Itsi route information
|
3
4
|
module RouteTester
|
4
|
-
|
5
5
|
require "set"
|
6
6
|
require "strscan"
|
7
|
-
|
7
|
+
|
8
8
|
def format_mw(mw)
|
9
9
|
mw_name, mw_args = mw
|
10
10
|
case mw_name
|
11
11
|
when "app"
|
12
|
-
"\e[33mapp\e[0m(#{mw_args[
|
12
|
+
"\e[33mapp\e[0m(#{mw_args["app_proc"].inspect.split(" ")[1][0...-1]})"
|
13
13
|
when "log_requests"
|
14
|
-
if mw_args[
|
15
|
-
"\e[33mlog_requests\e[0m(before: #{mw_args[
|
16
|
-
elsif mw_args[
|
17
|
-
"\e[33mlog_requests\e[0m(before: #{mw_args[
|
18
|
-
elsif mw_args[
|
19
|
-
"\e[33mlog_requests\e[0m(before: nil, after: #{mw_args[
|
14
|
+
if mw_args["before"] && mw_args["after"]
|
15
|
+
"\e[33mlog_requests\e[0m(before: #{mw_args["before"]["format"][0..6]}..., after: #{mw_args["after"]["format"][0..6]}...)"
|
16
|
+
elsif mw_args["before"]
|
17
|
+
"\e[33mlog_requests\e[0m(before: #{mw_args["before"]["format"][0..6]}...)"
|
18
|
+
elsif mw_args["after"]
|
19
|
+
"\e[33mlog_requests\e[0m(before: nil, after: #{mw_args["after"]["format"][0..6]}...)"
|
20
20
|
end
|
21
21
|
when "compress"
|
22
|
-
"\e[33mcompress\e[0m(#{mw_args[
|
22
|
+
"\e[33mcompress\e[0m(#{mw_args["algorithms"].join(" ")}, #{mw_args["mime_types"]})"
|
23
23
|
when "cors"
|
24
|
-
"\e[33mcors\e[0m(#{mw_args[
|
24
|
+
"\e[33mcors\e[0m(#{mw_args["allow_origins"].join(" ")}, #{mw_args["allow_methods"].join(" ")})"
|
25
25
|
when "etag"
|
26
|
-
"\e[33metag\e[0m(#{mw_args[
|
26
|
+
"\e[33metag\e[0m(#{mw_args["type"]}/#{mw_args["algorithm"]}, #{mw_args["handle_if_none_match"] ? "if_none_match" : ""})"
|
27
27
|
when "cache_control"
|
28
|
-
"\e[33mcache_control\e[0m(max_age: #{mw_args[
|
28
|
+
"\e[33mcache_control\e[0m(max_age: #{mw_args["max_age"]}, #{mw_args.select do |_, v|
|
29
|
+
v == true
|
30
|
+
end.keys.join(", ")})"
|
29
31
|
when "redirect"
|
30
|
-
"\e[33mredirect\e[0m(to: #{mw_args[
|
32
|
+
"\e[33mredirect\e[0m(to: #{mw_args["to"]}, type: #{mw_args["type"]})"
|
31
33
|
when "static_assets"
|
32
|
-
"\e[33mstatic_assets\e[0m(path: #{mw_args[
|
34
|
+
"\e[33mstatic_assets\e[0m(path: #{mw_args["root_dir"]})"
|
33
35
|
when "auth_api_key"
|
34
|
-
"\e[33mauth_api_key\e[0m(keys: #{mw_args[
|
36
|
+
"\e[33mauth_api_key\e[0m(keys: #{mw_args["valid_keys"].keys}#{mw_args["credentials_file"] ? ", credentials_file: #{mw_args["credentials_file"]}" : ""})"
|
35
37
|
when "auth_basic"
|
36
|
-
"\e[33mbasic_auth\e[0m(keys: #{mw_args[
|
38
|
+
"\e[33mbasic_auth\e[0m(keys: #{mw_args["realm"]}#{mw_args["credentials_file"] ? ", credentials_file: #{mw_args["credentials_file"]}" : ""})"
|
37
39
|
when "auth_jwt"
|
38
|
-
"\e[33mjwt_auth\e[0m(#{mw_args[
|
40
|
+
"\e[33mjwt_auth\e[0m(#{mw_args["verifiers"].keys.join(",")})"
|
39
41
|
when "rate_limit"
|
40
|
-
key = mw_args[
|
41
|
-
"\e[33mrate_limit\e[0m(rps: #{mw_args[
|
42
|
+
key = mw_args["key"].is_a?(Hash) ? mw_args["key"]["parameter"] : mw_args["key"]
|
43
|
+
"\e[33mrate_limit\e[0m(rps: #{mw_args["requests"]}/#{mw_args["seconds"]}, key: #{key})"
|
42
44
|
when "allow_list"
|
43
|
-
"\e[33mallow_list\e[0m(patterns: #{mw_args[
|
45
|
+
"\e[33mallow_list\e[0m(patterns: #{mw_args["allowed_patterns"].join(", ")})"
|
44
46
|
when "deny_list"
|
45
|
-
"\e[33mdeny_list\e[0m(patterns: #{mw_args[
|
47
|
+
"\e[33mdeny_list\e[0m(patterns: #{mw_args["denied_patterns"].join(", ")})"
|
46
48
|
when "csp"
|
47
|
-
"\e[33mcsp\e[0m(#{mw_args[
|
49
|
+
"\e[33mcsp\e[0m(#{mw_args["policy"].map { |k, v| "#{k}: #{v.join(",")}" }.join(", ")})"
|
48
50
|
when "intrusion_protection"
|
49
51
|
[mw_args].flatten.map do |mw_args|
|
50
|
-
"\e[33mintrusion_protection\e[0m(banned_url_patterns: #{mw_args[
|
52
|
+
"\e[33mintrusion_protection\e[0m(banned_url_patterns: #{mw_args["banned_url_patterns"]&.length}, banned_header_patterns: #{mw_args["banned_header_patterns"]&.keys&.join(", ")}, #{mw_args["banned_time_seconds"]}s)"
|
51
53
|
end.join("\n")
|
52
54
|
when "request_headers"
|
53
55
|
[mw_args].flatten.map do |mw_args|
|
@@ -143,6 +143,31 @@ module Itsi
|
|
143
143
|
# Fixed keys are converted to symbols, and regex-matched keys remain as strings.
|
144
144
|
# The current location in the params is tracked as an array of path segments.
|
145
145
|
def apply_schema!(params, schema, path = [])
|
146
|
+
# Support top-level array schema: homogeneous arrays.
|
147
|
+
if schema.is_a?(Array)
|
148
|
+
# Only allow homogeneous array types
|
149
|
+
unless schema.size == 1
|
150
|
+
raise ValidationError.new(["Schema Array must contain exactly one type. Got #{schema.size}"])
|
151
|
+
end
|
152
|
+
expected_type = schema.first
|
153
|
+
# Expect params to be an Array
|
154
|
+
unless params.is_a?(Array)
|
155
|
+
raise ValidationError.new(["Expected Array at #{format_path(path)}, got #{params.class}"])
|
156
|
+
end
|
157
|
+
errors = []
|
158
|
+
params.each_with_index do |_, idx|
|
159
|
+
err = cast_value!(params, idx, expected_type, path + [idx])
|
160
|
+
errors << err if err
|
161
|
+
end
|
162
|
+
raise ValidationError.new(errors) unless errors.empty?
|
163
|
+
return params
|
164
|
+
end
|
165
|
+
|
166
|
+
# Ensure schema is a Hash
|
167
|
+
unless schema.is_a?(Hash)
|
168
|
+
raise ValidationError.new(["Unsupported schema type: #{schema.class} at #{format_path(path)}"])
|
169
|
+
end
|
170
|
+
|
146
171
|
errors = []
|
147
172
|
processed = processed_schema(schema)
|
148
173
|
fixed_schema = processed[0]
|