itsi-server 0.2.16 → 0.2.17
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/Cargo.lock +3 -1
- data/exe/itsi +6 -1
- data/ext/itsi_acme/Cargo.toml +1 -1
- data/ext/itsi_scheduler/Cargo.toml +1 -1
- data/ext/itsi_server/Cargo.toml +3 -1
- data/ext/itsi_server/src/lib.rs +6 -1
- data/ext/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +2 -0
- data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +4 -4
- data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +14 -13
- data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +64 -33
- data/ext/itsi_server/src/ruby_types/itsi_http_response.rs +151 -152
- data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +6 -15
- data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +26 -5
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +1 -1
- data/ext/itsi_server/src/server/binds/listener.rs +45 -7
- data/ext/itsi_server/src/server/frame_stream.rs +142 -0
- data/ext/itsi_server/src/server/http_message_types.rs +142 -9
- data/ext/itsi_server/src/server/io_stream.rs +28 -5
- data/ext/itsi_server/src/server/lifecycle_event.rs +1 -1
- data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +2 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +8 -10
- data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +2 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +3 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +54 -56
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +5 -7
- data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +5 -5
- data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +7 -10
- data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +2 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +1 -2
- data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +4 -6
- data/ext/itsi_server/src/server/mod.rs +1 -0
- data/ext/itsi_server/src/server/process_worker.rs +3 -4
- data/ext/itsi_server/src/server/serve_strategy/acceptor.rs +16 -12
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +87 -31
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +158 -142
- data/ext/itsi_server/src/server/signal.rs +37 -9
- data/ext/itsi_server/src/server/thread_worker.rs +84 -69
- data/ext/itsi_server/src/services/itsi_http_service.rs +43 -43
- data/ext/itsi_server/src/services/static_file_server.rs +28 -47
- data/lib/itsi/http_request.rb +31 -39
- data/lib/itsi/http_response.rb +5 -0
- data/lib/itsi/rack_env_pool.rb +59 -0
- data/lib/itsi/server/config/dsl.rb +5 -4
- data/lib/itsi/server/config/middleware/proxy.rb +1 -1
- data/lib/itsi/server/config/middleware/rackup_file.rb +2 -2
- data/lib/itsi/server/config/options/auto_reload_config.rb +6 -2
- data/lib/itsi/server/config/options/include.rb +5 -2
- data/lib/itsi/server/config/options/pipeline_flush.md +16 -0
- data/lib/itsi/server/config/options/pipeline_flush.rb +19 -0
- data/lib/itsi/server/config/options/writev.md +25 -0
- data/lib/itsi/server/config/options/writev.rb +19 -0
- data/lib/itsi/server/config.rb +21 -8
- data/lib/itsi/server/default_config/Itsi.rb +1 -4
- data/lib/itsi/server/grpc/grpc_call.rb +2 -0
- data/lib/itsi/server/grpc/grpc_interface.rb +2 -2
- data/lib/itsi/server/rack/handler/itsi.rb +3 -1
- data/lib/itsi/server/rack_interface.rb +17 -12
- data/lib/itsi/server/scheduler_interface.rb +2 -0
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +1 -0
- data/lib/ruby_lsp/itsi/addon.rb +12 -13
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8c75e7602b936f8ca0140844efef4617149bcd9228826e93cecec3673cba14e
|
4
|
+
data.tar.gz: ec9f4ba2c83ab3a0e6683ca7cce2e029f0c62224db9ba3a058caffc30be01504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d2f60a69e5cf77986802f15c6168b27a74525fbfa2a8470e9fc28ab3e4f9ff7481ec372099298edb474ab9e7e5da555e6b295422ba3b2e2529cb83ff6a38ff4
|
7
|
+
data.tar.gz: 8c833ed1c2da13fd48b5895d334bd548bd651218ec9be952190f45b2b455745240276e090e5a5a621155e73cb8e39a9859437412af04741d7d8cb357e2a0da28
|
data/Cargo.lock
CHANGED
@@ -1644,7 +1644,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|
1644
1644
|
|
1645
1645
|
[[package]]
|
1646
1646
|
name = "itsi-server"
|
1647
|
-
version = "0.2.
|
1647
|
+
version = "0.2.17"
|
1648
1648
|
dependencies = [
|
1649
1649
|
"argon2",
|
1650
1650
|
"async-channel",
|
@@ -1660,6 +1660,7 @@ dependencies = [
|
|
1660
1660
|
"either",
|
1661
1661
|
"fs2",
|
1662
1662
|
"futures",
|
1663
|
+
"futures-util",
|
1663
1664
|
"globset",
|
1664
1665
|
"http 1.3.1",
|
1665
1666
|
"http-body-util",
|
@@ -1695,6 +1696,7 @@ dependencies = [
|
|
1695
1696
|
"serde_magnus",
|
1696
1697
|
"sha-crypt",
|
1697
1698
|
"sha2",
|
1699
|
+
"smallvec",
|
1698
1700
|
"socket2",
|
1699
1701
|
"sysinfo",
|
1700
1702
|
"tempfile",
|
data/exe/itsi
CHANGED
@@ -164,7 +164,12 @@ if ENV['COMP_LINE'] || ARGV.include?('--completion')
|
|
164
164
|
exit
|
165
165
|
end
|
166
166
|
|
167
|
-
|
167
|
+
begin
|
168
|
+
parser.parse!
|
169
|
+
rescue StandardError => e
|
170
|
+
puts e.message
|
171
|
+
exit
|
172
|
+
end
|
168
173
|
|
169
174
|
case (command = ARGV.shift)
|
170
175
|
when *COMMANDS.keys
|
data/ext/itsi_acme/Cargo.toml
CHANGED
data/ext/itsi_server/Cargo.toml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
[package]
|
2
2
|
name = "itsi-server"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.17"
|
4
4
|
edition = "2021"
|
5
5
|
authors = ["Wouter Coppieters <wc@pico.net.nz>"]
|
6
6
|
license = "MIT"
|
@@ -90,3 +90,5 @@ argon2 = "0.5.3"
|
|
90
90
|
core_affinity = "0.8.3"
|
91
91
|
memchr = "2.7.4"
|
92
92
|
quick_cache = "0.6.13"
|
93
|
+
smallvec = "1.15.0"
|
94
|
+
futures-util = "0.3.31"
|
data/ext/itsi_server/src/lib.rs
CHANGED
@@ -58,6 +58,7 @@ fn init(ruby: &Ruby) -> Result<()> {
|
|
58
58
|
request.define_method("rack_protocol", method!(ItsiHttpRequest::rack_protocol, 0))?;
|
59
59
|
request.define_method("host", method!(ItsiHttpRequest::host, 0))?;
|
60
60
|
request.define_method("headers", method!(ItsiHttpRequest::headers, 0))?;
|
61
|
+
request.define_method("each_header", method!(ItsiHttpRequest::each_header, 0))?;
|
61
62
|
request.define_method("uri", method!(ItsiHttpRequest::uri, 0))?;
|
62
63
|
request.define_method("header", method!(ItsiHttpRequest::header, 1))?;
|
63
64
|
request.define_method("[]", method!(ItsiHttpRequest::header, 1))?;
|
@@ -71,6 +72,7 @@ fn init(ruby: &Ruby) -> Result<()> {
|
|
71
72
|
request.define_method("url_encoded?", method!(ItsiHttpRequest::is_url_encoded, 0))?;
|
72
73
|
request.define_method("multipart?", method!(ItsiHttpRequest::is_multipart, 0))?;
|
73
74
|
request.define_method("url_params", method!(ItsiHttpRequest::url_params, 0))?;
|
75
|
+
request.define_method("server_error", method!(ItsiHttpRequest::error, 1))?;
|
74
76
|
|
75
77
|
let body_proxy = ruby.get_inner(&ITSI_BODY_PROXY);
|
76
78
|
body_proxy.define_method("gets", method!(ItsiBodyProxy::gets, 0))?;
|
@@ -80,6 +82,10 @@ fn init(ruby: &Ruby) -> Result<()> {
|
|
80
82
|
|
81
83
|
let response = ruby.get_inner(&ITSI_RESPONSE);
|
82
84
|
response.define_method("[]=", method!(ItsiHttpResponse::add_header, 2))?;
|
85
|
+
response.define_method(
|
86
|
+
"reserve_headers",
|
87
|
+
method!(ItsiHttpResponse::reserve_headers, 1),
|
88
|
+
)?;
|
83
89
|
response.define_method("add_header", method!(ItsiHttpResponse::add_header, 2))?;
|
84
90
|
response.define_method("add_headers", method!(ItsiHttpResponse::add_headers, 1))?;
|
85
91
|
response.define_method("status=", method!(ItsiHttpResponse::set_status, 1))?;
|
@@ -87,7 +93,6 @@ fn init(ruby: &Ruby) -> Result<()> {
|
|
87
93
|
response.define_method("<<", method!(ItsiHttpResponse::send_frame, 1))?;
|
88
94
|
response.define_method("write", method!(ItsiHttpResponse::send_frame, 1))?;
|
89
95
|
response.define_method("read", method!(ItsiHttpResponse::recv_frame, 0))?;
|
90
|
-
response.define_method("flush", method!(ItsiHttpResponse::flush, 0))?;
|
91
96
|
response.define_method("closed?", method!(ItsiHttpResponse::is_closed, 0))?;
|
92
97
|
response.define_method(
|
93
98
|
"send_and_close",
|
@@ -25,6 +25,7 @@ pub struct ItsiBodyProxy {
|
|
25
25
|
pub enum ItsiBody {
|
26
26
|
Buffered(BigBytes),
|
27
27
|
Stream(ItsiBodyProxy),
|
28
|
+
Empty,
|
28
29
|
}
|
29
30
|
|
30
31
|
impl ItsiBody {
|
@@ -32,6 +33,7 @@ impl ItsiBody {
|
|
32
33
|
match self {
|
33
34
|
ItsiBody::Buffered(bytes) => bytes.as_value(),
|
34
35
|
ItsiBody::Stream(proxy) => Some(proxy.clone().into_value()),
|
36
|
+
ItsiBody::Empty => None,
|
35
37
|
}
|
36
38
|
}
|
37
39
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
use super::itsi_grpc_response_stream::ItsiGrpcResponseStream;
|
2
2
|
use crate::prelude::*;
|
3
|
-
use crate::server::http_message_types::{HttpRequest, HttpResponse};
|
3
|
+
use crate::server::http_message_types::{HttpBody, HttpRequest, HttpResponse};
|
4
4
|
use crate::server::{byte_frame::ByteFrame, request_job::RequestJob};
|
5
5
|
use crate::services::itsi_http_service::HttpRequestContext;
|
6
6
|
use async_compression::futures::bufread::{GzipDecoder, GzipEncoder, ZlibDecoder, ZlibEncoder};
|
@@ -8,7 +8,7 @@ use bytes::Bytes;
|
|
8
8
|
use derive_more::Debug;
|
9
9
|
use futures::{executor::block_on, io::Cursor, AsyncReadExt};
|
10
10
|
use http::{request::Parts, Response, StatusCode};
|
11
|
-
use http_body_util::
|
11
|
+
use http_body_util::BodyExt;
|
12
12
|
use itsi_error::CLIENT_CONNECTION_CLOSED;
|
13
13
|
use itsi_rb_helpers::{print_rb_backtrace, HeapValue};
|
14
14
|
use itsi_tracing::debug;
|
@@ -139,7 +139,7 @@ impl ItsiGrpcCall {
|
|
139
139
|
{
|
140
140
|
Err(err) => {
|
141
141
|
error!("Error occurred: {}", err);
|
142
|
-
let mut response = Response::new(
|
142
|
+
let mut response = Response::new(HttpBody::empty());
|
143
143
|
*response.status_mut() = StatusCode::BAD_REQUEST;
|
144
144
|
Ok(response)
|
145
145
|
}
|
@@ -147,7 +147,7 @@ impl ItsiGrpcCall {
|
|
147
147
|
Some(first_frame) => Ok(response_stream
|
148
148
|
.build_response(first_frame, receiver, shutdown_channel)
|
149
149
|
.await),
|
150
|
-
None => Ok(Response::new(
|
150
|
+
None => Ok(Response::new(HttpBody::empty())),
|
151
151
|
},
|
152
152
|
}
|
153
153
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
use super::itsi_grpc_call::CompressionAlgorithm;
|
2
2
|
use crate::prelude::*;
|
3
|
-
use crate::server::http_message_types::HttpResponse;
|
3
|
+
use crate::server::http_message_types::{HttpBody, HttpResponse};
|
4
4
|
use crate::server::size_limited_incoming::SizeLimitedIncoming;
|
5
5
|
use crate::server::{byte_frame::ByteFrame, serve_strategy::single_mode::RunningPhase};
|
6
6
|
use bytes::Bytes;
|
@@ -11,8 +11,8 @@ use http::{
|
|
11
11
|
header::{HeaderName, HeaderValue},
|
12
12
|
HeaderMap, Response,
|
13
13
|
};
|
14
|
-
use http_body_util::
|
15
|
-
use hyper::body::
|
14
|
+
use http_body_util::BodyDataStream;
|
15
|
+
use hyper::body::Incoming;
|
16
16
|
use magnus::error::Result as MagnusResult;
|
17
17
|
use nix::unistd::pipe;
|
18
18
|
use parking_lot::Mutex;
|
@@ -161,7 +161,7 @@ impl ItsiGrpcResponseStream {
|
|
161
161
|
response_headers,
|
162
162
|
incoming_reader: Some(pipe_read),
|
163
163
|
response_sender,
|
164
|
-
response: Some(Response::new(
|
164
|
+
response: Some(Response::new(HttpBody::empty())),
|
165
165
|
trailer_tx,
|
166
166
|
trailer_rx: Some(trailer_rx),
|
167
167
|
})),
|
@@ -207,12 +207,12 @@ impl ItsiGrpcResponseStream {
|
|
207
207
|
let rx = self.inner.lock().trailer_rx.take().unwrap();
|
208
208
|
*response.version_mut() = Version::HTTP_2;
|
209
209
|
*response.headers_mut() = self.inner.lock().response_headers.clone();
|
210
|
-
|
211
|
-
|
210
|
+
let body_with_trailers = if matches!(first_frame, ByteFrame::Empty) {
|
211
|
+
HttpBody::empty()
|
212
212
|
} else if matches!(first_frame, ByteFrame::End(_)) {
|
213
|
-
|
213
|
+
HttpBody::full(first_frame.into())
|
214
214
|
} else {
|
215
|
-
let initial_frame = tokio_stream::once(Ok(
|
215
|
+
let initial_frame = tokio_stream::once(Ok(Bytes::from(first_frame)));
|
216
216
|
let frame_stream = unfold(
|
217
217
|
(ReceiverStream::new(receiver), shutdown_rx),
|
218
218
|
|(mut receiver, mut shutdown_rx)| async move {
|
@@ -224,7 +224,7 @@ impl ItsiGrpcResponseStream {
|
|
224
224
|
maybe_bytes = receiver.next() => {
|
225
225
|
match maybe_bytes {
|
226
226
|
Some(ByteFrame::Data(bytes)) | Some(ByteFrame::End(bytes)) => {
|
227
|
-
return Some((Ok(
|
227
|
+
return Some((Ok(bytes), (receiver, shutdown_rx)));
|
228
228
|
}
|
229
229
|
_ => {
|
230
230
|
return None;
|
@@ -234,7 +234,7 @@ impl ItsiGrpcResponseStream {
|
|
234
234
|
_ = shutdown_rx.changed() => {
|
235
235
|
match *shutdown_rx.borrow() {
|
236
236
|
RunningPhase::ShutdownPending => {
|
237
|
-
|
237
|
+
debug!("Disconnecting streaming client.");
|
238
238
|
return None;
|
239
239
|
},
|
240
240
|
_ => continue,
|
@@ -246,15 +246,16 @@ impl ItsiGrpcResponseStream {
|
|
246
246
|
);
|
247
247
|
|
248
248
|
let combined_stream = initial_frame.chain(frame_stream);
|
249
|
-
|
249
|
+
HttpBody::stream(combined_stream)
|
250
250
|
}
|
251
251
|
.with_trailers(async move {
|
252
252
|
match rx.await {
|
253
253
|
Ok(trailers) => Some(Ok(trailers)),
|
254
254
|
Err(_err) => None,
|
255
255
|
}
|
256
|
-
})
|
257
|
-
|
256
|
+
});
|
257
|
+
|
258
|
+
*response.body_mut() = body_with_trailers;
|
258
259
|
response
|
259
260
|
}
|
260
261
|
|
@@ -1,31 +1,30 @@
|
|
1
1
|
use derive_more::Debug;
|
2
2
|
use futures::StreamExt;
|
3
|
-
use http::{header::CONTENT_LENGTH, request::Parts, Response, StatusCode, Version};
|
4
|
-
use http_body_util::
|
3
|
+
use http::{header::CONTENT_LENGTH, request::Parts, HeaderValue, Response, StatusCode, Version};
|
4
|
+
use http_body_util::BodyExt;
|
5
5
|
use itsi_error::CLIENT_CONNECTION_CLOSED;
|
6
|
-
use itsi_rb_helpers::{print_rb_backtrace, HeapValue};
|
7
|
-
use itsi_tracing::
|
6
|
+
use itsi_rb_helpers::{funcall_no_ret, print_rb_backtrace, HeapValue};
|
7
|
+
use itsi_tracing::debug;
|
8
8
|
use magnus::{
|
9
|
-
block::Proc,
|
9
|
+
block::{yield_values, Proc},
|
10
10
|
error::{ErrorType, Result as MagnusResult},
|
11
|
-
Error, RHash, Symbol,
|
11
|
+
Error, IntoValue, RHash, Symbol,
|
12
12
|
};
|
13
13
|
use magnus::{
|
14
14
|
value::{LazyId, ReprValue},
|
15
15
|
Ruby, Value,
|
16
16
|
};
|
17
17
|
use std::{fmt, io::Write, sync::Arc, time::Instant};
|
18
|
-
use
|
18
|
+
use tracing::error;
|
19
19
|
|
20
20
|
use super::{
|
21
21
|
itsi_body_proxy::{big_bytes::BigBytes, ItsiBody, ItsiBodyProxy},
|
22
|
-
itsi_http_response::ItsiHttpResponse,
|
22
|
+
itsi_http_response::{ItsiHttpResponse, ResponseFrame},
|
23
23
|
};
|
24
24
|
use crate::{
|
25
25
|
default_responses::{INTERNAL_SERVER_ERROR_RESPONSE, SERVICE_UNAVAILABLE_RESPONSE},
|
26
26
|
server::{
|
27
|
-
|
28
|
-
http_message_types::{HttpRequest, HttpResponse},
|
27
|
+
http_message_types::{HttpBody, HttpRequest, HttpResponse},
|
29
28
|
request_job::RequestJob,
|
30
29
|
size_limited_incoming::MaxBodySizeReached,
|
31
30
|
},
|
@@ -33,11 +32,13 @@ use crate::{
|
|
33
32
|
};
|
34
33
|
|
35
34
|
static ID_MESSAGE: LazyId = LazyId::new("message");
|
35
|
+
static ID_CALL: LazyId = LazyId::new("call");
|
36
|
+
static ZERO_HEADER_VALUE: HeaderValue = HeaderValue::from_static("0");
|
36
37
|
|
37
38
|
#[derive(Debug)]
|
38
39
|
#[magnus::wrap(class = "Itsi::HttpRequest", free_immediately, size)]
|
39
40
|
pub struct ItsiHttpRequest {
|
40
|
-
pub parts: Parts
|
41
|
+
pub parts: Arc<Parts>,
|
41
42
|
#[debug(skip)]
|
42
43
|
pub body: ItsiBody,
|
43
44
|
pub version: Version,
|
@@ -148,8 +149,10 @@ impl ItsiHttpRequest {
|
|
148
149
|
|
149
150
|
pub fn process(self, ruby: &Ruby, app_proc: Arc<HeapValue<Proc>>) -> magnus::error::Result<()> {
|
150
151
|
let response = self.response.clone();
|
151
|
-
|
152
|
-
if let Err(err) =
|
152
|
+
|
153
|
+
if let Err(err) =
|
154
|
+
funcall_no_ret(app_proc.as_value(), *ID_CALL, [self.into_value_with(ruby)])
|
155
|
+
{
|
153
156
|
Self::internal_error(ruby, response, err);
|
154
157
|
}
|
155
158
|
Ok(())
|
@@ -158,7 +161,7 @@ impl ItsiHttpRequest {
|
|
158
161
|
pub fn internal_error(ruby: &Ruby, response: ItsiHttpResponse, err: Error) {
|
159
162
|
if Self::is_connection_closed_err(ruby, &err) {
|
160
163
|
debug!("Connection closed by client");
|
161
|
-
response.close();
|
164
|
+
response.close().ok();
|
162
165
|
} else if let Some(rb_err) = err.value() {
|
163
166
|
print_rb_backtrace(rb_err);
|
164
167
|
response.internal_server_error(err.to_string());
|
@@ -167,7 +170,7 @@ impl ItsiHttpRequest {
|
|
167
170
|
}
|
168
171
|
}
|
169
172
|
|
170
|
-
pub fn error(self, message: String) {
|
173
|
+
pub fn error(&self, message: String) {
|
171
174
|
self.response.internal_server_error(message);
|
172
175
|
}
|
173
176
|
|
@@ -179,9 +182,7 @@ impl ItsiHttpRequest {
|
|
179
182
|
nonblocking: bool,
|
180
183
|
) -> itsi_error::Result<HttpResponse> {
|
181
184
|
match ItsiHttpRequest::new(hyper_request, context, script_name).await {
|
182
|
-
Ok((request,
|
183
|
-
let shutdown_channel = context.service.shutdown_receiver.clone();
|
184
|
-
let response = request.response.clone();
|
185
|
+
Ok((request, receiver)) => {
|
185
186
|
let sender = if nonblocking {
|
186
187
|
&context.nonblocking_sender
|
187
188
|
} else {
|
@@ -192,20 +193,30 @@ impl ItsiHttpRequest {
|
|
192
193
|
async_channel::TrySendError::Full(_) => Ok(SERVICE_UNAVAILABLE_RESPONSE
|
193
194
|
.to_http_response(context.accept)
|
194
195
|
.await),
|
195
|
-
async_channel::TrySendError::Closed(
|
196
|
-
error!("
|
196
|
+
async_channel::TrySendError::Closed(_) => {
|
197
|
+
error!("Channel closed while sending request job");
|
197
198
|
Ok(INTERNAL_SERVER_ERROR_RESPONSE
|
198
199
|
.to_http_response(context.accept)
|
199
200
|
.await)
|
200
201
|
}
|
201
202
|
},
|
202
|
-
_ => match receiver.
|
203
|
-
|
204
|
-
|
205
|
-
.await
|
206
|
-
|
207
|
-
|
208
|
-
|
203
|
+
Ok(_) => match receiver.await {
|
204
|
+
Ok(ResponseFrame::HttpResponse(response)) => Ok(response),
|
205
|
+
Ok(ResponseFrame::HijackedResponse(response)) => {
|
206
|
+
match response.process_hijacked_response().await {
|
207
|
+
Ok(result) => Ok(result),
|
208
|
+
Err(e) => {
|
209
|
+
error!("Error processing hijacked response: {}", e);
|
210
|
+
Ok(Response::new(HttpBody::empty()))
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
Err(_) => {
|
215
|
+
error!("Failed to receive response from receiver");
|
216
|
+
Ok(INTERNAL_SERVER_ERROR_RESPONSE
|
217
|
+
.to_http_response(context.accept)
|
218
|
+
.await)
|
219
|
+
}
|
209
220
|
},
|
210
221
|
}
|
211
222
|
}
|
@@ -217,9 +228,18 @@ impl ItsiHttpRequest {
|
|
217
228
|
request: HttpRequest,
|
218
229
|
context: &HttpRequestContext,
|
219
230
|
script_name: String,
|
220
|
-
) -> Result<
|
231
|
+
) -> Result<
|
232
|
+
(
|
233
|
+
ItsiHttpRequest,
|
234
|
+
tokio::sync::oneshot::Receiver<ResponseFrame>,
|
235
|
+
),
|
236
|
+
HttpResponse,
|
237
|
+
> {
|
221
238
|
let (parts, body) = request.into_parts();
|
222
|
-
let
|
239
|
+
let parts = Arc::new(parts);
|
240
|
+
let body = if parts.headers.get(CONTENT_LENGTH) == Some(&ZERO_HEADER_VALUE) {
|
241
|
+
ItsiBody::Empty
|
242
|
+
} else if context.server_params.streamable_body {
|
223
243
|
ItsiBody::Stream(ItsiBodyProxy::new(body))
|
224
244
|
} else {
|
225
245
|
let mut body_bytes = BigBytes::new();
|
@@ -228,7 +248,7 @@ impl ItsiHttpRequest {
|
|
228
248
|
match chunk {
|
229
249
|
Ok(byte_array) => body_bytes.write_all(&byte_array).unwrap(),
|
230
250
|
Err(e) => {
|
231
|
-
let mut err_resp = Response::new(
|
251
|
+
let mut err_resp = Response::new(HttpBody::empty());
|
232
252
|
if e.downcast_ref::<MaxBodySizeReached>().is_some() {
|
233
253
|
*err_resp.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
|
234
254
|
}
|
@@ -238,18 +258,22 @@ impl ItsiHttpRequest {
|
|
238
258
|
}
|
239
259
|
ItsiBody::Buffered(body_bytes)
|
240
260
|
};
|
241
|
-
let
|
261
|
+
let (sender, receiver) = tokio::sync::oneshot::channel::<ResponseFrame>();
|
242
262
|
Ok((
|
243
263
|
Self {
|
244
264
|
context: context.clone(),
|
245
265
|
version: parts.version,
|
246
|
-
response: ItsiHttpResponse::new(
|
266
|
+
response: ItsiHttpResponse::new(
|
267
|
+
parts.clone(),
|
268
|
+
sender,
|
269
|
+
context.service.shutdown_receiver.clone(),
|
270
|
+
),
|
247
271
|
start: Instant::now(),
|
248
272
|
script_name,
|
249
273
|
body,
|
250
274
|
parts,
|
251
275
|
},
|
252
|
-
|
276
|
+
receiver,
|
253
277
|
))
|
254
278
|
}
|
255
279
|
|
@@ -328,6 +352,13 @@ impl ItsiHttpRequest {
|
|
328
352
|
.collect::<Vec<(&str, &str)>>())
|
329
353
|
}
|
330
354
|
|
355
|
+
pub(crate) fn each_header(&self) -> MagnusResult<()> {
|
356
|
+
self.parts.headers.iter().for_each(|(hn, hv)| {
|
357
|
+
yield_values::<_, Value>((hn.as_str(), hv.to_str().unwrap_or(""))).ok();
|
358
|
+
});
|
359
|
+
Ok(())
|
360
|
+
}
|
361
|
+
|
331
362
|
pub(crate) fn uri(&self) -> MagnusResult<String> {
|
332
363
|
Ok(self.parts.uri.to_string())
|
333
364
|
}
|