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
@@ -33,13 +33,14 @@ use reqwest::{
|
|
33
33
|
Body, Client, Url,
|
34
34
|
};
|
35
35
|
use serde::Deserialize;
|
36
|
+
use tracing::{debug, info};
|
36
37
|
|
37
38
|
#[derive(Debug, Clone, Deserialize)]
|
38
39
|
pub struct Proxy {
|
39
40
|
pub to: StringRewrite,
|
40
41
|
pub backends: Vec<String>,
|
41
42
|
pub backend_priority: BackendPriority,
|
42
|
-
pub headers: HashMap<String, Option<
|
43
|
+
pub headers: HashMap<String, Option<StringRewrite>>,
|
43
44
|
pub verify_ssl: bool,
|
44
45
|
pub timeout: u64,
|
45
46
|
pub tls_sni: bool,
|
@@ -63,23 +64,6 @@ pub enum BackendPriority {
|
|
63
64
|
Random,
|
64
65
|
}
|
65
66
|
|
66
|
-
#[derive(Debug, Clone, Deserialize)]
|
67
|
-
pub enum ProxiedHeader {
|
68
|
-
#[serde(rename(deserialize = "value"))]
|
69
|
-
String(String),
|
70
|
-
#[serde(rename(deserialize = "rewrite"))]
|
71
|
-
StringRewrite(StringRewrite),
|
72
|
-
}
|
73
|
-
|
74
|
-
impl ProxiedHeader {
|
75
|
-
pub fn to_string(&self, req: &HttpRequest, context: &HttpRequestContext) -> String {
|
76
|
-
match self {
|
77
|
-
ProxiedHeader::String(value) => value.clone(),
|
78
|
-
ProxiedHeader::StringRewrite(rewrite) => rewrite.rewrite_request(req, context),
|
79
|
-
}
|
80
|
-
}
|
81
|
-
}
|
82
|
-
|
83
67
|
#[derive(Debug, Clone)]
|
84
68
|
pub struct Resolver {
|
85
69
|
backends: Arc<Vec<SocketAddr>>,
|
@@ -164,7 +148,7 @@ impl Proxy {
|
|
164
148
|
for (name, header_opt) in self.headers.iter() {
|
165
149
|
if let Some(header_value) = header_opt {
|
166
150
|
// Compute the header value using the full HttpRequest.
|
167
|
-
let value_str = header_value.
|
151
|
+
let value_str = header_value.rewrite_request(req, context);
|
168
152
|
if let Ok(header_val) = http::HeaderValue::from_str(&value_str) {
|
169
153
|
if let Ok(header_name) = name.parse::<http::header::HeaderName>() {
|
170
154
|
headers.insert(header_name, header_val);
|
@@ -201,6 +185,7 @@ impl Proxy {
|
|
201
185
|
|
202
186
|
// Add a Host header if not overridden.
|
203
187
|
if !overriding_headers.contains_key("host") && !host_str.is_empty() {
|
188
|
+
debug!("Adding Host header: {}", host_str);
|
204
189
|
builder = builder.header("Host", host_str);
|
205
190
|
}
|
206
191
|
|
@@ -231,6 +216,7 @@ impl Proxy {
|
|
231
216
|
Err(e) => {
|
232
217
|
// Retry for connectivity-related errors.
|
233
218
|
if e.is_connect() {
|
219
|
+
debug!(target: "middleware::proxy", "Connection error, retrying");
|
234
220
|
last_err = Some(e);
|
235
221
|
if attempt + 1 < max_attempts {
|
236
222
|
continue;
|
@@ -278,6 +264,7 @@ impl MiddlewareLayer for Proxy {
|
|
278
264
|
}
|
279
265
|
})
|
280
266
|
.collect::<Vec<_>>();
|
267
|
+
debug!(target: "middleware::proxy", "backends: {:?}", backends);
|
281
268
|
|
282
269
|
self.client
|
283
270
|
.set(
|
@@ -314,14 +301,20 @@ impl MiddlewareLayer for Proxy {
|
|
314
301
|
context: &mut HttpRequestContext,
|
315
302
|
) -> Result<Either<HttpRequest, HttpResponse>> {
|
316
303
|
let url = self.to.rewrite_request(&req, context);
|
304
|
+
|
317
305
|
let accept: ResponseFormat = req.accept().into();
|
318
306
|
let error_response = self.error_response.to_http_response(accept.clone()).await;
|
319
307
|
|
320
308
|
let destination = match Url::parse(&url) {
|
321
309
|
Ok(dest) => dest,
|
322
|
-
Err(_) =>
|
310
|
+
Err(_) => {
|
311
|
+
debug!(target: "middleware::proxy", "Failed to parse URL: {}", url);
|
312
|
+
return Ok(Either::Right(error_response));
|
313
|
+
}
|
323
314
|
};
|
324
315
|
|
316
|
+
debug!(target: "middleware::proxy", "Proxying to: {:?}", destination);
|
317
|
+
|
325
318
|
// Clone the headers before consuming the request.
|
326
319
|
let req_headers = req.headers().clone();
|
327
320
|
let host_str = destination.host_str().unwrap_or_else(|| {
|
@@ -331,6 +324,7 @@ impl MiddlewareLayer for Proxy {
|
|
331
324
|
.unwrap_or("")
|
332
325
|
});
|
333
326
|
|
327
|
+
info!("Extracted host str is {}", host_str);
|
334
328
|
let req_info = RequestInfo {
|
335
329
|
method: req.method().clone(),
|
336
330
|
headers: req_headers.clone(),
|
@@ -373,6 +367,8 @@ impl MiddlewareLayer for Proxy {
|
|
373
367
|
|
374
368
|
let response = match reqwest_response_result {
|
375
369
|
Ok(response) => {
|
370
|
+
debug!(target: "middleware::proxy", "Response {} received", response.status());
|
371
|
+
|
376
372
|
let status = response.status();
|
377
373
|
let mut builder = Response::builder().status(status);
|
378
374
|
for (hn, hv) in response.headers() {
|
@@ -387,6 +383,7 @@ impl MiddlewareLayer for Proxy {
|
|
387
383
|
response.unwrap_or(error_response)
|
388
384
|
}
|
389
385
|
Err(e) => {
|
386
|
+
debug!(target: "middleware::proxy", "Error {:?} received", e);
|
390
387
|
if let Some(inner) = e.source() {
|
391
388
|
if inner.downcast_ref::<MaxBodySizeReached>().is_some() {
|
392
389
|
let mut max_body_response = Response::new(BoxBody::new(Empty::new()));
|
@@ -8,8 +8,10 @@ use async_trait::async_trait;
|
|
8
8
|
use either::Either;
|
9
9
|
use magnus::error::Result;
|
10
10
|
use serde::Deserialize;
|
11
|
+
use std::collections::HashMap;
|
11
12
|
use std::sync::{Arc, OnceLock};
|
12
13
|
use std::time::Duration;
|
14
|
+
use tracing::{debug, error, warn};
|
13
15
|
|
14
16
|
#[derive(Debug, Clone, Deserialize)]
|
15
17
|
pub struct RateLimit {
|
@@ -19,6 +21,7 @@ pub struct RateLimit {
|
|
19
21
|
#[serde(skip_deserializing)]
|
20
22
|
pub rate_limiter: OnceLock<Arc<dyn RateLimiter>>,
|
21
23
|
pub store_config: RateLimiterConfig,
|
24
|
+
pub trusted_proxies: HashMap<String, TokenSource>,
|
22
25
|
#[serde(default = "too_many_requests_error_response")]
|
23
26
|
pub error_response: ErrorResponse,
|
24
27
|
}
|
@@ -55,7 +58,12 @@ impl MiddlewareLayer for RateLimit {
|
|
55
58
|
let key_value = match &self.key {
|
56
59
|
RateLimitKey::SocketAddress => {
|
57
60
|
// Use the socket address from the context
|
58
|
-
&context.addr
|
61
|
+
if self.trusted_proxies.contains_key(&context.addr) {
|
62
|
+
let source = self.trusted_proxies.get(&context.addr).unwrap();
|
63
|
+
source.extract_token(&req).unwrap_or(&context.addr)
|
64
|
+
} else {
|
65
|
+
&context.addr
|
66
|
+
}
|
59
67
|
}
|
60
68
|
RateLimitKey::Parameter(token_source) => {
|
61
69
|
match token_source {
|
@@ -68,7 +76,7 @@ impl MiddlewareLayer for RateLimit {
|
|
68
76
|
}
|
69
77
|
} else {
|
70
78
|
// If no token is found, skip rate limiting
|
71
|
-
|
79
|
+
warn!("No token found in header for rate limiting");
|
72
80
|
return Ok(Either::Left(req));
|
73
81
|
}
|
74
82
|
}
|
@@ -77,7 +85,7 @@ impl MiddlewareLayer for RateLimit {
|
|
77
85
|
value
|
78
86
|
} else {
|
79
87
|
// If no token is found, skip rate limiting
|
80
|
-
|
88
|
+
warn!("No token found in query for rate limiting");
|
81
89
|
return Ok(Either::Left(req));
|
82
90
|
}
|
83
91
|
}
|
@@ -88,6 +96,7 @@ impl MiddlewareLayer for RateLimit {
|
|
88
96
|
// Create a rate limit key
|
89
97
|
let rate_limit_key = create_rate_limit_key(key_value, req.uri().path());
|
90
98
|
|
99
|
+
debug!(target: "middleware::rate_limit", "Rate limit key: {}", rate_limit_key);
|
91
100
|
// Get the rate limiter
|
92
101
|
if let Some(limiter) = self.rate_limiter.get() {
|
93
102
|
// Check if rate limit is exceeded
|
@@ -95,8 +104,12 @@ impl MiddlewareLayer for RateLimit {
|
|
95
104
|
let limit = self.requests;
|
96
105
|
|
97
106
|
match limiter.check_limit(&rate_limit_key, limit, timeout).await {
|
98
|
-
Ok(_) =>
|
107
|
+
Ok(_) => {
|
108
|
+
debug!(target: "middleware::rate_limit", "Rate limit not exceeded");
|
109
|
+
Ok(Either::Left(req))
|
110
|
+
}
|
99
111
|
Err(RateLimitError::RateLimitExceeded { limit, ttl, .. }) => {
|
112
|
+
debug!(target: "middleware::rate_limit", "Rate limit exceeded. Limit: {}, ttl: {}", limit, ttl);
|
100
113
|
let mut response = self
|
101
114
|
.error_response
|
102
115
|
.to_http_response(req.accept().into())
|
@@ -116,14 +129,12 @@ impl MiddlewareLayer for RateLimit {
|
|
116
129
|
Ok(Either::Right(response))
|
117
130
|
}
|
118
131
|
Err(e) => {
|
119
|
-
|
120
|
-
tracing::error!("Rate limiter error: {:?}", e);
|
132
|
+
error!("Rate limiter error: {:?}", e);
|
121
133
|
Ok(Either::Left(req))
|
122
134
|
}
|
123
135
|
}
|
124
136
|
} else {
|
125
|
-
|
126
|
-
tracing::warn!("Rate limiter not initialized");
|
137
|
+
warn!("Rate limiter not initialized");
|
127
138
|
Ok(Either::Left(req))
|
128
139
|
}
|
129
140
|
}
|
@@ -1,21 +1,19 @@
|
|
1
|
+
use super::{string_rewrite::StringRewrite, FromValue, MiddlewareLayer};
|
1
2
|
use crate::{
|
2
|
-
server::
|
3
|
+
server::{
|
4
|
+
http_message_types::{HttpRequest, HttpResponse},
|
5
|
+
redirect_type::RedirectType,
|
6
|
+
},
|
3
7
|
services::itsi_http_service::HttpRequestContext,
|
4
8
|
};
|
5
|
-
|
6
|
-
use super::{string_rewrite::StringRewrite, FromValue, MiddlewareLayer};
|
7
|
-
|
8
9
|
use async_trait::async_trait;
|
9
10
|
use either::Either;
|
10
|
-
use http::
|
11
|
+
use http::Response;
|
11
12
|
use http_body_util::{combinators::BoxBody, Empty};
|
12
13
|
use magnus::error::Result;
|
13
14
|
use serde::Deserialize;
|
15
|
+
use tracing::debug;
|
14
16
|
|
15
|
-
/// A simple API key filter.
|
16
|
-
/// The API key can be given inside the header or a query string
|
17
|
-
/// Keys are validated against a list of allowed key values (Changing these requires a restart)
|
18
|
-
///
|
19
17
|
#[derive(Debug, Clone, Deserialize)]
|
20
18
|
pub struct Redirect {
|
21
19
|
pub to: StringRewrite,
|
@@ -24,19 +22,6 @@ pub struct Redirect {
|
|
24
22
|
pub redirect_type: RedirectType,
|
25
23
|
}
|
26
24
|
|
27
|
-
#[derive(Debug, Clone, Deserialize, Default)]
|
28
|
-
pub enum RedirectType {
|
29
|
-
#[serde(rename(deserialize = "permanent"))]
|
30
|
-
#[default]
|
31
|
-
Permanent,
|
32
|
-
#[serde(rename(deserialize = "temporary"))]
|
33
|
-
Temporary,
|
34
|
-
#[serde(rename(deserialize = "found"))]
|
35
|
-
Found,
|
36
|
-
#[serde(rename(deserialize = "moved_permanently"))]
|
37
|
-
MovedPermanently,
|
38
|
-
}
|
39
|
-
|
40
25
|
#[async_trait]
|
41
26
|
impl MiddlewareLayer for Redirect {
|
42
27
|
async fn before(
|
@@ -55,21 +40,15 @@ impl Redirect {
|
|
55
40
|
context: &mut HttpRequestContext,
|
56
41
|
) -> Result<HttpResponse> {
|
57
42
|
let mut response = Response::new(BoxBody::new(Empty::new()));
|
58
|
-
*response.status_mut() =
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
magnus::Error::new(
|
68
|
-
magnus::exception::standard_error(),
|
69
|
-
format!("Invalid Rewrite String: {:?}: {}", self.to, e),
|
70
|
-
)
|
71
|
-
})?,
|
72
|
-
);
|
43
|
+
*response.status_mut() = self.redirect_type.status_code();
|
44
|
+
let destination = self.to.rewrite_request(req, context).parse().map_err(|e| {
|
45
|
+
magnus::Error::new(
|
46
|
+
magnus::exception::standard_error(),
|
47
|
+
format!("Invalid Rewrite String: {:?}: {}", self.to, e),
|
48
|
+
)
|
49
|
+
})?;
|
50
|
+
debug!(target: "middleware::redirect", "Redirecting to {:?}", destination);
|
51
|
+
response.headers_mut().append("Location", destination);
|
73
52
|
Ok(response)
|
74
53
|
}
|
75
54
|
}
|
@@ -5,7 +5,7 @@ use crate::{
|
|
5
5
|
services::itsi_http_service::HttpRequestContext,
|
6
6
|
};
|
7
7
|
|
8
|
-
use super::{FromValue, MiddlewareLayer};
|
8
|
+
use super::{FromValue, MiddlewareLayer, StringRewrite};
|
9
9
|
use async_trait::async_trait;
|
10
10
|
use either::Either;
|
11
11
|
use http::HeaderName;
|
@@ -14,30 +14,40 @@ use serde::Deserialize;
|
|
14
14
|
|
15
15
|
#[derive(Debug, Clone, Deserialize)]
|
16
16
|
pub struct RequestHeaders {
|
17
|
-
pub additions: HashMap<String, Vec<
|
17
|
+
pub additions: HashMap<String, Vec<StringRewrite>>,
|
18
18
|
pub removals: Vec<String>,
|
19
19
|
}
|
20
|
-
|
21
20
|
#[async_trait]
|
22
21
|
impl MiddlewareLayer for RequestHeaders {
|
23
22
|
async fn before(
|
24
23
|
&self,
|
25
24
|
mut req: HttpRequest,
|
26
|
-
|
25
|
+
context: &mut HttpRequestContext,
|
27
26
|
) -> Result<Either<HttpRequest, HttpResponse>> {
|
28
|
-
let
|
29
|
-
|
30
|
-
headers.remove(removal);
|
31
|
-
}
|
27
|
+
let mut headers_to_add = Vec::new();
|
28
|
+
|
32
29
|
for (header_name, header_values) in &self.additions {
|
33
|
-
|
34
|
-
|
35
|
-
if let Ok(parsed_header_value) =
|
36
|
-
|
30
|
+
if let Ok(parsed_header_name) = header_name.parse::<HeaderName>() {
|
31
|
+
for header_value in header_values {
|
32
|
+
if let Ok(parsed_header_value) =
|
33
|
+
header_value.rewrite_request(&req, context).parse()
|
34
|
+
{
|
35
|
+
headers_to_add.push((parsed_header_name.clone(), parsed_header_value));
|
37
36
|
}
|
38
37
|
}
|
39
38
|
}
|
40
39
|
}
|
40
|
+
|
41
|
+
let headers = req.headers_mut();
|
42
|
+
|
43
|
+
for removal in &self.removals {
|
44
|
+
headers.remove(removal);
|
45
|
+
}
|
46
|
+
|
47
|
+
for (name, value) in headers_to_add {
|
48
|
+
headers.append(name, value);
|
49
|
+
}
|
50
|
+
|
41
51
|
Ok(Either::Left(req))
|
42
52
|
}
|
43
53
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
use std::collections::HashMap;
|
2
2
|
|
3
|
-
use super::{FromValue, MiddlewareLayer};
|
3
|
+
use super::{FromValue, MiddlewareLayer, StringRewrite};
|
4
4
|
use crate::{
|
5
5
|
server::http_message_types::HttpResponse, services::itsi_http_service::HttpRequestContext,
|
6
6
|
};
|
@@ -10,26 +10,41 @@ use serde::Deserialize;
|
|
10
10
|
|
11
11
|
#[derive(Debug, Clone, Deserialize)]
|
12
12
|
pub struct ResponseHeaders {
|
13
|
-
pub additions: HashMap<String, Vec<
|
13
|
+
pub additions: HashMap<String, Vec<StringRewrite>>,
|
14
14
|
pub removals: Vec<String>,
|
15
15
|
}
|
16
16
|
|
17
17
|
#[async_trait]
|
18
18
|
impl MiddlewareLayer for ResponseHeaders {
|
19
|
-
async fn after(
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
async fn after(
|
20
|
+
&self,
|
21
|
+
mut resp: HttpResponse,
|
22
|
+
context: &mut HttpRequestContext,
|
23
|
+
) -> HttpResponse {
|
24
|
+
let mut headers_to_add = Vec::new();
|
25
|
+
|
24
26
|
for (header_name, header_values) in &self.additions {
|
25
|
-
|
26
|
-
|
27
|
-
if let Ok(parsed_header_value) =
|
28
|
-
|
27
|
+
if let Ok(parsed_header_name) = header_name.parse::<HeaderName>() {
|
28
|
+
for header_value in header_values {
|
29
|
+
if let Ok(parsed_header_value) =
|
30
|
+
header_value.rewrite_response(&resp, context).parse()
|
31
|
+
{
|
32
|
+
headers_to_add.push((parsed_header_name.clone(), parsed_header_value));
|
29
33
|
}
|
30
34
|
}
|
31
35
|
}
|
32
36
|
}
|
37
|
+
|
38
|
+
let headers = resp.headers_mut();
|
39
|
+
|
40
|
+
for removal in &self.removals {
|
41
|
+
headers.remove(removal);
|
42
|
+
}
|
43
|
+
|
44
|
+
for (name, value) in headers_to_add {
|
45
|
+
headers.append(name, value);
|
46
|
+
}
|
47
|
+
|
33
48
|
resp
|
34
49
|
}
|
35
50
|
}
|
@@ -19,6 +19,7 @@ use magnus::error::Result;
|
|
19
19
|
use regex::Regex;
|
20
20
|
use serde::Deserialize;
|
21
21
|
use std::{collections::HashMap, path::PathBuf, sync::OnceLock, time::Duration};
|
22
|
+
use tracing::debug;
|
22
23
|
|
23
24
|
#[derive(Debug, Deserialize)]
|
24
25
|
pub struct StaticAssets {
|
@@ -60,6 +61,8 @@ impl MiddlewareLayer for StaticAssets {
|
|
60
61
|
.set(Regex::new(&self.base_path).map_err(ItsiError::new)?)
|
61
62
|
.map_err(ItsiError::new)?;
|
62
63
|
|
64
|
+
debug!(target: "middleware::static_assets", "Base path regexp: {}", self.base_path);
|
65
|
+
|
63
66
|
self.file_server
|
64
67
|
.set(StaticFileServer::new(StaticFileServerConfig {
|
65
68
|
root_dir: self.root_dir.clone(),
|
@@ -68,6 +71,7 @@ impl MiddlewareLayer for StaticAssets {
|
|
68
71
|
max_entries: self.max_files_in_memory,
|
69
72
|
try_html_extension: self.try_html_extension,
|
70
73
|
max_file_size: self.max_file_size_in_memory,
|
74
|
+
headers: self.headers.clone(),
|
71
75
|
recheck_interval: Duration::from_secs(self.file_check_interval),
|
72
76
|
serve_hidden_files: self.serve_hidden_files,
|
73
77
|
allowed_extensions: self.allowed_extensions.clone(),
|
@@ -83,11 +87,12 @@ impl MiddlewareLayer for StaticAssets {
|
|
83
87
|
) -> Result<Either<HttpRequest, HttpResponse>> {
|
84
88
|
// Only handle GET and HEAD requests
|
85
89
|
if req.method() != Method::GET && req.method() != Method::HEAD {
|
90
|
+
debug!(target: "middleware::static_assets", "Refusing to handle non-GET/HEAD request");
|
86
91
|
return Ok(Either::Left(req));
|
87
92
|
}
|
88
93
|
let abs_path = req.uri().path();
|
89
94
|
let rel_path = if !self.relative_path {
|
90
|
-
abs_path
|
95
|
+
abs_path.trim_start_matches("/")
|
91
96
|
} else {
|
92
97
|
let base_path = self
|
93
98
|
.base_path_regex
|
@@ -104,6 +109,7 @@ impl MiddlewareLayer for StaticAssets {
|
|
104
109
|
}
|
105
110
|
};
|
106
111
|
|
112
|
+
debug!(target: "middleware::static_assets", "Asset path is {}", rel_path);
|
107
113
|
// Determine if this is a HEAD request
|
108
114
|
let is_head_request = req.method() == Method::HEAD;
|
109
115
|
|
@@ -98,8 +98,13 @@ impl StringRewrite {
|
|
98
98
|
}
|
99
99
|
}
|
100
100
|
other => {
|
101
|
-
|
102
|
-
|
101
|
+
if let Some(header_val) = req.headers().get(other) {
|
102
|
+
if let Ok(s) = header_val.to_str() {
|
103
|
+
s.to_string()
|
104
|
+
} else {
|
105
|
+
"".to_string()
|
106
|
+
}
|
107
|
+
} else if let Some(caps) = &captures {
|
103
108
|
if let Some(m) = caps.name(other) {
|
104
109
|
m.as_str().to_string()
|
105
110
|
} else {
|
@@ -146,8 +151,13 @@ impl StringRewrite {
|
|
146
151
|
}
|
147
152
|
}
|
148
153
|
other => {
|
149
|
-
|
150
|
-
|
154
|
+
// Try pulling from response headers first
|
155
|
+
if let Some(val) = resp.headers().get(other) {
|
156
|
+
if let Ok(s) = val.to_str() {
|
157
|
+
s.to_string()
|
158
|
+
} else {
|
159
|
+
"".to_string()
|
160
|
+
}
|
151
161
|
} else {
|
152
162
|
format!("{{{}}}", other)
|
153
163
|
}
|
@@ -1,5 +1,7 @@
|
|
1
1
|
use serde::{Deserialize, Serialize};
|
2
2
|
|
3
|
+
use crate::server::http_message_types::{HttpRequest, RequestExt};
|
4
|
+
|
3
5
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
4
6
|
pub enum TokenSource {
|
5
7
|
#[serde(rename(deserialize = "header"))]
|
@@ -10,3 +12,20 @@ pub enum TokenSource {
|
|
10
12
|
#[serde(rename(deserialize = "query"))]
|
11
13
|
Query(String),
|
12
14
|
}
|
15
|
+
|
16
|
+
impl TokenSource {
|
17
|
+
pub fn extract_token<'req>(&self, req: &'req HttpRequest) -> Option<&'req str> {
|
18
|
+
match self {
|
19
|
+
TokenSource::Header { name, prefix } => req.headers().get(name).and_then(|value| {
|
20
|
+
value.to_str().ok().and_then(|value| {
|
21
|
+
if let Some(prefix) = prefix {
|
22
|
+
value.strip_prefix(prefix).map(|v| v.trim())
|
23
|
+
} else {
|
24
|
+
Some(value)
|
25
|
+
}
|
26
|
+
})
|
27
|
+
}),
|
28
|
+
TokenSource::Query(query_name) => req.query_param(query_name),
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
@@ -8,8 +8,11 @@ use magnus::{
|
|
8
8
|
pub use middleware::Middleware;
|
9
9
|
pub use middlewares::*;
|
10
10
|
use regex::{Regex, RegexSet};
|
11
|
-
use std::{
|
12
|
-
|
11
|
+
use std::{
|
12
|
+
collections::{hash_map::Entry::Vacant, HashMap},
|
13
|
+
sync::Arc,
|
14
|
+
};
|
15
|
+
use tracing::debug;
|
13
16
|
|
14
17
|
use super::http_message_types::HttpRequest;
|
15
18
|
|
@@ -132,6 +135,8 @@ impl MiddlewareStack {
|
|
132
135
|
impl MiddlewareSet {
|
133
136
|
pub fn new(routes_raw: Option<HeapVal>) -> Result<Self> {
|
134
137
|
let mut unique_middlewares = HashMap::new();
|
138
|
+
clear_value_cache();
|
139
|
+
|
135
140
|
if let Some(routes_raw) = routes_raw {
|
136
141
|
let mut stacks = HashMap::new();
|
137
142
|
let mut routes = vec![];
|
@@ -162,22 +167,54 @@ impl MiddlewareSet {
|
|
162
167
|
format!("middleware must be a hash. Got {:?}", routes_raw),
|
163
168
|
))?;
|
164
169
|
|
170
|
+
let ruby = Ruby::get().unwrap();
|
165
171
|
let mut layers = middleware
|
166
172
|
.enumeratorize("each", ())
|
167
|
-
.
|
173
|
+
.flat_map(|pair| {
|
168
174
|
let pair = RArray::from_value(pair.unwrap()).unwrap();
|
169
175
|
let middleware_type: String = pair.entry(0).unwrap();
|
170
176
|
let value: Value = pair.entry(1).unwrap();
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
177
|
+
let middleware_values: Vec<Value> = if value.is_kind_of(ruby.class_array())
|
178
|
+
{
|
179
|
+
RArray::from_value(value)
|
180
|
+
.ok_or_else(|| {
|
181
|
+
magnus::Error::new(
|
182
|
+
magnus::exception::type_error(),
|
183
|
+
"Expected array",
|
184
|
+
)
|
185
|
+
})
|
186
|
+
.unwrap()
|
187
|
+
.into_iter()
|
188
|
+
.collect()
|
189
|
+
} else {
|
190
|
+
vec![value]
|
175
191
|
};
|
176
|
-
|
192
|
+
middleware_values
|
193
|
+
.into_iter()
|
194
|
+
.map(|value| {
|
195
|
+
let middleware =
|
196
|
+
if let Vacant(e) = unique_middlewares.entry(value.as_raw()) {
|
197
|
+
let middleware = MiddlewareSet::parse_middleware(
|
198
|
+
middleware_type.clone(),
|
199
|
+
value,
|
200
|
+
);
|
201
|
+
if let Ok(middleware) = middleware.as_ref() {
|
202
|
+
e.insert(middleware.clone());
|
203
|
+
};
|
204
|
+
middleware
|
205
|
+
} else {
|
206
|
+
Ok(unique_middlewares.get(&value.as_raw()).unwrap().clone())
|
207
|
+
};
|
208
|
+
middleware
|
209
|
+
})
|
210
|
+
.collect::<Vec<Result<Middleware>>>()
|
177
211
|
})
|
178
212
|
.collect::<Result<Vec<_>>>()?;
|
179
213
|
routes.push(route_raw);
|
180
214
|
layers.sort();
|
215
|
+
|
216
|
+
debug!("Middleware at index: {} has layers: {:?}", index, layers);
|
217
|
+
|
181
218
|
stacks.insert(
|
182
219
|
index,
|
183
220
|
MiddlewareStack {
|
@@ -260,6 +297,7 @@ impl MiddlewareSet {
|
|
260
297
|
pub fn parse_middleware(middleware_type: String, parameters: Value) -> Result<Middleware> {
|
261
298
|
let mw_type = middleware_type.clone();
|
262
299
|
|
300
|
+
debug!(target: "itsi_server::middleware_stack", "Parsing middleware: {} from {}", mw_type, parameters);
|
263
301
|
let result = (move || -> Result<Middleware> {
|
264
302
|
match mw_type.as_str() {
|
265
303
|
"allow_list" => Ok(Middleware::AllowList(AllowList::from_value(parameters)?)),
|
@@ -290,7 +328,7 @@ impl MiddlewareSet {
|
|
290
328
|
"static_response" => Ok(Middleware::StaticResponse(StaticResponse::from_value(
|
291
329
|
parameters,
|
292
330
|
)?)),
|
293
|
-
"
|
331
|
+
"compress" => Ok(Middleware::Compression(Compression::from_value(
|
294
332
|
parameters,
|
295
333
|
)?)),
|
296
334
|
"log_requests" => Ok(Middleware::LogRequests(LogRequests::from_value(
|
@@ -306,6 +344,8 @@ impl MiddlewareSet {
|
|
306
344
|
}
|
307
345
|
})();
|
308
346
|
|
347
|
+
debug!(target: "itsi_server::middleware_stack", "Stack layer init result {:?}", result);
|
348
|
+
|
309
349
|
match result {
|
310
350
|
Ok(result) => Ok(result),
|
311
351
|
Err(err) => Err(magnus::Error::new(
|
@@ -319,10 +359,6 @@ impl MiddlewareSet {
|
|
319
359
|
}
|
320
360
|
|
321
361
|
pub async fn initialize_layers(&self) -> Result<()> {
|
322
|
-
info!(
|
323
|
-
"Unique middleware keys: {:?}",
|
324
|
-
self.unique_middlewares.keys()
|
325
|
-
);
|
326
362
|
for middleware in self.unique_middlewares.values() {
|
327
363
|
middleware.initialize().await?;
|
328
364
|
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
use http::StatusCode;
|
2
|
+
use serde::Deserialize;
|
3
|
+
|
4
|
+
#[derive(Debug, Clone, Deserialize, Default)]
|
5
|
+
pub enum RedirectType {
|
6
|
+
#[serde(rename(deserialize = "permanent"))]
|
7
|
+
#[default]
|
8
|
+
Permanent,
|
9
|
+
#[serde(rename(deserialize = "temporary"))]
|
10
|
+
Temporary,
|
11
|
+
#[serde(rename(deserialize = "found"))]
|
12
|
+
Found,
|
13
|
+
#[serde(rename(deserialize = "moved_permanently"))]
|
14
|
+
MovedPermanently,
|
15
|
+
}
|
16
|
+
|
17
|
+
impl RedirectType {
|
18
|
+
pub fn status_code(&self) -> StatusCode {
|
19
|
+
match self {
|
20
|
+
RedirectType::Permanent => StatusCode::PERMANENT_REDIRECT,
|
21
|
+
RedirectType::Temporary => StatusCode::TEMPORARY_REDIRECT,
|
22
|
+
RedirectType::Found => StatusCode::FOUND,
|
23
|
+
RedirectType::MovedPermanently => StatusCode::MOVED_PERMANENTLY,
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|