itsi-server 0.1.1 → 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/Cargo.lock +4487 -0
- data/Cargo.toml +7 -0
- data/README.md +6 -0
- data/Rakefile +7 -4
- data/exe/itsi +152 -46
- data/ext/itsi_acme/Cargo.toml +86 -0
- data/ext/itsi_acme/examples/high_level.rs +63 -0
- data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
- data/ext/itsi_acme/examples/low_level.rs +87 -0
- data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
- data/ext/itsi_acme/src/acceptor.rs +81 -0
- data/ext/itsi_acme/src/acme.rs +354 -0
- data/ext/itsi_acme/src/axum.rs +86 -0
- data/ext/itsi_acme/src/cache.rs +39 -0
- data/ext/itsi_acme/src/caches/boxed.rs +80 -0
- data/ext/itsi_acme/src/caches/composite.rs +69 -0
- data/ext/itsi_acme/src/caches/dir.rs +106 -0
- data/ext/itsi_acme/src/caches/mod.rs +11 -0
- data/ext/itsi_acme/src/caches/no.rs +78 -0
- data/ext/itsi_acme/src/caches/test.rs +136 -0
- data/ext/itsi_acme/src/config.rs +172 -0
- data/ext/itsi_acme/src/https_helper.rs +69 -0
- data/ext/itsi_acme/src/incoming.rs +142 -0
- data/ext/itsi_acme/src/jose.rs +161 -0
- data/ext/itsi_acme/src/lib.rs +142 -0
- data/ext/itsi_acme/src/resolver.rs +59 -0
- data/ext/itsi_acme/src/state.rs +424 -0
- data/ext/itsi_error/Cargo.toml +3 -0
- data/ext/itsi_error/src/lib.rs +98 -24
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
- data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
- data/ext/itsi_instrument_entry/Cargo.toml +15 -0
- data/ext/itsi_instrument_entry/src/lib.rs +31 -0
- data/ext/itsi_rb_helpers/Cargo.toml +3 -0
- data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
- data/ext/itsi_rb_helpers/src/lib.rs +141 -10
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
- data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
- data/ext/itsi_scheduler/Cargo.toml +24 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
- data/ext/itsi_scheduler/src/itsi_scheduler.rs +314 -0
- data/ext/itsi_scheduler/src/lib.rs +39 -0
- data/ext/itsi_server/Cargo.lock +2956 -0
- data/ext/itsi_server/Cargo.toml +75 -14
- data/ext/itsi_server/extconf.rb +1 -1
- data/ext/itsi_server/src/default_responses/html/401.html +68 -0
- data/ext/itsi_server/src/default_responses/html/403.html +68 -0
- data/ext/itsi_server/src/default_responses/html/404.html +68 -0
- data/ext/itsi_server/src/default_responses/html/413.html +71 -0
- data/ext/itsi_server/src/default_responses/html/429.html +68 -0
- data/ext/itsi_server/src/default_responses/html/500.html +71 -0
- data/ext/itsi_server/src/default_responses/html/502.html +71 -0
- data/ext/itsi_server/src/default_responses/html/503.html +68 -0
- data/ext/itsi_server/src/default_responses/html/504.html +69 -0
- data/ext/itsi_server/src/default_responses/html/index.html +238 -0
- data/ext/itsi_server/src/default_responses/json/401.json +6 -0
- data/ext/itsi_server/src/default_responses/json/403.json +6 -0
- data/ext/itsi_server/src/default_responses/json/404.json +6 -0
- data/ext/itsi_server/src/default_responses/json/413.json +6 -0
- data/ext/itsi_server/src/default_responses/json/429.json +6 -0
- data/ext/itsi_server/src/default_responses/json/500.json +6 -0
- data/ext/itsi_server/src/default_responses/json/502.json +6 -0
- data/ext/itsi_server/src/default_responses/json/503.json +6 -0
- data/ext/itsi_server/src/default_responses/json/504.json +6 -0
- data/ext/itsi_server/src/default_responses/mod.rs +11 -0
- data/ext/itsi_server/src/env.rs +43 -0
- data/ext/itsi_server/src/lib.rs +133 -40
- data/ext/itsi_server/src/prelude.rs +2 -0
- data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +109 -0
- data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +143 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
- data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
- data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +391 -0
- data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
- data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
- data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
- data/ext/itsi_server/src/server/binds/bind.rs +204 -0
- data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
- data/ext/itsi_server/src/server/binds/listener.rs +444 -0
- data/ext/itsi_server/src/server/binds/mod.rs +4 -0
- data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
- data/ext/itsi_server/src/server/binds/tls.rs +278 -0
- data/ext/itsi_server/src/server/byte_frame.rs +32 -0
- data/ext/itsi_server/src/server/http_message_types.rs +97 -0
- data/ext/itsi_server/src/server/io_stream.rs +105 -0
- data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
- data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
- data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
- data/ext/itsi_server/src/server/mod.rs +13 -5
- data/ext/itsi_server/src/server/process_worker.rs +247 -0
- data/ext/itsi_server/src/server/redirect_type.rs +26 -0
- data/ext/itsi_server/src/server/request_job.rs +11 -0
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +354 -0
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +30 -0
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +481 -0
- data/ext/itsi_server/src/server/signal.rs +77 -0
- data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
- data/ext/itsi_server/src/server/thread_worker.rs +479 -0
- data/ext/itsi_server/src/services/cache_store.rs +74 -0
- data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
- data/ext/itsi_server/src/services/mime_types.rs +1416 -0
- data/ext/itsi_server/src/services/mod.rs +6 -0
- data/ext/itsi_server/src/services/password_hasher.rs +83 -0
- data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
- data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
- data/ext/itsi_tracing/Cargo.toml +5 -0
- data/ext/itsi_tracing/src/lib.rs +366 -7
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
- data/lib/itsi/http_request/response_status_shortcodes.rb +76 -0
- data/lib/itsi/http_request.rb +218 -0
- data/lib/itsi/http_response.rb +42 -0
- data/lib/itsi/passfile.rb +108 -0
- data/lib/itsi/server/config/config_helpers.rb +105 -0
- data/lib/itsi/server/config/dsl.rb +211 -0
- data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
- data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
- data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
- data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
- data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
- data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
- data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
- data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
- data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
- data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
- data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
- data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
- data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
- data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
- data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
- data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
- data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
- data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
- data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
- data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
- data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
- data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
- data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
- data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
- data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
- data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
- data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
- data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
- data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
- data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
- data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
- data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
- data/lib/itsi/server/config/known_paths.rb +20 -0
- data/lib/itsi/server/config/middleware/_index.md +56 -0
- data/lib/itsi/server/config/middleware/allow_list.md +46 -0
- data/lib/itsi/server/config/middleware/allow_list.rb +42 -0
- data/lib/itsi/server/config/middleware/auth_api_key.md +90 -0
- data/lib/itsi/server/config/middleware/auth_api_key.rb +51 -0
- data/lib/itsi/server/config/middleware/auth_basic.md +45 -0
- data/lib/itsi/server/config/middleware/auth_basic.rb +44 -0
- data/lib/itsi/server/config/middleware/auth_jwt.md +82 -0
- data/lib/itsi/server/config/middleware/auth_jwt.rb +38 -0
- data/lib/itsi/server/config/middleware/cache_control.md +78 -0
- data/lib/itsi/server/config/middleware/cache_control.rb +45 -0
- data/lib/itsi/server/config/middleware/cidr_to_regex.rb +50 -0
- data/lib/itsi/server/config/middleware/compression.md +50 -0
- data/lib/itsi/server/config/middleware/compression.rb +37 -0
- data/lib/itsi/server/config/middleware/cors.md +93 -0
- data/lib/itsi/server/config/middleware/cors.rb +32 -0
- data/lib/itsi/server/config/middleware/csp.md +37 -0
- data/lib/itsi/server/config/middleware/csp.rb +44 -0
- data/lib/itsi/server/config/middleware/deny_list.md +45 -0
- data/lib/itsi/server/config/middleware/deny_list.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/_index.md +159 -0
- data/lib/itsi/server/config/middleware/endpoint/controller.md +186 -0
- data/lib/itsi/server/config/middleware/endpoint/controller.rb +33 -0
- data/lib/itsi/server/config/middleware/endpoint/delete.md +12 -0
- data/lib/itsi/server/config/middleware/endpoint/delete.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/endpoint.rb +99 -0
- data/lib/itsi/server/config/middleware/endpoint/get.md +12 -0
- data/lib/itsi/server/config/middleware/endpoint/get.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/http_request.md +44 -0
- data/lib/itsi/server/config/middleware/endpoint/http_response.md +39 -0
- data/lib/itsi/server/config/middleware/endpoint/patch.md +12 -0
- data/lib/itsi/server/config/middleware/endpoint/patch.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/post.md +12 -0
- data/lib/itsi/server/config/middleware/endpoint/post.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/put.md +12 -0
- data/lib/itsi/server/config/middleware/endpoint/put.rb +42 -0
- data/lib/itsi/server/config/middleware/endpoint/schemas.md +122 -0
- data/lib/itsi/server/config/middleware/error_response.md +61 -0
- data/lib/itsi/server/config/middleware/error_response.rb +36 -0
- data/lib/itsi/server/config/middleware/etag.md +59 -0
- data/lib/itsi/server/config/middleware/etag.rb +27 -0
- data/lib/itsi/server/config/middleware/grpc.md +172 -0
- data/lib/itsi/server/config/middleware/grpc.rb +54 -0
- data/lib/itsi/server/config/middleware/intrusion_protection.md +124 -0
- data/lib/itsi/server/config/middleware/intrusion_protection.rb +61 -0
- data/lib/itsi/server/config/middleware/location.md +107 -0
- data/lib/itsi/server/config/middleware/location.rb +99 -0
- data/lib/itsi/server/config/middleware/log_requests.md +65 -0
- data/lib/itsi/server/config/middleware/log_requests.rb +31 -0
- data/lib/itsi/server/config/middleware/max_body.md +18 -0
- data/lib/itsi/server/config/middleware/max_body.rb +21 -0
- data/lib/itsi/server/config/middleware/proxy.md +62 -0
- data/lib/itsi/server/config/middleware/proxy.rb +41 -0
- data/lib/itsi/server/config/middleware/rackup_file.md +54 -0
- data/lib/itsi/server/config/middleware/rackup_file.rb +44 -0
- data/lib/itsi/server/config/middleware/rate_limit.md +126 -0
- data/lib/itsi/server/config/middleware/rate_limit.rb +34 -0
- data/lib/itsi/server/config/middleware/rate_limit_store.rb +25 -0
- data/lib/itsi/server/config/middleware/redirect.md +55 -0
- data/lib/itsi/server/config/middleware/redirect.rb +25 -0
- data/lib/itsi/server/config/middleware/request_headers.md +34 -0
- data/lib/itsi/server/config/middleware/request_headers.rb +24 -0
- data/lib/itsi/server/config/middleware/response_headers.md +33 -0
- data/lib/itsi/server/config/middleware/response_headers.rb +25 -0
- data/lib/itsi/server/config/middleware/run.md +60 -0
- data/lib/itsi/server/config/middleware/run.rb +43 -0
- data/lib/itsi/server/config/middleware/static_assets.md +73 -0
- data/lib/itsi/server/config/middleware/static_assets.rb +87 -0
- data/lib/itsi/server/config/middleware/static_response.md +44 -0
- data/lib/itsi/server/config/middleware/static_response.rb +29 -0
- data/lib/itsi/server/config/middleware/string_rewrite.md +67 -0
- data/lib/itsi/server/config/middleware/token_source.rb +32 -0
- data/lib/itsi/server/config/middleware.rb +13 -0
- data/lib/itsi/server/config/option.rb +14 -0
- data/lib/itsi/server/config/options/_index.md +37 -0
- data/lib/itsi/server/config/options/auto_reload_config.md +13 -0
- data/lib/itsi/server/config/options/auto_reload_config.rb +41 -0
- data/lib/itsi/server/config/options/bind.md +71 -0
- data/lib/itsi/server/config/options/bind.rb +26 -0
- data/lib/itsi/server/config/options/certificates.md +65 -0
- data/lib/itsi/server/config/options/daemonize.md +14 -0
- data/lib/itsi/server/config/options/daemonize.rb +19 -0
- data/lib/itsi/server/config/options/fiber_scheduler.md +34 -0
- data/lib/itsi/server/config/options/fiber_scheduler.rb +21 -0
- data/lib/itsi/server/config/options/header_read_timeout.md +17 -0
- data/lib/itsi/server/config/options/header_read_timeout.rb +19 -0
- data/lib/itsi/server/config/options/hooks/_index.md +11 -0
- data/lib/itsi/server/config/options/hooks/after_fork.md +13 -0
- data/lib/itsi/server/config/options/hooks/after_fork.rb +28 -0
- data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.md +14 -0
- data/lib/itsi/server/config/options/hooks/after_memory_limit_reached.rb +28 -0
- data/lib/itsi/server/config/options/hooks/after_start.md +12 -0
- data/lib/itsi/server/config/options/hooks/after_start.rb +28 -0
- data/lib/itsi/server/config/options/hooks/before_fork.md +13 -0
- data/lib/itsi/server/config/options/hooks/before_fork.rb +28 -0
- data/lib/itsi/server/config/options/hooks/before_restart.md +12 -0
- data/lib/itsi/server/config/options/hooks/before_restart.rb +28 -0
- data/lib/itsi/server/config/options/hooks/before_shutdown.md +12 -0
- data/lib/itsi/server/config/options/hooks/before_shutdown.rb +28 -0
- data/lib/itsi/server/config/options/include.md +20 -0
- data/lib/itsi/server/config/options/include.rb +36 -0
- data/lib/itsi/server/config/options/listen_backlog.md +11 -0
- data/lib/itsi/server/config/options/listen_backlog.rb +19 -0
- data/lib/itsi/server/config/options/log_format.md +18 -0
- data/lib/itsi/server/config/options/log_format.rb +19 -0
- data/lib/itsi/server/config/options/log_level.md +34 -0
- data/lib/itsi/server/config/options/log_level.rb +20 -0
- data/lib/itsi/server/config/options/log_target.md +38 -0
- data/lib/itsi/server/config/options/log_target.rb +19 -0
- data/lib/itsi/server/config/options/log_target_filters.md +17 -0
- data/lib/itsi/server/config/options/log_target_filters.rb +19 -0
- data/lib/itsi/server/config/options/multithreaded_reactor.md +27 -0
- data/lib/itsi/server/config/options/multithreaded_reactor.rb +24 -0
- data/lib/itsi/server/config/options/nodelay.md +16 -0
- data/lib/itsi/server/config/options/nodelay.rb +19 -0
- data/lib/itsi/server/config/options/oob_gc_responses_threshold.md +19 -0
- data/lib/itsi/server/config/options/oob_gc_responses_threshold.rb +18 -0
- data/lib/itsi/server/config/options/pin_worker_cores.md +17 -0
- data/lib/itsi/server/config/options/pin_worker_cores.rb +19 -0
- data/lib/itsi/server/config/options/preload.md +21 -0
- data/lib/itsi/server/config/options/preload.rb +18 -0
- data/lib/itsi/server/config/options/recv_buffer_size.md +15 -0
- data/lib/itsi/server/config/options/recv_buffer_size.rb +19 -0
- data/lib/itsi/server/config/options/redirect_http_to_https.md +21 -0
- data/lib/itsi/server/config/options/redirect_http_to_https.rb +30 -0
- data/lib/itsi/server/config/options/request_timeout.md +23 -0
- data/lib/itsi/server/config/options/request_timeout.rb +19 -0
- data/lib/itsi/server/config/options/reuse_address.md +16 -0
- data/lib/itsi/server/config/options/reuse_address.rb +19 -0
- data/lib/itsi/server/config/options/reuse_port.md +16 -0
- data/lib/itsi/server/config/options/reuse_port.rb +19 -0
- data/lib/itsi/server/config/options/scheduler_threads.md +34 -0
- data/lib/itsi/server/config/options/scheduler_threads.rb +17 -0
- data/lib/itsi/server/config/options/shutdown_timeout.md +17 -0
- data/lib/itsi/server/config/options/shutdown_timeout.rb +19 -0
- data/lib/itsi/server/config/options/stream_body.md +32 -0
- data/lib/itsi/server/config/options/stream_body.rb +18 -0
- data/lib/itsi/server/config/options/threads.md +44 -0
- data/lib/itsi/server/config/options/threads.rb +17 -0
- data/lib/itsi/server/config/options/watch.md +16 -0
- data/lib/itsi/server/config/options/watch.rb +28 -0
- data/lib/itsi/server/config/options/worker_memory_limit.md +22 -0
- data/lib/itsi/server/config/options/worker_memory_limit.rb +18 -0
- data/lib/itsi/server/config/options/workers.md +42 -0
- data/lib/itsi/server/config/options/workers.rb +17 -0
- data/lib/itsi/server/config/typed_struct.rb +242 -0
- data/lib/itsi/server/config.rb +289 -0
- data/lib/itsi/server/default_app/default_app.rb +34 -0
- data/lib/itsi/server/default_app/index.html +115 -0
- data/lib/itsi/server/default_config/Itsi.rb +107 -0
- data/lib/itsi/server/grpc/grpc_call.rb +246 -0
- data/lib/itsi/server/grpc/grpc_interface.rb +107 -0
- data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
- data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
- data/lib/itsi/server/rack/handler/itsi.rb +27 -0
- data/lib/itsi/server/rack_interface.rb +94 -0
- data/lib/itsi/server/route_tester.rb +157 -0
- data/lib/itsi/server/scheduler_interface.rb +21 -0
- data/lib/itsi/server/scheduler_mode.rb +10 -0
- data/lib/itsi/server/signal_trap.rb +33 -0
- data/lib/itsi/server/typed_handlers/param_parser.rb +196 -0
- data/lib/itsi/server/typed_handlers/source_parser.rb +56 -0
- data/lib/itsi/server/typed_handlers.rb +25 -0
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +265 -9
- data/lib/itsi/standard_headers.rb +86 -0
- data/lib/ruby_lsp/itsi/addon.rb +129 -0
- data/lib/shell_completions/completions.rb +26 -0
- metadata +454 -28
- data/CHANGELOG.md +0 -5
- data/CODE_OF_CONDUCT.md +0 -132
- data/LICENSE.txt +0 -21
- data/ext/itsi_server/src/request/itsi_request.rs +0 -143
- data/ext/itsi_server/src/request/mod.rs +0 -1
- data/ext/itsi_server/src/server/bind.rs +0 -138
- data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -32
- data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -52
- data/ext/itsi_server/src/server/itsi_server.rs +0 -182
- data/ext/itsi_server/src/server/listener.rs +0 -218
- data/ext/itsi_server/src/server/tls.rs +0 -138
- data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
- data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
- data/lib/itsi/request.rb +0 -39
@@ -0,0 +1,94 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module RackInterface
|
4
|
+
|
5
|
+
# Builds a handler proc that is compatible with Rack applications.
|
6
|
+
def self.for(app)
|
7
|
+
require "rack"
|
8
|
+
if app.is_a?(String)
|
9
|
+
dir = File.expand_path(File.dirname(app))
|
10
|
+
Dir.chdir(dir) do
|
11
|
+
loaded_app = ::Rack::Builder.parse_file(app)
|
12
|
+
app = loaded_app.is_a?(Array) ? loaded_app.first : loaded_app
|
13
|
+
end
|
14
|
+
end
|
15
|
+
lambda do |request|
|
16
|
+
Server.respond(request, app.call(request.to_rack_env))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Interface to Rack applications.
|
21
|
+
# Here we build the env, and invoke the Rack app's call method.
|
22
|
+
# We then turn the Rack response into something Itsi server understands.
|
23
|
+
def call(app, request)
|
24
|
+
respond request, app.call(request.to_rack_env)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Itsi responses are asynchronous and can be streamed.
|
28
|
+
# Response chunks are sent using response.send_frame
|
29
|
+
# and the response is finished using response.close_write.
|
30
|
+
# If only a single chunk is written, you can use the #send_and_close method.
|
31
|
+
def respond(request, (status, headers, body))
|
32
|
+
response = request.response
|
33
|
+
|
34
|
+
# Don't try and respond if we've been hijacked.
|
35
|
+
# The hijacker is now responsible for this.
|
36
|
+
return if request.hijacked
|
37
|
+
|
38
|
+
# 1. Set Status
|
39
|
+
response.status = status
|
40
|
+
|
41
|
+
# 2. Set Headers
|
42
|
+
body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack")
|
43
|
+
headers.each do |key, value|
|
44
|
+
unless value.is_a?(Array)
|
45
|
+
response[key] = value
|
46
|
+
next
|
47
|
+
end
|
48
|
+
|
49
|
+
value.each do |v|
|
50
|
+
response[key] = v
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# 3. Set Body
|
55
|
+
# As soon as we start setting the response
|
56
|
+
# the server will begin to stream it to the client.
|
57
|
+
|
58
|
+
# If we're partially hijacked or returned a streaming body,
|
59
|
+
# stream this response.
|
60
|
+
|
61
|
+
if body_streamer
|
62
|
+
body_streamer.call(response)
|
63
|
+
|
64
|
+
# If we're enumerable with more than one chunk
|
65
|
+
# also stream, otherwise write in a single chunk
|
66
|
+
elsif body.respond_to?(:each) || body.respond_to?(:to_ary)
|
67
|
+
unless body.respond_to?(:each)
|
68
|
+
body = body.to_ary
|
69
|
+
raise "Body #to_ary didn't return an array" unless body.is_a?(Array)
|
70
|
+
end
|
71
|
+
# We offset this iteration intentionally,
|
72
|
+
# to optimize for the case where there's only one chunk.
|
73
|
+
buffer = nil
|
74
|
+
body.each do |part|
|
75
|
+
response << buffer.to_s if buffer
|
76
|
+
buffer = part
|
77
|
+
end
|
78
|
+
|
79
|
+
response.send_and_close(buffer.to_s)
|
80
|
+
else
|
81
|
+
response.send_and_close(body.to_s)
|
82
|
+
end
|
83
|
+
ensure
|
84
|
+
response.close_write
|
85
|
+
body.close if body.respond_to?(:close)
|
86
|
+
end
|
87
|
+
|
88
|
+
# A streaming body is one that responds to #call and not #each.
|
89
|
+
def streaming_body?(body)
|
90
|
+
body.respond_to?(:call) && !body.respond_to?(:each)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module RouteTester
|
4
|
+
|
5
|
+
require "set"
|
6
|
+
require "strscan"
|
7
|
+
require "debug"
|
8
|
+
def format_mw(mw)
|
9
|
+
mw_name, mw_args = mw
|
10
|
+
case mw_name
|
11
|
+
when "app"
|
12
|
+
"\e[33mapp\e[0m(#{mw_args['app_proc'].inspect.split(' ')[1][0...-1]})"
|
13
|
+
when "log_requests"
|
14
|
+
if mw_args['before'] && mw_args['after']
|
15
|
+
"\e[33mlog_requests\e[0m(before: #{mw_args['before']['format'][0..6]}..., after: #{mw_args['after']['format'][0..6]}...)"
|
16
|
+
elsif mw_args['before']
|
17
|
+
"\e[33mlog_requests\e[0m(before: #{mw_args['before']['format'][0..6]}...)"
|
18
|
+
elsif mw_args['after']
|
19
|
+
"\e[33mlog_requests\e[0m(before: nil, after: #{mw_args['after']['format'][0..6]}...)"
|
20
|
+
end
|
21
|
+
when "compress"
|
22
|
+
"\e[33mcompress\e[0m(#{mw_args['algorithms'].join(' ')}, #{mw_args['mime_types']})"
|
23
|
+
when "cors"
|
24
|
+
"\e[33mcors\e[0m(#{mw_args['allow_origins'].join(' ')}, #{mw_args['allow_methods'].join(' ')})"
|
25
|
+
when "etag"
|
26
|
+
"\e[33metag\e[0m(#{mw_args['type']}/#{mw_args['algorithm']}, #{mw_args['handle_if_none_match'] ? 'if_none_match' : ''})"
|
27
|
+
when "cache_control"
|
28
|
+
"\e[33mcache_control\e[0m(max_age: #{mw_args['max_age']}, #{mw_args.select{|_,v| v == true }.keys.join(", ")})"
|
29
|
+
when "redirect"
|
30
|
+
"\e[33mredirect\e[0m(to: #{mw_args['to']}, type: #{mw_args['type']})"
|
31
|
+
when "static_assets"
|
32
|
+
"\e[33mstatic_assets\e[0m(path: #{mw_args['root_dir']})"
|
33
|
+
when "auth_api_key"
|
34
|
+
"\e[33mauth_api_key\e[0m(keys: #{mw_args['valid_keys'].keys}#{mw_args['credentials_file'] ? ", credentials_file: #{mw_args['credentials_file']}" : ""})"
|
35
|
+
when "auth_basic"
|
36
|
+
"\e[33mbasic_auth\e[0m(keys: #{mw_args['realm']}#{mw_args['credentials_file'] ? ", credentials_file: #{mw_args['credentials_file']}" : ""})"
|
37
|
+
when "auth_jwt"
|
38
|
+
"\e[33mjwt_auth\e[0m(#{mw_args['verifiers'].keys.join(",")})"
|
39
|
+
when "rate_limit"
|
40
|
+
key = mw_args['key'].kind_of?(Hash) ? mw_args['key']["parameter"] : mw_args['key']
|
41
|
+
"\e[33mrate_limit\e[0m(rps: #{mw_args['requests']}/#{mw_args['seconds']}, key: #{key})"
|
42
|
+
when "allow_list"
|
43
|
+
"\e[33mallow_list\e[0m(patterns: #{mw_args['allowed_patterns'].join(", ")})"
|
44
|
+
when "deny_list"
|
45
|
+
"\e[33mdeny_list\e[0m(patterns: #{mw_args['denied_patterns'].join(", ")})"
|
46
|
+
when "csp"
|
47
|
+
"\e[33mcsp\e[0m(#{mw_args['policy'].map{|k,v| "#{k}: #{v.join(",")}"}.join(", ")})"
|
48
|
+
when "intrusion_protection"
|
49
|
+
[mw_args].flatten.map do |mw_args|
|
50
|
+
"\e[33mintrusion_protection\e[0m(banned_url_patterns: #{mw_args['banned_url_patterns']&.length}, banned_header_patterns: #{mw_args['banned_header_patterns']&.keys&.join(", ")}, #{mw_args['banned_time_seconds']}s)"
|
51
|
+
end.join("\n")
|
52
|
+
when "request_headers"
|
53
|
+
[mw_args].flatten.map do |mw_args|
|
54
|
+
"\e[33mrequest_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
|
55
|
+
end.join("\n")
|
56
|
+
when "response_headers"
|
57
|
+
[mw_args].flatten.map do |mw_args|
|
58
|
+
"\e[33mresponse_headers\e[0m(added: #{mw_args["additions"].keys}, removed: #{mw_args["removals"]})"
|
59
|
+
end.join("\n")
|
60
|
+
when "static_response"
|
61
|
+
"\e[response_headers\e[0m(#{mw_args["code"]} body: #{mw_args["body"][0..10]})"
|
62
|
+
else
|
63
|
+
"\e[33m#{mw.first}\e[0m"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_route(route_str, stack)
|
68
|
+
filters = %w[methods ports protocols extensions].map do |key|
|
69
|
+
val = stack[key]
|
70
|
+
val ? "#{key}: #{Array(val).join(",")}" : nil
|
71
|
+
end.compact
|
72
|
+
filter_str = filters.any? ? filters.join(", ") : "(none)"
|
73
|
+
|
74
|
+
middlewares = stack["middleware"].to_a
|
75
|
+
|
76
|
+
puts "─" * 76
|
77
|
+
puts "\e[32mRoute:\e[0m \e[33m#{route_str}\e[0m"
|
78
|
+
puts "\e[32mConditions:\e[0m \e[34m#{filter_str}\e[0m"
|
79
|
+
puts "\e[32mMiddleware:\e[0m • #{format_mw(middlewares.first)}"
|
80
|
+
middlewares[1..].each do |mw|
|
81
|
+
puts " • #{format_mw(mw)}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def explode_route_pattern(pattern)
|
86
|
+
pattern = pattern.gsub(/^\^|\$$/, "")
|
87
|
+
pattern = pattern.gsub("\\", "")
|
88
|
+
tokens = parse_expression(StringScanner.new(pattern))
|
89
|
+
expand_tokens(tokens)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Parses the expression into a nested tree of tokens
|
93
|
+
def parse_expression(scanner)
|
94
|
+
tokens = []
|
95
|
+
buffer = ""
|
96
|
+
|
97
|
+
until scanner.eos?
|
98
|
+
if scanner.scan(/\(\?:/)
|
99
|
+
tokens << buffer unless buffer.empty?
|
100
|
+
buffer = ""
|
101
|
+
tokens << parse_alternation(scanner)
|
102
|
+
elsif scanner.peek(1) == ")"
|
103
|
+
scanner.getch # consume ')'
|
104
|
+
break
|
105
|
+
else
|
106
|
+
buffer << scanner.getch
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
tokens << buffer unless buffer.empty?
|
111
|
+
tokens
|
112
|
+
end
|
113
|
+
|
114
|
+
# Parses inside a non-capturing group (?:A|B|C)
|
115
|
+
def parse_alternation(scanner)
|
116
|
+
options = []
|
117
|
+
current = []
|
118
|
+
|
119
|
+
until scanner.eos?
|
120
|
+
if scanner.scan(/\(\?:/)
|
121
|
+
current << parse_alternation(scanner)
|
122
|
+
elsif scanner.peek(1) == ")"
|
123
|
+
scanner.getch # consume ')'
|
124
|
+
break
|
125
|
+
elsif scanner.peek(1) == "|"
|
126
|
+
scanner.getch # consume '|'
|
127
|
+
options << current
|
128
|
+
current = []
|
129
|
+
else
|
130
|
+
current << scanner.getch
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
options << current
|
135
|
+
{ alt: options }
|
136
|
+
end
|
137
|
+
|
138
|
+
def expand_tokens(tokens)
|
139
|
+
parts = tokens.map do |token|
|
140
|
+
if token.is_a?(String)
|
141
|
+
[token]
|
142
|
+
elsif token.is_a?(Hash) && token[:alt]
|
143
|
+
# Recurse into each branch of the alternation
|
144
|
+
token[:alt].map { |branch| expand_tokens(branch) }.flatten
|
145
|
+
else
|
146
|
+
raise "Unexpected token: #{token.inspect}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Cartesian product of all parts
|
151
|
+
parts.inject([""]) do |acc, part|
|
152
|
+
acc.product(part).map { |a, b| a + b }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module SchedulerInterface
|
4
|
+
# Simple wrapper to instantiate a scheduler, start it,
|
5
|
+
# and immediate have it invoke a scheduler proc
|
6
|
+
def start_scheduler_loop(scheduler_class, scheduler_task)
|
7
|
+
scheduler = scheduler_class.new
|
8
|
+
Fiber.set_scheduler(scheduler)
|
9
|
+
[scheduler, Fiber.schedule(&scheduler_task)]
|
10
|
+
end
|
11
|
+
|
12
|
+
# When running in scheduler mode,
|
13
|
+
# each request is wrapped in a Fiber.
|
14
|
+
def schedule(app, request)
|
15
|
+
Fiber.schedule do
|
16
|
+
app.call(request)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Running with a Fiber scheduler enabled but with an ActiveSupport isolation_level set to Thread
|
2
|
+
# can be dangerous. A thread isolation level means that all fibers sharing a thread can content
|
3
|
+
# for the same resources, which can lead to race conditions.
|
4
|
+
# This hook should *only* be disabled if you know there are no such shared resources.
|
5
|
+
if defined?(ActiveSupport::IsolatedExecutionState) && !ENV["ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL"]
|
6
|
+
Itsi.log_info \
|
7
|
+
"ActiveSupport Isolated Execution state detected. Automatically switching to :fiber mode. "\
|
8
|
+
"Set ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL to disable this behavior"
|
9
|
+
ActiveSupport::IsolatedExecutionState.isolation_level = :fiber
|
10
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Itsi
|
2
|
+
# This trap is necessary for debuggers and similar which intercept certain signals
|
3
|
+
# then attempt to restore these to the previous signal when finished.
|
4
|
+
# If the previous signal handler was registered in native code, this restoration doesn't
|
5
|
+
# work as expected and the native signal handler is lost.
|
6
|
+
# We intercept restored signals here and reinstate the Itsi server signal handlers
|
7
|
+
# (if the server is still running).
|
8
|
+
module SignalTrap
|
9
|
+
DEFAULT_SIGNALS = ["DEFAULT", "", nil].freeze
|
10
|
+
INTERCEPTED_SIGNALS = ["INT"].freeze
|
11
|
+
|
12
|
+
def trap(signal, *args, &block)
|
13
|
+
unless INTERCEPTED_SIGNALS.include?(signal.to_s) && block.nil? && server_running?
|
14
|
+
return super(signal, *args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
Itsi::Server.reset_signal_handlers
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def server_running?
|
22
|
+
Itsi::Server.respond_to?(:running?) && Itsi::Server.running?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
[Kernel, Signal].each do |receiver|
|
28
|
+
receiver.singleton_class.prepend(Itsi::SignalTrap)
|
29
|
+
end
|
30
|
+
|
31
|
+
[Object].each do |receiver|
|
32
|
+
receiver.include(Itsi::SignalTrap)
|
33
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module TypedHandlers
|
4
|
+
module ParamParser
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
class ValidationError < StandardError
|
8
|
+
attr_reader :errors
|
9
|
+
def initialize(errors)
|
10
|
+
@errors = errors
|
11
|
+
super("Validation failed: #{errors.join('; ')}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Conversion map for primitive/base type conversions.
|
16
|
+
CONVERSION_MAP = {
|
17
|
+
String => ->(v){ v.to_s },
|
18
|
+
Symbol => ->(v){ v.to_sym },
|
19
|
+
Integer => ->(v){ Integer(v) },
|
20
|
+
Float => ->(v){ Float(v) },
|
21
|
+
:Number => ->(v){ Float(v) },
|
22
|
+
TrueClass => ->(v){
|
23
|
+
case v
|
24
|
+
when true, 'true', '1', 1 then true
|
25
|
+
when false, 'false', '0', 0 then false
|
26
|
+
else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
|
27
|
+
end
|
28
|
+
},
|
29
|
+
FalseClass => ->(v){
|
30
|
+
case v
|
31
|
+
when true, 'true', '1', 1 then true
|
32
|
+
when false, 'false', '0', 0 then false
|
33
|
+
else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
|
34
|
+
end
|
35
|
+
},
|
36
|
+
:Boolean => ->(v){
|
37
|
+
case v
|
38
|
+
when true, 'true', '1', 1 then true
|
39
|
+
when false, 'false', '0', 0 then false
|
40
|
+
else raise ValidationError.new("Cannot cast #{v.inspect} to Boolean")
|
41
|
+
end
|
42
|
+
},
|
43
|
+
Date => ->(v){ Date.parse(v.to_s) },
|
44
|
+
Time => ->(v){ Time.parse(v.to_s) },
|
45
|
+
DateTime => ->(v){ DateTime.parse(v.to_s) }
|
46
|
+
}.compare_by_identity
|
47
|
+
|
48
|
+
# Preprocess the schema into fixed keys (as symbols) and regex keys.
|
49
|
+
# Memoizes the result based on the schema.
|
50
|
+
def processed_schema(schema)
|
51
|
+
@@schema_cache ||= {}
|
52
|
+
@@schema_cache[schema] ||= begin
|
53
|
+
fixed = {}
|
54
|
+
regex = []
|
55
|
+
required_params = schema[:_required] || []
|
56
|
+
schema.each do |k, schema_def|
|
57
|
+
expected_type, required = schema_def, required_params.include?(k)
|
58
|
+
if k.is_a?(Regexp)
|
59
|
+
regex << [k, [expected_type, required]]
|
60
|
+
else
|
61
|
+
fixed[k.to_sym] = [expected_type, required]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
[fixed, regex]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Helper that converts an array of path segments into a string.
|
69
|
+
# For example, [:user, "addresses", 0, :street] becomes "user.addresses[0].street".
|
70
|
+
def format_path(path)
|
71
|
+
result = "".dup
|
72
|
+
path.each do |seg|
|
73
|
+
if seg.is_a?(Integer)
|
74
|
+
result << "[#{seg}]"
|
75
|
+
else
|
76
|
+
result << (result.empty? ? seg.to_s : ".#{seg}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
# In-place casts the value at container[key] according to expected_type.
|
83
|
+
# On success, updates container[key] and returns nil.
|
84
|
+
# On failure, returns an error message string that uses the formatted path.
|
85
|
+
def cast_value!(container, key, expected_type, path)
|
86
|
+
if expected_type.is_a?(Array)
|
87
|
+
# Only allow homogeneous array types.
|
88
|
+
return "Only homogeneous array types are supported at #{format_path(path)}" if expected_type.size != 1
|
89
|
+
|
90
|
+
# Expect container[key] to be an Array; process each element in place.
|
91
|
+
unless container[key].is_a?(Array)
|
92
|
+
return "Expected an Array at #{format_path(path)}, got #{container[key].class}"
|
93
|
+
end
|
94
|
+
container[key].each_with_index do |_, idx|
|
95
|
+
err = cast_value!(container[key], idx, expected_type.first, path + [idx])
|
96
|
+
return err if err
|
97
|
+
end
|
98
|
+
return nil
|
99
|
+
|
100
|
+
elsif expected_type.is_a?(Hash)
|
101
|
+
# Nested schema: expect container[key] to be a Hash; process it in place.
|
102
|
+
unless container[key].is_a?(Hash)
|
103
|
+
return "Expected a Hash at #{format_path(path)}, got #{container[key].class}"
|
104
|
+
end
|
105
|
+
begin
|
106
|
+
apply_schema!(container[key], expected_type, path)
|
107
|
+
return nil
|
108
|
+
rescue ValidationError => ve
|
109
|
+
return ve.errors.join('; ')
|
110
|
+
end
|
111
|
+
|
112
|
+
else
|
113
|
+
converter = CONVERSION_MAP[expected_type]
|
114
|
+
if converter
|
115
|
+
begin
|
116
|
+
container[key] = converter.call(container[key])
|
117
|
+
return nil
|
118
|
+
rescue => e
|
119
|
+
return "Invalid value for #{expected_type} at #{format_path(path)}: #{container[key].inspect} (#{e.message})"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Fallbacks.
|
124
|
+
if expected_type == Array
|
125
|
+
unless container[key].is_a?(Array)
|
126
|
+
return "Expected Array at #{format_path(path)}, got #{container[key].class}"
|
127
|
+
end
|
128
|
+
return nil
|
129
|
+
elsif expected_type == Hash
|
130
|
+
unless container[key].is_a?(Hash)
|
131
|
+
return "Expected Hash at #{format_path(path)}, got #{container[key].class}"
|
132
|
+
end
|
133
|
+
return nil
|
134
|
+
elsif expected_type == File && container[key].is_a?(Hash) && container[key][:tempfile].is_a?(Tempfile)
|
135
|
+
return nil
|
136
|
+
else
|
137
|
+
return "Unsupported type: #{expected_type.inspect} at #{format_path(path)}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Applies the schema in place to the given params hash.
|
143
|
+
# Fixed keys are converted to symbols, and regex-matched keys remain as strings.
|
144
|
+
# The current location in the params is tracked as an array of path segments.
|
145
|
+
def apply_schema!(params, schema, path = [])
|
146
|
+
errors = []
|
147
|
+
processed = processed_schema(schema)
|
148
|
+
fixed_schema = processed[0]
|
149
|
+
regex_schema = processed[1]
|
150
|
+
|
151
|
+
# Process fixed keys.
|
152
|
+
fixed_schema.each do |fixed_key, (expected_type, required)|
|
153
|
+
new_path = path + [fixed_key]
|
154
|
+
if params.key?(fixed_key)
|
155
|
+
# Symbol key present.
|
156
|
+
elsif params.key?(fixed_key.to_s)
|
157
|
+
params[fixed_key] = params.delete(fixed_key.to_s)
|
158
|
+
else
|
159
|
+
if required
|
160
|
+
errors << "Missing required key: #{format_path(new_path)}"
|
161
|
+
else
|
162
|
+
params[fixed_key] = nil
|
163
|
+
end
|
164
|
+
next
|
165
|
+
end
|
166
|
+
|
167
|
+
err = cast_value!(params, fixed_key, expected_type, new_path)
|
168
|
+
errors << err if err
|
169
|
+
end
|
170
|
+
|
171
|
+
# Process regex keys (only string keys not already handled as fixed keys).
|
172
|
+
params.keys.each do |key|
|
173
|
+
if key == :_required
|
174
|
+
params.delete(key)
|
175
|
+
next
|
176
|
+
end
|
177
|
+
next if fixed_schema.has_key?(key.to_sym) || fixed_schema.has_key?(key)
|
178
|
+
unless regex_schema.find do |regex, (expected_type, _required)|
|
179
|
+
if regex.match(key)
|
180
|
+
new_path = path + [key]
|
181
|
+
err = cast_value!(params, key, expected_type, new_path)
|
182
|
+
errors << err if err
|
183
|
+
true # only use the first matching regex
|
184
|
+
end
|
185
|
+
end
|
186
|
+
params.delete(key)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
raise ValidationError.new(errors) unless errors.empty?
|
191
|
+
params
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module TypedHandlers
|
4
|
+
module SourceParser
|
5
|
+
require 'prism'
|
6
|
+
|
7
|
+
|
8
|
+
def self.extract_expr_from_source_location(proc)
|
9
|
+
source_location = proc.source_location
|
10
|
+
source_lines = IO.readlines(source_location.first)
|
11
|
+
|
12
|
+
proc_line = source_location.last - 1
|
13
|
+
first_line = source_lines[proc_line]
|
14
|
+
|
15
|
+
until first_line =~ /(?:lambda|proc|->|def|.*?do\s*|.*?\{.*?\|)/ || proc_line.zero?
|
16
|
+
proc_line -= 1
|
17
|
+
first_line = source_lines[proc_line]
|
18
|
+
end
|
19
|
+
lines = source_lines[proc_line..]
|
20
|
+
lines[0] = lines[0][/(?:lambda|proc|->|def|.*?do\s+|.*?\{.*?\|).*/]
|
21
|
+
src_str = lines.first << "\n"
|
22
|
+
intermediate = Prism.parse(src_str)
|
23
|
+
|
24
|
+
lines[1..-1].each do |line|
|
25
|
+
break if intermediate.success?
|
26
|
+
token_count = 0
|
27
|
+
line.split(/(?=\s|;|\)|\})/).each do |token|
|
28
|
+
src_str << token
|
29
|
+
token_count += 1
|
30
|
+
intermediate = Prism.parse(src_str)
|
31
|
+
next unless intermediate.success? && token_count > 1
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
raise 'Source Extraction Failed' unless intermediate.success?
|
37
|
+
|
38
|
+
src = intermediate.value.statements.body.first.yield_self do |s|
|
39
|
+
s.type == :call_node ? s.block : s
|
40
|
+
end
|
41
|
+
params = src.parameters
|
42
|
+
params = params.parameters if params.respond_to?(:parameters)
|
43
|
+
requireds = (params&.requireds || []).map(&:name)
|
44
|
+
optionals = params&.optionals || []
|
45
|
+
keywords = (params&.keywords || []).map do |kw|
|
46
|
+
[kw.name, kw.value.slice.gsub(/^_\./, '$.')]
|
47
|
+
end.to_h
|
48
|
+
|
49
|
+
[requireds.length, keywords]
|
50
|
+
rescue
|
51
|
+
[ proc.parameters.select{|p| p == :req }&.length || 0, {}]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative "typed_handlers/source_parser"
|
2
|
+
require_relative "typed_handlers/param_parser"
|
3
|
+
|
4
|
+
module Itsi
|
5
|
+
class Server
|
6
|
+
module TypedHandlers
|
7
|
+
def self.handler_for(proc, input_schema)
|
8
|
+
if input_schema
|
9
|
+
input_schema = proc.binding.eval(input_schema)
|
10
|
+
lambda do |req|
|
11
|
+
req.params(input_schema) do |params|
|
12
|
+
proc.call(req, params: params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
else
|
16
|
+
lambda do |req|
|
17
|
+
req.params do |params|
|
18
|
+
proc.call(req, params)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|