itsi-scheduler 0.1.11 → 0.1.12
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/CODE_OF_CONDUCT.md +7 -0
- data/Cargo.lock +75 -14
- data/README.md +5 -0
- data/_index.md +7 -0
- data/ext/itsi_error/src/lib.rs +9 -0
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
- data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
- data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
- data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
- data/ext/itsi_rb_helpers/Cargo.toml +1 -0
- data/ext/itsi_rb_helpers/src/heap_value.rs +18 -0
- data/ext/itsi_rb_helpers/src/lib.rs +34 -7
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
- data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
- 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
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
- data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
- data/ext/itsi_server/Cargo.toml +69 -30
- data/ext/itsi_server/src/lib.rs +79 -147
- data/ext/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
- data/ext/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +22 -3
- data/ext/itsi_server/src/ruby_types/itsi_grpc_request.rs +147 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_response.rs +19 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_stream/mod.rs +216 -0
- data/ext/itsi_server/src/{request/itsi_request.rs → ruby_types/itsi_http_request.rs} +101 -117
- data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +72 -41
- data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
- data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +355 -0
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +82 -0
- data/ext/itsi_server/src/ruby_types/mod.rs +55 -0
- data/ext/itsi_server/src/server/bind.rs +13 -5
- data/ext/itsi_server/src/server/byte_frame.rs +32 -0
- data/ext/itsi_server/src/server/cache_store.rs +74 -0
- data/ext/itsi_server/src/server/itsi_service.rs +172 -0
- data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
- data/ext/itsi_server/src/server/listener.rs +102 -2
- data/ext/itsi_server/src/server/middleware_stack/middleware.rs +153 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +47 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +58 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +321 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +139 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +300 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +287 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +48 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +127 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +191 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +72 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +85 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +195 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +216 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +124 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +43 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +34 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +93 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +162 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +158 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
- data/ext/itsi_server/src/server/middleware_stack/mod.rs +315 -0
- data/ext/itsi_server/src/server/mod.rs +8 -1
- data/ext/itsi_server/src/server/process_worker.rs +38 -12
- data/ext/itsi_server/src/server/rate_limiter.rs +565 -0
- data/ext/itsi_server/src/server/request_job.rs +11 -0
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +119 -42
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +256 -111
- data/ext/itsi_server/src/server/signal.rs +19 -0
- data/ext/itsi_server/src/server/static_file_server.rs +984 -0
- data/ext/itsi_server/src/server/thread_worker.rs +139 -94
- data/ext/itsi_server/src/server/types.rs +43 -0
- data/ext/itsi_tracing/Cargo.toml +1 -0
- data/ext/itsi_tracing/src/lib.rs +216 -45
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
- data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
- data/lib/itsi/scheduler/version.rb +1 -1
- data/lib/itsi/scheduler.rb +2 -2
- metadata +77 -12
- data/ext/itsi_server/extconf.rb +0 -6
- data/ext/itsi_server/src/body_proxy/mod.rs +0 -2
- data/ext/itsi_server/src/request/mod.rs +0 -1
- data/ext/itsi_server/src/response/mod.rs +0 -1
- data/ext/itsi_server/src/server/itsi_server.rs +0 -288
@@ -0,0 +1,315 @@
|
|
1
|
+
mod middleware;
|
2
|
+
mod middlewares;
|
3
|
+
use super::types::HttpRequest;
|
4
|
+
use http::header::{ACCEPT, CONTENT_TYPE, HOST};
|
5
|
+
use itsi_rb_helpers::HeapVal;
|
6
|
+
use magnus::{error::Result, value::ReprValue, RArray, RHash, Ruby, TryConvert, Value};
|
7
|
+
pub use middleware::Middleware;
|
8
|
+
pub use middlewares::*;
|
9
|
+
use regex::{Regex, RegexSet};
|
10
|
+
use std::{collections::HashMap, sync::Arc};
|
11
|
+
use tracing::info;
|
12
|
+
|
13
|
+
#[derive(Debug)]
|
14
|
+
pub struct MiddlewareSet {
|
15
|
+
pub route_set: RegexSet,
|
16
|
+
pub patterns: Vec<Arc<Regex>>,
|
17
|
+
pub stacks: HashMap<usize, MiddlewareStack>,
|
18
|
+
pub default_stack: Vec<Middleware>,
|
19
|
+
}
|
20
|
+
|
21
|
+
#[derive(Debug)]
|
22
|
+
pub struct MiddlewareStack {
|
23
|
+
layers: Vec<Middleware>,
|
24
|
+
methods: Option<Vec<StringMatch>>,
|
25
|
+
protocols: Option<Vec<StringMatch>>,
|
26
|
+
hosts: Option<Vec<StringMatch>>,
|
27
|
+
extensions: Option<Vec<StringMatch>>,
|
28
|
+
ports: Option<Vec<StringMatch>>,
|
29
|
+
content_types: Option<Vec<StringMatch>>,
|
30
|
+
accepts: Option<Vec<StringMatch>>,
|
31
|
+
}
|
32
|
+
|
33
|
+
#[derive(Debug)]
|
34
|
+
enum StringMatch {
|
35
|
+
Exact(String),
|
36
|
+
Wildcard(Regex),
|
37
|
+
}
|
38
|
+
|
39
|
+
impl StringMatch {
|
40
|
+
fn from_value(value: Value) -> Result<Self> {
|
41
|
+
let ruby = Ruby::get().unwrap();
|
42
|
+
if value.is_kind_of(ruby.class_regexp()) {
|
43
|
+
let src_str = value.funcall::<_, _, String>("source", ())?;
|
44
|
+
let regex = Regex::new(&src_str).map_err(|e| {
|
45
|
+
magnus::Error::new(
|
46
|
+
magnus::exception::exception(),
|
47
|
+
format!("Invalid regexp: {}", e),
|
48
|
+
)
|
49
|
+
})?;
|
50
|
+
Ok(StringMatch::Wildcard(regex))
|
51
|
+
} else {
|
52
|
+
Ok(StringMatch::Exact(value.to_string()))
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
fn matches(&self, value: &str) -> bool {
|
57
|
+
match self {
|
58
|
+
StringMatch::Exact(s) => s.eq_ignore_ascii_case(value),
|
59
|
+
StringMatch::Wildcard(re) => re.is_match(value),
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
impl MiddlewareStack {
|
65
|
+
pub fn matches(&self, request: &HttpRequest) -> bool {
|
66
|
+
if let Some(methods) = &self.methods {
|
67
|
+
let method = request.method().as_str();
|
68
|
+
if !methods.iter().any(|m| m.matches(method)) {
|
69
|
+
return false;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
if let (Some(protocols), Some(protocol)) = (&self.protocols, request.uri().scheme()) {
|
74
|
+
if !protocols.iter().any(|p| p.matches(protocol.as_str())) {
|
75
|
+
return false;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
if let (Some(hosts), Some(host)) = (&self.hosts, request.headers().get(HOST)) {
|
80
|
+
if let Ok(host) = host.to_str() {
|
81
|
+
if !hosts.iter().any(|d| d.matches(host)) {
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
if let (Some(ports), Some(port)) = (&self.ports, request.uri().port()) {
|
88
|
+
if !ports.iter().any(|d| d.matches(port.as_str())) {
|
89
|
+
info!("No match between port {} and {:?}", port, ports);
|
90
|
+
return false;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
if let Some(extensions) = &self.extensions {
|
95
|
+
let extension = request.uri().path().split('.').next_back().unwrap_or("");
|
96
|
+
if !extensions.iter().any(|e| e.matches(extension)) {
|
97
|
+
return false;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
if let Some(content_types) = &self.content_types {
|
102
|
+
if let Some(content_type) = request.headers().get(CONTENT_TYPE) {
|
103
|
+
if !content_types
|
104
|
+
.iter()
|
105
|
+
.any(|ct| ct.matches(content_type.to_str().unwrap_or("")))
|
106
|
+
{
|
107
|
+
return false;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
if let Some(accepts) = &self.accepts {
|
113
|
+
if let Some(accept) = request.headers().get(ACCEPT) {
|
114
|
+
if !accepts
|
115
|
+
.iter()
|
116
|
+
.any(|a| a.matches(accept.to_str().unwrap_or("")))
|
117
|
+
{
|
118
|
+
return false;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
true
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
impl MiddlewareSet {
|
128
|
+
pub fn new(routes_raw: Option<HeapVal>, default_app: HeapVal) -> Result<Self> {
|
129
|
+
if let Some(routes_raw) = routes_raw {
|
130
|
+
let mut stacks = HashMap::new();
|
131
|
+
let mut routes = vec![];
|
132
|
+
for (index, route) in RArray::from_value(*routes_raw)
|
133
|
+
.ok_or(magnus::Error::new(
|
134
|
+
magnus::exception::exception(),
|
135
|
+
format!("Routes must be an array. Got {:?}", routes_raw),
|
136
|
+
))?
|
137
|
+
.into_iter()
|
138
|
+
.enumerate()
|
139
|
+
{
|
140
|
+
let route_hash: RHash = RHash::try_convert(route)?;
|
141
|
+
let route_raw = route_hash
|
142
|
+
.get("route")
|
143
|
+
.ok_or(magnus::Error::new(
|
144
|
+
magnus::exception::exception(),
|
145
|
+
"Route is missing :route key",
|
146
|
+
))?
|
147
|
+
.funcall::<_, _, String>("source", ())?;
|
148
|
+
let middleware =
|
149
|
+
RArray::from_value(route_hash.get("middleware").ok_or(magnus::Error::new(
|
150
|
+
magnus::exception::exception(),
|
151
|
+
"Route is missing middleware key",
|
152
|
+
))?)
|
153
|
+
.ok_or(magnus::Error::new(
|
154
|
+
magnus::exception::exception(),
|
155
|
+
format!("middleware must be an array. Got {:?}", routes_raw),
|
156
|
+
))?;
|
157
|
+
|
158
|
+
let mut layers = middleware
|
159
|
+
.into_iter()
|
160
|
+
.map(MiddlewareSet::parse_middleware)
|
161
|
+
.collect::<Result<Vec<_>>>()?;
|
162
|
+
layers.push(Middleware::RubyApp(RubyApp::from_value(
|
163
|
+
default_app.clone(),
|
164
|
+
)?));
|
165
|
+
routes.push(route_raw);
|
166
|
+
layers.sort();
|
167
|
+
stacks.insert(
|
168
|
+
index,
|
169
|
+
MiddlewareStack {
|
170
|
+
layers,
|
171
|
+
methods: extract_optional_match_array(route_hash, "methods")?,
|
172
|
+
protocols: extract_optional_match_array(route_hash, "protocols")?,
|
173
|
+
hosts: extract_optional_match_array(route_hash, "hosts")?,
|
174
|
+
extensions: extract_optional_match_array(route_hash, "extensions")?,
|
175
|
+
ports: extract_optional_match_array(route_hash, "ports")?,
|
176
|
+
content_types: extract_optional_match_array(route_hash, "content_types")?,
|
177
|
+
accepts: extract_optional_match_array(route_hash, "accepts")?,
|
178
|
+
},
|
179
|
+
);
|
180
|
+
}
|
181
|
+
info!("Routes are {:?}", routes);
|
182
|
+
Ok(Self {
|
183
|
+
route_set: RegexSet::new(&routes).map_err(|e| {
|
184
|
+
magnus::Error::new(
|
185
|
+
magnus::exception::exception(),
|
186
|
+
format!("Failed to create route set: {}", e),
|
187
|
+
)
|
188
|
+
})?,
|
189
|
+
patterns: routes
|
190
|
+
.into_iter()
|
191
|
+
.map(|r| Regex::new(&r))
|
192
|
+
.collect::<std::result::Result<Vec<Regex>, regex::Error>>()
|
193
|
+
.map_err(|e| {
|
194
|
+
magnus::Error::new(
|
195
|
+
magnus::exception::exception(),
|
196
|
+
format!("Failed to create route set: {}", e),
|
197
|
+
)
|
198
|
+
})?
|
199
|
+
.into_iter()
|
200
|
+
.map(Arc::new)
|
201
|
+
.collect(),
|
202
|
+
stacks,
|
203
|
+
default_stack: vec![Middleware::RubyApp(RubyApp::from_value(default_app)?)],
|
204
|
+
})
|
205
|
+
} else {
|
206
|
+
Ok(Self {
|
207
|
+
route_set: RegexSet::empty(),
|
208
|
+
patterns: Vec::new(),
|
209
|
+
stacks: HashMap::new(),
|
210
|
+
default_stack: vec![Middleware::RubyApp(RubyApp::from_value(default_app)?)],
|
211
|
+
})
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
pub fn stack_for(&self, request: &HttpRequest) -> (&Vec<Middleware>, Option<Arc<Regex>>) {
|
216
|
+
let binding = self.route_set.matches(request.uri().path());
|
217
|
+
let matches = binding.iter();
|
218
|
+
for index in matches {
|
219
|
+
let matching_pattern = self.patterns.get(index).cloned();
|
220
|
+
if let Some(stack) = self.stacks.get(&index) {
|
221
|
+
if stack.matches(request) {
|
222
|
+
return (&stack.layers, matching_pattern);
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
(self.default_stack(), None)
|
227
|
+
}
|
228
|
+
|
229
|
+
pub fn parse_middleware(middleware: Value) -> Result<Middleware> {
|
230
|
+
let middleware_hash = RHash::from_value(middleware).ok_or(magnus::Error::new(
|
231
|
+
magnus::exception::exception(),
|
232
|
+
format!("Filter must be a hash. Got {:?}", middleware),
|
233
|
+
))?;
|
234
|
+
let middleware_type: String = middleware_hash
|
235
|
+
.get("type")
|
236
|
+
.ok_or(magnus::Error::new(
|
237
|
+
magnus::exception::exception(),
|
238
|
+
format!("Filter must have a :type key. Got {:?}", middleware_hash),
|
239
|
+
))?
|
240
|
+
.to_string();
|
241
|
+
|
242
|
+
let parameters: Value = middleware_hash.get("parameters").ok_or(magnus::Error::new(
|
243
|
+
magnus::exception::exception(),
|
244
|
+
format!(
|
245
|
+
"Filter must have a :parameters key. Got {:?}",
|
246
|
+
middleware_hash
|
247
|
+
),
|
248
|
+
))?;
|
249
|
+
|
250
|
+
let result = match middleware_type.as_str() {
|
251
|
+
"allow_list" => Middleware::AllowList(AllowList::from_value(parameters)?),
|
252
|
+
"auth_basic" => Middleware::AuthBasic(AuthBasic::from_value(parameters)?),
|
253
|
+
"auth_jwt" => Middleware::AuthJwt(Box::new(AuthJwt::from_value(parameters)?)),
|
254
|
+
"auth_api_key" => Middleware::AuthAPIKey(AuthAPIKey::from_value(parameters)?),
|
255
|
+
"cache_control" => Middleware::CacheControl(CacheControl::from_value(parameters)?),
|
256
|
+
"deny_list" => Middleware::DenyList(DenyList::from_value(parameters)?),
|
257
|
+
"etag" => Middleware::ETag(ETag::from_value(parameters)?),
|
258
|
+
"intrusion_protection" => {
|
259
|
+
Middleware::IntrusionProtection(IntrusionProtection::from_value(parameters)?)
|
260
|
+
}
|
261
|
+
"rate_limit" => Middleware::RateLimit(RateLimit::from_value(parameters)?),
|
262
|
+
"cors" => Middleware::Cors(Box::new(Cors::from_value(parameters)?)),
|
263
|
+
"request_headers" => {
|
264
|
+
Middleware::RequestHeaders(RequestHeaders::from_value(parameters)?)
|
265
|
+
}
|
266
|
+
"response_headers" => {
|
267
|
+
Middleware::ResponseHeaders(ResponseHeaders::from_value(parameters)?)
|
268
|
+
}
|
269
|
+
"static_assets" => Middleware::StaticAssets(StaticAssets::from_value(parameters)?),
|
270
|
+
"compression" => Middleware::Compression(Compression::from_value(parameters)?),
|
271
|
+
"log_requests" => Middleware::LogRequests(LogRequests::from_value(parameters)?),
|
272
|
+
"redirect" => Middleware::Redirect(Redirect::from_value(parameters)?),
|
273
|
+
"app" => Middleware::RubyApp(RubyApp::from_value(parameters.into())?),
|
274
|
+
"proxy" => Middleware::Proxy(Proxy::from_value(parameters)?),
|
275
|
+
_ => {
|
276
|
+
return Err(magnus::Error::new(
|
277
|
+
magnus::exception::exception(),
|
278
|
+
format!("Unknown filter type: {}", middleware_type),
|
279
|
+
))
|
280
|
+
}
|
281
|
+
};
|
282
|
+
|
283
|
+
Ok(result)
|
284
|
+
}
|
285
|
+
|
286
|
+
fn default_stack(&self) -> &Vec<Middleware> {
|
287
|
+
&self.default_stack
|
288
|
+
}
|
289
|
+
|
290
|
+
pub async fn initialize_layers(&self) -> Result<()> {
|
291
|
+
for middleware in &self.default_stack {
|
292
|
+
middleware.initialize().await?;
|
293
|
+
}
|
294
|
+
for stack in self.stacks.values() {
|
295
|
+
for middleware in &stack.layers {
|
296
|
+
middleware.initialize().await?;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
Ok(())
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
fn extract_optional_match_array(route_hash: RHash, arg: &str) -> Result<Option<Vec<StringMatch>>> {
|
304
|
+
let rarray = route_hash.aref::<_, Option<RArray>>(arg)?;
|
305
|
+
if let Some(array) = rarray {
|
306
|
+
Ok(Some(
|
307
|
+
array
|
308
|
+
.into_iter()
|
309
|
+
.map(StringMatch::from_value)
|
310
|
+
.collect::<Result<Vec<StringMatch>>>()?,
|
311
|
+
))
|
312
|
+
} else {
|
313
|
+
Ok(None)
|
314
|
+
}
|
315
|
+
}
|
@@ -1,11 +1,18 @@
|
|
1
1
|
pub mod bind;
|
2
2
|
pub mod bind_protocol;
|
3
|
+
pub mod byte_frame;
|
4
|
+
pub mod cache_store;
|
3
5
|
pub mod io_stream;
|
4
|
-
pub mod
|
6
|
+
pub mod itsi_service;
|
5
7
|
pub mod lifecycle_event;
|
6
8
|
pub mod listener;
|
9
|
+
pub mod middleware_stack;
|
7
10
|
pub mod process_worker;
|
11
|
+
pub mod rate_limiter;
|
12
|
+
pub mod request_job;
|
8
13
|
pub mod serve_strategy;
|
9
14
|
pub mod signal;
|
15
|
+
pub mod static_file_server;
|
10
16
|
pub mod thread_worker;
|
11
17
|
pub mod tls;
|
18
|
+
pub mod types;
|
@@ -7,7 +7,7 @@ use nix::{
|
|
7
7
|
sys::{
|
8
8
|
signal::{
|
9
9
|
kill,
|
10
|
-
Signal::{SIGKILL, SIGTERM},
|
10
|
+
Signal::{SIGINFO, SIGKILL, SIGTERM},
|
11
11
|
},
|
12
12
|
wait::{waitpid, WaitPidFlag, WaitStatus},
|
13
13
|
},
|
@@ -53,8 +53,18 @@ impl ProcessWorker {
|
|
53
53
|
}
|
54
54
|
*self.child_pid.lock() = None;
|
55
55
|
}
|
56
|
-
|
57
|
-
{
|
56
|
+
|
57
|
+
match call_with_gvl(|_ruby| {
|
58
|
+
fork(
|
59
|
+
cluster_template
|
60
|
+
.server_config
|
61
|
+
.server_params
|
62
|
+
.read()
|
63
|
+
.hooks
|
64
|
+
.get("after_fork")
|
65
|
+
.cloned(),
|
66
|
+
)
|
67
|
+
}) {
|
58
68
|
Some(pid) => {
|
59
69
|
*self.child_pid.lock() = Some(Pid::from_raw(pid));
|
60
70
|
}
|
@@ -65,11 +75,7 @@ impl ProcessWorker {
|
|
65
75
|
) {
|
66
76
|
error!("Failed to set process group ID: {}", e);
|
67
77
|
}
|
68
|
-
match SingleMode::new(
|
69
|
-
cluster_template.server.clone(),
|
70
|
-
cluster_template.listeners.lock().drain(..).collect(),
|
71
|
-
cluster_template.lifecycle_channel.clone(),
|
72
|
-
) {
|
78
|
+
match SingleMode::new(cluster_template.server_config.clone()) {
|
73
79
|
Ok(single_mode) => {
|
74
80
|
Arc::new(single_mode).run().ok();
|
75
81
|
}
|
@@ -129,8 +135,14 @@ impl ProcessWorker {
|
|
129
135
|
pub(crate) async fn graceful_shutdown(&self, cluster_template: Arc<ClusterMode>) {
|
130
136
|
let self_clone = self.clone();
|
131
137
|
self_clone.request_shutdown();
|
132
|
-
let force_kill_time =
|
133
|
-
|
138
|
+
let force_kill_time = Instant::now()
|
139
|
+
+ Duration::from_secs_f64(
|
140
|
+
cluster_template
|
141
|
+
.server_config
|
142
|
+
.server_params
|
143
|
+
.read()
|
144
|
+
.shutdown_timeout,
|
145
|
+
);
|
134
146
|
while self_clone.is_alive() && force_kill_time > Instant::now() {
|
135
147
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
136
148
|
}
|
@@ -171,10 +183,24 @@ impl ProcessWorker {
|
|
171
183
|
pub(crate) fn force_kill(&self) {
|
172
184
|
let child_pid = *self.child_pid.lock();
|
173
185
|
if let Some(pid) = child_pid {
|
174
|
-
if
|
175
|
-
|
186
|
+
if self.is_alive() {
|
187
|
+
if let Err(e) = kill(pid, SIGKILL) {
|
188
|
+
error!("Failed to force kill process {}: {}", pid, e);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
pub fn print_info(&self) -> Result<()> {
|
195
|
+
let child_pid = *self.child_pid.lock();
|
196
|
+
if let Some(pid) = child_pid {
|
197
|
+
println!("Worker {:?}, PID: {:?}", self.worker_id, pid);
|
198
|
+
if let Err(e) = kill(pid, SIGINFO) {
|
199
|
+
error!("Failed to send SIGINFO to process {}: {}", pid, e);
|
176
200
|
}
|
177
201
|
}
|
202
|
+
|
203
|
+
Ok(())
|
178
204
|
}
|
179
205
|
|
180
206
|
pub(crate) fn just_started(&self) -> bool {
|