itsi-server 0.2.27.rc1-x86_64-darwin → 0.2.27-x86_64-darwin
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 +1 -1
- data/ext/itsi_scheduler/Cargo.toml +1 -1
- data/ext/itsi_server/Cargo.toml +1 -1
- data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +0 -1
- data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +19 -4
- data/ext/itsi_server/src/server/signal.rs +14 -9
- data/lib/itsi/server/3.1/itsi_server.bundle +0 -0
- data/lib/itsi/server/3.2/itsi_server.bundle +0 -0
- data/lib/itsi/server/3.3/itsi_server.bundle +0 -0
- data/lib/itsi/server/3.4/itsi_server.bundle +0 -0
- data/lib/itsi/server/4.0/itsi_server.bundle +0 -0
- data/lib/itsi/server/config/options/certificates.md +37 -9
- data/lib/itsi/server/config/options/fiber_scheduler.md +2 -0
- data/lib/itsi/server/default_config/Itsi.rb +4 -0
- data/lib/itsi/server/rack_interface.rb +2 -1
- data/lib/itsi/server/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fb1782b200aa6febf6e08fcf2fddfff43c36bb79b6adbbe3312e8bd65a7440aa
|
|
4
|
+
data.tar.gz: 65954cd463d29b6f472c64981cdcfa8d71beb2a58f568dca31ea010429361de6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: daa87b7488630e1f74a1a89e1e377de76fc7ebf31d5996bcec2bd579fb0c639f6313d8ca005a1630c46b0c6856948adb5a7683c0e2e7074f9e45af6fbf2bdde3
|
|
7
|
+
data.tar.gz: de9f9aa9f02f656afe66cb21a0fc4d1728fc9135365765f1ef3156f86e1958c76fdce1da82ac9ad8bd9814f69dfc1d13bd52151448f5cc66bccc0807829ca2d0
|
data/Cargo.lock
CHANGED
data/ext/itsi_server/Cargo.toml
CHANGED
|
@@ -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
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
data/lib/itsi/server/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: itsi-server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.27
|
|
4
|
+
version: 0.2.27
|
|
5
5
|
platform: x86_64-darwin
|
|
6
6
|
authors:
|
|
7
7
|
- Wouter Coppieters
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|