itsi-server 0.1.1 → 0.1.18

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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/CODE_OF_CONDUCT.md +7 -0
  4. data/Cargo.lock +3937 -0
  5. data/Cargo.toml +7 -0
  6. data/README.md +4 -0
  7. data/Rakefile +8 -1
  8. data/_index.md +6 -0
  9. data/exe/itsi +141 -46
  10. data/ext/itsi_error/Cargo.toml +3 -0
  11. data/ext/itsi_error/src/lib.rs +98 -24
  12. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  13. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  14. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  15. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  16. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  17. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  18. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  19. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  20. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  21. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  22. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  23. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  24. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  25. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  26. data/ext/itsi_instrument_entry/Cargo.toml +15 -0
  27. data/ext/itsi_instrument_entry/src/lib.rs +31 -0
  28. data/ext/itsi_rb_helpers/Cargo.toml +3 -0
  29. data/ext/itsi_rb_helpers/src/heap_value.rs +139 -0
  30. data/ext/itsi_rb_helpers/src/lib.rs +140 -10
  31. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  32. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  33. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  34. 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
  35. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  36. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  37. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  38. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  39. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  40. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  41. data/ext/itsi_scheduler/Cargo.toml +24 -0
  42. data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  43. data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  44. data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  45. data/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  46. data/ext/itsi_scheduler/src/lib.rs +38 -0
  47. data/ext/itsi_server/Cargo.lock +2956 -0
  48. data/ext/itsi_server/Cargo.toml +72 -14
  49. data/ext/itsi_server/extconf.rb +1 -1
  50. data/ext/itsi_server/src/default_responses/html/401.html +68 -0
  51. data/ext/itsi_server/src/default_responses/html/403.html +68 -0
  52. data/ext/itsi_server/src/default_responses/html/404.html +68 -0
  53. data/ext/itsi_server/src/default_responses/html/413.html +71 -0
  54. data/ext/itsi_server/src/default_responses/html/429.html +68 -0
  55. data/ext/itsi_server/src/default_responses/html/500.html +71 -0
  56. data/ext/itsi_server/src/default_responses/html/502.html +71 -0
  57. data/ext/itsi_server/src/default_responses/html/503.html +68 -0
  58. data/ext/itsi_server/src/default_responses/html/504.html +69 -0
  59. data/ext/itsi_server/src/default_responses/html/index.html +238 -0
  60. data/ext/itsi_server/src/default_responses/json/401.json +6 -0
  61. data/ext/itsi_server/src/default_responses/json/403.json +6 -0
  62. data/ext/itsi_server/src/default_responses/json/404.json +6 -0
  63. data/ext/itsi_server/src/default_responses/json/413.json +6 -0
  64. data/ext/itsi_server/src/default_responses/json/429.json +6 -0
  65. data/ext/itsi_server/src/default_responses/json/500.json +6 -0
  66. data/ext/itsi_server/src/default_responses/json/502.json +6 -0
  67. data/ext/itsi_server/src/default_responses/json/503.json +6 -0
  68. data/ext/itsi_server/src/default_responses/json/504.json +6 -0
  69. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  70. data/ext/itsi_server/src/env.rs +43 -0
  71. data/ext/itsi_server/src/lib.rs +132 -40
  72. data/ext/itsi_server/src/prelude.rs +2 -0
  73. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/big_bytes.rs +109 -0
  74. data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +143 -0
  75. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  76. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  77. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +345 -0
  78. data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +391 -0
  79. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
  80. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +375 -0
  81. data/ext/itsi_server/src/ruby_types/itsi_server.rs +83 -0
  82. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  83. data/ext/itsi_server/src/server/binds/bind.rs +201 -0
  84. data/ext/itsi_server/src/server/binds/bind_protocol.rs +37 -0
  85. data/ext/itsi_server/src/server/binds/listener.rs +432 -0
  86. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  87. data/ext/itsi_server/src/server/binds/tls/locked_dir_cache.rs +132 -0
  88. data/ext/itsi_server/src/server/binds/tls.rs +270 -0
  89. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  90. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  91. data/ext/itsi_server/src/server/io_stream.rs +105 -0
  92. data/ext/itsi_server/src/server/lifecycle_event.rs +12 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +165 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +56 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +87 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +86 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +285 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +142 -0
  99. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +289 -0
  100. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +292 -0
  101. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +55 -0
  102. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
  103. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +157 -0
  104. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +195 -0
  105. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  106. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +201 -0
  107. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  108. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  109. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +87 -0
  110. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +414 -0
  111. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +131 -0
  112. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  113. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +44 -0
  114. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +36 -0
  115. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  116. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +180 -0
  117. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  118. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +163 -0
  119. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  120. data/ext/itsi_server/src/server/middleware_stack/mod.rs +347 -0
  121. data/ext/itsi_server/src/server/mod.rs +12 -5
  122. data/ext/itsi_server/src/server/process_worker.rs +247 -0
  123. data/ext/itsi_server/src/server/request_job.rs +11 -0
  124. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +342 -0
  125. data/ext/itsi_server/src/server/serve_strategy/mod.rs +30 -0
  126. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +421 -0
  127. data/ext/itsi_server/src/server/signal.rs +76 -0
  128. data/ext/itsi_server/src/server/size_limited_incoming.rs +101 -0
  129. data/ext/itsi_server/src/server/thread_worker.rs +475 -0
  130. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  131. data/ext/itsi_server/src/services/itsi_http_service.rs +239 -0
  132. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  133. data/ext/itsi_server/src/services/mod.rs +6 -0
  134. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  135. data/ext/itsi_server/src/services/rate_limiter.rs +569 -0
  136. data/ext/itsi_server/src/services/static_file_server.rs +1324 -0
  137. data/ext/itsi_tracing/Cargo.toml +5 -0
  138. data/ext/itsi_tracing/src/lib.rs +315 -7
  139. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  140. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  141. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  142. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  143. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  144. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  145. data/lib/itsi/http_request/response_status_shortcodes.rb +74 -0
  146. data/lib/itsi/http_request.rb +186 -0
  147. data/lib/itsi/http_response.rb +41 -0
  148. data/lib/itsi/passfile.rb +109 -0
  149. data/lib/itsi/server/config/dsl.rb +565 -0
  150. data/lib/itsi/server/config.rb +166 -0
  151. data/lib/itsi/server/default_app/default_app.rb +34 -0
  152. data/lib/itsi/server/default_app/index.html +115 -0
  153. data/lib/itsi/server/default_config/Itsi-rackup.rb +119 -0
  154. data/lib/itsi/server/default_config/Itsi.rb +107 -0
  155. data/lib/itsi/server/grpc/grpc_call.rb +246 -0
  156. data/lib/itsi/server/grpc/grpc_interface.rb +100 -0
  157. data/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  158. data/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  159. data/lib/itsi/server/rack/handler/itsi.rb +27 -0
  160. data/lib/itsi/server/rack_interface.rb +94 -0
  161. data/lib/itsi/server/route_tester.rb +107 -0
  162. data/lib/itsi/server/scheduler_interface.rb +21 -0
  163. data/lib/itsi/server/scheduler_mode.rb +10 -0
  164. data/lib/itsi/server/signal_trap.rb +29 -0
  165. data/lib/itsi/server/typed_handlers/param_parser.rb +200 -0
  166. data/lib/itsi/server/typed_handlers/source_parser.rb +55 -0
  167. data/lib/itsi/server/typed_handlers.rb +17 -0
  168. data/lib/itsi/server/version.rb +1 -1
  169. data/lib/itsi/server.rb +160 -9
  170. data/lib/itsi/standard_headers.rb +86 -0
  171. data/lib/ruby_lsp/itsi/addon.rb +111 -0
  172. data/lib/shell_completions/completions.rb +26 -0
  173. metadata +182 -25
  174. data/ext/itsi_server/src/request/itsi_request.rs +0 -143
  175. data/ext/itsi_server/src/request/mod.rs +0 -1
  176. data/ext/itsi_server/src/server/bind.rs +0 -138
  177. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -32
  178. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -52
  179. data/ext/itsi_server/src/server/itsi_server.rs +0 -182
  180. data/ext/itsi_server/src/server/listener.rs +0 -218
  181. data/ext/itsi_server/src/server/tls.rs +0 -138
  182. data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  183. data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
  184. data/lib/itsi/request.rb +0 -39
