itsi-scheduler 0.1.5 → 0.1.19
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.
Potentially problematic release.
This version of itsi-scheduler might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +7 -0
- data/Cargo.lock +90 -22
- data/README.md +5 -0
- data/_index.md +7 -0
- data/ext/itsi_error/Cargo.toml +1 -0
- data/ext/itsi_error/src/lib.rs +106 -7
- 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 +59 -9
- 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_scheduler/src/itsi_scheduler.rs +1 -1
- data/ext/itsi_server/Cargo.lock +2956 -0
- data/ext/itsi_server/Cargo.toml +72 -28
- data/ext/itsi_server/src/default_responses/mod.rs +11 -0
- data/ext/itsi_server/src/env.rs +43 -0
- data/ext/itsi_server/src/lib.rs +113 -75
- data/ext/itsi_server/src/prelude.rs +2 -0
- 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} +29 -8
- data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
- data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +345 -0
- data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +84 -40
- 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 +375 -0
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +83 -0
- data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
- data/ext/itsi_server/src/server/{bind.rs → binds/bind.rs} +56 -24
- data/ext/itsi_server/src/server/{listener.rs → binds/listener.rs} +218 -113
- data/ext/itsi_server/src/server/binds/mod.rs +4 -0
- data/ext/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +55 -17
- data/ext/itsi_server/src/server/{tls.rs → binds/tls.rs} +109 -28
- data/ext/itsi_server/src/server/byte_frame.rs +32 -0
- data/ext/itsi_server/src/server/http_message_types.rs +97 -0
- data/ext/itsi_server/src/server/io_stream.rs +2 -1
- data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
- data/ext/itsi_server/src/server/middleware_stack/middleware.rs +165 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +56 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +87 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +86 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +285 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +142 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +289 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +292 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +55 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +157 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +195 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +201 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +87 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +414 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +131 -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 +44 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +36 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +180 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
- data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +163 -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 +347 -0
- data/ext/itsi_server/src/server/mod.rs +6 -5
- data/ext/itsi_server/src/server/process_worker.rs +65 -14
- data/ext/itsi_server/src/server/request_job.rs +11 -0
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +137 -49
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +338 -164
- data/ext/itsi_server/src/server/signal.rs +32 -26
- data/ext/itsi_server/src/server/size_limited_incoming.rs +101 -0
- data/ext/itsi_server/src/server/thread_worker.rs +214 -107
- data/ext/itsi_server/src/services/cache_store.rs +74 -0
- data/ext/itsi_server/src/services/itsi_http_service.rs +239 -0
- data/ext/itsi_server/src/services/mime_types.rs +1416 -0
- data/ext/itsi_server/src/services/mod.rs +6 -0
- data/ext/itsi_server/src/services/password_hasher.rs +83 -0
- data/ext/itsi_server/src/services/rate_limiter.rs +569 -0
- data/ext/itsi_server/src/services/static_file_server.rs +1324 -0
- data/ext/itsi_tracing/Cargo.toml +1 -0
- data/ext/itsi_tracing/src/lib.rs +312 -34
- 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 +93 -21
- data/ext/itsi_error/src/from.rs +0 -71
- 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/itsi_request.rs +0 -277
- 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_ca/itsi_ca.crt +0 -13
- data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
- data/ext/itsi_server/src/server/itsi_server.rs +0 -244
- /data/ext/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
use async_trait::async_trait;
|
2
|
+
use redis::aio::ConnectionManager;
|
3
|
+
use redis::{Client, RedisError, Script};
|
4
|
+
use std::sync::Arc;
|
5
|
+
use std::time::Duration;
|
6
|
+
|
7
|
+
#[derive(Debug)]
|
8
|
+
pub enum CacheError {
|
9
|
+
RedisError(RedisError),
|
10
|
+
// Other error variants as needed.
|
11
|
+
}
|
12
|
+
/// A general-purpose cache trait with an atomic “increment with timeout” operation.
|
13
|
+
#[async_trait]
|
14
|
+
pub trait CacheStore: Send + Sync + std::fmt::Debug {
|
15
|
+
/// Increments the counter associated with `key` and sets (or extends) its expiration.
|
16
|
+
/// Returns the new counter value.
|
17
|
+
async fn increment(&self, key: &str, timeout: Duration) -> Result<u64, CacheError>;
|
18
|
+
}
|
19
|
+
|
20
|
+
/// A Redis-backed cache store using an async connection manager.
|
21
|
+
/// This uses a TLS-enabled connection when the URL is prefixed with "rediss://".
|
22
|
+
#[derive(Clone)]
|
23
|
+
pub struct RedisCacheStore {
|
24
|
+
connection: Arc<ConnectionManager>,
|
25
|
+
}
|
26
|
+
|
27
|
+
impl std::fmt::Debug for RedisCacheStore {
|
28
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
29
|
+
f.debug_struct("RedisCacheStore").finish()
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
impl RedisCacheStore {
|
34
|
+
/// Constructs a new RedisCacheStore.
|
35
|
+
///
|
36
|
+
/// Use a connection URL like "rediss://host:port" to enable TLS (with rustls under the hood).
|
37
|
+
/// This constructor is async because it sets up the connection manager.
|
38
|
+
pub async fn new(connection_url: &str) -> Result<Self, CacheError> {
|
39
|
+
let client = Client::open(connection_url).map_err(CacheError::RedisError)?;
|
40
|
+
let connection_manager = ConnectionManager::new(client)
|
41
|
+
.await
|
42
|
+
.map_err(CacheError::RedisError)?;
|
43
|
+
Ok(Self {
|
44
|
+
connection: Arc::new(connection_manager),
|
45
|
+
})
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
#[async_trait]
|
50
|
+
impl CacheStore for RedisCacheStore {
|
51
|
+
async fn increment(&self, key: &str, timeout: Duration) -> Result<u64, CacheError> {
|
52
|
+
let timeout_secs = timeout.as_secs();
|
53
|
+
// Lua script to:
|
54
|
+
// 1. INCR the key.
|
55
|
+
// 2. If the key doesn't have a TTL, set it.
|
56
|
+
let script = r#"
|
57
|
+
local current = redis.call('INCR', KEYS[1])
|
58
|
+
if redis.call('TTL', KEYS[1]) < 0 then
|
59
|
+
redis.call('EXPIRE', KEYS[1], ARGV[1])
|
60
|
+
end
|
61
|
+
return current
|
62
|
+
"#;
|
63
|
+
let script = Script::new(script);
|
64
|
+
// The ConnectionManager is cloneable and can be used concurrently.
|
65
|
+
let mut connection = (*self.connection).clone();
|
66
|
+
let value: i64 = script
|
67
|
+
.key(key)
|
68
|
+
.arg(timeout_secs)
|
69
|
+
.invoke_async(&mut connection)
|
70
|
+
.await
|
71
|
+
.map_err(CacheError::RedisError)?;
|
72
|
+
Ok(value as u64)
|
73
|
+
}
|
74
|
+
}
|
@@ -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
|
+
}
|