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.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +950 -239
  3. data/README.md +2 -0
  4. data/exe/itsi +5 -5
  5. data/ext/itsi_acme/Cargo.toml +86 -0
  6. data/ext/itsi_acme/examples/high_level.rs +63 -0
  7. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  8. data/ext/itsi_acme/examples/low_level.rs +87 -0
  9. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  10. data/ext/itsi_acme/src/acceptor.rs +81 -0
  11. data/ext/itsi_acme/src/acme.rs +354 -0
  12. data/ext/itsi_acme/src/axum.rs +86 -0
  13. data/ext/itsi_acme/src/cache.rs +39 -0
  14. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  15. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  16. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  17. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  18. data/ext/itsi_acme/src/caches/no.rs +78 -0
  19. data/ext/itsi_acme/src/caches/test.rs +136 -0
  20. data/ext/itsi_acme/src/config.rs +172 -0
  21. data/ext/itsi_acme/src/https_helper.rs +69 -0
  22. data/ext/itsi_acme/src/incoming.rs +142 -0
  23. data/ext/itsi_acme/src/jose.rs +161 -0
  24. data/ext/itsi_acme/src/lib.rs +142 -0
  25. data/ext/itsi_acme/src/resolver.rs +59 -0
  26. data/ext/itsi_acme/src/state.rs +424 -0
  27. data/ext/itsi_server/Cargo.toml +3 -3
  28. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +2 -2
  29. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +150 -19
  30. data/ext/itsi_server/src/ruby_types/itsi_server.rs +1 -0
  31. data/ext/itsi_server/src/server/binds/listener.rs +34 -29
  32. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +2 -2
  33. data/ext/itsi_server/src/server/binds/tls.rs +1 -1
  34. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +33 -28
  35. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +56 -3
  36. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +179 -0
  37. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +25 -2
  38. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +3 -3
  39. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +2 -1
  40. data/ext/itsi_server/src/server/middleware_stack/mod.rs +32 -34
  41. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +10 -4
  42. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +30 -7
  43. data/ext/itsi_server/src/server/thread_worker.rs +2 -2
  44. data/ext/itsi_server/src/services/static_file_server.rs +30 -28
  45. data/ext/itsi_tracing/src/lib.rs +39 -8
  46. data/lib/itsi/server/config/config_helpers.rb +93 -0
  47. data/lib/itsi/server/config/dsl.rb +81 -33
  48. data/lib/itsi/server/config/known_paths/KitchensinkDirectories.txt +2346 -0
  49. data/lib/itsi/server/config/known_paths/Randomfiles.txt +24 -0
  50. data/lib/itsi/server/config/known_paths/UnixDotfiles.txt +52 -0
  51. data/lib/itsi/server/config/known_paths/backdoors/ASP_CommonBackdoors.txt +29 -0
  52. data/lib/itsi/server/config/known_paths/backdoors/bot_control_panels.txt +1668 -0
  53. data/lib/itsi/server/config/known_paths/backdoors/shells.txt +1167 -0
  54. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST.txt +7 -0
  55. data/lib/itsi/server/config/known_paths/cgi/CGI_HTTP_POST_Windows.txt +6 -0
  56. data/lib/itsi/server/config/known_paths/cgi/CGI_Microsoft.txt +79 -0
  57. data/lib/itsi/server/config/known_paths/cgi/CGI_XPlatform.txt +3948 -0
  58. data/lib/itsi/server/config/known_paths/cms/README.md +5 -0
  59. data/lib/itsi/server/config/known_paths/cms/drupal_plugins.txt +6320 -0
  60. data/lib/itsi/server/config/known_paths/cms/drupal_themes.txt +828 -0
  61. data/lib/itsi/server/config/known_paths/cms/joomla_plugins.txt +224 -0
  62. data/lib/itsi/server/config/known_paths/cms/joomla_themes.txt +30 -0
  63. data/lib/itsi/server/config/known_paths/cms/php-nuke.txt +2142 -0
  64. data/lib/itsi/server/config/known_paths/cms/wordpress.txt +1566 -0
  65. data/lib/itsi/server/config/known_paths/cms/wp_common_theme_files.txt +46 -0
  66. data/lib/itsi/server/config/known_paths/cms/wp_plugins.txt +13366 -0
  67. data/lib/itsi/server/config/known_paths/cms/wp_plugins_full.txt +68662 -0
  68. data/lib/itsi/server/config/known_paths/cms/wp_plugins_top225.txt +225 -0
  69. data/lib/itsi/server/config/known_paths/cms/wp_themes.readme +12 -0
  70. data/lib/itsi/server/config/known_paths/cms/wp_themes.txt +7336 -0
  71. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/3CharExtBrute.txt +17576 -0
  72. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/CommonWebExtensions.txt +80 -0
  73. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Backup.txt +14 -0
  74. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Common.txt +865 -0
  75. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Compressed.txt +186 -0
  76. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Mostcommon.txt +30 -0
  77. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/Extensions.Skipfish.txt +93 -0
  78. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/WordlistSkipfish.txt +1918 -0
  79. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/copy_of.txt +8 -0
  80. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories-lowercase.txt +56180 -0
  81. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-directories.txt +62290 -0
  82. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions-lowercase.txt +2367 -0
  83. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-extensions.txt +2450 -0
  84. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files-lowercase.txt +35323 -0
  85. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-files.txt +37037 -0
  86. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words-lowercase.txt +107982 -0
  87. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-large-words.txt +119600 -0
  88. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories-lowercase.txt +26593 -0
  89. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-directories.txt +30009 -0
  90. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions-lowercase.txt +1233 -0
  91. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-extensions.txt +1289 -0
  92. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files-lowercase.txt +16243 -0
  93. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-files.txt +17128 -0
  94. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words-lowercase.txt +56293 -0
  95. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-medium-words.txt +63087 -0
  96. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories-lowercase.txt +17776 -0
  97. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-directories.txt +20122 -0
  98. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions-lowercase.txt +914 -0
  99. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-extensions.txt +963 -0
  100. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files-lowercase.txt +10848 -0
  101. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-files.txt +11424 -0
  102. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words-lowercase.txt +38267 -0
  103. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/raft-small-words.txt +43003 -0
  104. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/spanish.txt +445 -0
  105. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/test_demo.txt +36 -0
  106. data/lib/itsi/server/config/known_paths/filename-dirname-bruteforce/upload_variants.txt +44 -0
  107. data/lib/itsi/server/config/known_paths/login-file-locations/Logins.txt +71 -0
  108. data/lib/itsi/server/config/known_paths/login-file-locations/cfm.txt +294 -0
  109. data/lib/itsi/server/config/known_paths/login-file-locations/html.txt +295 -0
  110. data/lib/itsi/server/config/known_paths/login-file-locations/jsp.txt +294 -0
  111. data/lib/itsi/server/config/known_paths/login-file-locations/php.txt +294 -0
  112. data/lib/itsi/server/config/known_paths/login-file-locations/windows-asp.txt +294 -0
  113. data/lib/itsi/server/config/known_paths/login-file-locations/windows-aspx.txt +294 -0
  114. data/lib/itsi/server/config/known_paths/password-file-locations/Passwords.txt +47 -0
  115. data/lib/itsi/server/config/known_paths/php/PHP.txt +30 -0
  116. data/lib/itsi/server/config/known_paths/php/PHP_CommonBackdoors.txt +5 -0
  117. data/lib/itsi/server/config/known_paths/proxy-conf.txt +31 -0
  118. data/lib/itsi/server/config/known_paths/tftp.txt +79 -0
  119. data/lib/itsi/server/config/known_paths/webservers-appservers/ADFS.txt +86 -0
  120. data/lib/itsi/server/config/known_paths/webservers-appservers/AdobeXML.txt +16 -0
  121. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache.txt +101 -0
  122. data/lib/itsi/server/config/known_paths/webservers-appservers/ApacheTomcat.txt +47 -0
  123. data/lib/itsi/server/config/known_paths/webservers-appservers/Apache_Axis.txt +16 -0
  124. data/lib/itsi/server/config/known_paths/webservers-appservers/ColdFusion.txt +111 -0
  125. data/lib/itsi/server/config/known_paths/webservers-appservers/FatwireCMS.txt +390 -0
  126. data/lib/itsi/server/config/known_paths/webservers-appservers/Frontpage.txt +38 -0
  127. data/lib/itsi/server/config/known_paths/webservers-appservers/HP_System_Mgmt_Homepage.txt +239 -0
  128. data/lib/itsi/server/config/known_paths/webservers-appservers/HTTP_POST_Microsoft.txt +2 -0
  129. data/lib/itsi/server/config/known_paths/webservers-appservers/Hyperion.txt +578 -0
  130. data/lib/itsi/server/config/known_paths/webservers-appservers/IIS.txt +187 -0
  131. data/lib/itsi/server/config/known_paths/webservers-appservers/JBoss.txt +5 -0
  132. data/lib/itsi/server/config/known_paths/webservers-appservers/JRun.txt +13 -0
  133. data/lib/itsi/server/config/known_paths/webservers-appservers/JavaServlets_Common.txt +3 -0
  134. data/lib/itsi/server/config/known_paths/webservers-appservers/Joomla_exploitable.txt +1937 -0
  135. data/lib/itsi/server/config/known_paths/webservers-appservers/LotusNotes.txt +206 -0
  136. data/lib/itsi/server/config/known_paths/webservers-appservers/Netware.txt +18 -0
  137. data/lib/itsi/server/config/known_paths/webservers-appservers/Oracle9i.txt +60 -0
  138. data/lib/itsi/server/config/known_paths/webservers-appservers/OracleAppServer.txt +192 -0
  139. data/lib/itsi/server/config/known_paths/webservers-appservers/README.md +6 -0
  140. data/lib/itsi/server/config/known_paths/webservers-appservers/Ruby_Rails.txt +121 -0
  141. data/lib/itsi/server/config/known_paths/webservers-appservers/SAP.txt +463 -0
  142. data/lib/itsi/server/config/known_paths/webservers-appservers/Sharepoint.txt +1707 -0
  143. data/lib/itsi/server/config/known_paths/webservers-appservers/SiteMinder.txt +19 -0
  144. data/lib/itsi/server/config/known_paths/webservers-appservers/SunAppServerGlassfish.txt +51 -0
  145. data/lib/itsi/server/config/known_paths/webservers-appservers/SuniPlanet.txt +35 -0
  146. data/lib/itsi/server/config/known_paths/webservers-appservers/Vignette.txt +73 -0
  147. data/lib/itsi/server/config/known_paths/webservers-appservers/Weblogic.txt +160 -0
  148. data/lib/itsi/server/config/known_paths/webservers-appservers/Websphere.txt +366 -0
  149. data/lib/itsi/server/config/known_paths/wellknown-rfc5785.txt +30 -0
  150. data/lib/itsi/server/config/known_paths.rb +17 -0
  151. data/lib/itsi/server/config/middleware/_index.md +54 -0
  152. data/lib/itsi/server/config/middleware/log_requests.md +63 -0
  153. data/lib/itsi/server/config/middleware/log_requests.rb +33 -0
  154. data/lib/itsi/server/config/middleware.rb +9 -0
  155. data/lib/itsi/server/config/option.rb +9 -0
  156. data/lib/itsi/server/config/options/_index.md +36 -0
  157. data/lib/itsi/server/config/options/fiber_scheduler.md +35 -0
  158. data/lib/itsi/server/config/options/fiber_scheduler.rb +18 -0
  159. data/lib/itsi/server/config/options/threads.md +39 -0
  160. data/lib/itsi/server/config/options/threads.rb +17 -0
  161. data/lib/itsi/server/config/options/workers.md +43 -0
  162. data/lib/itsi/server/config/options/workers.rb +17 -0
  163. data/lib/itsi/server/config/typed_struct.rb +203 -0
  164. data/lib/itsi/server/config.rb +124 -30
  165. data/lib/itsi/server/signal_trap.rb +5 -1
  166. data/lib/itsi/server/typed_handlers/source_parser.rb +1 -1
  167. data/lib/itsi/server/version.rb +1 -1
  168. data/lib/itsi/server.rb +27 -6
  169. data/lib/ruby_lsp/itsi/addon.rb +64 -48
  170. metadata +141 -5
  171. data/CHANGELOG.md +0 -10
  172. data/CODE_OF_CONDUCT.md +0 -139
  173. data/LICENSE.txt +0 -21
  174. 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,9 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Middleware
5
+ include ConfigHelpers
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Option
5
+ include ConfigHelpers
6
+ end
7
+ end
8
+ end
9
+ 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,17 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Threads < Option
5
+
6
+ insert_text "threads ${1|1,2,Etc.nprocessors|}"
7
+
8
+ detail "Number of threads to run per worker"
9
+
10
+ schema do
11
+ Range(1..255)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -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,17 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class Workers < Option
5
+
6
+ insert_text "workers ${1|1,2,Etc.nprocessors|}"
7
+
8
+ detail "Number of worker processes to run"
9
+
10
+ schema do
11
+ Range(1..255)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -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