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,216 @@
|
|
1
|
+
use std::{collections::HashMap, sync::Arc};
|
2
|
+
|
3
|
+
use crate::server::{
|
4
|
+
byte_frame::ByteFrame, serve_strategy::single_mode::RunningPhase, types::HttpResponse,
|
5
|
+
};
|
6
|
+
use bytes::Bytes;
|
7
|
+
use derive_more::Debug;
|
8
|
+
use futures::{executor::block_on, stream::unfold};
|
9
|
+
use http::{
|
10
|
+
header::{HeaderName, HeaderValue, CONTENT_TYPE},
|
11
|
+
HeaderMap, Response,
|
12
|
+
};
|
13
|
+
use http_body_util::{combinators::BoxBody, BodyDataStream, BodyExt, Empty, Full, StreamBody};
|
14
|
+
use hyper::body::{Frame, Incoming};
|
15
|
+
use magnus::error::Result as MagnusResult;
|
16
|
+
use parking_lot::Mutex;
|
17
|
+
use tokio::sync::{
|
18
|
+
mpsc::{Receiver, Sender},
|
19
|
+
oneshot, watch,
|
20
|
+
};
|
21
|
+
use tokio_stream::{wrappers::ReceiverStream, StreamExt};
|
22
|
+
use tracing::{error, info, warn};
|
23
|
+
|
24
|
+
#[derive(Debug, Clone)]
|
25
|
+
#[magnus::wrap(class = "Itsi::GrpcStream", free_immediately, size)]
|
26
|
+
pub struct ItsiGrpcStream {
|
27
|
+
pub inner: Arc<Mutex<ItsiGrpcStreamInner>>,
|
28
|
+
}
|
29
|
+
|
30
|
+
#[derive(Debug)]
|
31
|
+
pub struct ItsiGrpcStreamInner {
|
32
|
+
pub body: BodyDataStream<Incoming>,
|
33
|
+
pub buf: Vec<u8>,
|
34
|
+
pub response_sender: Sender<ByteFrame>,
|
35
|
+
pub response: Option<HttpResponse>,
|
36
|
+
trailer_tx: oneshot::Sender<HeaderMap>,
|
37
|
+
trailer_rx: Option<oneshot::Receiver<HeaderMap>>,
|
38
|
+
}
|
39
|
+
|
40
|
+
impl ItsiGrpcStreamInner {
|
41
|
+
pub fn read(&mut self, bytes: usize) -> MagnusResult<Bytes> {
|
42
|
+
let stream = &mut self.body;
|
43
|
+
let buf = &mut self.buf;
|
44
|
+
let mut result = Vec::with_capacity(bytes);
|
45
|
+
|
46
|
+
info!("Entering read with {:?}. Current buf is {:?}", bytes, buf);
|
47
|
+
|
48
|
+
// First, use any data already in the buffer
|
49
|
+
if !buf.is_empty() {
|
50
|
+
let remaining = bytes.min(buf.len());
|
51
|
+
result.extend_from_slice(&buf[..remaining]);
|
52
|
+
buf.drain(..remaining);
|
53
|
+
}
|
54
|
+
|
55
|
+
while result.len() < bytes {
|
56
|
+
if let Some(chunk) = block_on(stream.next()) {
|
57
|
+
let chunk = chunk.map_err(|err| {
|
58
|
+
magnus::Error::new(
|
59
|
+
magnus::exception::exception(),
|
60
|
+
format!("Error reading body {:?}", err),
|
61
|
+
)
|
62
|
+
})?;
|
63
|
+
let remaining = bytes - result.len();
|
64
|
+
if chunk.len() > remaining {
|
65
|
+
result.extend_from_slice(&chunk[..remaining]);
|
66
|
+
buf.extend_from_slice(&chunk[remaining..]);
|
67
|
+
} else {
|
68
|
+
result.extend_from_slice(&chunk);
|
69
|
+
}
|
70
|
+
} else {
|
71
|
+
break;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
Ok(result.into())
|
76
|
+
}
|
77
|
+
|
78
|
+
pub fn write(&mut self, bytes: Bytes) -> MagnusResult<()> {
|
79
|
+
self.response_sender
|
80
|
+
.blocking_send(ByteFrame::Data(bytes))
|
81
|
+
.map_err(|err| {
|
82
|
+
magnus::Error::new(
|
83
|
+
magnus::exception::exception(),
|
84
|
+
format!("Error writing body {:?}", err),
|
85
|
+
)
|
86
|
+
})?;
|
87
|
+
Ok(())
|
88
|
+
}
|
89
|
+
|
90
|
+
pub fn flush(&mut self) -> MagnusResult<()> {
|
91
|
+
Ok(())
|
92
|
+
}
|
93
|
+
|
94
|
+
pub fn send_trailers(&mut self, trailers: HashMap<String, String>) -> MagnusResult<()> {
|
95
|
+
let mut header_map = HeaderMap::new();
|
96
|
+
for (key, value) in trailers {
|
97
|
+
if let (Ok(hn), Ok(hv)) = (key.parse::<HeaderName>(), value.parse::<HeaderValue>()) {
|
98
|
+
header_map.insert(hn, hv);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
let trailer_tx = std::mem::replace(&mut self.trailer_tx, oneshot::channel().0);
|
102
|
+
trailer_tx.send(header_map).map_err(|err| {
|
103
|
+
magnus::Error::new(
|
104
|
+
magnus::exception::exception(),
|
105
|
+
format!("Error sending trailers {:?}", err),
|
106
|
+
)
|
107
|
+
})?;
|
108
|
+
self.response_sender
|
109
|
+
.blocking_send(ByteFrame::Empty)
|
110
|
+
.map_err(|err| {
|
111
|
+
magnus::Error::new(
|
112
|
+
magnus::exception::exception(),
|
113
|
+
format!("Error flushing {:?}", err),
|
114
|
+
)
|
115
|
+
})?;
|
116
|
+
Ok(())
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
impl ItsiGrpcStream {
|
121
|
+
pub fn new(response_sender: Sender<ByteFrame>, body: BodyDataStream<Incoming>) -> Self {
|
122
|
+
let (trailer_tx, trailer_rx) = oneshot::channel::<HeaderMap>();
|
123
|
+
ItsiGrpcStream {
|
124
|
+
inner: Arc::new(Mutex::new(ItsiGrpcStreamInner {
|
125
|
+
body,
|
126
|
+
buf: Vec::new(),
|
127
|
+
response_sender,
|
128
|
+
response: Some(Response::new(BoxBody::new(Empty::new()))),
|
129
|
+
trailer_tx,
|
130
|
+
trailer_rx: Some(trailer_rx),
|
131
|
+
})),
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
pub fn read(&self, bytes: usize) -> MagnusResult<Bytes> {
|
136
|
+
self.inner.lock().read(bytes)
|
137
|
+
}
|
138
|
+
|
139
|
+
pub fn write(&self, bytes: Bytes) -> MagnusResult<()> {
|
140
|
+
self.inner.lock().write(bytes)
|
141
|
+
}
|
142
|
+
|
143
|
+
pub fn flush(&self) -> MagnusResult<()> {
|
144
|
+
self.inner.lock().flush()
|
145
|
+
}
|
146
|
+
|
147
|
+
pub fn send_trailers(&self, trailers: HashMap<String, String>) -> MagnusResult<()> {
|
148
|
+
self.inner.lock().send_trailers(trailers)
|
149
|
+
}
|
150
|
+
|
151
|
+
pub async fn build_response(
|
152
|
+
&self,
|
153
|
+
first_frame: ByteFrame,
|
154
|
+
receiver: Receiver<ByteFrame>,
|
155
|
+
shutdown_rx: watch::Receiver<RunningPhase>,
|
156
|
+
) -> HttpResponse {
|
157
|
+
let mut response = self.inner.lock().response.take().unwrap();
|
158
|
+
let rx = self.inner.lock().trailer_rx.take().unwrap();
|
159
|
+
response
|
160
|
+
.headers_mut()
|
161
|
+
.append(CONTENT_TYPE, "application/grpc".parse().unwrap());
|
162
|
+
*response.body_mut() = if matches!(first_frame, ByteFrame::Empty) {
|
163
|
+
BoxBody::new(Empty::new())
|
164
|
+
} else if matches!(first_frame, ByteFrame::End(_)) {
|
165
|
+
BoxBody::new(Full::new(first_frame.into()))
|
166
|
+
} else {
|
167
|
+
let initial_frame = tokio_stream::once(Ok(Frame::data(Bytes::from(first_frame))));
|
168
|
+
let frame_stream = unfold(
|
169
|
+
(ReceiverStream::new(receiver), shutdown_rx),
|
170
|
+
|(mut receiver, mut shutdown_rx)| async move {
|
171
|
+
if let RunningPhase::ShutdownPending = *shutdown_rx.borrow() {
|
172
|
+
return None;
|
173
|
+
}
|
174
|
+
loop {
|
175
|
+
tokio::select! {
|
176
|
+
maybe_bytes = receiver.next() => {
|
177
|
+
match maybe_bytes {
|
178
|
+
Some(ByteFrame::Data(bytes)) | Some(ByteFrame::End(bytes)) => {
|
179
|
+
return Some((Ok(Frame::data(bytes)), (receiver, shutdown_rx)));
|
180
|
+
}
|
181
|
+
_ => {
|
182
|
+
return None;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
},
|
186
|
+
_ = shutdown_rx.changed() => {
|
187
|
+
match *shutdown_rx.borrow() {
|
188
|
+
RunningPhase::ShutdownPending => {
|
189
|
+
warn!("Disconnecting streaming client.");
|
190
|
+
return None;
|
191
|
+
},
|
192
|
+
_ => continue,
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
},
|
198
|
+
);
|
199
|
+
|
200
|
+
let combined_stream = initial_frame.chain(frame_stream);
|
201
|
+
BoxBody::new(StreamBody::new(combined_stream))
|
202
|
+
}
|
203
|
+
.with_trailers(async move {
|
204
|
+
match rx.await {
|
205
|
+
Ok(trailers) => Some(Ok(trailers)),
|
206
|
+
Err(_err) => None,
|
207
|
+
}
|
208
|
+
})
|
209
|
+
.boxed();
|
210
|
+
response
|
211
|
+
}
|
212
|
+
|
213
|
+
pub fn internal_server_error(&self, message: String) {
|
214
|
+
error!(message);
|
215
|
+
}
|
216
|
+
}
|
@@ -1,58 +1,49 @@
|
|
1
|
-
use crate::{
|
2
|
-
body_proxy::{
|
3
|
-
big_bytes::BigBytes,
|
4
|
-
itsi_body_proxy::{ItsiBody, ItsiBodyProxy},
|
5
|
-
},
|
6
|
-
response::itsi_response::ItsiResponse,
|
7
|
-
server::{
|
8
|
-
itsi_server::{RequestJob, Server},
|
9
|
-
listener::{ListenerInfo, SockAddr},
|
10
|
-
serve_strategy::single_mode::RunningPhase,
|
11
|
-
},
|
12
|
-
};
|
13
|
-
use bytes::Bytes;
|
14
1
|
use derive_more::Debug;
|
15
2
|
use futures::StreamExt;
|
16
|
-
use http::{request::Parts,
|
3
|
+
use http::{request::Parts, Response, StatusCode, Version};
|
17
4
|
use http_body_util::{combinators::BoxBody, BodyExt, Empty};
|
18
|
-
use hyper::{body::Incoming, Request};
|
19
5
|
use itsi_error::from::CLIENT_CONNECTION_CLOSED;
|
20
|
-
use itsi_rb_helpers::print_rb_backtrace;
|
6
|
+
use itsi_rb_helpers::{print_rb_backtrace, HeapValue};
|
21
7
|
use itsi_tracing::{debug, error};
|
22
8
|
use magnus::{
|
9
|
+
block::Proc,
|
23
10
|
error::{ErrorType, Result as MagnusResult},
|
24
11
|
Error,
|
25
12
|
};
|
26
13
|
use magnus::{
|
27
|
-
value::{LazyId,
|
28
|
-
|
14
|
+
value::{LazyId, ReprValue},
|
15
|
+
Ruby, Value,
|
16
|
+
};
|
17
|
+
use std::{fmt, io::Write, sync::Arc, time::Instant};
|
18
|
+
use tokio::sync::mpsc::{self};
|
19
|
+
|
20
|
+
use super::{
|
21
|
+
itsi_body_proxy::{big_bytes::BigBytes, ItsiBody, ItsiBodyProxy},
|
22
|
+
itsi_http_response::ItsiHttpResponse,
|
29
23
|
};
|
30
|
-
use
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
use crate::server::{
|
25
|
+
byte_frame::ByteFrame,
|
26
|
+
itsi_service::RequestContext,
|
27
|
+
request_job::RequestJob,
|
28
|
+
types::{HttpRequest, HttpResponse},
|
34
29
|
};
|
35
|
-
|
30
|
+
|
36
31
|
static ID_MESSAGE: LazyId = LazyId::new("message");
|
37
32
|
|
38
33
|
#[derive(Debug)]
|
39
|
-
#[magnus::wrap(class = "Itsi::
|
40
|
-
pub struct
|
34
|
+
#[magnus::wrap(class = "Itsi::HttpRequest", free_immediately, size)]
|
35
|
+
pub struct ItsiHttpRequest {
|
41
36
|
pub parts: Parts,
|
42
37
|
#[debug(skip)]
|
43
38
|
pub body: ItsiBody,
|
44
|
-
pub
|
45
|
-
pub
|
46
|
-
#[debug(skip)]
|
47
|
-
pub(crate) listener: Arc<ListenerInfo>,
|
48
|
-
#[debug(skip)]
|
49
|
-
pub server: Arc<Server>,
|
50
|
-
pub response: ItsiResponse,
|
39
|
+
pub version: Version,
|
40
|
+
pub response: ItsiHttpResponse,
|
51
41
|
pub start: Instant,
|
52
|
-
|
42
|
+
#[debug(skip)]
|
43
|
+
pub context: RequestContext,
|
53
44
|
}
|
54
45
|
|
55
|
-
impl fmt::Display for
|
46
|
+
impl fmt::Display for ItsiHttpRequest {
|
56
47
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
57
48
|
write!(
|
58
49
|
f,
|
@@ -64,7 +55,7 @@ impl fmt::Display for ItsiRequest {
|
|
64
55
|
}
|
65
56
|
}
|
66
57
|
|
67
|
-
impl
|
58
|
+
impl ItsiHttpRequest {
|
68
59
|
pub fn is_connection_closed_err(ruby: &Ruby, err: &Error) -> bool {
|
69
60
|
match err.error_type() {
|
70
61
|
ErrorType::Jump(_) => false,
|
@@ -82,35 +73,32 @@ impl ItsiRequest {
|
|
82
73
|
}
|
83
74
|
}
|
84
75
|
}
|
76
|
+
fn content_type_str(&self) -> &str {
|
77
|
+
self.parts
|
78
|
+
.headers
|
79
|
+
.get("Content-Type")
|
80
|
+
.and_then(|hv| hv.to_str().ok())
|
81
|
+
.unwrap_or("application/x-www-form-urlencoded")
|
82
|
+
}
|
85
83
|
|
86
84
|
pub fn is_json(&self) -> bool {
|
87
|
-
self.
|
85
|
+
self.content_type_str() == "application/json"
|
88
86
|
}
|
89
87
|
|
90
88
|
pub fn is_html(&self) -> bool {
|
91
|
-
self.
|
89
|
+
self.content_type_str() == "text/html"
|
92
90
|
}
|
93
91
|
|
94
|
-
pub fn process(
|
95
|
-
self,
|
96
|
-
ruby: &Ruby,
|
97
|
-
server: RClass,
|
98
|
-
app: Opaque<Value>,
|
99
|
-
) -> magnus::error::Result<()> {
|
100
|
-
let req = format!("{}", self);
|
92
|
+
pub fn process(self, ruby: &Ruby, app_proc: Arc<HeapValue<Proc>>) -> magnus::error::Result<()> {
|
101
93
|
let response = self.response.clone();
|
102
|
-
let
|
103
|
-
debug!("{} Started", req);
|
104
|
-
let result = server.funcall::<_, _, Value>(*ID_CALL, (app, self));
|
94
|
+
let result = app_proc.call::<_, Value>((self,));
|
105
95
|
if let Err(err) = result {
|
106
96
|
Self::internal_error(ruby, response, err);
|
107
97
|
}
|
108
|
-
debug!("{} Finished in {:?}", req, start.elapsed());
|
109
|
-
|
110
98
|
Ok(())
|
111
99
|
}
|
112
100
|
|
113
|
-
pub fn internal_error(ruby: &Ruby, response:
|
101
|
+
pub fn internal_error(ruby: &Ruby, response: ItsiHttpResponse, err: Error) {
|
114
102
|
if Self::is_connection_closed_err(ruby, &err) {
|
115
103
|
debug!("Connection closed by client");
|
116
104
|
response.close();
|
@@ -127,17 +115,18 @@ impl ItsiRequest {
|
|
127
115
|
}
|
128
116
|
|
129
117
|
pub(crate) async fn process_request(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
) -> itsi_error::Result<Response<BoxBody<Bytes, Infallible>>> {
|
137
|
-
let (request, mut receiver) = ItsiRequest::new(hyper_request, addr, server, listener).await;
|
138
|
-
|
118
|
+
app: Arc<HeapValue<Proc>>,
|
119
|
+
hyper_request: HttpRequest,
|
120
|
+
context: &RequestContext,
|
121
|
+
) -> itsi_error::Result<HttpResponse> {
|
122
|
+
let (request, mut receiver) = ItsiHttpRequest::new(hyper_request, context).await;
|
123
|
+
let shutdown_channel = context.service.shutdown_channel.clone();
|
139
124
|
let response = request.response.clone();
|
140
|
-
match
|
125
|
+
match context
|
126
|
+
.sender
|
127
|
+
.send(RequestJob::ProcessHttpRequest(request, app))
|
128
|
+
.await
|
129
|
+
{
|
141
130
|
Err(err) => {
|
142
131
|
error!("Error occurred: {}", err);
|
143
132
|
let mut response = Response::new(BoxBody::new(Empty::new()));
|
@@ -145,20 +134,22 @@ impl ItsiRequest {
|
|
145
134
|
Ok(response)
|
146
135
|
}
|
147
136
|
_ => match receiver.recv().await {
|
148
|
-
Some(first_frame) => Ok(response
|
149
|
-
|
137
|
+
Some(first_frame) => Ok(response
|
138
|
+
.build(first_frame, receiver, shutdown_channel)
|
139
|
+
.await),
|
140
|
+
None => Ok(response
|
141
|
+
.build(ByteFrame::Empty, receiver, shutdown_channel)
|
142
|
+
.await),
|
150
143
|
},
|
151
144
|
}
|
152
145
|
}
|
153
146
|
|
154
147
|
pub(crate) async fn new(
|
155
|
-
request:
|
156
|
-
|
157
|
-
|
158
|
-
listener: Arc<ListenerInfo>,
|
159
|
-
) -> (ItsiRequest, mpsc::Receiver<Option<Bytes>>) {
|
148
|
+
request: HttpRequest,
|
149
|
+
context: &RequestContext,
|
150
|
+
) -> (ItsiHttpRequest, mpsc::Receiver<ByteFrame>) {
|
160
151
|
let (parts, body) = request.into_parts();
|
161
|
-
let body = if
|
152
|
+
let body = if context.server_params.streamable_body {
|
162
153
|
ItsiBody::Stream(ItsiBodyProxy::new(body))
|
163
154
|
} else {
|
164
155
|
let mut body_bytes = BigBytes::new();
|
@@ -169,35 +160,14 @@ impl ItsiRequest {
|
|
169
160
|
}
|
170
161
|
ItsiBody::Buffered(body_bytes)
|
171
162
|
};
|
172
|
-
let response_channel = mpsc::channel::<
|
163
|
+
let response_channel = mpsc::channel::<ByteFrame>(100);
|
173
164
|
(
|
174
165
|
Self {
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
listener,
|
179
|
-
version: format!("{:?}", &parts.version),
|
180
|
-
response: ItsiResponse::new(
|
181
|
-
parts.clone(),
|
182
|
-
response_channel.0,
|
183
|
-
parts
|
184
|
-
.headers
|
185
|
-
.get("Accept")
|
186
|
-
.unwrap_or(&HeaderValue::from_static("text/html"))
|
187
|
-
.to_str()
|
188
|
-
.unwrap()
|
189
|
-
.to_string(),
|
190
|
-
),
|
166
|
+
context: context.clone(),
|
167
|
+
version: parts.version,
|
168
|
+
response: ItsiHttpResponse::new(parts.clone(), response_channel.0),
|
191
169
|
start: Instant::now(),
|
192
|
-
|
193
|
-
.headers
|
194
|
-
.get("Content-Type")
|
195
|
-
.unwrap_or(&HeaderValue::from_static(
|
196
|
-
"application/x-www-form-urlencoded",
|
197
|
-
))
|
198
|
-
.to_str()
|
199
|
-
.unwrap()
|
200
|
-
.to_string(),
|
170
|
+
body,
|
201
171
|
parts,
|
202
172
|
},
|
203
173
|
response_channel.1,
|
@@ -209,12 +179,12 @@ impl ItsiRequest {
|
|
209
179
|
.parts
|
210
180
|
.uri
|
211
181
|
.path()
|
212
|
-
.strip_prefix(&self.
|
182
|
+
.strip_prefix(&self.context.server_params.script_name)
|
213
183
|
.unwrap_or(self.parts.uri.path()))
|
214
184
|
}
|
215
185
|
|
216
186
|
pub(crate) fn script_name(&self) -> MagnusResult<&str> {
|
217
|
-
Ok(&self.
|
187
|
+
Ok(&self.context.server_params.script_name)
|
218
188
|
}
|
219
189
|
|
220
190
|
pub(crate) fn query_string(&self) -> MagnusResult<&str> {
|
@@ -226,7 +196,14 @@ impl ItsiRequest {
|
|
226
196
|
}
|
227
197
|
|
228
198
|
pub(crate) fn version(&self) -> MagnusResult<&str> {
|
229
|
-
Ok(
|
199
|
+
Ok(match self.version {
|
200
|
+
Version::HTTP_09 => "HTTP/0.9",
|
201
|
+
Version::HTTP_10 => "HTTP/1.0",
|
202
|
+
Version::HTTP_11 => "HTTP/1.1",
|
203
|
+
Version::HTTP_2 => "HTTP/2.0",
|
204
|
+
Version::HTTP_3 => "HTTP/3.0",
|
205
|
+
_ => "HTTP/Unknown",
|
206
|
+
})
|
230
207
|
}
|
231
208
|
|
232
209
|
pub(crate) fn rack_protocol(&self) -> MagnusResult<Vec<&str>> {
|
@@ -246,53 +223,60 @@ impl ItsiRequest {
|
|
246
223
|
.unwrap_or_else(|| vec!["http"]))
|
247
224
|
}
|
248
225
|
|
249
|
-
pub(crate) fn host(&self) -> MagnusResult
|
226
|
+
pub(crate) fn host(&self) -> MagnusResult<&str> {
|
250
227
|
Ok(self
|
251
228
|
.parts
|
252
229
|
.uri
|
253
230
|
.host()
|
254
|
-
.
|
255
|
-
.unwrap_or_else(|| self.listener.host.clone()))
|
231
|
+
.unwrap_or_else(|| &self.context.listener.host))
|
256
232
|
}
|
257
233
|
|
258
|
-
pub(crate) fn scheme(&self) -> MagnusResult
|
234
|
+
pub(crate) fn scheme(&self) -> MagnusResult<&str> {
|
259
235
|
Ok(self
|
260
236
|
.parts
|
261
237
|
.uri
|
262
238
|
.scheme()
|
263
|
-
.map(|scheme| scheme.
|
264
|
-
.unwrap_or_else(|| self.listener.scheme
|
239
|
+
.map(|scheme| scheme.as_str())
|
240
|
+
.unwrap_or_else(|| &self.context.listener.scheme))
|
265
241
|
}
|
266
242
|
|
267
|
-
pub(crate) fn headers(&self) -> MagnusResult<Vec<(
|
243
|
+
pub(crate) fn headers(&self) -> MagnusResult<Vec<(&str, &str)>> {
|
268
244
|
Ok(self
|
269
245
|
.parts
|
270
246
|
.headers
|
271
247
|
.iter()
|
272
|
-
.map(|(hn, hv)|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
.
|
248
|
+
.map(|(hn, hv)| (hn.as_str(), hv.to_str().unwrap_or("")))
|
249
|
+
.collect::<Vec<(&str, &str)>>())
|
250
|
+
}
|
251
|
+
|
252
|
+
pub fn header(&self, name: String) -> MagnusResult<Option<Vec<&str>>> {
|
253
|
+
let result: Vec<&str> = self
|
254
|
+
.parts
|
255
|
+
.headers
|
256
|
+
.get_all(&name)
|
257
|
+
.iter()
|
258
|
+
.filter_map(|value| value.to_str().ok())
|
259
|
+
.collect();
|
260
|
+
Ok(Some(result))
|
281
261
|
}
|
282
262
|
|
283
263
|
pub(crate) fn remote_addr(&self) -> MagnusResult<&str> {
|
284
|
-
Ok(&self.
|
264
|
+
Ok(&self.context.addr)
|
285
265
|
}
|
286
266
|
|
287
267
|
pub(crate) fn port(&self) -> MagnusResult<u16> {
|
288
|
-
Ok(self
|
268
|
+
Ok(self
|
269
|
+
.parts
|
270
|
+
.uri
|
271
|
+
.port_u16()
|
272
|
+
.unwrap_or(self.context.listener.port))
|
289
273
|
}
|
290
274
|
|
291
|
-
pub(crate) fn body(&self) -> MagnusResult<Value
|
275
|
+
pub(crate) fn body(&self) -> MagnusResult<Option<Value>> {
|
292
276
|
Ok(self.body.into_value())
|
293
277
|
}
|
294
278
|
|
295
|
-
pub(crate) fn response(&self) -> MagnusResult<
|
279
|
+
pub(crate) fn response(&self) -> MagnusResult<ItsiHttpResponse> {
|
296
280
|
Ok(self.response.clone())
|
297
281
|
}
|
298
282
|
}
|