itsi 0.1.20 → 0.2.3
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 -8
- data/Cargo.lock +29 -30
- data/LICENSE.txt +698 -0
- data/README.md +16 -4
- data/Rakefile +9 -5
- data/crates/itsi_acme/.gitignore +4 -0
- data/crates/itsi_acme/Cargo.toml +86 -0
- data/crates/itsi_acme/LICENSE-APACHE +201 -0
- data/crates/itsi_acme/LICENSE-MIT +23 -0
- data/crates/itsi_acme/README.md +9 -0
- data/crates/itsi_acme/examples/high_level.rs +63 -0
- data/crates/itsi_acme/examples/high_level_warp.rs +52 -0
- data/crates/itsi_acme/examples/low_level.rs +87 -0
- data/crates/itsi_acme/examples/low_level_axum.rs +66 -0
- data/crates/itsi_acme/src/acceptor.rs +81 -0
- data/crates/itsi_acme/src/acme.rs +354 -0
- data/crates/itsi_acme/src/axum.rs +86 -0
- data/crates/itsi_acme/src/cache.rs +39 -0
- data/crates/itsi_acme/src/caches/boxed.rs +80 -0
- data/crates/itsi_acme/src/caches/composite.rs +69 -0
- data/crates/itsi_acme/src/caches/dir.rs +106 -0
- data/crates/itsi_acme/src/caches/mod.rs +11 -0
- data/crates/itsi_acme/src/caches/no.rs +78 -0
- data/crates/itsi_acme/src/caches/test.rs +136 -0
- data/crates/itsi_acme/src/config.rs +172 -0
- data/crates/itsi_acme/src/https_helper.rs +69 -0
- data/crates/itsi_acme/src/incoming.rs +142 -0
- data/crates/itsi_acme/src/jose.rs +161 -0
- data/crates/itsi_acme/src/lib.rs +142 -0
- data/crates/itsi_acme/src/resolver.rs +59 -0
- data/crates/itsi_acme/src/state.rs +424 -0
- data/crates/itsi_rb_helpers/src/lib.rs +4 -3
- data/crates/itsi_scheduler/Cargo.toml +1 -1
- data/crates/itsi_scheduler/src/itsi_scheduler.rs +8 -2
- data/crates/itsi_scheduler/src/lib.rs +1 -0
- data/crates/itsi_server/Cargo.toml +1 -1
- data/crates/itsi_server/src/lib.rs +2 -1
- data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +18 -1
- data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +11 -3
- data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +148 -66
- data/crates/itsi_server/src/ruby_types/itsi_server.rs +2 -0
- data/crates/itsi_server/src/server/binds/bind.rs +3 -0
- data/crates/itsi_server/src/server/binds/listener.rs +12 -5
- data/crates/itsi_server/src/server/binds/tls.rs +13 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +12 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +8 -1
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +9 -1
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +48 -43
- data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +11 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +39 -12
- data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +36 -27
- data/crates/itsi_server/src/server/middleware_stack/middlewares/csp.rs +25 -11
- data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +12 -3
- data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +74 -72
- data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +15 -1
- data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +11 -8
- data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +19 -11
- data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +5 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +2 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +11 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +17 -20
- data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +19 -8
- data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +16 -37
- data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +22 -12
- data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +26 -11
- data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +7 -1
- data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +14 -4
- data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +19 -0
- data/crates/itsi_server/src/server/middleware_stack/mod.rs +49 -13
- data/crates/itsi_server/src/server/mod.rs +1 -0
- data/crates/itsi_server/src/server/redirect_type.rs +26 -0
- data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +22 -16
- data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +49 -12
- data/crates/itsi_server/src/server/signal.rs +1 -0
- data/crates/itsi_server/src/server/size_limited_incoming.rs +6 -0
- data/crates/itsi_server/src/server/thread_worker.rs +5 -1
- data/crates/itsi_server/src/services/itsi_http_service.rs +20 -2
- data/crates/itsi_server/src/services/rate_limiter.rs +15 -4
- data/crates/itsi_server/src/services/static_file_server.rs +33 -19
- data/crates/itsi_tracing/src/lib.rs +42 -22
- data/docs/content/_index.md +2 -3
- data/docs/content/acknowledgements/_index.md +5 -2
- data/docs/content/configuration/_index.md +8 -5
- data/docs/content/contact/_index.md +8 -1
- data/docs/content/directory_listing.jpg +0 -0
- data/docs/content/error_page.jpg +0 -0
- data/docs/content/faqs/_index.md +5 -3
- data/docs/content/features/_index.md +56 -50
- data/docs/content/getting_started/_index.md +8 -5
- data/docs/content/getting_started/local_development.md +76 -9
- data/docs/content/getting_started/logging.md +15 -9
- data/docs/content/getting_started/running_itsi_in_production.md +5 -3
- data/docs/content/getting_started/signals.md +37 -0
- data/docs/content/itsi_scheduler/_index.md +8 -7
- data/docs/content/utilities/_index.md +13 -0
- data/docs/content/utilities/config_file_testing.md +17 -0
- data/docs/content/utilities/passfile_generator.md +41 -0
- data/docs/content/utilities/route_testing.md +27 -0
- data/docs/content/utilities/secrets_management.md +30 -0
- data/docs/hugo.yaml +4 -1
- data/fairytale.txt +3 -4
- data/gems/scheduler/Cargo.lock +74 -17
- data/gems/scheduler/README.md +4 -5
- data/gems/scheduler/Rakefile +0 -4
- data/gems/scheduler/itsi-scheduler.gemspec +2 -2
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/scheduler/lib/itsi/scheduler.rb +9 -4
- data/gems/scheduler/test/test_active_record.rb +12 -7
- data/gems/server/Cargo.lock +28 -29
- data/gems/server/Rakefile +0 -4
- data/gems/server/exe/itsi +13 -2
- data/gems/server/itsi-server.gemspec +2 -2
- data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +2 -0
- data/gems/server/lib/itsi/http_request.rb +58 -30
- data/gems/server/lib/itsi/http_response.rb +10 -7
- data/gems/server/lib/itsi/passfile.rb +6 -7
- data/gems/server/lib/itsi/server/config/config_helpers.rb +41 -29
- data/gems/server/lib/itsi/server/config/dsl.rb +22 -442
- data/gems/server/lib/itsi/server/config/known_paths.rb +14 -7
- data/gems/server/lib/itsi/server/config/middleware/_index.md +6 -4
- data/gems/server/lib/itsi/server/config/middleware/allow_list.md +46 -0
- data/gems/server/lib/itsi/server/config/middleware/allow_list.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_basic.md +45 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
- data/gems/server/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
- data/gems/server/lib/itsi/server/config/middleware/cache_control.md +78 -0
- data/gems/server/lib/itsi/server/config/middleware/cache_control.rb +45 -0
- data/gems/server/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
- data/gems/server/lib/itsi/server/config/middleware/compression.md +50 -0
- data/gems/server/lib/itsi/server/config/middleware/compression.rb +37 -0
- data/gems/server/lib/itsi/server/config/middleware/cors.md +93 -0
- data/gems/server/lib/itsi/server/config/middleware/cors.rb +32 -0
- data/gems/server/lib/itsi/server/config/middleware/csp.md +37 -0
- data/gems/server/lib/itsi/server/config/middleware/csp.rb +44 -0
- data/gems/server/lib/itsi/server/config/middleware/deny_list.md +45 -0
- data/gems/server/lib/itsi/server/config/middleware/deny_list.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
- data/gems/server/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
- data/gems/server/lib/itsi/server/config/middleware/error_response.md +74 -0
- data/gems/server/lib/itsi/server/config/middleware/error_response.rb +36 -0
- data/gems/server/lib/itsi/server/config/middleware/etag.md +59 -0
- data/gems/server/lib/itsi/server/config/middleware/etag.rb +27 -0
- data/gems/server/lib/itsi/server/config/middleware/grpc.md +172 -0
- data/gems/server/lib/itsi/server/config/middleware/grpc.rb +54 -0
- data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
- data/gems/server/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
- data/gems/server/lib/itsi/server/config/middleware/location.md +107 -0
- data/gems/server/lib/itsi/server/config/middleware/location.rb +99 -0
- data/gems/server/lib/itsi/server/config/middleware/log_requests.md +13 -11
- data/gems/server/lib/itsi/server/config/middleware/log_requests.rb +1 -3
- data/gems/server/lib/itsi/server/config/middleware/max_body.md +18 -0
- data/gems/server/lib/itsi/server/config/middleware/max_body.rb +21 -0
- data/gems/server/lib/itsi/server/config/middleware/proxy.md +62 -0
- data/gems/server/lib/itsi/server/config/middleware/proxy.rb +41 -0
- data/gems/server/lib/itsi/server/config/middleware/rackup_file.md +54 -0
- data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
- data/gems/server/lib/itsi/server/config/middleware/rate_limit.md +126 -0
- data/gems/server/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
- data/gems/server/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
- data/gems/server/lib/itsi/server/config/middleware/redirect.md +55 -0
- data/gems/server/lib/itsi/server/config/middleware/redirect.rb +25 -0
- data/gems/server/lib/itsi/server/config/middleware/request_headers.md +34 -0
- data/gems/server/lib/itsi/server/config/middleware/request_headers.rb +24 -0
- data/gems/server/lib/itsi/server/config/middleware/response_headers.md +33 -0
- data/gems/server/lib/itsi/server/config/middleware/response_headers.rb +25 -0
- data/gems/server/lib/itsi/server/config/middleware/run.md +60 -0
- data/gems/server/lib/itsi/server/config/middleware/run.rb +43 -0
- data/gems/server/lib/itsi/server/config/middleware/static_assets.md +113 -0
- data/gems/server/lib/itsi/server/config/middleware/static_assets.rb +87 -0
- data/gems/server/lib/itsi/server/config/middleware/static_response.md +44 -0
- data/gems/server/lib/itsi/server/config/middleware/static_response.rb +29 -0
- data/gems/server/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
- data/gems/server/lib/itsi/server/config/middleware/token_source.rb +32 -0
- data/gems/server/lib/itsi/server/config/middleware.rb +4 -0
- data/gems/server/lib/itsi/server/config/option.rb +4 -0
- data/gems/server/lib/itsi/server/config/options/_index.md +3 -2
- data/gems/server/lib/itsi/server/config/options/auto_reload_config.md +13 -0
- data/gems/server/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
- data/gems/server/lib/itsi/server/config/options/bind.md +71 -0
- data/gems/server/lib/itsi/server/config/options/bind.rb +26 -0
- data/gems/server/lib/itsi/server/config/options/certificates.md +65 -0
- data/gems/server/lib/itsi/server/config/options/daemonize.md +14 -0
- data/gems/server/lib/itsi/server/config/options/daemonize.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/fiber_scheduler.md +1 -2
- data/gems/server/lib/itsi/server/config/options/fiber_scheduler.rb +6 -3
- data/gems/server/lib/itsi/server/config/options/header_read_timeout.md +17 -0
- data/gems/server/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/hooks/_index.md +11 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_start.md +12 -0
- data/gems/server/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
- data/gems/server/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/include.md +20 -0
- data/gems/server/lib/itsi/server/config/options/include.rb +36 -0
- data/gems/server/lib/itsi/server/config/options/listen_backlog.md +11 -0
- data/gems/server/lib/itsi/server/config/options/listen_backlog.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/log_format.md +18 -0
- data/gems/server/lib/itsi/server/config/options/log_format.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/log_level.md +34 -0
- data/gems/server/lib/itsi/server/config/options/log_level.rb +20 -0
- data/gems/server/lib/itsi/server/config/options/log_target.md +38 -0
- data/gems/server/lib/itsi/server/config/options/log_target.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/log_target_filters.md +17 -0
- data/gems/server/lib/itsi/server/config/options/log_target_filters.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
- data/gems/server/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
- data/gems/server/lib/itsi/server/config/options/nodelay.md +16 -0
- data/gems/server/lib/itsi/server/config/options/nodelay.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
- data/gems/server/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
- data/gems/server/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
- data/gems/server/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/preload.md +21 -0
- data/gems/server/lib/itsi/server/config/options/preload.rb +18 -0
- data/gems/server/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
- data/gems/server/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
- data/gems/server/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
- data/gems/server/lib/itsi/server/config/options/request_timeout.md +23 -0
- data/gems/server/lib/itsi/server/config/options/request_timeout.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/reuse_address.md +16 -0
- data/gems/server/lib/itsi/server/config/options/reuse_address.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/reuse_port.md +16 -0
- data/gems/server/lib/itsi/server/config/options/reuse_port.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/scheduler_threads.md +34 -0
- data/gems/server/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
- data/gems/server/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
- data/gems/server/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
- data/gems/server/lib/itsi/server/config/options/stream_body.md +32 -0
- data/gems/server/lib/itsi/server/config/options/stream_body.rb +18 -0
- data/gems/server/lib/itsi/server/config/options/threads.md +7 -2
- data/gems/server/lib/itsi/server/config/options/threads.rb +1 -1
- data/gems/server/lib/itsi/server/config/options/watch.md +16 -0
- data/gems/server/lib/itsi/server/config/options/watch.rb +28 -0
- data/gems/server/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
- data/gems/server/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
- data/gems/server/lib/itsi/server/config/options/workers.md +1 -2
- data/gems/server/lib/itsi/server/config/options/workers.rb +1 -1
- data/gems/server/lib/itsi/server/config/typed_struct.rb +68 -32
- data/gems/server/lib/itsi/server/config.rb +163 -119
- data/gems/server/lib/itsi/server/default_app/default_app.rb +1 -1
- data/gems/server/lib/itsi/server/default_config/Itsi.rb +3 -3
- data/gems/server/lib/itsi/server/grpc/grpc_call.rb +4 -5
- data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +10 -4
- data/gems/server/lib/itsi/server/rack/handler/itsi.rb +2 -3
- data/gems/server/lib/itsi/server/rack_interface.rb +0 -1
- data/gems/server/lib/itsi/server/route_tester.rb +61 -9
- data/gems/server/lib/itsi/server/signal_trap.rb +1 -1
- data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +14 -18
- data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +13 -10
- data/gems/server/lib/itsi/server/typed_handlers.rb +12 -4
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/gems/server/lib/itsi/server.rb +111 -27
- data/gems/server/lib/itsi/standard_headers.rb +80 -80
- data/gems/server/lib/ruby_lsp/itsi/addon.rb +20 -18
- data/gems/server/test/helpers/test_helper.rb +90 -29
- data/gems/server/test/middleware/allow_list.rb +128 -0
- data/gems/server/test/middleware/auth_api_key.rb +141 -0
- data/gems/server/test/middleware/auth_basic.rb +91 -0
- data/gems/server/test/middleware/auth_jwt.rb +214 -0
- data/gems/server/test/middleware/cache_control.rb +82 -0
- data/gems/server/test/middleware/cidr_to_regex.rb +46 -0
- data/gems/server/test/middleware/compression.rb +89 -0
- data/gems/server/test/middleware/cors.rb +113 -0
- data/gems/server/test/middleware/csp.rb +62 -0
- data/gems/server/test/middleware/deny_list.rb +131 -0
- data/gems/server/test/middleware/endpoint.rb +300 -0
- data/gems/server/test/middleware/etag.rb +75 -0
- data/gems/server/test/middleware/grpc/grpc.rb +158 -0
- data/gems/server/test/middleware/grpc/test_service.proto +32 -0
- data/gems/server/test/middleware/grpc/test_service_impl.rb +28 -0
- data/gems/server/test/middleware/grpc/test_service_pb.rb +18 -0
- data/gems/server/test/middleware/grpc/test_service_services_pb.rb +30 -0
- data/gems/server/test/middleware/header_interpolation.rb +35 -0
- data/gems/server/test/middleware/intrusion_protection.rb +259 -0
- data/gems/server/test/middleware/location.rb +220 -0
- data/gems/server/test/middleware/max_body.rb +20 -0
- data/gems/server/test/middleware/proxy.rb +415 -0
- data/gems/server/test/middleware/rate_limit.rb +211 -0
- data/gems/server/test/middleware/redirect.rb +85 -0
- data/gems/server/test/middleware/request_headers.rb +50 -0
- data/gems/server/test/middleware/response_headers.rb +50 -0
- data/gems/server/test/middleware/static_assets.rb +374 -0
- data/gems/server/test/middleware/static_response.rb +56 -0
- data/gems/server/test/middleware/string_rewrite.rb +112 -0
- data/gems/server/test/middleware/test_log_requests.rb +54 -2
- data/gems/server/test/options/bind.rb +47 -0
- data/gems/server/test/options/header_read_timeout.rb +23 -0
- data/gems/server/test/options/test_request_timeout.rb +16 -0
- data/gems/server/test/options/test_workers.rb +11 -6
- data/gems/server/test/{test_itsi_server.rb → rack/test_rack_server.rb} +2 -2
- data/lib/itsi/version.rb +1 -1
- data/tasks.txt +15 -72
- metadata +209 -10
- data/examples/static_assets_example.rb +0 -83
- data/gems/server/lib/itsi/server/default_config/Itsi-rackup.rb +0 -119
@@ -7,14 +7,14 @@ use crate::{
|
|
7
7
|
},
|
8
8
|
};
|
9
9
|
use derive_more::Debug;
|
10
|
-
use
|
10
|
+
use itsi_error::ItsiError;
|
11
11
|
use itsi_rb_helpers::{call_with_gvl, print_rb_backtrace, HeapValue};
|
12
12
|
use itsi_tracing::{set_format, set_level, set_target, set_target_filters};
|
13
13
|
use magnus::{
|
14
14
|
block::Proc,
|
15
15
|
error::Result,
|
16
16
|
value::{LazyId, ReprValue},
|
17
|
-
RArray, RHash, Ruby, Symbol, Value,
|
17
|
+
RArray, RHash, Ruby, Symbol, TryConvert, Value,
|
18
18
|
};
|
19
19
|
use nix::{
|
20
20
|
fcntl::{fcntl, FcntlArg, FdFlag},
|
@@ -25,7 +25,11 @@ use std::{
|
|
25
25
|
collections::HashMap,
|
26
26
|
os::fd::{AsRawFd, OwnedFd, RawFd},
|
27
27
|
path::PathBuf,
|
28
|
-
|
28
|
+
str::FromStr,
|
29
|
+
sync::{
|
30
|
+
atomic::{AtomicBool, Ordering::Relaxed},
|
31
|
+
Arc, OnceLock,
|
32
|
+
},
|
29
33
|
time::Duration,
|
30
34
|
};
|
31
35
|
use tracing::{debug, error};
|
@@ -71,8 +75,33 @@ pub struct ServerParams {
|
|
71
75
|
#[debug(skip)]
|
72
76
|
pub(crate) listeners: Mutex<Vec<Listener>>,
|
73
77
|
listener_info: Mutex<HashMap<String, i32>>,
|
78
|
+
pub itsi_server_token_preference: ItsiServerTokenPreference,
|
79
|
+
pub preloaded: AtomicBool,
|
80
|
+
socket_opts: SocketOpts,
|
81
|
+
preexisting_listeners: Option<String>,
|
82
|
+
}
|
83
|
+
|
84
|
+
#[derive(Debug, Clone)]
|
85
|
+
pub enum ItsiServerTokenPreference {
|
86
|
+
Version,
|
87
|
+
Name,
|
88
|
+
None,
|
89
|
+
}
|
90
|
+
|
91
|
+
impl FromStr for ItsiServerTokenPreference {
|
92
|
+
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
93
|
+
Ok(match s {
|
94
|
+
"version" => ItsiServerTokenPreference::Version,
|
95
|
+
"name" => ItsiServerTokenPreference::Name,
|
96
|
+
"none" => ItsiServerTokenPreference::None,
|
97
|
+
_ => ItsiServerTokenPreference::Version,
|
98
|
+
})
|
99
|
+
}
|
100
|
+
|
101
|
+
type Err = ItsiError;
|
74
102
|
}
|
75
103
|
|
104
|
+
#[derive(Debug, Clone)]
|
76
105
|
pub struct SocketOpts {
|
77
106
|
pub reuse_address: bool,
|
78
107
|
pub reuse_port: bool,
|
@@ -83,8 +112,10 @@ pub struct SocketOpts {
|
|
83
112
|
|
84
113
|
impl ServerParams {
|
85
114
|
pub fn preload_ruby(self: &Arc<Self>) -> Result<()> {
|
115
|
+
if self.preloaded.load(Relaxed) {
|
116
|
+
return Ok(());
|
117
|
+
}
|
86
118
|
call_with_gvl(|ruby| -> Result<()> {
|
87
|
-
debug!("Preloading Ruby");
|
88
119
|
if self
|
89
120
|
.scheduler_class
|
90
121
|
.as_ref()
|
@@ -93,9 +124,17 @@ impl ServerParams {
|
|
93
124
|
debug!("Loading Itsi Scheduler");
|
94
125
|
ruby.require("itsi/scheduler")?;
|
95
126
|
}
|
96
|
-
let
|
127
|
+
let result_pair = self
|
97
128
|
.middleware_loader
|
98
|
-
.call::<
|
129
|
+
.call::<(), RArray>(())
|
130
|
+
.inspect_err(|e| {
|
131
|
+
eprintln!("Error loading middleware: {:?}", e);
|
132
|
+
if let Some(err_value) = e.value() {
|
133
|
+
print_rb_backtrace(err_value);
|
134
|
+
}
|
135
|
+
})?;
|
136
|
+
let routes_raw = result_pair
|
137
|
+
.entry::<Option<Value>>(0)
|
99
138
|
.inspect_err(|e| {
|
100
139
|
eprintln!("Error loading middleware: {:?}", e);
|
101
140
|
if let Some(err_value) = e.value() {
|
@@ -103,9 +142,22 @@ impl ServerParams {
|
|
103
142
|
}
|
104
143
|
})?
|
105
144
|
.map(|mw| mw.into());
|
106
|
-
|
145
|
+
let error_lines = result_pair.entry::<Option<RArray>>(1).inspect_err(|e| {
|
146
|
+
eprintln!("Error loading middleware: {:?}", e);
|
147
|
+
if let Some(err_value) = e.value() {
|
148
|
+
print_rb_backtrace(err_value);
|
149
|
+
}
|
150
|
+
})?;
|
151
|
+
if error_lines.is_some_and(|r| !r.is_empty()) {
|
152
|
+
let errors: Vec<String> =
|
153
|
+
Vec::<String>::try_convert(error_lines.unwrap().as_value())?;
|
154
|
+
ItsiServerConfig::print_config_errors(errors);
|
155
|
+
return Err(magnus::Error::new(
|
156
|
+
magnus::exception::runtime_error(),
|
157
|
+
"Failed to set middleware",
|
158
|
+
));
|
159
|
+
}
|
107
160
|
let middleware = MiddlewareSet::new(routes_raw)?;
|
108
|
-
debug!("Middleware loaded");
|
109
161
|
self.middleware.set(middleware).map_err(|_| {
|
110
162
|
magnus::Error::new(
|
111
163
|
magnus::exception::runtime_error(),
|
@@ -114,6 +166,7 @@ impl ServerParams {
|
|
114
166
|
})?;
|
115
167
|
Ok(())
|
116
168
|
})?;
|
169
|
+
self.preloaded.store(true, Relaxed);
|
117
170
|
Ok(())
|
118
171
|
}
|
119
172
|
|
@@ -154,11 +207,11 @@ impl ServerParams {
|
|
154
207
|
.transpose()?
|
155
208
|
.unwrap_or_default();
|
156
209
|
let preload: bool = rb_param_hash.fetch("preload")?;
|
157
|
-
let request_timeout: Option<
|
158
|
-
let request_timeout = request_timeout.map(Duration::
|
210
|
+
let request_timeout: Option<f64> = rb_param_hash.fetch("request_timeout")?;
|
211
|
+
let request_timeout = request_timeout.map(Duration::from_secs_f64);
|
159
212
|
let header_read_timeout: Duration = rb_param_hash
|
160
|
-
.fetch::<_, Option<
|
161
|
-
.map(Duration::
|
213
|
+
.fetch::<_, Option<f64>>("header_read_timeout")?
|
214
|
+
.map(Duration::from_secs_f64)
|
162
215
|
.unwrap_or(Duration::from_secs(1));
|
163
216
|
|
164
217
|
let notify_watchers: Option<Vec<(String, Vec<Vec<String>>)>> =
|
@@ -226,6 +279,12 @@ impl ServerParams {
|
|
226
279
|
.map(|s| s.parse())
|
227
280
|
.collect::<itsi_error::Result<Vec<Bind>>>()?;
|
228
281
|
|
282
|
+
let itsi_server_token_preference: String = rb_param_hash
|
283
|
+
.fetch("itsi_server_token_preference")
|
284
|
+
.unwrap_or_default();
|
285
|
+
let itsi_server_token_preference: ItsiServerTokenPreference =
|
286
|
+
itsi_server_token_preference.parse()?;
|
287
|
+
|
229
288
|
let socket_opts = SocketOpts {
|
230
289
|
reuse_address,
|
231
290
|
reuse_port,
|
@@ -233,10 +292,42 @@ impl ServerParams {
|
|
233
292
|
nodelay,
|
234
293
|
recv_buffer_size,
|
235
294
|
};
|
236
|
-
let
|
237
|
-
|
238
|
-
{
|
239
|
-
|
295
|
+
let preexisting_listeners = rb_param_hash.delete::<_, Option<String>>("listeners")?;
|
296
|
+
|
297
|
+
let params = ServerParams {
|
298
|
+
workers,
|
299
|
+
worker_memory_limit,
|
300
|
+
silence,
|
301
|
+
multithreaded_reactor,
|
302
|
+
pin_worker_cores,
|
303
|
+
shutdown_timeout,
|
304
|
+
hooks,
|
305
|
+
preload,
|
306
|
+
request_timeout,
|
307
|
+
header_read_timeout,
|
308
|
+
notify_watchers,
|
309
|
+
threads,
|
310
|
+
scheduler_threads,
|
311
|
+
streamable_body,
|
312
|
+
scheduler_class,
|
313
|
+
oob_gc_responses_threshold,
|
314
|
+
binds,
|
315
|
+
itsi_server_token_preference,
|
316
|
+
socket_opts,
|
317
|
+
preexisting_listeners,
|
318
|
+
listener_info: Mutex::new(HashMap::new()),
|
319
|
+
listeners: Mutex::new(Vec::new()),
|
320
|
+
middleware_loader: middleware_loader.into(),
|
321
|
+
middleware: OnceLock::new(),
|
322
|
+
preloaded: AtomicBool::new(false),
|
323
|
+
};
|
324
|
+
|
325
|
+
Ok(params)
|
326
|
+
}
|
327
|
+
|
328
|
+
pub fn setup_listeners(&self) -> Result<()> {
|
329
|
+
let listeners = if let Some(preexisting_listeners) = self.preexisting_listeners.as_ref() {
|
330
|
+
let bind_to_fd_map: HashMap<String, i32> = serde_json::from_str(preexisting_listeners)
|
240
331
|
.map_err(|e| {
|
241
332
|
magnus::Error::new(
|
242
333
|
magnus::exception::standard_error(),
|
@@ -244,24 +335,24 @@ impl ServerParams {
|
|
244
335
|
)
|
245
336
|
})?;
|
246
337
|
|
247
|
-
binds
|
338
|
+
self.binds
|
248
339
|
.iter()
|
249
340
|
.cloned()
|
250
341
|
.map(|bind| {
|
251
342
|
if let Some(fd) = bind_to_fd_map.get(&bind.listener_address_string()) {
|
252
|
-
Listener::inherit_fd(bind, *fd, &socket_opts)
|
343
|
+
Listener::inherit_fd(bind, *fd, &self.socket_opts)
|
253
344
|
} else {
|
254
|
-
Listener::build(bind, &socket_opts)
|
345
|
+
Listener::build(bind, &self.socket_opts)
|
255
346
|
}
|
256
347
|
})
|
257
348
|
.collect::<std::result::Result<Vec<Listener>, _>>()?
|
258
349
|
.into_iter()
|
259
350
|
.collect::<Vec<_>>()
|
260
351
|
} else {
|
261
|
-
binds
|
352
|
+
self.binds
|
262
353
|
.iter()
|
263
354
|
.cloned()
|
264
|
-
.map(|b| Listener::build(b, &socket_opts))
|
355
|
+
.map(|b| Listener::build(b, &self.socket_opts))
|
265
356
|
.collect::<std::result::Result<Vec<Listener>, _>>()?
|
266
357
|
.into_iter()
|
267
358
|
.collect::<Vec<_>>()
|
@@ -276,29 +367,9 @@ impl ServerParams {
|
|
276
367
|
})
|
277
368
|
.collect::<Result<HashMap<String, i32>>>()?;
|
278
369
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
silence,
|
283
|
-
multithreaded_reactor,
|
284
|
-
pin_worker_cores,
|
285
|
-
shutdown_timeout,
|
286
|
-
hooks,
|
287
|
-
preload,
|
288
|
-
request_timeout,
|
289
|
-
header_read_timeout,
|
290
|
-
notify_watchers,
|
291
|
-
threads,
|
292
|
-
scheduler_threads,
|
293
|
-
streamable_body,
|
294
|
-
scheduler_class,
|
295
|
-
oob_gc_responses_threshold,
|
296
|
-
binds,
|
297
|
-
listener_info: Mutex::new(listener_info),
|
298
|
-
listeners: Mutex::new(listeners),
|
299
|
-
middleware_loader: middleware_loader.into(),
|
300
|
-
middleware: OnceLock::new(),
|
301
|
-
})
|
370
|
+
*self.listener_info.lock() = listener_info;
|
371
|
+
*self.listeners.lock() = listeners;
|
372
|
+
Ok(())
|
302
373
|
}
|
303
374
|
}
|
304
375
|
|
@@ -310,28 +381,34 @@ impl ItsiServerConfig {
|
|
310
381
|
itsi_config_proc: Option<Proc>,
|
311
382
|
) -> Result<Self> {
|
312
383
|
let itsi_config_proc = Arc::new(itsi_config_proc.map(HeapValue::from));
|
313
|
-
|
384
|
+
match Self::combine_params(
|
314
385
|
ruby,
|
315
386
|
cli_params,
|
316
387
|
itsifile_path.as_ref(),
|
317
388
|
itsi_config_proc.clone(),
|
318
|
-
)
|
319
|
-
|
320
|
-
|
389
|
+
) {
|
390
|
+
Ok(server_params) => {
|
391
|
+
cli_params.delete::<_, Value>(Symbol::new("listeners"))?;
|
321
392
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
393
|
+
let watcher_fd = if let Some(watchers) = server_params.notify_watchers.clone() {
|
394
|
+
file_watcher::watch_groups(watchers)?
|
395
|
+
} else {
|
396
|
+
None
|
397
|
+
};
|
398
|
+
|
399
|
+
Ok(ItsiServerConfig {
|
400
|
+
cli_params: Arc::new(cli_params.into()),
|
401
|
+
server_params: RwLock::new(server_params.clone()).into(),
|
402
|
+
itsi_config_proc,
|
403
|
+
itsifile_path,
|
404
|
+
watcher_fd: watcher_fd.into(),
|
405
|
+
})
|
406
|
+
}
|
407
|
+
Err(err) => Err(magnus::Error::new(
|
408
|
+
magnus::exception::standard_error(),
|
409
|
+
format!("Error loading initial configuration {:?}", err),
|
410
|
+
)),
|
411
|
+
}
|
335
412
|
}
|
336
413
|
|
337
414
|
/// Reload
|
@@ -397,7 +474,7 @@ impl ItsiServerConfig {
|
|
397
474
|
Ok(())
|
398
475
|
}
|
399
476
|
|
400
|
-
pub fn get_config_errors(&self) -> Option<Vec<String>> {
|
477
|
+
pub async fn get_config_errors(&self) -> Option<Vec<String>> {
|
401
478
|
let rb_param_hash = call_with_gvl(|ruby| {
|
402
479
|
let inner = self
|
403
480
|
.itsi_config_proc
|
@@ -424,8 +501,13 @@ impl ItsiServerConfig {
|
|
424
501
|
let err_val = call_with_gvl(|_| format!("{}", err));
|
425
502
|
return Some(vec![err_val]);
|
426
503
|
}
|
427
|
-
|
428
|
-
|
504
|
+
|
505
|
+
if let Err(err) = params_arc
|
506
|
+
.middleware
|
507
|
+
.get()
|
508
|
+
.unwrap()
|
509
|
+
.initialize_layers()
|
510
|
+
.await
|
429
511
|
{
|
430
512
|
let err_val = call_with_gvl(|_| format!("{}", err));
|
431
513
|
return Some(vec![err_val]);
|
@@ -477,8 +559,8 @@ impl ItsiServerConfig {
|
|
477
559
|
}
|
478
560
|
}
|
479
561
|
|
480
|
-
pub fn check_config(&self) -> bool {
|
481
|
-
if let Some(errors) = self.get_config_errors() {
|
562
|
+
pub async fn check_config(&self) -> bool {
|
563
|
+
if let Some(errors) = self.get_config_errors().await {
|
482
564
|
Self::print_config_errors(errors);
|
483
565
|
return false;
|
484
566
|
}
|
@@ -42,6 +42,7 @@ impl ItsiServer {
|
|
42
42
|
|
43
43
|
#[instrument(skip(self))]
|
44
44
|
pub fn start(&self) -> Result<()> {
|
45
|
+
self.config.lock().server_params.read().setup_listeners()?;
|
45
46
|
let result = if self.config.lock().server_params.read().silence {
|
46
47
|
run_silently(|| self.build_and_run_strategy())
|
47
48
|
} else {
|
@@ -49,6 +50,7 @@ impl ItsiServer {
|
|
49
50
|
self.build_and_run_strategy()
|
50
51
|
};
|
51
52
|
if let Err(e) = result {
|
53
|
+
error!("Error starting server: {:?}", e);
|
52
54
|
if let Some(err_value) = e.value() {
|
53
55
|
print_rb_backtrace(err_value);
|
54
56
|
}
|
@@ -10,6 +10,7 @@ use std::{
|
|
10
10
|
path::PathBuf,
|
11
11
|
str::FromStr,
|
12
12
|
};
|
13
|
+
use tracing::{instrument, Level};
|
13
14
|
|
14
15
|
#[derive(Debug, Clone)]
|
15
16
|
pub enum BindAddress {
|
@@ -86,6 +87,7 @@ impl std::fmt::Debug for Bind {
|
|
86
87
|
impl FromStr for Bind {
|
87
88
|
type Err = ItsiError;
|
88
89
|
|
90
|
+
#[instrument(ret(level = Level::DEBUG))]
|
89
91
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
90
92
|
let (protocol, remainder) = if let Some((proto, rest)) = s.split_once("://") {
|
91
93
|
(proto.parse::<BindProtocol>()?, rest)
|
@@ -180,6 +182,7 @@ fn parse_bind_options(query: &str) -> HashMap<String, String> {
|
|
180
182
|
}
|
181
183
|
|
182
184
|
/// Attempts to resolve a hostname into an IP address.
|
185
|
+
#[instrument(ret(level = Level::DEBUG))]
|
183
186
|
fn resolve_hostname(hostname: &str) -> Option<IpAddr> {
|
184
187
|
(hostname, 0)
|
185
188
|
.to_socket_addrs()
|
@@ -418,8 +418,12 @@ fn connect_tcp_socket(addr: IpAddr, port: u16, socket_opts: &SocketOpts) -> Resu
|
|
418
418
|
.set_recv_buffer_size(socket_opts.recv_buffer_size)
|
419
419
|
.ok();
|
420
420
|
socket.set_only_v6(false).ok();
|
421
|
-
socket.bind(&socket_address.into())
|
422
|
-
|
421
|
+
if let Err(e) = socket.bind(&socket_address.into()) {
|
422
|
+
error!("Failed to bind socket: {}", e);
|
423
|
+
};
|
424
|
+
if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
|
425
|
+
error!("Failed to listen on socket: {}", e);
|
426
|
+
};
|
423
427
|
Ok(socket.into())
|
424
428
|
}
|
425
429
|
|
@@ -430,8 +434,11 @@ fn connect_unix_socket(path: &PathBuf, socket_opts: &SocketOpts) -> Result<UnixL
|
|
430
434
|
|
431
435
|
let socket_address = socket2::SockAddr::unix(path)?;
|
432
436
|
|
433
|
-
socket.bind(&socket_address)
|
434
|
-
|
435
|
-
|
437
|
+
if let Err(e) = socket.bind(&socket_address) {
|
438
|
+
error!("Failed to bind socket: {}", e);
|
439
|
+
};
|
440
|
+
if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
|
441
|
+
error!("Failed to listen on socket: {}", e);
|
442
|
+
};
|
436
443
|
Ok(socket.into())
|
437
444
|
}
|
@@ -3,8 +3,10 @@ use itsi_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
|
|
3
3
|
use itsi_error::Result;
|
4
4
|
use itsi_tracing::info;
|
5
5
|
use locked_dir_cache::LockedDirCache;
|
6
|
+
use rcgen::ExtendedKeyUsagePurpose;
|
6
7
|
use rcgen::{
|
7
|
-
BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair,
|
8
|
+
BasicConstraints, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, KeyUsagePurpose,
|
9
|
+
SanType,
|
8
10
|
};
|
9
11
|
use rustls::{
|
10
12
|
pki_types::{CertificateDer, PrivateKeyDer},
|
@@ -228,13 +230,14 @@ pub fn generate_ca_signed_cert(
|
|
228
230
|
.push(DnType::CommonName, domains[0].clone());
|
229
231
|
|
230
232
|
ee_params.use_authority_key_identifier_extension = true;
|
233
|
+
ee_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth];
|
231
234
|
|
232
235
|
let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ca_kp).unwrap();
|
233
236
|
let ee_cert_der = ee_cert.der().to_vec();
|
234
237
|
let ee_cert = CertificateDer::from(ee_cert_der);
|
235
|
-
|
238
|
+
|
236
239
|
Ok((
|
237
|
-
vec![ee_cert
|
240
|
+
vec![ee_cert],
|
238
241
|
PrivateKeyDer::try_from(ee_key.serialize_der()).unwrap(),
|
239
242
|
))
|
240
243
|
}
|
@@ -253,12 +256,17 @@ fn get_or_create_local_dev_ca() -> Result<(String, String)> {
|
|
253
256
|
|
254
257
|
Ok((key_pem, cert_pem))
|
255
258
|
} else {
|
256
|
-
let subject_alt_names = vec!["
|
259
|
+
let subject_alt_names = vec!["ca.itsi.fyi".to_string(), "localhost".to_string()];
|
257
260
|
let mut params = CertificateParams::new(subject_alt_names)?;
|
258
261
|
let mut distinguished_name = DistinguishedName::new();
|
259
|
-
distinguished_name.push(DnType::CommonName, "
|
262
|
+
distinguished_name.push(DnType::CommonName, "ca.itsi.fyi");
|
260
263
|
params.distinguished_name = distinguished_name;
|
261
264
|
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
|
265
|
+
params.key_usages = vec![
|
266
|
+
KeyUsagePurpose::KeyCertSign,
|
267
|
+
KeyUsagePurpose::CrlSign,
|
268
|
+
KeyUsagePurpose::DigitalSignature, // useful for OCSP/CRL signing
|
269
|
+
];
|
262
270
|
let key_pair = KeyPair::generate()?;
|
263
271
|
let cert = params.self_signed(&key_pair)?;
|
264
272
|
|
@@ -1,23 +1,23 @@
|
|
1
|
+
use super::{token_source::TokenSource, ErrorResponse, FromValue, MiddlewareLayer};
|
1
2
|
use crate::{
|
2
3
|
server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
|
3
4
|
services::itsi_http_service::HttpRequestContext,
|
4
5
|
};
|
5
|
-
|
6
|
-
use super::{ErrorResponse, FromValue, MiddlewareLayer};
|
7
|
-
|
8
6
|
use async_trait::async_trait;
|
9
7
|
use either::Either;
|
10
8
|
use itsi_error::ItsiError;
|
11
9
|
use magnus::error::Result;
|
12
10
|
use regex::RegexSet;
|
13
11
|
use serde::Deserialize;
|
14
|
-
use std::sync::OnceLock;
|
12
|
+
use std::{collections::HashMap, sync::OnceLock};
|
13
|
+
use tracing::debug;
|
15
14
|
|
16
15
|
#[derive(Debug, Clone, Deserialize)]
|
17
16
|
pub struct AllowList {
|
18
17
|
#[serde(skip_deserializing)]
|
19
18
|
pub allowed_ips: OnceLock<RegexSet>,
|
20
19
|
pub allowed_patterns: Vec<String>,
|
20
|
+
pub trusted_proxies: HashMap<String, TokenSource>,
|
21
21
|
#[serde(default = "forbidden_error_response")]
|
22
22
|
pub error_response: ErrorResponse,
|
23
23
|
}
|
@@ -42,7 +42,14 @@ impl MiddlewareLayer for AllowList {
|
|
42
42
|
context: &mut HttpRequestContext,
|
43
43
|
) -> Result<Either<HttpRequest, HttpResponse>> {
|
44
44
|
if let Some(allowed_ips) = self.allowed_ips.get() {
|
45
|
-
if
|
45
|
+
let addr = if self.trusted_proxies.contains_key(&context.addr) {
|
46
|
+
let source = self.trusted_proxies.get(&context.addr).unwrap();
|
47
|
+
source.extract_token(&req).unwrap_or(&context.addr)
|
48
|
+
} else {
|
49
|
+
&context.addr
|
50
|
+
};
|
51
|
+
if !allowed_ips.is_match(addr) {
|
52
|
+
debug!(target: "middleware::allow_list", "IP address {} is not allowed", addr);
|
46
53
|
return Ok(Either::Right(
|
47
54
|
self.error_response
|
48
55
|
.to_http_response(req.accept().into())
|
@@ -11,6 +11,7 @@ use async_trait::async_trait;
|
|
11
11
|
use either::Either;
|
12
12
|
use magnus::error::Result;
|
13
13
|
use serde::Deserialize;
|
14
|
+
use tracing::debug;
|
14
15
|
|
15
16
|
type PasswordHash = String;
|
16
17
|
|
@@ -51,6 +52,8 @@ impl MiddlewareLayer for AuthAPIKey {
|
|
51
52
|
}
|
52
53
|
TokenSource::Query(query_name) => req.query_param(query_name),
|
53
54
|
} {
|
55
|
+
debug!(target: "middleware::auth_api_key", "API Key Retrieved. Anonymous {}", self.key_id_source.is_none());
|
56
|
+
|
54
57
|
if let Some(key_id) = self.key_id_source.as_ref() {
|
55
58
|
let key_id = match &key_id {
|
56
59
|
TokenSource::Header { name, prefix } => {
|
@@ -66,17 +69,21 @@ impl MiddlewareLayer for AuthAPIKey {
|
|
66
69
|
}
|
67
70
|
TokenSource::Query(query_name) => req.query_param(query_name),
|
68
71
|
};
|
72
|
+
debug!(target: "middleware::auth_api_key", "Key ID Retrieved");
|
69
73
|
if let Some(hash) = key_id.and_then(|kid| self.valid_keys.get(kid)) {
|
74
|
+
debug!(target: "middleware::auth_api_key", "Key for ID found");
|
70
75
|
if password_hasher::verify_password_hash(submitted_key, hash).is_ok_and(|v| v) {
|
71
76
|
return Ok(Either::Left(req));
|
72
77
|
}
|
73
78
|
}
|
74
|
-
} else if self.valid_keys.
|
79
|
+
} else if self.valid_keys.values().any(|key| {
|
75
80
|
password_hasher::verify_password_hash(submitted_key, key).is_ok_and(|v| v)
|
76
81
|
}) {
|
77
82
|
return Ok(Either::Left(req));
|
78
83
|
}
|
79
84
|
}
|
85
|
+
|
86
|
+
debug!(target: "middleware::auth_api_key", "Failed to authenticate API key");
|
80
87
|
Ok(Either::Right(
|
81
88
|
self.error_response
|
82
89
|
.to_http_response(req.accept().into())
|
@@ -8,6 +8,7 @@ use magnus::error::Result;
|
|
8
8
|
use serde::{Deserialize, Serialize};
|
9
9
|
use std::collections::HashMap;
|
10
10
|
use std::str;
|
11
|
+
use tracing::debug;
|
11
12
|
|
12
13
|
use crate::{
|
13
14
|
server::http_message_types::{HttpRequest, HttpResponse, RequestExt},
|
@@ -48,6 +49,7 @@ impl MiddlewareLayer for AuthBasic {
|
|
48
49
|
let auth_header = req.header("Authorization");
|
49
50
|
|
50
51
|
if !auth_header.is_some_and(|header| header.starts_with("Basic ")) {
|
52
|
+
debug!(target: "middleware::auth_basic", "Basic auth failed. Authorization Header doesn't start with 'Basic '");
|
51
53
|
return Ok(Either::Right(self.basic_auth_failed_response()));
|
52
54
|
}
|
53
55
|
|
@@ -57,6 +59,7 @@ impl MiddlewareLayer for AuthBasic {
|
|
57
59
|
let decoded = match general_purpose::STANDARD.decode(encoded_credentials) {
|
58
60
|
Ok(bytes) => bytes,
|
59
61
|
Err(_) => {
|
62
|
+
debug!(target: "middleware::auth_basic", "Basic auth failed. Decoding failed");
|
60
63
|
return Ok(Either::Right(self.basic_auth_failed_response()));
|
61
64
|
}
|
62
65
|
};
|
@@ -64,6 +67,7 @@ impl MiddlewareLayer for AuthBasic {
|
|
64
67
|
let decoded_str = match str::from_utf8(&decoded) {
|
65
68
|
Ok(s) => s,
|
66
69
|
Err(_) => {
|
70
|
+
debug!(target: "middleware::auth_basic", "Basic auth failed. Decoding failed");
|
67
71
|
return Ok(Either::Right(self.basic_auth_failed_response()));
|
68
72
|
}
|
69
73
|
};
|
@@ -71,6 +75,7 @@ impl MiddlewareLayer for AuthBasic {
|
|
71
75
|
let mut parts = decoded_str.splitn(2, ':');
|
72
76
|
let username = parts.next().unwrap_or("");
|
73
77
|
let password = parts.next().unwrap_or("");
|
78
|
+
|
74
79
|
match self.credential_pairs.get(username) {
|
75
80
|
Some(expected_password_hash) => {
|
76
81
|
match verify_password_hash(password, expected_password_hash) {
|
@@ -78,7 +83,10 @@ impl MiddlewareLayer for AuthBasic {
|
|
78
83
|
_ => Ok(Either::Right(self.basic_auth_failed_response())),
|
79
84
|
}
|
80
85
|
}
|
81
|
-
None =>
|
86
|
+
None => {
|
87
|
+
debug!(target: "middleware::auth_basic", "Basic auth failed. Username {} not found", username);
|
88
|
+
Ok(Either::Right(self.basic_auth_failed_response()))
|
89
|
+
}
|
82
90
|
}
|
83
91
|
}
|
84
92
|
}
|