itsi-scheduler 0.1.5 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +120 -52
  3. data/README.md +57 -24
  4. data/Rakefile +0 -4
  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_error/Cargo.toml +1 -0
  28. data/ext/itsi_error/src/lib.rs +106 -7
  29. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  30. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  31. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  32. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  33. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  34. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  35. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  36. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  37. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  38. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  39. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  40. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  41. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  42. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  43. data/ext/itsi_rb_helpers/Cargo.toml +1 -0
  44. data/ext/itsi_rb_helpers/src/heap_value.rs +18 -0
  45. data/ext/itsi_rb_helpers/src/lib.rs +63 -12
  46. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  47. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  48. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  49. data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  50. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  51. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  52. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  53. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  54. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  55. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  56. data/ext/itsi_scheduler/Cargo.toml +1 -1
  57. data/ext/itsi_scheduler/src/itsi_scheduler.rs +9 -3
  58. data/ext/itsi_scheduler/src/lib.rs +1 -0
  59. data/ext/itsi_server/Cargo.lock +2956 -0
  60. data/ext/itsi_server/Cargo.toml +73 -29
  61. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  62. data/ext/itsi_server/src/env.rs +43 -0
  63. data/ext/itsi_server/src/lib.rs +114 -75
  64. data/ext/itsi_server/src/prelude.rs +2 -0
  65. data/ext/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  66. data/ext/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +29 -8
  67. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  68. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  69. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
  70. data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +84 -40
  71. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
  72. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
  73. data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
  74. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  75. data/ext/itsi_server/src/server/{bind.rs → binds/bind.rs} +59 -24
  76. data/ext/itsi_server/src/server/binds/listener.rs +444 -0
  77. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  78. data/ext/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +57 -19
  79. data/ext/itsi_server/src/server/{tls.rs → binds/tls.rs} +120 -31
  80. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  81. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  82. data/ext/itsi_server/src/server/io_stream.rs +2 -1
  83. data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
  84. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  85. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  86. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  87. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
  88. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  89. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  90. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
  91. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
  92. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  99. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  100. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  101. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
  102. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
  103. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
  104. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
  105. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  106. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  107. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  108. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
  109. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  110. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
  111. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  112. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  113. data/ext/itsi_server/src/server/mod.rs +7 -5
  114. data/ext/itsi_server/src/server/process_worker.rs +65 -14
  115. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  116. data/ext/itsi_server/src/server/request_job.rs +11 -0
  117. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +150 -50
  118. data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  119. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +399 -165
  120. data/ext/itsi_server/src/server/signal.rs +33 -26
  121. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  122. data/ext/itsi_server/src/server/thread_worker.rs +218 -107
  123. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  124. data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
  125. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  126. data/ext/itsi_server/src/services/mod.rs +6 -0
  127. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  128. data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
  129. data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
  130. data/ext/itsi_tracing/Cargo.toml +1 -0
  131. data/ext/itsi_tracing/src/lib.rs +362 -33
  132. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  133. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  134. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  135. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  136. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  137. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  138. data/itsi-scheduler-100.png +0 -0
  139. data/lib/itsi/scheduler/version.rb +1 -1
  140. data/lib/itsi/scheduler.rb +11 -6
  141. metadata +117 -24
  142. data/CHANGELOG.md +0 -5
  143. data/CODE_OF_CONDUCT.md +0 -132
  144. data/LICENSE.txt +0 -21
  145. data/ext/itsi_error/src/from.rs +0 -71
  146. data/ext/itsi_server/extconf.rb +0 -6
  147. data/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  148. data/ext/itsi_server/src/request/itsi_request.rs +0 -277
  149. data/ext/itsi_server/src/request/mod.rs +0 -1
  150. data/ext/itsi_server/src/response/mod.rs +0 -1
  151. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  152. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  153. data/ext/itsi_server/src/server/itsi_server.rs +0 -244
  154. data/ext/itsi_server/src/server/listener.rs +0 -327
  155. /data/ext/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
@@ -2,6 +2,7 @@ use super::{
2
2
  bind_protocol::BindProtocol,
3
3
  tls::{configure_tls, ItsiTlsAcceptor},
4
4
  };