@@ -0,0 +1,239 @@
1
+ use crate::default_responses::{NOT_FOUND_RESPONSE, TIMEOUT_RESPONSE};
2
+ use crate::ruby_types::itsi_server::itsi_server_config::ServerParams;
3
+ use crate::server::binds::listener::ListenerInfo;
4
+ use crate::server::http_message_types::{ConversionExt, HttpResponse, RequestExt, ResponseFormat};
5
+ use crate::server::lifecycle_event::LifecycleEvent;
6
+ use crate::server::middleware_stack::MiddlewareLayer;
7
+ use crate::server::request_job::RequestJob;
8
+ use crate::server::serve_strategy::single_mode::RunningPhase;
9
+ use crate::server::signal::send_lifecycle_event;
10
+ use chrono;
11
+ use chrono::Local;
12
+ use either::Either;
13
+ use http::header::ACCEPT_ENCODING;
14
+ use http::{HeaderValue, Request};
15
+ use hyper::body::Incoming;
16
+ use hyper::service::Service;
17
+ use itsi_error::ItsiError;
18
+ use regex::Regex;
19
+ use std::sync::atomic::{AtomicBool, Ordering};
20
+ use std::sync::OnceLock;
21
+
22
+ use std::{future::Future, ops::Deref, pin::Pin, sync::Arc};
23
+ use tokio::sync::watch::{self};
24
+ use tokio::time::timeout;
25
+
26
+ #[derive(Clone)]
27
+ pub struct ItsiHttpService {
28
+ pub inner: Arc<ItsiHttpServiceInner>,
29
+ }
30
+
31
+ impl Deref for ItsiHttpService {
32
+ type Target = Arc<ItsiHttpServiceInner>;
33
+
34
+ fn deref(&self) -> &Self::Target {
35
+ &self.inner
36
+ }
37
+ }
38
+
39
+ pub struct ItsiHttpServiceInner {
40
+ pub sender: async_channel::Sender<RequestJob>,
41
+ pub nonblocking_sender: async_channel::Sender<RequestJob>,
42
+ pub server_params: Arc<ServerParams>,
43
+ pub listener: Arc<ListenerInfo>,
44
+ pub addr: String,
45
+ pub shutdown_channel: watch::Receiver<RunningPhase>,
46
+ }
47
+
48
+ #[derive(Clone)]
49
+ pub struct HttpRequestContext {
50
+ inner: Arc<RequestContextInner>,
51
+ }
52
+
53
+ impl Deref for HttpRequestContext {
54
+ type Target = Arc<RequestContextInner>;
55
+
56
+ fn deref(&self) -> &Self::Target {
57
+ &self.inner
58
+ }
59
+ }
60
+
61
+ impl Deref for RequestContextInner {
62
+ type Target = ItsiHttpService;
63
+
64
+ fn deref(&self) -> &Self::Target {
65
+ &self.service
66
+ }
67
+ }
68
+
69
+ pub struct RequestContextInner {
70
+ pub request_id: u128,
71
+ pub service: ItsiHttpService,
72
+ pub accept: ResponseFormat,
73
+ pub matching_pattern: Option<Arc<Regex>>,
74
+ pub origin: OnceLock<Option<String>>,
75
+ pub response_format: OnceLock<ResponseFormat>,
76
+ pub start_time: chrono::DateTime<chrono::Utc>,
77
+ pub request: Option<Arc<Request<Incoming>>>,
78
+ pub request_start_time: OnceLock<chrono::DateTime<Local>>,
79
+ pub if_none_match: OnceLock<Option<String>>,
80
+ pub supported_encoding_set: Vec<HeaderValue>,
81
+ pub is_ruby_request: Arc<AtomicBool>,
82
+ }
83
+
84
+ impl HttpRequestContext {
85
+ fn new(
86
+ service: ItsiHttpService,
87
+ matching_pattern: Option<Arc<Regex>>,
88
+ accept: ResponseFormat,
89
+ supported_encoding_set: Vec<HeaderValue>,
90
+ is_ruby_request: Arc<AtomicBool>,
91
+ ) -> Self {
92
+ HttpRequestContext {
93
+ inner: Arc::new(RequestContextInner {
94
+ request_id: rand::random::<u128>(),
95
+ service,
96
+ matching_pattern,
97
+ accept,
98
+ origin: OnceLock::new(),
99
+ response_format: OnceLock::new(),
100
+ start_time: chrono::Utc::now(),
101
+ request: None,
102
+ request_start_time: OnceLock::new(),
103
+ if_none_match: OnceLock::new(),
104
+ supported_encoding_set,
105
+ is_ruby_request,
106
+ }),
107
+ }
108
+ }
109
+
110
+ pub fn set_origin(&self, origin: Option<String>) {
111
+ self.inner.origin.set(origin).unwrap();
112
+ }
113
+
114
+ pub fn set_if_none_match(&self, value: Option<String>) {
115
+ self.inner.if_none_match.set(value).unwrap();
116
+ }
117
+
118
+ pub fn get_if_none_match(&self) -> Option<String> {
119
+ self.inner.if_none_match.get().cloned().flatten()
120
+ }
121
+
122
+ pub fn short_request_id(&self) -> String {
123
+ format!("{:016x}", self.inner.request_id & 0xffff_ffff_ffff_ffff)
124
+ }
125
+
126
+ pub fn request_id(&self) -> String {
127
+ format!("{:016x}", self.inner.request_id)
128
+ }
129
+
130
+ pub fn track_start_time(&self) {
131
+ self.inner
132
+ .request_start_time
133
+ .get_or_init(chrono::Local::now);
134
+ }
135
+
136
+ pub fn start_time(&self) -> Option<chrono::DateTime<Local>> {
137
+ self.inner.request_start_time.get().cloned()
138
+ }
139
+
140
+ pub fn get_response_time(&self) -> Option<chrono::TimeDelta> {
141
+ self.inner
142
+ .request_start_time
143
+ .get()
144
+ .map(|instant| Local::now() - instant)
145
+ }
146
+
147
+ pub fn set_response_format(&self, format: ResponseFormat) {
148
+ self.inner.response_format.set(format).unwrap()
149
+ }
150
+
151
+ pub fn response_format(&self) -> &ResponseFormat {
152
+ self.inner.response_format.get().unwrap()
153
+ }
154
+ }
155
+
156
+ impl Service<Request<Incoming>> for ItsiHttpService {
157
+ type Response = HttpResponse;
158
+ type Error = ItsiError;
159
+ type Future = Pin<Box<dyn Future<Output = itsi_error::Result<HttpResponse>> + Send>>;
160
+
161
+ fn call(&self, req: Request<Incoming>) -> Self::Future {
162
+ let params = self.server_params.clone();
163
+ let self_clone = self.clone();
164
+ let mut req = req.limit();
165
+ let accept: ResponseFormat = req.accept().into();
166
+ let accept_clone = accept.clone();
167
+ let is_single_mode = self.server_params.workers == 1;
168
+ let supported_encoding_set = req
169
+ .headers()
170
+ .get_all(ACCEPT_ENCODING)
171
+ .into_iter()
172
+ .cloned()
173
+ .collect::<Vec<_>>();
174
+ let request_timeout = self.server_params.request_timeout;
175
+ let is_ruby_request = Arc::new(AtomicBool::new(false));
176
+ let irr_clone = is_ruby_request.clone();
177
+ let service_future = async move {
178
+ let mut resp: Option<HttpResponse> = None;
179
+ let (stack, matching_pattern) = params.middleware.get().unwrap().stack_for(&req)?;
180
+
181
+ let mut context = HttpRequestContext::new(
182
+ self_clone,
183
+ matching_pattern,
184
+ accept_clone.clone(),
185
+ supported_encoding_set,
186
+ irr_clone,
187
+ );
188
+ let mut depth = 0;
189
+
190
+ for (index, elm) in stack.iter().enumerate() {
191
+ match elm.before(req, &mut context).await {
192
+ Ok(Either::Left(r)) => req = r,
193
+ Ok(Either::Right(r)) => {
194
+ resp = Some(r);
195
+ depth = index;
196
+ break;
197
+ }
198
+ Err(e) => return Err(e.into()),
199
+ }
200
+ }
201
+
202
+ let mut resp = match resp {
203
+ Some(r) => r,
204
+ None => return Ok(NOT_FOUND_RESPONSE.to_http_response(accept_clone).await),
205
+ };
206
+
207
+ for elm in stack.iter().rev().skip(stack.len() - depth - 1) {
208
+ resp = elm.after(resp, &mut context).await;
209
+ }
210
+
211
+ Ok(resp)
212
+ };
213
+
214
+ Box::pin(async move {
215
+ if let Some(timeout_duration) = request_timeout {
216
+ match timeout(timeout_duration, service_future).await {
217
+ Ok(result) => result,
218
+ Err(_) => {
219
+ // If we're still running Ruby at this point, we can't just kill the
220
+ // thread as it might be in a critical section.
221
+ // Instead we must ask the worker to hot restart.
222
+ if is_ruby_request.load(Ordering::Relaxed) {
223
+ if is_single_mode {
224
+ // If we're in single mode, re-exec the whole process
225
+ send_lifecycle_event(LifecycleEvent::Restart);
226
+ } else {
227
+ // Otherwise we can shutdown the worker and rely on the master to restart it
228
+ send_lifecycle_event(LifecycleEvent::Shutdown);
229
+ }
230
+ }
231
+ Ok(TIMEOUT_RESPONSE.to_http_response(accept).await)
232
+ }
233
+ }
234
+ } else {
235
+ service_future.await
236
+ }
237
+ })
238
+ }
239
+ }