itsi 0.2.27.rc1 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +4 -1
- data/crates/itsi_scheduler/Cargo.toml +1 -1
- data/crates/itsi_server/Cargo.toml +1 -1
- data/crates/itsi_server/src/ruby_types/itsi_grpc_call.rs +0 -1
- data/crates/itsi_server/src/ruby_types/itsi_http_response.rs +19 -4
- data/crates/itsi_server/src/server/signal.rs +14 -9
- data/docs/content/features/_index.md +3 -0
- data/docs/content/getting_started/_index.md +6 -2
- data/docs/content/getting_started/local_development.md +13 -0
- data/docs/content/itsi_scheduler/_index.md +3 -0
- data/gems/scheduler/Gemfile.lock +2 -2
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/server/Gemfile +1 -0
- data/gems/server/Gemfile.lock +77 -5
- data/gems/server/lib/itsi/server/config/options/certificates.md +37 -9
- data/gems/server/lib/itsi/server/config/options/fiber_scheduler.md +2 -0
- data/gems/server/lib/itsi/server/default_config/Itsi.rb +4 -0
- data/gems/server/lib/itsi/server/rack_interface.rb +2 -1
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/gems/server/test/rack/test_rack_server.rb +65 -0
- data/lib/itsi/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96078f9c8cc05b5683900c02d3a662a7d0b2253ed2292f8aafcda8915bb823ae
|
|
4
|
+
data.tar.gz: 860a06e7fbb91b0d5f38a4cf8d18165e0ae4194fa159bfa551a203ab40cc8a76
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72598619d4fea4bcb177dcb4cb16ec04a31388d066e33cf61fefcb1cdeccd0efde3ef97bd23392065d59ff30912f551c015fb70da67560c6a5ed073c549ca6d8
|
|
7
|
+
data.tar.gz: 42b120ce03f36f81d89814243ccfe6cd634a1202df6563d9da2a87529548a191e03156144267ddd9e0aba25f17918db936f5a7dd9d8e03e60a602c78d8aea103
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [0.2.27] - 2026-06-18
|
|
2
|
+
- Add `HTTP-01` ACME validation support alongside `TLS-ALPN-01`, including fallback-friendly deployments behind proxies and CDNs when an HTTP listener is reachable.
|
|
3
|
+
- Add runtime TLS domain registration APIs so Ruby code can enroll and remove ACME-managed domains without restarting Itsi.
|
|
4
|
+
- Expand ACME coverage with Pebble-backed end-to-end tests for direct issuance, HTTP fallback, and dynamic runtime issuance flows.
|
|
5
|
+
- Tighten scheduler compatibility around real Ruby fiber-scheduler hooks including DNS resolution, sleeps/timeouts, nested scheduling, and process waiting.
|
|
6
|
+
- Refresh release documentation for native gem packaging, ACME behavior, and local ACME testing.
|
|
7
|
+
|
|
1
8
|
## [0.2.26] - 2026-05-13
|
|
2
9
|
- Restore synchronized release source after the unsynchronized `0.2.24` / `0.2.25` pushes.
|
|
3
10
|
- Restore the multi-platform native gem packaging workflow so the next release can ship prebuilt binaries again.
|
data/README.md
CHANGED
|
@@ -29,12 +29,15 @@ Make sure you have Ruby installed! If not, look here:
|
|
|
29
29
|
### 2. Itsi
|
|
30
30
|
|
|
31
31
|
> On Linux?
|
|
32
|
-
You'll need at least `build-essential` and `libclang-dev` installed to build Itsi on Linux.
|
|
32
|
+
You'll need at least `build-essential` and `libclang-dev` installed to build Itsi on Linux if RubyGems falls back to a source build.
|
|
33
33
|
E.g.
|
|
34
34
|
```bash
|
|
35
35
|
apt-get install build-essential libclang-dev
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
> Precompiled native gems are published for common macOS and Linux targets on x86_64 and ARM64.
|
|
39
|
+
> On those platforms most installs can skip the local Rust toolchain entirely, while source gems remain available as a fallback.
|
|
40
|
+
|
|
38
41
|
Then, install Itsi using `gem`:
|
|
39
42
|
```bash
|
|
40
43
|
gem install itsi
|
|
@@ -11,7 +11,6 @@ use http::{request::Parts, Response, StatusCode};
|
|
|
11
11
|
use http_body_util::BodyExt;
|
|
12
12
|
use itsi_error::CLIENT_CONNECTION_CLOSED;
|
|
13
13
|
use itsi_rb_helpers::{print_rb_backtrace, HeapValue};
|
|
14
|
-
use itsi_tracing::debug;
|
|
15
14
|
use magnus::{
|
|
16
15
|
block::Proc,
|
|
17
16
|
error::{ErrorType, Result as MagnusResult},
|
|
@@ -72,6 +72,17 @@ pub enum ResponseFrame {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
impl ItsiHttpResponse {
|
|
75
|
+
fn is_expected_bridge_shutdown(err: &io::Error) -> bool {
|
|
76
|
+
matches!(
|
|
77
|
+
err.kind(),
|
|
78
|
+
io::ErrorKind::BrokenPipe
|
|
79
|
+
| io::ErrorKind::ConnectionAborted
|
|
80
|
+
| io::ErrorKind::ConnectionReset
|
|
81
|
+
| io::ErrorKind::NotConnected
|
|
82
|
+
| io::ErrorKind::UnexpectedEof
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
75
86
|
pub fn new(
|
|
76
87
|
parts: Arc<Parts>,
|
|
77
88
|
response_sender: OneshotSender<ResponseFrame>,
|
|
@@ -98,13 +109,17 @@ impl ItsiHttpResponse {
|
|
|
98
109
|
let (mut cr, mut cw) = tokio::io::split(client_io);
|
|
99
110
|
|
|
100
111
|
let to_ruby = tokio::spawn(async move {
|
|
101
|
-
if let Err(
|
|
102
|
-
|
|
112
|
+
if let Err(err) = tokio::io::copy(&mut cr, &mut lw).await {
|
|
113
|
+
if !Self::is_expected_bridge_shutdown(&err) {
|
|
114
|
+
eprintln!("Error copying upgraded->local: {:?}", err);
|
|
115
|
+
}
|
|
103
116
|
}
|
|
104
117
|
});
|
|
105
118
|
let from_ruby = tokio::spawn(async move {
|
|
106
|
-
if let Err(
|
|
107
|
-
|
|
119
|
+
if let Err(err) = tokio::io::copy(&mut lr, &mut cw).await {
|
|
120
|
+
if !Self::is_expected_bridge_shutdown(&err) {
|
|
121
|
+
eprintln!("Error copying local->upgraded: {:?}", err);
|
|
122
|
+
}
|
|
108
123
|
}
|
|
109
124
|
});
|
|
110
125
|
|
|
@@ -63,7 +63,7 @@ pub fn send_lifecycle_event(event: LifecycleEvent) {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
fn receive_signal(signum: i32
|
|
66
|
+
extern "C" fn receive_signal(signum: i32) {
|
|
67
67
|
debug!("Received signal: {}", signum);
|
|
68
68
|
SIGINT_COUNT.fetch_add(-1, Ordering::SeqCst);
|
|
69
69
|
let event = match signum {
|
|
@@ -96,20 +96,25 @@ fn receive_signal(signum: i32, _: sighandler_t) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
fn signal_handler() -> sighandler_t {
|
|
100
|
+
receive_signal as *const () as sighandler_t
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
pub fn reset_signal_handlers() -> bool {
|
|
100
104
|
debug!("Resetting signal handlers");
|
|
101
105
|
SIGINT_COUNT.store(0, Ordering::SeqCst);
|
|
102
106
|
SHUTDOWN_REQUESTED.store(false, Ordering::SeqCst);
|
|
103
107
|
|
|
104
108
|
unsafe {
|
|
105
|
-
|
|
106
|
-
libc::signal(libc::
|
|
107
|
-
libc::signal(libc::
|
|
108
|
-
libc::signal(libc::
|
|
109
|
-
libc::signal(libc::
|
|
110
|
-
libc::signal(libc::
|
|
111
|
-
libc::signal(libc::
|
|
112
|
-
libc::signal(libc::
|
|
109
|
+
let handler = signal_handler();
|
|
110
|
+
libc::signal(libc::SIGTERM, handler);
|
|
111
|
+
libc::signal(libc::SIGINT, handler);
|
|
112
|
+
libc::signal(libc::SIGUSR2, handler);
|
|
113
|
+
libc::signal(libc::SIGUSR1, handler);
|
|
114
|
+
libc::signal(libc::SIGHUP, handler);
|
|
115
|
+
libc::signal(libc::SIGTTIN, handler);
|
|
116
|
+
libc::signal(libc::SIGTTOU, handler);
|
|
117
|
+
libc::signal(libc::SIGCHLD, handler);
|
|
113
118
|
}
|
|
114
119
|
true
|
|
115
120
|
}
|
|
@@ -145,6 +145,8 @@ Itsi also comes bundled with a passfile generator, to help you manage your passw
|
|
|
145
145
|
* Automated provisioning of Let's Encrypt certificates.
|
|
146
146
|
* File system caching of certificate data to avoid excessive API calls.
|
|
147
147
|
* Supports usage of subject alternative names (SANs) for certificates that span multiple domains/sub-domains.
|
|
148
|
+
* Supports direct `TLS-ALPN-01` validation and `HTTP-01` validation when a reachable HTTP listener is available.
|
|
149
|
+
* Supports runtime domain registration for live certificate issuance without restarting the server.
|
|
148
150
|
* See <a target="_blank" href="/options/certificates#production-certificates-lets-encrypt">certificates</a>.
|
|
149
151
|
{{% /details %}}
|
|
150
152
|
|
|
@@ -225,6 +227,7 @@ Note: This is not the same as <a target="_blank" href="https://grpc.io/blog/grpc
|
|
|
225
227
|
{{% details title="Non-blocking(Fiber Scheduler) Mode" closed="true" %}}
|
|
226
228
|
* Support for Ruby’s fiber scheduler for non-blocking concurrency, boosting performance during I/O operations.
|
|
227
229
|
* Use Itsi's own high-performance built-in <a target="_blank" href="/itsi_scheduler">Fiber Scheduler</a> or if your prefer you can bring your own!
|
|
230
|
+
* Current native gems are built and tested across common Linux and macOS x86_64 and ARM64 targets.
|
|
228
231
|
* See <a target="_blank" href="/options/fiber_scheduler">fiber_scheduler</a>.
|
|
229
232
|
{{% /details %}}
|
|
230
233
|
|
|
@@ -20,7 +20,8 @@ Install Ruby
|
|
|
20
20
|
**Prerequisites**
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Most Linux installs on common x86_64 and ARM64 targets can use the precompiled native gems directly.
|
|
24
|
+
If RubyGems falls back to the source gems, you'll need a C/C++ build environment plus `clang` and `curl` (for running `rustup`).
|
|
24
25
|
|
|
25
26
|
#### For Ubuntu / Debian:
|
|
26
27
|
```bash
|
|
@@ -63,6 +64,9 @@ Then use `gem` to install Itsi, or its components based on your Ruby version.
|
|
|
63
64
|
{{< /tab >}}
|
|
64
65
|
{{< tab >}}
|
|
65
66
|
**Mac**:
|
|
67
|
+
Most macOS installs on Apple Silicon and Intel Macs can use the precompiled native gems directly.
|
|
68
|
+
If RubyGems falls back to the source gems, install Xcode Command Line Tools first.
|
|
69
|
+
|
|
66
70
|
**For Ruby >= 3.0**:
|
|
67
71
|
```bash
|
|
68
72
|
gem install itsi
|
|
@@ -88,7 +92,7 @@ Then use `gem` to install Itsi, or its components based on your Ruby version.
|
|
|
88
92
|
{{< tab >}}
|
|
89
93
|
**FreeBSD**
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
FreeBSD currently relies on source builds, so you'll need to install a few build tools manually:
|
|
92
96
|
```bash
|
|
93
97
|
pkg install gmake cmake curl llvm
|
|
94
98
|
```
|
|
@@ -75,6 +75,19 @@ Itsi will print informative error message if config validation fails. E.g.
|
|
|
75
75
|
| ^^^
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
## Local ACME Testing
|
|
79
|
+
Itsi includes end-to-end ACME tests that exercise both `TLS-ALPN-01` and `HTTP-01` flows against a local [Pebble](https://github.com/letsencrypt/pebble) certificate authority.
|
|
80
|
+
|
|
81
|
+
The test helper installs Pebble on demand using the Go toolchain, so the only prerequisite is a working `go` binary on your `PATH`.
|
|
82
|
+
|
|
83
|
+
Once Go is available, the local ACME tests can be run as part of the normal server suite:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
rake server:test
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If Go is not installed, those specific ACME integration tests will be skipped rather than failing the whole suite.
|
|
90
|
+
|
|
78
91
|
## Shell Completions
|
|
79
92
|
Itsi can also help you install shell completions, which are useful if you find yourself using the `itsi` executable a lot and forgetting the commands.
|
|
80
93
|
Add the following line to the bottom of your ~/.bashrc or ~/.zshrc file:
|
|
@@ -16,6 +16,9 @@ When combined with Itsi Server, you can write endpoints that look just like regu
|
|
|
16
16
|
If you're purely after a lightweight, yet efficient Ruby scheduler,
|
|
17
17
|
you can use Itsi Scheduler as a standalone scheduler for any Ruby application.
|
|
18
18
|
|
|
19
|
+
The current release line is packaged as precompiled native gems for common macOS and Linux x86_64 and ARM64 targets, with source builds still available as a fallback.
|
|
20
|
+
Recent scheduler work has also tightened compatibility around the Ruby scheduler hooks that matter in practice: network I/O, DNS resolution, sleep/timeouts, nested scheduling, and process waiting.
|
|
21
|
+
|
|
19
22
|
Just use `Fiber.set_scheduler` to set an instance `Itsi::Scheduler` as a scheduler to opt in to this IO weaving behavior
|
|
20
23
|
*automatically* for all blocking IO.
|
|
21
24
|
|
data/gems/scheduler/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
itsi-scheduler (0.2.27
|
|
4
|
+
itsi-scheduler (0.2.27)
|
|
5
5
|
rb_sys (~> 0.9.91)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -86,7 +86,7 @@ CHECKSUMS
|
|
|
86
86
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
87
87
|
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
|
|
88
88
|
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
|
|
89
|
-
itsi-scheduler (0.2.27
|
|
89
|
+
itsi-scheduler (0.2.27)
|
|
90
90
|
json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
|
|
91
91
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
92
92
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
data/gems/server/Gemfile
CHANGED
data/gems/server/Gemfile.lock
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ../scheduler
|
|
3
3
|
specs:
|
|
4
|
-
itsi-scheduler (0.2.27
|
|
4
|
+
itsi-scheduler (0.2.27)
|
|
5
5
|
rb_sys (~> 0.9.91)
|
|
6
6
|
|
|
7
7
|
PATH
|
|
8
8
|
remote: .
|
|
9
9
|
specs:
|
|
10
|
-
itsi-server (0.2.27
|
|
10
|
+
itsi-server (0.2.27)
|
|
11
11
|
json (~> 2)
|
|
12
12
|
prism (~> 1.4)
|
|
13
13
|
rack (>= 1.6)
|
|
@@ -17,10 +17,42 @@ GEM
|
|
|
17
17
|
remote: https://rubygems.org/
|
|
18
18
|
specs:
|
|
19
19
|
ansi (1.6.0)
|
|
20
|
+
async (2.39.0)
|
|
21
|
+
console (~> 1.29)
|
|
22
|
+
fiber-annotation
|
|
23
|
+
io-event (~> 1.11)
|
|
24
|
+
metrics (~> 0.12)
|
|
25
|
+
traces (~> 0.18)
|
|
26
|
+
async-http (0.95.1)
|
|
27
|
+
async (>= 2.10.2)
|
|
28
|
+
async-pool (~> 0.11)
|
|
29
|
+
io-endpoint (~> 0.14)
|
|
30
|
+
io-stream (~> 0.6)
|
|
31
|
+
metrics (~> 0.12)
|
|
32
|
+
protocol-http (~> 0.62)
|
|
33
|
+
protocol-http1 (~> 0.39)
|
|
34
|
+
protocol-http2 (~> 0.26)
|
|
35
|
+
protocol-url (~> 0.2)
|
|
36
|
+
traces (~> 0.10)
|
|
37
|
+
async-pool (0.11.2)
|
|
38
|
+
async (>= 2.0)
|
|
39
|
+
async-websocket (0.30.1)
|
|
40
|
+
async-http (~> 0.76)
|
|
41
|
+
protocol-http (~> 0.34)
|
|
42
|
+
protocol-rack (~> 0.7)
|
|
43
|
+
protocol-websocket (~> 0.17)
|
|
20
44
|
base64 (0.3.0)
|
|
21
45
|
bigdecimal (4.1.2)
|
|
22
46
|
builder (3.3.0)
|
|
23
47
|
connection_pool (3.0.2)
|
|
48
|
+
console (1.36.0)
|
|
49
|
+
fiber-annotation
|
|
50
|
+
fiber-local (~> 1.1)
|
|
51
|
+
json
|
|
52
|
+
fiber-annotation (0.2.0)
|
|
53
|
+
fiber-local (1.1.0)
|
|
54
|
+
fiber-storage
|
|
55
|
+
fiber-storage (1.0.1)
|
|
24
56
|
google-protobuf (4.30.2)
|
|
25
57
|
bigdecimal
|
|
26
58
|
rake (>= 13)
|
|
@@ -29,11 +61,15 @@ GEM
|
|
|
29
61
|
grpc (1.78.0)
|
|
30
62
|
google-protobuf (>= 3.25, < 5.0)
|
|
31
63
|
googleapis-common-protos-types (~> 1.0)
|
|
64
|
+
io-endpoint (0.17.2)
|
|
65
|
+
io-event (1.16.2)
|
|
66
|
+
io-stream (0.13.1)
|
|
32
67
|
json (2.19.4)
|
|
33
68
|
jwt (3.1.2)
|
|
34
69
|
base64
|
|
35
70
|
language_server-protocol (3.17.0.5)
|
|
36
71
|
logger (1.7.0)
|
|
72
|
+
metrics (0.15.0)
|
|
37
73
|
minitest (5.27.0)
|
|
38
74
|
minitest-reporters (1.8.0)
|
|
39
75
|
ansi
|
|
@@ -42,6 +78,20 @@ GEM
|
|
|
42
78
|
ruby-progressbar
|
|
43
79
|
net_http_unix (0.2.2)
|
|
44
80
|
prism (1.9.0)
|
|
81
|
+
protocol-hpack (1.5.1)
|
|
82
|
+
protocol-http (0.62.2)
|
|
83
|
+
protocol-http1 (0.39.0)
|
|
84
|
+
protocol-http (~> 0.62)
|
|
85
|
+
protocol-http2 (0.26.0)
|
|
86
|
+
protocol-hpack (~> 1.4)
|
|
87
|
+
protocol-http (~> 0.62)
|
|
88
|
+
protocol-rack (0.22.1)
|
|
89
|
+
io-stream (>= 0.10)
|
|
90
|
+
protocol-http (~> 0.58)
|
|
91
|
+
rack (>= 1.0)
|
|
92
|
+
protocol-url (0.4.0)
|
|
93
|
+
protocol-websocket (0.21.1)
|
|
94
|
+
protocol-http (~> 0.2)
|
|
45
95
|
rack (3.2.6)
|
|
46
96
|
rackup (2.3.1)
|
|
47
97
|
rack (>= 3)
|
|
@@ -64,6 +114,7 @@ GEM
|
|
|
64
114
|
prism (>= 1.2, < 2.0)
|
|
65
115
|
rbs (>= 3, < 5)
|
|
66
116
|
ruby-progressbar (1.13.0)
|
|
117
|
+
traces (0.18.2)
|
|
67
118
|
tsort (0.2.0)
|
|
68
119
|
|
|
69
120
|
PLATFORMS
|
|
@@ -71,6 +122,7 @@ PLATFORMS
|
|
|
71
122
|
ruby
|
|
72
123
|
|
|
73
124
|
DEPENDENCIES
|
|
125
|
+
async-websocket
|
|
74
126
|
bundler
|
|
75
127
|
grpc
|
|
76
128
|
itsi-scheduler!
|
|
@@ -89,23 +141,42 @@ DEPENDENCIES
|
|
|
89
141
|
|
|
90
142
|
CHECKSUMS
|
|
91
143
|
ansi (1.6.0) sha256=ac9ea0c0ea8d32fb4e271348e609963ac78882f34b73836c2a02b3622e666658
|
|
144
|
+
async (2.39.0) sha256=df18730073f2bbb45788077dfa20cb365ecc1b9453969f44de6796b5191a00aa
|
|
145
|
+
async-http (0.95.1) sha256=0c3dd458c204c06d5c4b20b01bbec4794a1203db627fb2ce536e1799ec14786c
|
|
146
|
+
async-pool (0.11.2) sha256=0a43a17b02b04d9c451b7d12fafa9a50e55dc6dd00d4369aca00433f16a7e3ed
|
|
147
|
+
async-websocket (0.30.1) sha256=54bb8a8f184e4aa64434c7a78ecc55850a67a3d1dcd02e3ae787376e2c673936
|
|
92
148
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
93
149
|
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
|
94
150
|
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
|
95
151
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
152
|
+
console (1.36.0) sha256=45599ea906cf80a73d8941f03abf873fe66a6a954e0bac5bc1c01e2cdc406f07
|
|
153
|
+
fiber-annotation (0.2.0) sha256=7abfadf1d119f508867d4103bf231c0354d019cc39a5738945dec2edadaf6c03
|
|
154
|
+
fiber-local (1.1.0) sha256=c885f94f210fb9b05737de65d511136ea602e00c5105953748aa0f8793489f06
|
|
155
|
+
fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1
|
|
96
156
|
google-protobuf (4.30.2) sha256=0f35168dbeeccf13d928acf6c128cfec17b9a826ae4505246a02c115f4ae16ed
|
|
97
157
|
googleapis-common-protos-types (1.19.0) sha256=aecb76ca5326f8bcc47ab083259bbc4971d07e87f56808af7e210669d9765694
|
|
98
158
|
grpc (1.78.0) sha256=7aaf47b6d7783fb0e7d40fc853d34e802d47aef7b1312862b6e719141b3527c9
|
|
99
|
-
|
|
100
|
-
|
|
159
|
+
io-endpoint (0.17.2) sha256=3feaf766c116b35839c11fac68b6aaadc47887bb488902a57bf8e1d288fb3338
|
|
160
|
+
io-event (1.16.2) sha256=9f9cb0a96ea5c3850a672606c65f27bc96d7621399ef6196acbfe2be0cd1279c
|
|
161
|
+
io-stream (0.13.1) sha256=570d7c4dfb0fbd767480b4a222048a2be6d9b78febc1ec68258d0e0a4cde20de
|
|
162
|
+
itsi-scheduler (0.2.27)
|
|
163
|
+
itsi-server (0.2.27)
|
|
101
164
|
json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
|
|
102
165
|
jwt (3.1.2) sha256=af6991f19a6bb4060d618d9add7a66f0eeb005ac0bc017cd01f63b42e122d535
|
|
103
166
|
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
104
167
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
168
|
+
metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
|
|
105
169
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
106
170
|
minitest-reporters (1.8.0) sha256=8ce5280fb73ad3178ae525454df169b6f28c1b38b1d088ea91815d3a370ba384
|
|
107
171
|
net_http_unix (0.2.2) sha256=98aa0e1e7787f8383e8dd8ff60fc18062c2ddb2aadbc76e92cfb4f95d2c9d71d
|
|
108
172
|
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
|
173
|
+
protocol-hpack (1.5.1) sha256=6feca238b8078da1cd295677d6f306c6001af92d75fe0643d33e6956cbc3ad91
|
|
174
|
+
protocol-http (0.62.2) sha256=e1c1f2f56029c1af8c4e2b8a67d0d096c76620f3afd8d99d1dcd2f6b8ffa773b
|
|
175
|
+
protocol-http1 (0.39.0) sha256=e49b3f4cda6f5d94c76a323d2b7f6977cba3ebd082d2da437039594da77ad8eb
|
|
176
|
+
protocol-http2 (0.26.0) sha256=bac89cd78082b241ccd0cf7246f5160e4bb0c9c975fb4bf7deef5f88cc317486
|
|
177
|
+
protocol-rack (0.22.1) sha256=1185d245927ef9849a603700d6991ca353bc89724fbf98efa4a4333ed62a9fc3
|
|
178
|
+
protocol-url (0.4.0) sha256=64d4c03b6b51ad815ac6fdaf77a1d91e5baf9220d26becb846c5459dacdea9e1
|
|
179
|
+
protocol-websocket (0.21.1) sha256=34325e4325697f0956877e67784bcc838cfd51ebbf4f8e9e5201be292041ee61
|
|
109
180
|
rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
|
|
110
181
|
rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868
|
|
111
182
|
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
|
@@ -117,7 +188,8 @@ CHECKSUMS
|
|
|
117
188
|
redis-client (0.24.0) sha256=ee65ee39cb2c38608b734566167fd912384f3c1241f59075e22858f23a085dbb
|
|
118
189
|
ruby-lsp (0.26.7) sha256=60a1199fc7e329348d63a2479854f94435725d833eeabf3d539b790185cbf21f
|
|
119
190
|
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
191
|
+
traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214
|
|
120
192
|
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
|
|
121
193
|
|
|
122
194
|
BUNDLED WITH
|
|
123
|
-
|
|
195
|
+
2.6.9
|
|
@@ -54,12 +54,40 @@ Let's Encrypt enforces strict rate limits on production certificate generation.
|
|
|
54
54
|
{{< /callout >}}
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
Itsi supports both ACME challenge types that matter for common deployments:
|
|
58
|
+
|
|
59
|
+
* `TLS-ALPN-01` is used when the certificate authority can reach Itsi directly on the HTTPS listener.
|
|
60
|
+
* `HTTP-01` can be used when you also expose a reachable HTTP listener for the same hostname. In real Let's Encrypt deployments this typically means port `80` must reach Itsi for `/.well-known/acme-challenge/*`.
|
|
61
|
+
|
|
62
|
+
This means setups behind a CDN, WAF, or TLS-terminating proxy can still use automated certificates, provided plain HTTP validation traffic is forwarded to Itsi.
|
|
63
|
+
|
|
64
|
+
E.g. a production configuration that allows HTTP-01 fallback might look like this:
|
|
65
|
+
|
|
66
|
+
```ruby {filename=Itsi.rb}
|
|
67
|
+
bind "http://0.0.0.0:80"
|
|
68
|
+
bind "https://0.0.0.0:443?cert=acme&domains=example.com&acme_email=you@example.com"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Dynamic Domain Registration
|
|
72
|
+
You can add or remove ACME-managed domains while Itsi is already running.
|
|
73
|
+
|
|
74
|
+
This is useful when hostnames are discovered dynamically by your Ruby application, or when you want to defer certificate issuance until a tenant, customer, or site is activated.
|
|
75
|
+
|
|
76
|
+
Runtime APIs:
|
|
77
|
+
|
|
78
|
+
* `Itsi::Server.tls_bindings`
|
|
79
|
+
* `Itsi::Server.tls_domains(listener_id = nil)`
|
|
80
|
+
* `Itsi::Server.tls_domain_statuses(listener_id = nil)`
|
|
81
|
+
* `Itsi::Server.register_tls_domain(domain, listener_id = nil)`
|
|
82
|
+
* `Itsi::Server.unregister_tls_domain(domain, listener_id = nil)`
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
Itsi::Server.register_tls_domain("customer-a.example.com")
|
|
88
|
+
|
|
89
|
+
status = Itsi::Server.tls_domain_statuses.find { |entry| entry["domain"] == "customer-a.example.com" }
|
|
90
|
+
puts status
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
When using dynamic issuance with HTTP-01, the same requirement still applies: the domain being issued must be able to reach an Itsi-managed HTTP listener for the ACME challenge path.
|
|
@@ -7,6 +7,8 @@ This allows Itsi to process a very large number of IO heavy requests concurrentl
|
|
|
7
7
|
|
|
8
8
|
Enabling Fiber Scheduler mode can drastically improve application performance if you perform large amounts of blocking IO operations.
|
|
9
9
|
|
|
10
|
+
Itsi's bundled scheduler is intended to be practical for real Ruby applications, not just toy socket examples. It integrates with the scheduler hooks used by modern Rubies for socket I/O, DNS lookups, sleeps and timeouts, and process waiting.
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
## Configuration File
|
|
12
14
|
```ruby {filename="Itsi.rb"}
|
|
@@ -37,6 +37,10 @@ fiber_scheduler nil
|
|
|
37
37
|
# bind "https://itsi.fyi?cert=acme&acme_email=admin@itsi.fyi"
|
|
38
38
|
# You can generate certificates for multiple domains at once, by passing a comma-separated list of domains
|
|
39
39
|
# bind "https://0.0.0.0?domains=foo.itsi.fyi,bar.itsi.fyi&cert=acme&acme_email=admin@itsi.fyi"
|
|
40
|
+
# If HTTPS on 443 is not directly reachable, you can also expose an HTTP listener and
|
|
41
|
+
# Let's Encrypt will be able to validate using HTTP-01 instead.
|
|
42
|
+
# bind "http://0.0.0.0:80"
|
|
43
|
+
# bind "https://0.0.0.0:443?domains=foo.itsi.fyi&cert=acme&acme_email=admin@itsi.fyi"
|
|
40
44
|
#
|
|
41
45
|
# If you already have a certificate you can specify it using the cert and key parameters
|
|
42
46
|
# bind "https://itsi.fyi?cert=/path/to/cert.pem&key=/path/to/key.pem"
|
|
@@ -103,7 +103,8 @@ module Itsi
|
|
|
103
103
|
elsif body_streamer
|
|
104
104
|
# If we're partially hijacked or returned a streaming body,
|
|
105
105
|
# stream this response.
|
|
106
|
-
|
|
106
|
+
stream = status == 101 ? request.partial_hijack : response
|
|
107
|
+
body_streamer.call(stream)
|
|
107
108
|
|
|
108
109
|
elsif body.is_a?(Array)
|
|
109
110
|
if body.length == 1
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
require_relative "../helpers/test_helper"
|
|
2
|
+
require "async/websocket/adapters/rack"
|
|
3
|
+
require "protocol/websocket/connection"
|
|
4
|
+
require "base64"
|
|
2
5
|
|
|
3
6
|
class TestRackServer < Minitest::Test
|
|
4
7
|
def test_that_it_has_a_version_number
|
|
@@ -145,6 +148,36 @@ class TestRackServer < Minitest::Test
|
|
|
145
148
|
assert_operator read_arity, :!=, 0
|
|
146
149
|
end
|
|
147
150
|
|
|
151
|
+
def test_async_websocket_rack_adapter_can_upgrade_and_echo_messages
|
|
152
|
+
callback_error = Queue.new
|
|
153
|
+
|
|
154
|
+
server(app_with_lint: lambda do |env|
|
|
155
|
+
Async::WebSocket::Adapters::Rack.open(env) do |connection|
|
|
156
|
+
begin
|
|
157
|
+
message = connection.read
|
|
158
|
+
connection.write(message)
|
|
159
|
+
connection.flush
|
|
160
|
+
rescue => e
|
|
161
|
+
callback_error << e
|
|
162
|
+
end
|
|
163
|
+
end || [200, { "content-type" => "text/plain" }, ["ok"]]
|
|
164
|
+
end) do |uri|
|
|
165
|
+
socket = websocket_upgrade_socket(uri)
|
|
166
|
+
connection = websocket_client_connection(socket)
|
|
167
|
+
|
|
168
|
+
connection.write("hello")
|
|
169
|
+
connection.flush
|
|
170
|
+
|
|
171
|
+
message = connection.read
|
|
172
|
+
assert_equal "hello", message.to_str
|
|
173
|
+
ensure
|
|
174
|
+
connection&.close rescue nil
|
|
175
|
+
socket&.close
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
raise callback_error.pop unless callback_error.empty?
|
|
179
|
+
end
|
|
180
|
+
|
|
148
181
|
def test_enumerable_body
|
|
149
182
|
server(app_with_lint: lambda do |env|
|
|
150
183
|
[200, { "content-type" => "application/json" },
|
|
@@ -503,4 +536,36 @@ class TestRackServer < Minitest::Test
|
|
|
503
536
|
assert_equal %w[a=b c=d], resp.get_fields("set-cookie")
|
|
504
537
|
end
|
|
505
538
|
end
|
|
539
|
+
|
|
540
|
+
private
|
|
541
|
+
|
|
542
|
+
def websocket_upgrade_socket(uri)
|
|
543
|
+
socket = TCPSocket.new(uri.host, uri.port)
|
|
544
|
+
socket.write(
|
|
545
|
+
"GET / HTTP/1.1\r\n" \
|
|
546
|
+
"Host: #{uri.host}:#{uri.port}\r\n" \
|
|
547
|
+
"Connection: Upgrade\r\n" \
|
|
548
|
+
"Upgrade: websocket\r\n" \
|
|
549
|
+
"Sec-WebSocket-Version: 13\r\n" \
|
|
550
|
+
"Sec-WebSocket-Key: #{Base64.strict_encode64(SecureRandom.random_bytes(16))}\r\n" \
|
|
551
|
+
"\r\n"
|
|
552
|
+
)
|
|
553
|
+
socket.flush
|
|
554
|
+
|
|
555
|
+
response = +""
|
|
556
|
+
until response.include?("\r\n\r\n")
|
|
557
|
+
chunk = socket.read(1)
|
|
558
|
+
raise EOFError, "Unexpected EOF during websocket handshake" unless chunk
|
|
559
|
+
|
|
560
|
+
response << chunk
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
assert_includes response, "101"
|
|
564
|
+
socket
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
def websocket_client_connection(socket)
|
|
568
|
+
framer = Protocol::WebSocket::Framer.new(socket)
|
|
569
|
+
Protocol::WebSocket::Connection.new(framer, mask: "\x01\x02\x03\x04")
|
|
570
|
+
end
|
|
506
571
|
end
|
data/lib/itsi/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: itsi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.27
|
|
4
|
+
version: 0.2.27
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wouter Coppieters
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.2.27
|
|
18
|
+
version: 0.2.27
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.2.27
|
|
25
|
+
version: 0.2.27
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: itsi-server
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - '='
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.2.27
|
|
32
|
+
version: 0.2.27
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - '='
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.2.27
|
|
39
|
+
version: 0.2.27
|
|
40
40
|
description: Wrapper Gem for both the Itsi server and the Itsi Fiber scheduler
|
|
41
41
|
email:
|
|
42
42
|
- wc@pico.net.nz
|