5
+ use crate::prelude::*;
5
6
  use itsi_error::ItsiError;
6
7
  use std::{
7
8
  collections::HashMap,
@@ -9,6 +10,8 @@ use std::{
9
10
  path::PathBuf,
10
11
  str::FromStr,
11
12
  };
13
+ use tracing::{instrument, Level};
14
+
12
15
  #[derive(Debug, Clone)]
13
16
  pub enum BindAddress {
14
17
  Ip(IpAddr),
@@ -27,16 +30,36 @@ pub struct Bind {
27
30
  pub address: BindAddress,
28
31
  pub port: Option<u16>, // None for Unix Sockets
29
32
  pub protocol: BindProtocol,
30
- pub tls_config: Option<ItsiTlsAcceptor>,
33
+ pub tls_config: Option<TlsOptions>,
34
+ }
35
+
36
+ #[derive(Default, Clone)]
37
+ pub struct TlsOptions {
38
+ pub host: String,
39
+ pub options: HashMap<String, String>,
40
+ }
41
+
42
+ impl TlsOptions {
43
+ pub fn build_acceptor(&self) -> Result<ItsiTlsAcceptor> {
44
+ configure_tls(&self.host, &self.options)
45
+ }
46
+ }
47
+
48
+ impl Bind {
49
+ pub fn listener_address_string(&self) -> String {
50
+ match &self.address {
51
+ BindAddress::Ip(ip) => format!("tcp://{}:{}", ip.to_canonical(), self.port.unwrap()),
52
+ BindAddress::UnixSocket(path) => {
53
+ format!("unix://{}", path.as_path().to_str().unwrap())
54
+ }
55
+ }
56
+ }
31
57
  }
32
58
 
33
59
  impl std::fmt::Debug for Bind {
34
60
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35
61
  match &self.address {
36
62
  BindAddress::Ip(ip) => match self.protocol {
37
- BindProtocol::Unix | BindProtocol::Unixs => {
38
- write!(f, "{}://{}", self.protocol, ip)
39
- }
40
63
  BindProtocol::Https if self.port == Some(443) => {
41
64
  write!(f, "{}://{}", self.protocol, ip)
42
65
  }
@@ -64,7 +87,8 @@ impl std::fmt::Debug for Bind {
64
87
  impl FromStr for Bind {
65
88
  type Err = ItsiError;
66
89
 
67
- fn from_str(s: &str) -> Result<Self, Self::Err> {
90
+ #[instrument(ret(level = Level::DEBUG))]
91
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
68
92
  let (protocol, remainder) = if let Some((proto, rest)) = s.split_once("://") {
69
93
  (proto.parse::<BindProtocol>()?, rest)
70
94
  } else {
@@ -100,7 +124,7 @@ impl FromStr for Bind {
100
124
  "IPv6 addresses must use [ ] when specifying a port".to_owned(),
101
125
  ));
102
126
  } else {
103
- (h, None) // Treat as a hostname
127
+ (h, p.parse::<u16>().ok()) // Treat as a hostname
104
128
  }
105
129
  } else {
106
130
  (url, None)
@@ -109,33 +133,43 @@ impl FromStr for Bind {
109
133
  let address = if let Ok(ip) = host.parse::<IpAddr>() {
110
134
  BindAddress::Ip(ip)
111
135
  } else {
112
- resolve_hostname(host)
113
- .map(BindAddress::Ip)
114
- .ok_or(ItsiError::ArgumentError(format!(
115
- "Failed to resolve hostname {}",
116
- host
117
- )))?
136
+ match protocol {
137
+ BindProtocol::Https | BindProtocol::Http => resolve_hostname(host)
138
+ .map(BindAddress::Ip)
139
+ .ok_or(ItsiError::ArgumentError(format!(
140
+ "Failed to resolve hostname {}",
141
+ host
142
+ )))?,
143
+ BindProtocol::Unix | BindProtocol::Unixs => BindAddress::UnixSocket(host.into()),
144
+ }
118
145
  };
119
- let (port, address) = match protocol {
120
- BindProtocol::Http => (port.or(Some(80)), address),
121
- BindProtocol::Https => (port.or(Some(443)), address),
122
- BindProtocol::Unix => (None, BindAddress::UnixSocket(host.into())),
123
- BindProtocol::Unixs => (None, BindAddress::UnixSocket(host.into())),
146
+
147
+ let port = match protocol {
148
+ BindProtocol::Http => port.or(Some(80)),
149
+ BindProtocol::Https => port.or(Some(443)),
150
+ BindProtocol::Unix => None,
151
+ BindProtocol::Unixs => None,
124
152
  };
125
153
 
126
154
  let tls_config = match protocol {
127
155
  BindProtocol::Http => None,
128
- BindProtocol::Https => Some(configure_tls(host, &options)?),
156
+ BindProtocol::Https => Some(TlsOptions {
157
+ host: host.to_owned(),
158
+ options,
159
+ }),
129
160
  BindProtocol::Unix => None,
130
- BindProtocol::Unixs => Some(configure_tls(host, &options)?),
161
+ BindProtocol::Unixs => Some(TlsOptions {
162
+ host: host.to_owned(),
163
+ options,
164
+ }),
131
165
  };
132
-
133
- Ok(Self {
166
+ let bind = Self {
134
167
  address,
135
168
  port,
136
169
  protocol,
137
170
  tls_config,
138
- })
171
+ };
172
+ Ok(bind)
139
173
  }
140
174
  }
141
175
 
@@ -148,13 +182,14 @@ fn parse_bind_options(query: &str) -> HashMap<String, String> {
148
182
  }
149
183
 
150
184
  /// Attempts to resolve a hostname into an IP address.
185
+ #[instrument(ret(level = Level::DEBUG))]
151
186
  fn resolve_hostname(hostname: &str) -> Option<IpAddr> {
152
187
  (hostname, 0)
153
188
  .to_socket_addrs()
154
189
  .ok()?
155
190
  .find_map(|addr| {
156
- if addr.is_ipv6() {
157
- Some(addr.ip()) // Prefer IPv6
191
+ if addr.is_ipv4() {
192
+ Some(addr.ip()) // Prefer IPv4
158
193
  } else {
159
194
  None
160
195
  }
@@ -0,0 +1,444 @@
1
+ use crate::prelude::*;
2
+ use crate::ruby_types::itsi_server::itsi_server_config::SocketOpts;
3
+ use crate::server::io_stream::IoStream;
4
+ use crate::server::serve_strategy::single_mode::RunningPhase;
5
+
6
+ use super::bind::{Bind, BindAddress};
7
+ use super::bind_protocol::BindProtocol;
8
+
9
+ use super::tls::ItsiTlsAcceptor;
10
+ use itsi_error::{ItsiError, Result};
11
+ use itsi_tracing::info;
12
+ use socket2::{Domain, Protocol, Socket, Type};
13
+ use std::fmt::Display;
14
+ use std::net::{IpAddr, SocketAddr, TcpListener};
15
+ use std::os::fd::{AsRawFd, FromRawFd, RawFd};
16
+ use std::sync::Arc;
17
+ use std::{os::unix::net::UnixListener, path::PathBuf};
18
+ use tokio::net::TcpListener as TokioTcpListener;
19
+ use tokio::net::UnixListener as TokioUnixListener;
20
+ use tokio::net::{unix, TcpStream, UnixStream};
21
+ use tokio::sync::watch::Receiver;
22
+ use tokio_rustls::TlsAcceptor;
23
+ use tokio_stream::StreamExt;
24
+
25
+ pub(crate) enum Listener {
26
+ Tcp(TcpListener),
27
+ TcpTls((TcpListener, ItsiTlsAcceptor)),
28
+ Unix(UnixListener),
29
+ UnixTls((UnixListener, ItsiTlsAcceptor)),
30
+ }
31
+
32
+ pub(crate) enum TokioListener {
33
+ Tcp(TokioTcpListener),
34
+ TcpTls(TokioTcpListener, ItsiTlsAcceptor),
35
+ Unix(TokioUnixListener),
36
+ UnixTls(TokioUnixListener, ItsiTlsAcceptor),
37
+ }
38
+
39
+ #[derive(Debug, Clone)]
40
+ pub struct ListenerInfo {
41
+ pub host: String,
42
+ pub port: u16,
43
+ pub scheme: String,
44
+ }
45
+
46
+ impl TokioListener {
47
+ pub fn listener_info(&self) -> ListenerInfo {
48
+ match self {
49
+ TokioListener::Tcp(listener) => ListenerInfo {
50
+ host: listener
51
+ .local_addr()
52
+ .unwrap()
53
+ .ip()
54
+ .to_canonical()
55
+ .to_string(),
56
+ port: listener.local_addr().unwrap().port(),
57
+ scheme: "http".to_string(),
58
+ },
59
+ TokioListener::TcpTls(listener, _) => ListenerInfo {
60
+ host: listener
61
+ .local_addr()
62
+ .unwrap()
63
+ .ip()
64
+ .to_canonical()
65
+ .to_string(),
66
+ port: listener.local_addr().unwrap().port(),
67
+ scheme: "https".to_string(),
68
+ },
69
+ TokioListener::Unix(listener) => ListenerInfo {
70
+ host: listener
71
+ .local_addr()
72
+ .unwrap()
73
+ .as_pathname()
74
+ .unwrap()
75
+ .to_str()
76
+ .unwrap()
77
+ .to_owned(),
78
+ port: 0,
79
+ scheme: "unix".to_string(),
80
+ },
81
+ TokioListener::UnixTls(listener, _) => ListenerInfo {
82
+ host: listener
83
+ .local_addr()
84
+ .unwrap()
85
+ .as_pathname()
86
+ .unwrap()
87
+ .to_str()
88
+ .unwrap()
89
+ .to_owned(),
90
+ port: 0,
91
+ scheme: "ssl".to_string(),
92
+ },
93
+ }
94
+ }
95
+
96
+ pub(crate) async fn accept(&self) -> Result<IoStream> {
97
+ match self {
98
+ TokioListener::Tcp(listener) => TokioListener::accept_tcp(listener).await,
99
+ TokioListener::TcpTls(listener, acceptor) => {
100
+ TokioListener::accept_tls(listener, acceptor).await
101
+ }
102
+ TokioListener::Unix(listener) => TokioListener::accept_unix(listener).await,
103
+ TokioListener::UnixTls(listener, acceptor) => {
104
+ TokioListener::accept_unix_tls(listener, acceptor).await
105
+ }
106
+ }
107
+ }
108
+
109
+ async fn accept_tcp(listener: &TokioTcpListener) -> Result<IoStream> {
110
+ let tcp_stream = listener.accept().await?;
111
+ Self::to_tokio_io(Stream::TcpStream(tcp_stream), None).await
112
+ }
113
+
114
+ pub async fn spawn_state_task(&self, mut shutdown_receiver: Receiver<RunningPhase>) {
115
+ if let TokioListener::TcpTls(
116
+ _,
117
+ ItsiTlsAcceptor::Automatic(_acme_acceptor, state, _server_config),
118
+ ) = self
119
+ {
120
+ let mut state = state.lock().await;
121
+ loop {
122
+ tokio::select! {
123
+ stream_event = StreamExt::next(&mut *state) => {
124
+ match stream_event {
125
+ Some(event) => info!("ACME Event: {:?}", event),
126
+ None => error!("Received no acme event"),
127
+ }
128
+ },
129
+ _ = shutdown_receiver.changed() => {
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+
137
+ async fn accept_tls(
138
+ listener: &TokioTcpListener,
139
+ acceptor: &ItsiTlsAcceptor,
140
+ ) -> Result<IoStream> {
141
+ let tcp_stream = listener.accept().await?;
142
+ match acceptor {
143
+ ItsiTlsAcceptor::Manual(tls_acceptor) => {
144
+ Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(tls_acceptor)).await
145
+ }
146
+ ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
147
+ let accept_future = acme_acceptor.accept(tcp_stream.0);
148
+ match accept_future.await {
149
+ Ok(None) => Err(ItsiError::Pass),
150
+ Ok(Some(start_handshake)) => {
151
+ let tls_stream = start_handshake.into_stream(rustls_config.clone()).await?;
152
+ Ok(IoStream::TcpTls {
153
+ stream: tls_stream,
154
+ addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
155
+ })
156
+ }
157
+ Err(error) => {
158
+ error!(error = format!("{:?}", error));
159
+ Err(ItsiError::Pass)
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ async fn accept_unix(listener: &TokioUnixListener) -> Result<IoStream> {
167
+ let unix_stream = listener.accept().await?;
168
+ Self::to_tokio_io(Stream::UnixStream(unix_stream), None).await
169
+ }
170
+
171
+ async fn accept_unix_tls(
172
+ listener: &TokioUnixListener,
173
+ acceptor: &ItsiTlsAcceptor,
174
+ ) -> Result<IoStream> {
175
+ let unix_stream = listener.accept().await?;
176
+ match acceptor {
177
+ ItsiTlsAcceptor::Manual(tls_acceptor) => {
178
+ Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(tls_acceptor)).await
179
+ }
180
+ ItsiTlsAcceptor::Automatic(_, _, _) => {
181
+ error!("Automatic TLS not supported on Unix sockets");
182
+ Err(ItsiError::UnsupportedProtocol(
183
+ "Automatic TLS on Unix Sockets".to_owned(),
184
+ ))
185
+ }
186
+ }
187
+ }
188
+
189
+ async fn to_tokio_io(
190
+ input_stream: Stream,
191
+ tls_acceptor: Option<&TlsAcceptor>,
192
+ ) -> Result<IoStream> {
193
+ match tls_acceptor {
194
+ Some(acceptor) => match input_stream {
195
+ Stream::TcpStream((tcp_stream, socket_address)) => {
196
+ match acceptor.accept(tcp_stream).await {
197
+ Ok(tls_stream) => Ok(IoStream::TcpTls {
198
+ stream: tls_stream,
199
+ addr: SockAddr::Tcp(Arc::new(socket_address)),
200
+ }),
201
+ Err(err) => Err(err.into()),
202
+ }
203
+ }
204
+ Stream::UnixStream((unix_stream, socket_address)) => {
205
+ match acceptor.accept(unix_stream).await {
206
+ Ok(tls_stream) => Ok(IoStream::UnixTls {
207
+ stream: tls_stream,
208
+ addr: SockAddr::Unix(Arc::new(socket_address)),
209
+ }),
210
+ Err(err) => Err(err.into()),
211
+ }
212
+ }
213
+ },
214
+ None => match input_stream {
215
+ Stream::TcpStream((tcp_stream, socket_address)) => Ok(IoStream::Tcp {
216
+ stream: tcp_stream,
217
+ addr: SockAddr::Tcp(Arc::new(socket_address)),
218
+ }),
219
+ Stream::UnixStream((unix_stream, socket_address)) => Ok(IoStream::Unix {
220
+ stream: unix_stream,
221
+ addr: SockAddr::Unix(Arc::new(socket_address)),
222
+ }),
223
+ },
224
+ }
225
+ }
226
+ }
227
+
228
+ enum Stream {
229
+ TcpStream((TcpStream, SocketAddr)),
230
+ UnixStream((UnixStream, unix::SocketAddr)),
231
+ }
232
+
233
+ #[derive(Clone, Debug)]
234
+ pub enum SockAddr {
235
+ Tcp(Arc<SocketAddr>),
236
+ Unix(Arc<unix::SocketAddr>),
237
+ }
238
+ impl std::fmt::Display for SockAddr {
239
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240
+ match self {
241
+ SockAddr::Tcp(socket_addr) => write!(f, "{}", socket_addr.ip().to_canonical()),
242
+ SockAddr::Unix(socket_addr) => match socket_addr.as_pathname() {
243
+ Some(path) => write!(f, "{:?}", path),
244
+ None => write!(f, ""),
245
+ },
246
+ }
247
+ }
248
+ }
249
+ impl Display for Listener {
250
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251
+ match self {
252
+ Listener::Tcp(listener) | Listener::TcpTls((listener, _)) => write!(
253
+ f,
254
+ "{}",
255
+ listener
256
+ .local_addr()
257
+ .map(|addr| addr.to_string())
258
+ .unwrap_or_else(|_| "".to_string())
259
+ ),
260
+
261
+ Listener::Unix(listener) | Listener::UnixTls((listener, _)) => write!(
262
+ f,
263
+ "{}",
264
+ listener
265
+ .local_addr()
266
+ .map(|addr| addr
267
+ .as_pathname()
268
+ .map(|path| path.to_str().unwrap_or("").to_owned())
269
+ .unwrap_or_default())
270
+ .unwrap_or_else(|_| "".to_string())
271
+ ),
272
+ }
273
+ }
274
+ }
275
+
276
+ impl Listener {
277
+ pub fn into_tokio_listener(self) -> TokioListener {
278
+ match self {
279
+ Listener::Tcp(listener) => {
280
+ TokioListener::Tcp(TokioTcpListener::from_std(listener).unwrap())
281
+ }
282
+ Listener::TcpTls((listener, acceptor)) => TokioListener::TcpTls(
283
+ TokioTcpListener::from_std(listener).unwrap(),
284
+ acceptor.clone(),
285
+ ),
286
+ Listener::Unix(listener) => {
287
+ TokioListener::Unix(TokioUnixListener::from_std(listener).unwrap())
288
+ }
289
+ Listener::UnixTls((listener, acceptor)) => TokioListener::UnixTls(
290
+ TokioUnixListener::from_std(listener).unwrap(),
291
+ acceptor.clone(),
292
+ ),
293
+ }
294
+ }
295
+
296
+ /// Handover information when using exec to hand over the listener to a replacement process.
297
+ pub fn handover(&self) -> Result<(String, i32)> {
298
+ match self {
299
+ Listener::Tcp(listener) => {
300
+ let addr = listener.local_addr()?;
301
+ Ok((
302
+ format!("tcp://{}:{}", addr.ip().to_canonical(), addr.port()),
303
+ listener.as_raw_fd(),
304
+ ))
305
+ }
306
+ Listener::TcpTls((listener, _)) => {
307
+ let addr = listener.local_addr()?;
308
+ Ok((
309
+ format!("tcp://{}:{}", addr.ip().to_canonical(), addr.port()),
310
+ listener.as_raw_fd(),
311
+ ))
312
+ }
313
+ Listener::Unix(listener) => {
314
+ let addr = listener.local_addr()?;
315
+ Ok((
316
+ format!("unix://{}", addr.as_pathname().unwrap().to_str().unwrap()),
317
+ listener.as_raw_fd(),
318
+ ))
319
+ }
320
+ Listener::UnixTls((listener, _)) => {
321
+ let addr = listener.local_addr()?;
322
+ Ok((
323
+ format!("unix://{}", addr.as_pathname().unwrap().to_str().unwrap()),
324
+ listener.as_raw_fd(),
325
+ ))
326
+ }
327
+ }
328
+ }
329
+
330
+ pub fn inherit_fd(bind: Bind, fd: RawFd, socket_opts: &SocketOpts) -> Result<Self> {
331
+ let bound = match bind.address {
332
+ BindAddress::Ip(_) => match bind.protocol {
333
+ BindProtocol::Http => Listener::Tcp(revive_tcp_socket(fd, socket_opts)?),
334
+ BindProtocol::Https => {
335
+ let tcp_listener = revive_tcp_socket(fd, socket_opts)?;
336
+ Listener::TcpTls((
337
+ tcp_listener,
338
+ bind.tls_config.unwrap().build_acceptor().unwrap(),
339
+ ))
340
+ }
341
+ _ => unreachable!(),
342
+ },
343
+ BindAddress::UnixSocket(_) => match bind.tls_config {
344
+ Some(tls_config) => Listener::UnixTls((
345
+ revive_unix_socket(fd, socket_opts)?,
346
+ tls_config.build_acceptor().unwrap(),
347
+ )),
348
+ None => Listener::Unix(revive_unix_socket(fd, socket_opts)?),
349
+ },
350
+ };
351
+ Ok(bound)
352
+ }
353
+ }
354
+
355
+ impl Listener {
356
+ pub fn build(bind: Bind, socket_opts: &SocketOpts) -> Result<Self> {
357
+ let bound = match bind.address {
358
+ BindAddress::Ip(addr) => match bind.protocol {
359
+ BindProtocol::Http => {
360
+ Listener::Tcp(connect_tcp_socket(addr, bind.port.unwrap(), socket_opts)?)
361
+ }
362
+ BindProtocol::Https => {
363
+ let tcp_listener = connect_tcp_socket(addr, bind.port.unwrap(), socket_opts)?;
364
+ Listener::TcpTls((
365
+ tcp_listener,
366
+ bind.tls_config.unwrap().build_acceptor().unwrap(),
367
+ ))
368
+ }
369
+ _ => unreachable!(),
370
+ },
371
+ BindAddress::UnixSocket(path) => match bind.tls_config {
372
+ Some(tls_config) => Listener::UnixTls((
373
+ connect_unix_socket(&path, socket_opts)?,
374
+ tls_config.build_acceptor().unwrap(),
375
+ )),
376
+ None => Listener::Unix(connect_unix_socket(&path, socket_opts)?),
377
+ },
378
+ };
379
+ Ok(bound)
380
+ }
381
+ }
382
+
383
+ fn revive_tcp_socket(fd: RawFd, socket_opts: &SocketOpts) -> Result<TcpListener> {
384
+ let socket = unsafe { Socket::from_raw_fd(fd) };
385
+ socket.set_reuse_port(socket_opts.reuse_port).ok();
386
+ socket.set_reuse_address(socket_opts.reuse_address).ok();
387
+ socket.set_nonblocking(true).ok();
388
+ socket.set_nodelay(socket_opts.nodelay).ok();
389
+ socket
390
+ .set_recv_buffer_size(socket_opts.recv_buffer_size)
391
+ .ok();
392
+ socket.set_cloexec(true)?;
393
+ socket.listen(socket_opts.listen_backlog as i32)?;
394
+ Ok(socket.into())
395
+ }
396
+
397
+ fn revive_unix_socket(fd: RawFd, socket_opts: &SocketOpts) -> Result<UnixListener> {
398
+ let socket = unsafe { Socket::from_raw_fd(fd) };
399
+ socket.set_nonblocking(true).ok();
400
+ socket.listen(socket_opts.listen_backlog as i32)?;
401
+ socket.set_cloexec(true)?;
402
+
403
+ Ok(socket.into())
404
+ }
405
+
406
+ fn connect_tcp_socket(addr: IpAddr, port: u16, socket_opts: &SocketOpts) -> Result<TcpListener> {
407
+ let domain = match addr {
408
+ IpAddr::V4(_) => Domain::IPV4,
409
+ IpAddr::V6(_) => Domain::IPV6,
410
+ };
411
+ let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
412
+ let socket_address: SocketAddr = SocketAddr::new(addr, port);
413
+ socket.set_reuse_address(socket_opts.reuse_address).ok();
414
+ socket.set_reuse_port(socket_opts.reuse_port).ok();
415
+ socket.set_nonblocking(true).ok();
416
+ socket.set_nodelay(socket_opts.nodelay).ok();
417
+ socket
418
+ .set_recv_buffer_size(socket_opts.recv_buffer_size)
419
+ .ok();
420
+ socket.set_only_v6(false).ok();
421
+ if let Err(e) = socket.bind(&socket_address.into()) {
422
+ error!("Failed to bind socket: {}", e);
423
+ };
424
+ if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
425
+ error!("Failed to listen on socket: {}", e);
426
+ };
427
+ Ok(socket.into())
428
+ }
429
+
430
+ fn connect_unix_socket(path: &PathBuf, socket_opts: &SocketOpts) -> Result<UnixListener> {
431
+ let _ = std::fs::remove_file(path);
432
+ let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
433
+ socket.set_nonblocking(true).ok();
434
+
435
+ let socket_address = socket2::SockAddr::unix(path)?;
436
+
437
+ if let Err(e) = socket.bind(&socket_address) {
438
+ error!("Failed to bind socket: {}", e);
439
+ };
440
+ if let Err(e) = socket.listen(socket_opts.listen_backlog as i32) {
441
+ error!("Failed to listen on socket: {}", e);
442
+ };
443
+ Ok(socket.into())
444
+ }
@@ -0,0 +1,4 @@
1
+ pub mod bind;
2
+ pub mod bind_protocol;
3
+ pub mod listener;
4
+ pub mod tls;