itsi-server 0.1.19 → 0.1.20
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 +950 -239
- data/README.md +2 -0
- data/exe/itsi +5 -5
- 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_server/Cargo.toml +3 -3
- data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +2 -2
- data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +150 -19
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +1 -0
- data/ext/itsi_server/src/server/binds/listener.rs +34 -29
- data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +2 -2
- data/ext/itsi_server/src/server/binds/tls.rs +1 -1
- data/ext/itsi_server/src/server/middleware_stack/middleware.rs +33 -28
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +56 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +179 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +25 -2
- data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +3 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +2 -1
- data/ext/itsi_server/src/server/middleware_stack/mod.rs +32 -34
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +10 -4
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +30 -7
- data/ext/itsi_server/src/server/thread_worker.rs +2 -2
- data/ext/itsi_server/src/services/static_file_server.rs +30 -28
- data/ext/itsi_tracing/src/lib.rs +39 -8
- data/lib/itsi/server/config/config_helpers.rb +93 -0
- data/lib/itsi/server/config/dsl.rb +81 -33
- 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 +17 -0
- data/lib/itsi/server/config/middleware/_index.md +54 -0
- data/lib/itsi/server/config/middleware/log_requests.md +63 -0
- data/lib/itsi/server/config/middleware/log_requests.rb +33 -0
- data/lib/itsi/server/config/middleware.rb +9 -0
- data/lib/itsi/server/config/option.rb +9 -0
- data/lib/itsi/server/config/options/_index.md +36 -0
- data/lib/itsi/server/config/options/fiber_scheduler.md +35 -0
- data/lib/itsi/server/config/options/fiber_scheduler.rb +18 -0
- data/lib/itsi/server/config/options/threads.md +39 -0
- data/lib/itsi/server/config/options/threads.rb +17 -0
- data/lib/itsi/server/config/options/workers.md +43 -0
- data/lib/itsi/server/config/options/workers.rb +17 -0
- data/lib/itsi/server/config/typed_struct.rb +203 -0
- data/lib/itsi/server/config.rb +124 -30
- data/lib/itsi/server/signal_trap.rb +5 -1
- data/lib/itsi/server/typed_handlers/source_parser.rb +1 -1
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +27 -6
- data/lib/ruby_lsp/itsi/addon.rb +64 -48
- metadata +141 -5
- data/CHANGELOG.md +0 -10
- data/CODE_OF_CONDUCT.md +0 -139
- data/LICENSE.txt +0 -21
- data/_index.md +0 -6
@@ -0,0 +1,30 @@
|
|
1
|
+
.well-known/
|
2
|
+
.well-known/acme-challenge
|
3
|
+
.well-known/apple-app-site-association
|
4
|
+
.well-known/apple-developer-merchant-domain-association
|
5
|
+
.well-known/ashrae
|
6
|
+
.well-known/assetlinks.json
|
7
|
+
.well-known/browserid
|
8
|
+
.well-known/caldav
|
9
|
+
.well-known/carddav
|
10
|
+
.well-known/core
|
11
|
+
.well-known/csvm
|
12
|
+
.well-known/dnt
|
13
|
+
.well-known/dnt-policy.txt
|
14
|
+
.well-known/est
|
15
|
+
.well-known/genid
|
16
|
+
.well-known/hoba
|
17
|
+
.well-known/host-meta
|
18
|
+
.well-known/host-meta.json
|
19
|
+
.well-known/keybase.txt
|
20
|
+
.well-known/ni
|
21
|
+
.well-known/openid-configuration
|
22
|
+
.well-known/openorg
|
23
|
+
.well-known/posh
|
24
|
+
.well-known/reload-config
|
25
|
+
.well-known/repute-template
|
26
|
+
.well-known/stun-key
|
27
|
+
.well-known/time
|
28
|
+
.well-known/timezone
|
29
|
+
.well-known/void
|
30
|
+
.well-known/webfinger
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module KnownPaths
|
4
|
+
Dir.glob(File.join(__dir__, 'known_paths', '**', '*.txt')).each do |file|
|
5
|
+
method_name = file[/known_paths\/(.*?)\.txt/,1].gsub(/([a-z])([A-Z])/, "\\1_\\2")
|
6
|
+
.gsub(/-|\.|\//, "_")
|
7
|
+
.gsub(/(^|\/)[0-9]/){|match| "FO"}.downcase
|
8
|
+
self.define_singleton_method(method_name) do
|
9
|
+
File.readlines(file).map do |s|
|
10
|
+
s.force_encoding('UTF-8')
|
11
|
+
s.valid_encoding? ? s.strip : s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '').strip
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
---
|
2
|
+
title: Middleware
|
3
|
+
type: docs
|
4
|
+
next: /features/server/lib/itsi/server/config/options/workers/
|
5
|
+
url: /middleware
|
6
|
+
cascade:
|
7
|
+
type: docs
|
8
|
+
weight: 2
|
9
|
+
---
|
10
|
+
|
11
|
+
|
12
|
+
Itsi Middleware stacks are modular in nature.
|
13
|
+
You can pick and choose **just** the features that make sense for you,
|
14
|
+
and apply these on a *location-by-location* basis.
|
15
|
+
|
16
|
+
{{% details title="What's a location?" closed="false" %}}
|
17
|
+
|
18
|
+
> A location in Itsi is similar to a Location in NGINX. It's a logical container for all requests matching some combination of:
|
19
|
+
* Routes/Route expressions
|
20
|
+
* Request Methods
|
21
|
+
* Content Types
|
22
|
+
* Accept Headers
|
23
|
+
* File types
|
24
|
+
* Host/port/scheme.
|
25
|
+
|
26
|
+
E.g.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
location "/admin/*" do
|
30
|
+
|
31
|
+
etag \
|
32
|
+
type: 'strong',
|
33
|
+
algorithm: 'md5',
|
34
|
+
min_body_size: 1024 * 1024
|
35
|
+
# ...
|
36
|
+
|
37
|
+
location "/public/images", extensions: %w[jpg png] do
|
38
|
+
compress \
|
39
|
+
min_size: 1024 * 1024,
|
40
|
+
level: 'fastest',
|
41
|
+
algorithms: %w[zstd gzip brotli deflate],
|
42
|
+
mime_types: %w[all],
|
43
|
+
compress_streams: true
|
44
|
+
# ...
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
When a route matches a location block, it recursively inherits *all* middleware that is defined within outer ancestor blocks.
|
52
|
+
Where a child and an ancestor define the same middleware, the child's middleware takes precedence.
|
53
|
+
|
54
|
+
{{% /details %}}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
title: Request Logging Middleware
|
3
|
+
url: /middleware/log_requests
|
4
|
+
weight: 1
|
5
|
+
---
|
6
|
+
|
7
|
+
The request logging middleware allows you to define customized log statements to occur before and/or after each request is processed.
|
8
|
+
|
9
|
+
You can provide a log level and format string to be written before and after each request.
|
10
|
+
|
11
|
+
|
12
|
+
```ruby {filename=Itsi.rb}
|
13
|
+
log_requests \
|
14
|
+
before: {
|
15
|
+
level: "INFO",
|
16
|
+
format: "[{request_id}] {method} {path_and_query} - {addr} "
|
17
|
+
},
|
18
|
+
after: {
|
19
|
+
level: "INFO",
|
20
|
+
format: "[{request_id}] └─ {status} in {response_time}"
|
21
|
+
}
|
22
|
+
```
|
23
|
+
|
24
|
+
|
25
|
+
The log statement can populated with several different placeholders.
|
26
|
+
Available values are:
|
27
|
+
|
28
|
+
### `before` Format String
|
29
|
+
* `request_id` - (A short, unique hexadecimal request identifier)
|
30
|
+
* `request_id_full` - (A full 128-bit unique request identifier)
|
31
|
+
* `method` - The HTTP method
|
32
|
+
* `path` - The HTTP Path
|
33
|
+
* `addr` - The client's IP address
|
34
|
+
* `host` - The request host
|
35
|
+
* `path_and_query` - The path and query combined
|
36
|
+
* `query` - The request query string
|
37
|
+
* `port` - The bound port
|
38
|
+
* `start_time` - The request start time
|
39
|
+
|
40
|
+
### `after` Format String
|
41
|
+
* `request_id` - (A short, unique hexadecimal request identifier)
|
42
|
+
* `request_id_full` - (A full 128-bit unique request identifier)
|
43
|
+
* `status` - The HTTP status code
|
44
|
+
* `addr` - The client's IP address
|
45
|
+
* `response_time` - The response time in milliseconds
|
46
|
+
|
47
|
+
|
48
|
+
### Path Attributes
|
49
|
+
In addition to this, any capture groups referenced by container location blocks
|
50
|
+
are also made available, to be interpolated into the log statement. E.g.:
|
51
|
+
|
52
|
+
```ruby {filename=Itsi.rb}
|
53
|
+
|
54
|
+
location "/users/:user_id" do # 1. If we capture user_id here.
|
55
|
+
|
56
|
+
log_requests before: {
|
57
|
+
level: "INFO",
|
58
|
+
format: "[{request_id}] User: {user_id}" # 2. Then we can log the user_id here.
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
```
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module Config
|
4
|
+
class LogRequests < Middleware
|
5
|
+
|
6
|
+
attr_accessor :log_requests
|
7
|
+
|
8
|
+
insert_text <<~SNIPPET
|
9
|
+
log_requests \\
|
10
|
+
before: { level: ${1|"INFO","WARN","ERROR","DEBUG"|} format: ${2|"[{request_id}] {method} {path_and_query} - {addr} "|} },
|
11
|
+
after: { level: ${3|"INFO","WARN","ERROR","DEBUG"|}, format: ${4|"[{request_id}] └─ {status} in {response_time}"|} }
|
12
|
+
SNIPPET
|
13
|
+
|
14
|
+
detail "Enable logging before or after requests"
|
15
|
+
|
16
|
+
LogRequestConfig = TypedStruct.new do
|
17
|
+
{
|
18
|
+
level: (Required() + Enum(%w[INFO WARN ERROR DEBUG])).default("INFO"),
|
19
|
+
format: Type(String)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
schema do
|
24
|
+
{
|
25
|
+
before: Type(LogRequestConfig),
|
26
|
+
after: Type(LogRequestConfig)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
---
|
2
|
+
title: Options
|
3
|
+
type: docs
|
4
|
+
next: /options/server/lib/itsi/server/config/options/workers/
|
5
|
+
url: /options
|
6
|
+
cascade:
|
7
|
+
type: docs
|
8
|
+
weight: 1
|
9
|
+
---
|
10
|
+
|
11
|
+
Most of Itsi's capabilities are unlocked via the Itsi.rb config file.
|
12
|
+
The config file uses a simple DSL, where you can write plain Ruby to define your application's configuration.
|
13
|
+
For the best development experience, be sure to use [RubyLSP](https://shopify.github.io/ruby-lsp/) for snippets, autocomplete and documentation, right in your editor.
|
14
|
+
|
15
|
+
{{< details title="An example Itsi.rb file" >}}
|
16
|
+
|
17
|
+
|
18
|
+
```ruby {filename="Itsi.rb"}
|
19
|
+
workers 2
|
20
|
+
threads 2
|
21
|
+
scheduler_threads 3
|
22
|
+
|
23
|
+
fiber_scheduler true
|
24
|
+
|
25
|
+
rate_limiter requests: 100, seconds: 10
|
26
|
+
|
27
|
+
auth_basic realm: "Restricted Area", credentials_file: "credentials.txt"
|
28
|
+
|
29
|
+
location "/app" do
|
30
|
+
get "/" do |req|
|
31
|
+
req.ok "Hello, World!"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
```
|
36
|
+
{{< /details >}}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
title: Fiber Scheduler
|
3
|
+
url: /options/fiber_scheduler
|
4
|
+
weight: 3
|
5
|
+
---
|
6
|
+
Itsi supports processing requests in threads that are managed by a fiber scheduler.
|
7
|
+
This allows Itsi to process a very large number of IO heavy requests concurrently without the memory and context switching overhead of managing multiple threads.
|
8
|
+
|
9
|
+
Enabling Fiber Scheduler mode can drastically improve application performance if you perform large amounts of blocking IO operations.
|
10
|
+
|
11
|
+
|
12
|
+
## Configuration File
|
13
|
+
```ruby {filename="Itsi.rb"}
|
14
|
+
# Enable Itsi's fiber scheduler mode
|
15
|
+
# (This will use an instance of `Itsi::Scheduler`
|
16
|
+
# This is Itsi's built in Fiber scheduler.)
|
17
|
+
fiber_scheduler true
|
18
|
+
```
|
19
|
+
|
20
|
+
```ruby {filename="Itsi.rb"}
|
21
|
+
# In the spirit of the Fiber::Scheduler interface,
|
22
|
+
# you can bring your own scheduler!.
|
23
|
+
# E.g. using the scheduler from the popular Async library.
|
24
|
+
fiber_scheduler "Async::Scheduler"
|
25
|
+
```
|
26
|
+
|
27
|
+
{{< callout type="warning" >}}
|
28
|
+
Running in Fiber scheduler mode can be a huge performance boon, but it's not without tradeoffs. Because it enables drastically more in-flight requests,
|
29
|
+
it can have a substantial impact on memory usage. Similarly, it can increase the amount of simultaneous demand on pooled resources (like database connections or network sockets)
|
30
|
+
and can cause increased contention on shared locks.
|
31
|
+
|
32
|
+
While well-tuned Fiber based servers can drastically outperform their blocking counterparts in some scenarios, the above compromises can make it an unsafe blanket choice, particularly for some large applications with dependencies not specifically designed for a cooperative multitasking environment.
|
33
|
+
|
34
|
+
To see Itsi's recommended approach to enjoying the benefits of a Fiber scheduler while managing these risks, consider using Itsi's [hybrid mode](https://itsi.fyi/options/scheduler_threads).
|
35
|
+
{{< /callout >}}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Itsi
|
2
|
+
class Server
|
3
|
+
module Config
|
4
|
+
class FiberScheduler < Option
|
5
|
+
|
6
|
+
|
7
|
+
insert_text "fiber_scheduler ${1|true,'Itsi::Scheduler'|}"
|
8
|
+
|
9
|
+
detail "Enable Fiber Scheduler mode"
|
10
|
+
|
11
|
+
schema do
|
12
|
+
Or(Bool(), (Type(String) + Required()))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
---
|
2
|
+
title: Threads
|
3
|
+
url: /options/threads
|
4
|
+
weight: 2
|
5
|
+
---
|
6
|
+
Itsi supports running in threaded mode. Spawning more than one thread per worker is helpful for applications that require high concurrency and low latency.
|
7
|
+
|
8
|
+
Note, that while threading allows for concurrent execution of tasks, it also introduces additional overhead due to context switching between threads.
|
9
|
+
This overhead can be significant, especially when dealing with a large number of concurrent tasks.
|
10
|
+
To minimize this overhead, it's recommended to keep the number of threads low, and tune this parameter based on your specific use case.
|
11
|
+
|
12
|
+
When running Itsi in blocking mode, the total number of concurrent requests will be equal to `workers` x `threads`
|
13
|
+
|
14
|
+
## Configuration File
|
15
|
+
The number of threads to use can be specified inside the configuration file (usually `./Itsi.rb` at the project root)
|
16
|
+
using the `threads` function.
|
17
|
+
|
18
|
+
## Examples
|
19
|
+
```ruby {filename="Itsi.rb"}
|
20
|
+
# Starts each worker with a single thread
|
21
|
+
threads 1
|
22
|
+
```
|
23
|
+
|
24
|
+
```ruby {filename="Itsi.rb"}
|
25
|
+
# Each worker will start 4 threads
|
26
|
+
threads 4
|
27
|
+
```
|
28
|
+
|
29
|
+
Threads increase concurrency at the expense of memory usage and CPU overhead.
|
30
|
+
For IO heavy workloads, consider using non-blocking mode instead, which can achieve higher concurrency with fewer threads.
|
31
|
+
Non-blocking mode and threads can be used simultaneously in a hybrid configuration.
|
32
|
+
|
33
|
+
## Command Line
|
34
|
+
You can also override the number of threads using either the `-t` or `--threads` command line option.
|
35
|
+
E.g.
|
36
|
+
|
37
|
+
```bash
|
38
|
+
itsi -t 3
|
39
|
+
```
|
@@ -0,0 +1,43 @@
|
|
1
|
+
---
|
2
|
+
title: Workers
|
3
|
+
url: /options/workers
|
4
|
+
prev: /options
|
5
|
+
weight: 1
|
6
|
+
---
|
7
|
+
Itsi is a preforking server. It can run as either a single process (`workers 1`) or in clustered mode (`workers > 1`).
|
8
|
+
<br/>You can switch between the two without downtime.
|
9
|
+
|
10
|
+
## Configuration File
|
11
|
+
The number of workers to use can be specified inside the configuration file (usually `./Itsi.rb` at the project root)
|
12
|
+
using the `workers` function.
|
13
|
+
|
14
|
+
## Examples
|
15
|
+
|
16
|
+
```ruby {filename="Itsi.rb"}
|
17
|
+
# Starts a single worker, putting Itsi in single-process mode
|
18
|
+
workers 1
|
19
|
+
```
|
20
|
+
|
21
|
+
```ruby {filename="Itsi.rb"}
|
22
|
+
# Starts 4 workers, putting Itsi in cluster-process mode
|
23
|
+
workers 4
|
24
|
+
```
|
25
|
+
|
26
|
+
```ruby {filename="Itsi.rb"}
|
27
|
+
# Sets the number of workers to the number of CPU cores available on the system
|
28
|
+
workers Etc.nprocessors
|
29
|
+
```
|
30
|
+
|
31
|
+
To maximize performance, it's typical to increase number of workers
|
32
|
+
to be at or near the number of CPU cores available on your system.
|
33
|
+
|
34
|
+
However, note hyperthreads and efficiency cores may impact this and using every available core is not
|
35
|
+
always the most effective choice.
|
36
|
+
|
37
|
+
## Command Line
|
38
|
+
You can also override the number of workers using either the `-w` or workers `--workers` command line option.
|
39
|
+
E.g.
|
40
|
+
|
41
|
+
```bash
|
42
|
+
itsi -w 4
|
43
|
+
```
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module Itsi
|
5
|
+
class Server
|
6
|
+
module Config
|
7
|
+
module TypedStruct
|
8
|
+
VALUE = 0
|
9
|
+
VALIDATE = 1
|
10
|
+
|
11
|
+
def self.new(defaults = nil, &defaults_blk)
|
12
|
+
defaults = TypedStruct.module_eval(&defaults_blk) if defaults_blk
|
13
|
+
unless defaults.is_a?(Hash)
|
14
|
+
return defaults
|
15
|
+
end
|
16
|
+
defaults.transform_values! { _1.is_a?(Validation) ? _1.default(nil) : _1 }
|
17
|
+
Struct.new(*defaults.keys, keyword_init: true) do
|
18
|
+
define_method(:initialize) do |*input, validate: true, **raw_input|
|
19
|
+
raw_input.transform_keys!{|k| k.to_s.downcase.to_sym }
|
20
|
+
raw_input.merge!(input.pop) if input.last.is_a?(Hash)
|
21
|
+
|
22
|
+
excess_keys = raw_input.keys - defaults.keys
|
23
|
+
|
24
|
+
raise "Unsupported keys #{excess_keys}" if excess_keys.any?
|
25
|
+
|
26
|
+
initial_values = defaults.each_with_object({}) do |(k, default_config), inputs|
|
27
|
+
value = raw_input.key?(k) ? raw_input[k] : default_config[VALUE].dup
|
28
|
+
next inputs[k] = value unless validate
|
29
|
+
|
30
|
+
begin
|
31
|
+
inputs[k] = default_config[VALIDATE].validate!(value)
|
32
|
+
rescue StandardError => e
|
33
|
+
raise ArgumentError, e.message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
super(initial_values)
|
38
|
+
validator = self.class.instance_eval { @validators }
|
39
|
+
instance_eval(&validator) if validator
|
40
|
+
end
|
41
|
+
|
42
|
+
define_singleton_method(:validate) do |&blk|
|
43
|
+
@validators = blk
|
44
|
+
end
|
45
|
+
|
46
|
+
defaults.each do |key, (_, validation)|
|
47
|
+
define_method(:"#{key}?") do
|
48
|
+
!!self[key]
|
49
|
+
end
|
50
|
+
define_method(:"#{key}=") do |value|
|
51
|
+
self[key] = validation.validate!(value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
define_method(:[]=) do |key, value|
|
56
|
+
super(key, defaults[key][VALIDATE].validate!(value))
|
57
|
+
end
|
58
|
+
|
59
|
+
def is_typed_struct?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_config(other)
|
64
|
+
self.class.new(members.map do |key|
|
65
|
+
value = self[key]
|
66
|
+
has_merged_val = (other.is_a?(Hash) ? other.key?(key) : other.member?(key))
|
67
|
+
next [key, value] unless has_merged_val
|
68
|
+
|
69
|
+
[
|
70
|
+
key,
|
71
|
+
TypedStruct.typed_struct?(value) ? value.merge_config(other[key]) : other[key]
|
72
|
+
]
|
73
|
+
end.to_h)
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_h
|
77
|
+
super.transform_values { |v| v.respond_to?(:merge_config) ? v.to_h : v }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.typed_struct?(inst)
|
83
|
+
inst.respond_to?(:is_typed_struct?) && inst.is_typed_struct?
|
84
|
+
end
|
85
|
+
|
86
|
+
class Validation
|
87
|
+
attr_reader :name, :validations
|
88
|
+
attr_accessor :next
|
89
|
+
|
90
|
+
def initialize(name, validations)
|
91
|
+
@name = name.to_s
|
92
|
+
@validations = Array(validations)
|
93
|
+
@next = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def inspect
|
97
|
+
"#{@name}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def +(other)
|
101
|
+
tail = self
|
102
|
+
while tail.next
|
103
|
+
tail = tail.next
|
104
|
+
end
|
105
|
+
tail.next = other
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def default(value)
|
110
|
+
[value, self]
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate!(value)
|
114
|
+
value = value.to_s if value.is_a?(Symbol)
|
115
|
+
@validations.each do |validation|
|
116
|
+
case validation
|
117
|
+
when Proc
|
118
|
+
unless validation.call(value)
|
119
|
+
raise ArgumentError,
|
120
|
+
"─ `#{@name}` validation failed. Invalid value: #{value.inspect}"
|
121
|
+
end
|
122
|
+
when Array
|
123
|
+
unless !value || validation.include?(value)
|
124
|
+
raise ArgumentError,
|
125
|
+
"─ `#{@name}` validation failed. Invalid #{validation} value: #{value.inspect}"
|
126
|
+
end
|
127
|
+
when Range
|
128
|
+
unless !value || validation.include?(value)
|
129
|
+
raise ArgumentError,
|
130
|
+
"─ `#{@name}` validation failed. Invalid #{validation} value: #{value.inspect}"
|
131
|
+
end
|
132
|
+
when Regexp
|
133
|
+
unless !value || validation.match?(value)
|
134
|
+
raise ArgumentError,
|
135
|
+
"─ `#{@name}` validation failed. Invalid #{validation} value: #{value.inspect}"
|
136
|
+
end
|
137
|
+
when Class
|
138
|
+
|
139
|
+
if value && !value.is_a?(validation)
|
140
|
+
begin
|
141
|
+
value = \
|
142
|
+
if validation.eql?(Time) then Time.parse(value.to_s)
|
143
|
+
elsif validation.eql?(::Date) then Date.parse(value.to_s)
|
144
|
+
elsif validation.eql?(Float) then Float(value)
|
145
|
+
elsif validation.eql?(String) then value.to_s
|
146
|
+
elsif validation.eql?(Symbol) then value.is_a?(Symbol) ? value : value.to_s.to_sym
|
147
|
+
else validation.new(value)
|
148
|
+
end
|
149
|
+
rescue StandardError => e
|
150
|
+
raise ArgumentError,
|
151
|
+
"─ `#{@name}` Validation Failed. Invalid #{validation.to_s.split("::").last} value: #{value.inspect}. Failure reason: \n └#{e.message}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
if self.next
|
157
|
+
self.next.validate!(value)
|
158
|
+
else
|
159
|
+
value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
{
|
165
|
+
Bool: Validation.new(:Bool, [[true, false]]),
|
166
|
+
Required: Validation.new(:Required, ->(value) { !value.nil? }),
|
167
|
+
Or: ->(validation_a, validation_b){
|
168
|
+
Validation.new(:Or, ->(v){
|
169
|
+
validation_a.validate!(v) || validation_b.validate!(v)
|
170
|
+
})
|
171
|
+
},
|
172
|
+
Range: ->(input_range) {
|
173
|
+
Validation.new(:Range, [input_range])
|
174
|
+
},
|
175
|
+
Length: lambda { |input_length|
|
176
|
+
Validation.new(:Length, ->(value) { input_length === value.length })
|
177
|
+
},
|
178
|
+
Type: ->(input_type) { Validation.new(:Type, input_type) },
|
179
|
+
Enum: ->(allowed_values) { Validation.new(:Enum, [allowed_values.map{|v| v.kind_of?(Symbol) ? v.to_s : v}]) },
|
180
|
+
Array: lambda { |*value_validations|
|
181
|
+
Validation.new(:Array, [::Array, lambda { |value|
|
182
|
+
return true unless value
|
183
|
+
|
184
|
+
value&.map! do |v|
|
185
|
+
value_validations.all? { v = _1.validate!(v) }
|
186
|
+
v
|
187
|
+
end
|
188
|
+
}])
|
189
|
+
}
|
190
|
+
}.each do |name, factory|
|
191
|
+
if factory.is_a?(Proc)
|
192
|
+
define_singleton_method(name, &factory)
|
193
|
+
define_singleton_method(name.to_s.downcase, &factory)
|
194
|
+
else
|
195
|
+
const_set(name, factory)
|
196
|
+
define_singleton_method(name, -> { factory })
|
197
|
+
define_singleton_method(name.to_s.downcase, -> { factory })
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|