itsi 0.1.20 → 0.2.2
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 +2 -2
- data/LICENSE.txt +698 -0
- data/README.md +15 -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 +122 -63
- 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 +1 -2
- 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/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 +68 -8
- data/docs/content/getting_started/logging.md +16 -9
- data/docs/content/getting_started/running_itsi_in_production.md +5 -3
- data/docs/content/getting_started/signals.md +38 -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 +1 -1
- data/fairytale.txt +3 -4
- data/gems/scheduler/Cargo.lock +1 -1
- data/gems/scheduler/README.md +4 -5
- data/gems/scheduler/Rakefile +0 -4
- 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 +1 -1
- data/gems/server/Rakefile +0 -4
- data/gems/server/exe/itsi +13 -2
- data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +2 -0
- data/gems/server/lib/itsi/http_request.rb +40 -9
- data/gems/server/lib/itsi/http_response.rb +2 -1
- data/gems/server/lib/itsi/passfile.rb +0 -1
- data/gems/server/lib/itsi/server/config/config_helpers.rb +20 -8
- data/gems/server/lib/itsi/server/config/dsl.rb +20 -435
- data/gems/server/lib/itsi/server/config/known_paths.rb +4 -1
- 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 +61 -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 +73 -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 +5 -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 +59 -20
- data/gems/server/lib/itsi/server/config.rb +77 -48
- data/gems/server/lib/itsi/server/default_config/Itsi.rb +3 -3
- data/gems/server/lib/itsi/server/grpc/grpc_call.rb +1 -1
- data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +11 -4
- data/gems/server/lib/itsi/server/rack/handler/itsi.rb +3 -3
- data/gems/server/lib/itsi/server/route_tester.rb +58 -8
- 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 +5 -4
- 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 +98 -14
- data/gems/server/lib/ruby_lsp/itsi/addon.rb +20 -18
- data/gems/server/test/helpers/test_helper.rb +89 -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/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 +2 -4
- data/gems/server/test/{test_itsi_server.rb → rack/test_rack_server.rb} +2 -2
- data/grpc_test/Itsi.rb +11 -0
- data/grpc_test/echo.proto +14 -0
- data/grpc_test/echo_pb.rb +16 -0
- data/grpc_test/echo_service_impl.rb +8 -0
- data/grpc_test/echo_services_pb.rb +22 -0
- data/lib/itsi/version.rb +1 -1
- data/tasks.txt +15 -72
- metadata +210 -7
- data/gems/server/lib/itsi/server/default_config/Itsi-rackup.rb +0 -119
@@ -18,7 +18,7 @@ use std::{
|
|
18
18
|
collections::{HashMap, HashSet},
|
19
19
|
sync::OnceLock,
|
20
20
|
};
|
21
|
-
use tracing::
|
21
|
+
use tracing::debug;
|
22
22
|
|
23
23
|
#[derive(Debug, Clone, Deserialize)]
|
24
24
|
pub struct AuthJwt {
|
@@ -32,6 +32,10 @@ pub struct AuthJwt {
|
|
32
32
|
pub audiences: Option<HashSet<String>>,
|
33
33
|
pub subjects: Option<HashSet<String>>,
|
34
34
|
pub issuers: Option<HashSet<String>>,
|
35
|
+
#[serde(skip_deserializing)]
|
36
|
+
pub audience_vec: OnceLock<Option<Vec<String>>>,
|
37
|
+
#[serde(skip_deserializing)]
|
38
|
+
pub issuer_vec: OnceLock<Option<Vec<String>>>,
|
35
39
|
pub leeway: Option<u64>,
|
36
40
|
#[serde(default = "unauthorized_error_response")]
|
37
41
|
pub error_response: ErrorResponse,
|
@@ -91,7 +95,7 @@ impl JwtAlgorithm {
|
|
91
95
|
/// Given a base64-encoded key string, decode and construct a jsonwebtoken::DecodingKey.
|
92
96
|
pub fn key_from(&self, base64: &str) -> itsi_error::Result<DecodingKey> {
|
93
97
|
match self {
|
94
|
-
// For HMAC algorithms,
|
98
|
+
// For HMAC algorithms, expect a base64 encoded secret.
|
95
99
|
JwtAlgorithm::Hs256 | JwtAlgorithm::Hs384 | JwtAlgorithm::Hs512 => {
|
96
100
|
Ok(DecodingKey::from_secret(
|
97
101
|
&general_purpose::STANDARD
|
@@ -118,15 +122,16 @@ impl JwtAlgorithm {
|
|
118
122
|
|
119
123
|
#[derive(Debug, Deserialize)]
|
120
124
|
#[serde(untagged)]
|
125
|
+
#[allow(dead_code)]
|
121
126
|
enum Audience {
|
122
127
|
Single(String),
|
123
128
|
Multiple(Vec<String>),
|
124
129
|
}
|
125
130
|
|
126
131
|
#[derive(Debug, Deserialize)]
|
132
|
+
#[allow(dead_code)]
|
127
133
|
struct Claims {
|
128
134
|
// Here we assume the token includes an expiration.
|
129
|
-
#[allow(dead_code)]
|
130
135
|
exp: usize,
|
131
136
|
// The audience claim may be a single string or an array.
|
132
137
|
aud: Option<Audience>,
|
@@ -171,6 +176,17 @@ impl MiddlewareLayer for AuthJwt {
|
|
171
176
|
self.keys
|
172
177
|
.set(keys)
|
173
178
|
.map_err(|_| ItsiError::new("Failed to set keys"))?;
|
179
|
+
|
180
|
+
if let Some(audiences) = self.audiences.as_ref() {
|
181
|
+
self.audience_vec
|
182
|
+
.set(Some(audiences.iter().cloned().collect::<Vec<_>>()))
|
183
|
+
.ok();
|
184
|
+
}
|
185
|
+
if let Some(issuers) = self.issuers.as_ref() {
|
186
|
+
self.issuer_vec
|
187
|
+
.set(Some(issuers.iter().cloned().collect::<Vec<_>>()))
|
188
|
+
.ok();
|
189
|
+
}
|
174
190
|
Ok(())
|
175
191
|
}
|
176
192
|
|
@@ -219,8 +235,17 @@ impl MiddlewareLayer for AuthJwt {
|
|
219
235
|
));
|
220
236
|
}
|
221
237
|
let token_str = token_str.unwrap();
|
222
|
-
let header =
|
223
|
-
|
238
|
+
let header = match decode_header(token_str) {
|
239
|
+
Ok(header) => header,
|
240
|
+
Err(_) => {
|
241
|
+
debug!(target: "middleware::auth_jwt", "JWT decoding failed");
|
242
|
+
return Ok(Either::Right(
|
243
|
+
self.error_response
|
244
|
+
.to_http_response(req.accept().into())
|
245
|
+
.await,
|
246
|
+
));
|
247
|
+
}
|
248
|
+
};
|
224
249
|
|
225
250
|
let alg: JwtAlgorithm = header.alg.into();
|
226
251
|
|
@@ -256,12 +281,28 @@ impl MiddlewareLayer for AuthJwt {
|
|
256
281
|
validation.leeway = leeway;
|
257
282
|
}
|
258
283
|
|
284
|
+
if let Some(Some(auds)) = &self.audience_vec.get() {
|
285
|
+
validation.set_audience(auds);
|
286
|
+
validation.required_spec_claims.insert("aud".to_owned());
|
287
|
+
} else {
|
288
|
+
validation.validate_aud = false;
|
289
|
+
}
|
290
|
+
|
291
|
+
if let Some(Some(issuers)) = &self.issuer_vec.get() {
|
292
|
+
validation.set_issuer(issuers);
|
293
|
+
validation.required_spec_claims.insert("iss".to_owned());
|
294
|
+
}
|
295
|
+
|
296
|
+
if self.subjects.is_some() {
|
297
|
+
validation.required_spec_claims.insert("sub".to_owned());
|
298
|
+
}
|
299
|
+
|
259
300
|
let token_data: Option<TokenData<Claims>> =
|
260
301
|
keys.iter()
|
261
302
|
.find_map(|key| match decode::<Claims>(token_str, key, &validation) {
|
262
303
|
Ok(data) => Some(data),
|
263
304
|
Err(e) => {
|
264
|
-
|
305
|
+
debug!("Token validation failed: {:?}", e);
|
265
306
|
None
|
266
307
|
}
|
267
308
|
});
|
@@ -278,30 +319,11 @@ impl MiddlewareLayer for AuthJwt {
|
|
278
319
|
|
279
320
|
let claims = token_data.claims;
|
280
321
|
|
281
|
-
if let Some(expected_audiences) = &self.audiences {
|
282
|
-
if let Some(aud) = &claims.aud {
|
283
|
-
let token_auds: HashSet<String> = match aud {
|
284
|
-
Audience::Single(s) => [s.clone()].into_iter().collect(),
|
285
|
-
Audience::Multiple(v) => v.iter().cloned().collect(),
|
286
|
-
};
|
287
|
-
if expected_audiences.is_disjoint(&token_auds) {
|
288
|
-
debug!(
|
289
|
-
"AUD check failed, token_auds: {:?}, expected_audiences: {:?}",
|
290
|
-
token_auds, expected_audiences
|
291
|
-
);
|
292
|
-
return Ok(Either::Right(
|
293
|
-
self.error_response
|
294
|
-
.to_http_response(req.accept().into())
|
295
|
-
.await,
|
296
|
-
));
|
297
|
-
}
|
298
|
-
}
|
299
|
-
}
|
300
|
-
|
301
322
|
if let Some(expected_subjects) = &self.subjects {
|
302
323
|
if let Some(sub) = &claims.sub {
|
303
324
|
if !expected_subjects.contains(sub) {
|
304
325
|
debug!(
|
326
|
+
target: "middleware::auth_jwt",
|
305
327
|
"SUB check failed, token_sub: {:?}, expected_subjects: {:?}",
|
306
328
|
sub, expected_subjects
|
307
329
|
);
|
@@ -314,23 +336,6 @@ impl MiddlewareLayer for AuthJwt {
|
|
314
336
|
}
|
315
337
|
}
|
316
338
|
|
317
|
-
// Verify expected issuer.
|
318
|
-
if let Some(expected_issuers) = &self.issuers {
|
319
|
-
if let Some(iss) = &claims.iss {
|
320
|
-
if !expected_issuers.contains(iss) {
|
321
|
-
debug!(
|
322
|
-
"ISS check failed, token_iss: {:?}, expected_issuers: {:?}",
|
323
|
-
iss, expected_issuers
|
324
|
-
);
|
325
|
-
return Ok(Either::Right(
|
326
|
-
self.error_response
|
327
|
-
.to_http_response(req.accept().into())
|
328
|
-
.await,
|
329
|
-
));
|
330
|
-
}
|
331
|
-
}
|
332
|
-
}
|
333
|
-
|
334
339
|
Ok(Either::Left(req))
|
335
340
|
}
|
336
341
|
}
|
@@ -8,8 +8,9 @@ use http::{HeaderName, HeaderValue};
|
|
8
8
|
use magnus::error::Result;
|
9
9
|
use serde::Deserialize;
|
10
10
|
use std::{collections::HashMap, sync::OnceLock};
|
11
|
+
use tracing::debug;
|
11
12
|
|
12
|
-
#[derive(Debug,
|
13
|
+
#[derive(Debug, Deserialize)]
|
13
14
|
pub struct CacheControl {
|
14
15
|
#[serde(default)]
|
15
16
|
pub max_age: Option<u64>,
|
@@ -87,6 +88,7 @@ impl MiddlewareLayer for CacheControl {
|
|
87
88
|
// Set the Cache-Control header if we have directives
|
88
89
|
if !directives.is_empty() {
|
89
90
|
let cache_control_value = directives.join(", ");
|
91
|
+
debug!(target: "middleware::cache_control", "Built cache-control directive {}", cache_control_value);
|
90
92
|
self.cache_control_str.set(cache_control_value).unwrap();
|
91
93
|
}
|
92
94
|
|
@@ -97,20 +99,27 @@ impl MiddlewareLayer for CacheControl {
|
|
97
99
|
// Skip for statuses where caching doesn't make sense
|
98
100
|
let status = resp.status().as_u16();
|
99
101
|
if matches!(status, 401 | 403 | 500..=599) {
|
102
|
+
debug!(target: "middleware::cache_control", "Skipping cache-control for status {}", status);
|
100
103
|
return resp;
|
101
104
|
}
|
102
105
|
|
103
106
|
// Set the Cache-Control header if we have directives
|
104
107
|
if let Some(cache_control_value) = self.cache_control_str.get() {
|
105
108
|
if let Ok(value) = HeaderValue::from_str(cache_control_value) {
|
109
|
+
debug!(target: "middleware::cache_control", "Setting cache-control header to {}", cache_control_value);
|
106
110
|
resp.headers_mut().insert("Cache-Control", value);
|
111
|
+
} else {
|
112
|
+
debug!(target: "middleware::cache_control", "Failed to parse cache-control value {}", cache_control_value);
|
107
113
|
}
|
114
|
+
} else {
|
115
|
+
debug!(target: "middleware::cache_control", "No cache-control value provided");
|
108
116
|
}
|
109
117
|
|
110
118
|
// Set Expires header based on max-age if present
|
111
119
|
if let Some(max_age) = self.max_age {
|
112
120
|
// Set the Expires header based on max-age
|
113
121
|
// Use a helper to format the HTTP date correctly
|
122
|
+
debug!(target: "middleware::cache_control", "Setting expires header to {}", max_age);
|
114
123
|
let expires = chrono::Utc::now() + chrono::Duration::seconds(max_age as i64);
|
115
124
|
let expires_str = expires.format("%a, %d %b %Y %H:%M:%S GMT").to_string();
|
116
125
|
if let Ok(value) = HeaderValue::from_str(&expires_str) {
|
@@ -118,7 +127,6 @@ impl MiddlewareLayer for CacheControl {
|
|
118
127
|
}
|
119
128
|
}
|
120
129
|
|
121
|
-
// Set Vary header
|
122
130
|
if !self.vary.is_empty() {
|
123
131
|
let vary_value = self.vary.join(", ");
|
124
132
|
if let Ok(value) = HeaderValue::from_str(&vary_value) {
|
@@ -130,6 +138,7 @@ impl MiddlewareLayer for CacheControl {
|
|
130
138
|
for (name, value) in &self.additional_headers {
|
131
139
|
if let Ok(header_value) = HeaderValue::from_str(value) {
|
132
140
|
if let Ok(header_name) = name.parse::<HeaderName>() {
|
141
|
+
debug!(target: "middleware::cache_control", "Setting custom header {} to {:?}", header_name, header_value);
|
133
142
|
resp.headers_mut().insert(header_name, header_value);
|
134
143
|
}
|
135
144
|
}
|
@@ -25,6 +25,7 @@ use std::convert::Infallible;
|
|
25
25
|
use tokio::io::{AsyncRead, AsyncReadExt, BufReader};
|
26
26
|
use tokio_stream::StreamExt;
|
27
27
|
use tokio_util::io::{ReaderStream, StreamReader};
|
28
|
+
use tracing::debug;
|
28
29
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
29
30
|
pub struct Compression {
|
30
31
|
min_size: usize,
|
@@ -40,8 +41,8 @@ enum CompressionLevel {
|
|
40
41
|
Fastest,
|
41
42
|
#[serde(rename(deserialize = "best"))]
|
42
43
|
Best,
|
43
|
-
#[serde(rename(deserialize = "
|
44
|
-
|
44
|
+
#[serde(rename(deserialize = "balanced"))]
|
45
|
+
Balanced,
|
45
46
|
#[serde(rename(deserialize = "precise"))]
|
46
47
|
Precise(i32),
|
47
48
|
}
|
@@ -51,7 +52,7 @@ impl CompressionLevel {
|
|
51
52
|
match self {
|
52
53
|
CompressionLevel::Fastest => Level::Fastest,
|
53
54
|
CompressionLevel::Best => Level::Best,
|
54
|
-
CompressionLevel::
|
55
|
+
CompressionLevel::Balanced => Level::Default,
|
55
56
|
CompressionLevel::Precise(level) => Level::Precise(*level),
|
56
57
|
}
|
57
58
|
}
|
@@ -61,14 +62,14 @@ impl CompressionLevel {
|
|
61
62
|
pub enum CompressionAlgorithm {
|
62
63
|
#[serde(rename(deserialize = "gzip"))]
|
63
64
|
Gzip,
|
64
|
-
#[serde(rename(deserialize = "
|
65
|
+
#[serde(rename(deserialize = "br"))]
|
65
66
|
Brotli,
|
66
67
|
#[serde(rename(deserialize = "deflate"))]
|
67
68
|
Deflate,
|
68
69
|
#[serde(rename(deserialize = "zstd"))]
|
69
70
|
Zstd,
|
70
|
-
#[serde(rename(deserialize = "
|
71
|
-
|
71
|
+
#[serde(rename(deserialize = "identity"))]
|
72
|
+
Identity,
|
72
73
|
}
|
73
74
|
|
74
75
|
impl CompressionAlgorithm {
|
@@ -78,7 +79,7 @@ impl CompressionAlgorithm {
|
|
78
79
|
CompressionAlgorithm::Brotli => "br",
|
79
80
|
CompressionAlgorithm::Deflate => "deflate",
|
80
81
|
CompressionAlgorithm::Zstd => "zstd",
|
81
|
-
CompressionAlgorithm::
|
82
|
+
CompressionAlgorithm::Identity => "identity",
|
82
83
|
}
|
83
84
|
}
|
84
85
|
|
@@ -99,6 +100,8 @@ enum MimeType {
|
|
99
100
|
Audio,
|
100
101
|
#[serde(rename(deserialize = "video"))]
|
101
102
|
Video,
|
103
|
+
#[serde(rename(deserialize = "font"))]
|
104
|
+
Font,
|
102
105
|
#[serde(rename(deserialize = "other"))]
|
103
106
|
Other(String),
|
104
107
|
#[serde(rename(deserialize = "all"))]
|
@@ -113,6 +116,7 @@ impl MimeType {
|
|
113
116
|
MimeType::Application => header_contains(content_encodings, "application/*"),
|
114
117
|
MimeType::Audio => header_contains(content_encodings, "audio/*"),
|
115
118
|
MimeType::Video => header_contains(content_encodings, "video/*"),
|
119
|
+
MimeType::Font => header_contains(content_encodings, "font/*"),
|
116
120
|
MimeType::Other(v) => header_contains(content_encodings, v),
|
117
121
|
MimeType::All => header_contains(content_encodings, "*"),
|
118
122
|
}
|
@@ -162,16 +166,28 @@ impl MiddlewareLayer for Compression {
|
|
162
166
|
.iter()
|
163
167
|
.any(|mt| mt.matches(&resp.headers().get_all(CONTENT_TYPE)))
|
164
168
|
{
|
169
|
+
debug!(
|
170
|
+
target: "middleware::compress",
|
171
|
+
"Mime type not supported for compression"
|
172
|
+
);
|
165
173
|
return resp;
|
166
174
|
}
|
167
175
|
|
168
176
|
// Don't compress streams unless compress streams is enabled.
|
169
177
|
if body_size.is_none() && !self.compress_streams {
|
178
|
+
debug!(
|
179
|
+
target: "middleware::compress",
|
180
|
+
"Stream compression disabled"
|
181
|
+
);
|
170
182
|
return resp;
|
171
183
|
}
|
172
184
|
|
173
185
|
// Don't compress too small bodies
|
174
186
|
if body_size.is_some_and(|s| s < self.min_size as u64) {
|
187
|
+
debug!(
|
188
|
+
target: "middleware::compress",
|
189
|
+
"Body size too small for compression"
|
190
|
+
);
|
175
191
|
return resp;
|
176
192
|
}
|
177
193
|
|
@@ -181,6 +197,10 @@ impl MiddlewareLayer for Compression {
|
|
181
197
|
for encoding in encodings.split(',').map(str::trim) {
|
182
198
|
let encoding = encoding.split(';').next().unwrap_or(encoding).trim();
|
183
199
|
if self.algorithms.iter().any(|algo| algo.as_str() == encoding) {
|
200
|
+
debug!(
|
201
|
+
target: "middleware::compress",
|
202
|
+
"Body already compressed with supported algorithm"
|
203
|
+
);
|
184
204
|
return resp;
|
185
205
|
}
|
186
206
|
}
|
@@ -195,10 +215,14 @@ impl MiddlewareLayer for Compression {
|
|
195
215
|
Some("br") => CompressionAlgorithm::Brotli,
|
196
216
|
Some("deflate") => CompressionAlgorithm::Deflate,
|
197
217
|
Some("zstd") => CompressionAlgorithm::Zstd,
|
198
|
-
_ => CompressionAlgorithm::
|
218
|
+
_ => CompressionAlgorithm::Identity,
|
199
219
|
};
|
200
220
|
|
201
|
-
|
221
|
+
debug!(
|
222
|
+
target: "middleware::compress",
|
223
|
+
"Selected compression method: {:?}", compression_method
|
224
|
+
);
|
225
|
+
if matches!(compression_method, CompressionAlgorithm::Identity) {
|
202
226
|
return resp;
|
203
227
|
}
|
204
228
|
|
@@ -250,7 +274,7 @@ impl MiddlewareLayer for Compression {
|
|
250
274
|
encoder.read_to_end(&mut buf).await.unwrap();
|
251
275
|
buf
|
252
276
|
}
|
253
|
-
CompressionAlgorithm::
|
277
|
+
CompressionAlgorithm::Identity => unreachable!(),
|
254
278
|
};
|
255
279
|
BoxBody::new(Full::new(Bytes::from(compressed_bytes)))
|
256
280
|
} else {
|
@@ -276,13 +300,16 @@ impl MiddlewareLayer for Compression {
|
|
276
300
|
reader,
|
277
301
|
self.level.to_async_compression_level(),
|
278
302
|
)),
|
279
|
-
CompressionAlgorithm::
|
303
|
+
CompressionAlgorithm::Identity => unreachable!(),
|
280
304
|
}
|
281
305
|
};
|
282
306
|
|
283
307
|
update_content_encoding(&mut parts, compression_method.header_value());
|
284
308
|
parts.headers.remove(CONTENT_LENGTH);
|
285
|
-
|
309
|
+
debug!(
|
310
|
+
target: "middleware::compress",
|
311
|
+
"Response compressed"
|
312
|
+
);
|
286
313
|
Response::from_parts(parts, new_body)
|
287
314
|
}
|
288
315
|
}
|
@@ -10,14 +10,15 @@ use http_body_util::{combinators::BoxBody, Empty};
|
|
10
10
|
use itsi_error::ItsiError;
|
11
11
|
use magnus::error::Result;
|
12
12
|
use serde::Deserialize;
|
13
|
+
use tracing::debug;
|
13
14
|
|
14
15
|
#[derive(Debug, Clone, Deserialize)]
|
15
16
|
pub struct Cors {
|
16
|
-
pub
|
17
|
-
pub
|
18
|
-
pub
|
19
|
-
pub exposed_headers: Vec<String>,
|
17
|
+
pub allow_origins: Vec<String>,
|
18
|
+
pub allow_methods: Vec<HttpMethod>,
|
19
|
+
pub allow_headers: Vec<String>,
|
20
20
|
pub allow_credentials: bool,
|
21
|
+
pub expose_headers: Vec<String>,
|
21
22
|
pub max_age: Option<u64>,
|
22
23
|
}
|
23
24
|
|
@@ -74,6 +75,7 @@ impl Cors {
|
|
74
75
|
|
75
76
|
if origin.is_empty() {
|
76
77
|
// When credentials are allowed, you cannot return "*".
|
78
|
+
debug!(target: "middleware::cors", "Origin empty {}", origin);
|
77
79
|
if !self.allow_credentials {
|
78
80
|
headers.insert(
|
79
81
|
"Access-Control-Allow-Origin",
|
@@ -84,13 +86,13 @@ impl Cors {
|
|
84
86
|
}
|
85
87
|
|
86
88
|
// Only return a header if the origin is allowed.
|
87
|
-
if self.
|
89
|
+
if self.allow_origins.iter().any(|o| o == origin || o == "*") {
|
88
90
|
// If credentials are allowed, we must echo back the exact origin.
|
89
91
|
let value = if self.allow_credentials {
|
90
92
|
origin
|
91
93
|
} else {
|
92
94
|
// If not, and if "*" is allowed, you can still use "*".
|
93
|
-
if self.
|
95
|
+
if self.allow_origins.iter().any(|o| o == "*") {
|
94
96
|
"*"
|
95
97
|
} else {
|
96
98
|
origin
|
@@ -102,10 +104,10 @@ impl Cors {
|
|
102
104
|
);
|
103
105
|
}
|
104
106
|
|
105
|
-
if !self.
|
107
|
+
if !self.allow_methods.is_empty() {
|
106
108
|
headers.insert(
|
107
109
|
"Access-Control-Allow-Methods",
|
108
|
-
self.
|
110
|
+
self.allow_methods
|
109
111
|
.iter()
|
110
112
|
.map(HttpMethod::to_str)
|
111
113
|
.collect::<Vec<&str>>()
|
@@ -114,10 +116,10 @@ impl Cors {
|
|
114
116
|
.map_err(ItsiError::new)?,
|
115
117
|
);
|
116
118
|
}
|
117
|
-
if !self.
|
119
|
+
if !self.allow_headers.is_empty() {
|
118
120
|
headers.insert(
|
119
121
|
"Access-Control-Allow-Headers",
|
120
|
-
self.
|
122
|
+
self.allow_headers
|
121
123
|
.join(", ")
|
122
124
|
.parse()
|
123
125
|
.map_err(ItsiError::new)?,
|
@@ -135,10 +137,10 @@ impl Cors {
|
|
135
137
|
max_age.to_string().parse().map_err(ItsiError::new)?,
|
136
138
|
);
|
137
139
|
}
|
138
|
-
if !self.
|
140
|
+
if !self.expose_headers.is_empty() {
|
139
141
|
headers.insert(
|
140
142
|
"Access-Control-Expose-Headers",
|
141
|
-
self.
|
143
|
+
self.expose_headers
|
142
144
|
.join(", ")
|
143
145
|
.parse()
|
144
146
|
.map_err(ItsiError::new)?,
|
@@ -159,27 +161,31 @@ impl Cors {
|
|
159
161
|
|
160
162
|
let origin = match origin {
|
161
163
|
Some(o) if !o.is_empty() => o,
|
162
|
-
_ =>
|
164
|
+
_ => {
|
165
|
+
debug!(target: "middleware::cors", "Missing Origin – preflight fails");
|
166
|
+
return Ok(headers);
|
167
|
+
}
|
163
168
|
};
|
164
169
|
|
165
170
|
if !self
|
166
|
-
.
|
171
|
+
.allow_origins
|
167
172
|
.iter()
|
168
173
|
.any(|allowed| allowed == "*" || allowed == origin)
|
169
174
|
{
|
175
|
+
debug!(target: "middleware::cors", "Origin not allowed");
|
170
176
|
return Ok(headers);
|
171
177
|
}
|
172
178
|
|
173
179
|
let request_method = match req_method {
|
174
180
|
Some(m) if !m.is_empty() => m,
|
175
|
-
_ =>
|
181
|
+
_ => {
|
182
|
+
debug!(target: "middleware::cors", "Missing request method – preflight fails");
|
183
|
+
return Ok(headers);
|
184
|
+
}
|
176
185
|
};
|
177
186
|
|
178
|
-
if !self
|
179
|
-
|
180
|
-
.iter()
|
181
|
-
.any(|m| m.matches(request_method))
|
182
|
-
{
|
187
|
+
if !self.allow_methods.iter().any(|m| m.matches(request_method)) {
|
188
|
+
debug!(target: "middleware::cors", "Method not allowed");
|
183
189
|
return Ok(headers);
|
184
190
|
}
|
185
191
|
|
@@ -191,10 +197,11 @@ impl Cors {
|
|
191
197
|
.collect();
|
192
198
|
for header in req_headers_list {
|
193
199
|
if !self
|
194
|
-
.
|
200
|
+
.allow_headers
|
195
201
|
.iter()
|
196
202
|
.any(|allowed| allowed.eq_ignore_ascii_case(header))
|
197
203
|
{
|
204
|
+
debug!(target: "middleware::cors", "Header not allowed {}", header);
|
198
205
|
return Ok(headers);
|
199
206
|
}
|
200
207
|
}
|
@@ -203,7 +210,7 @@ impl Cors {
|
|
203
210
|
headers.insert("Access-Control-Allow-Origin", origin.parse().unwrap());
|
204
211
|
headers.insert(
|
205
212
|
"Access-Control-Allow-Methods",
|
206
|
-
self.
|
213
|
+
self.allow_methods
|
207
214
|
.iter()
|
208
215
|
.map(HttpMethod::to_str)
|
209
216
|
.collect::<Vec<&str>>()
|
@@ -213,7 +220,7 @@ impl Cors {
|
|
213
220
|
);
|
214
221
|
headers.insert(
|
215
222
|
"Access-Control-Allow-Headers",
|
216
|
-
self.
|
223
|
+
self.allow_headers
|
217
224
|
.join(", ")
|
218
225
|
.parse()
|
219
226
|
.map_err(ItsiError::new)?,
|
@@ -230,10 +237,10 @@ impl Cors {
|
|
230
237
|
max_age.to_string().parse().map_err(ItsiError::new)?,
|
231
238
|
);
|
232
239
|
}
|
233
|
-
if !self.
|
240
|
+
if !self.expose_headers.is_empty() {
|
234
241
|
headers.insert(
|
235
242
|
"Access-Control-Expose-Headers",
|
236
|
-
self.
|
243
|
+
self.expose_headers
|
237
244
|
.join(", ")
|
238
245
|
.parse()
|
239
246
|
.map_err(ItsiError::new)?,
|
@@ -257,11 +264,12 @@ impl MiddlewareLayer for Cors {
|
|
257
264
|
context: &mut HttpRequestContext,
|
258
265
|
) -> Result<either::Either<HttpRequest, HttpResponse>> {
|
259
266
|
let origin = req.header("Origin");
|
267
|
+
debug!(target: "middleware::cors", "Origin: {:?}", origin);
|
260
268
|
if req.method() == Method::OPTIONS {
|
261
269
|
let ac_request_method = req.header("Access-Control-Request-Method");
|
262
270
|
let ac_request_headers = req.header("Access-Control-Request-Headers");
|
263
271
|
let headers = self.preflight_headers(origin, ac_request_method, ac_request_headers)?;
|
264
|
-
|
272
|
+
debug!(target: "middleware::cors", "Preflight Headers: {:?}", headers);
|
265
273
|
let mut response_builder = Response::builder().status(204);
|
266
274
|
*response_builder.headers_mut().unwrap() = headers;
|
267
275
|
let response = response_builder
|
@@ -273,14 +281,15 @@ impl MiddlewareLayer for Cors {
|
|
273
281
|
Ok(either::Either::Left(req))
|
274
282
|
}
|
275
283
|
|
276
|
-
// The after hook can be used to inject CORS headers into non-preflight responses.
|
277
284
|
async fn after(
|
278
285
|
&self,
|
279
286
|
mut resp: HttpResponse,
|
280
287
|
context: &mut HttpRequestContext,
|
281
288
|
) -> HttpResponse {
|
282
289
|
if let Some(Some(origin)) = context.origin.get() {
|
290
|
+
debug!(target: "middleware::cors", "fetching cors headers for origin {}", origin);
|
283
291
|
if let Ok(cors_headers) = self.cors_headers(origin) {
|
292
|
+
debug!(target: "middleware::cors", "Cors Headers: {:?}", cors_headers);
|
284
293
|
for (key, value) in cors_headers.iter() {
|
285
294
|
resp.headers_mut().insert(key.clone(), value.clone());
|
286
295
|
}
|