itsi-server 0.2.15 → 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 +75 -73
- 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.lock +1 -1
- data/ext/itsi_server/Cargo.toml +3 -1
- data/ext/itsi_server/extconf.rb +3 -1
- data/ext/itsi_server/src/lib.rs +7 -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 +6 -6
- 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 +71 -42
- 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 +32 -6
- data/ext/itsi_server/src/ruby_types/itsi_server.rs +1 -1
- data/ext/itsi_server/src/server/binds/listener.rs +49 -8
- data/ext/itsi_server/src/server/frame_stream.rs +142 -0
- data/ext/itsi_server/src/server/http_message_types.rs +143 -10
- 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 -58
- data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +6 -9
- data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +27 -42
- data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +65 -14
- data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +1 -1
- data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +8 -11
- data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +21 -8
- data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +2 -3
- data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +1 -5
- 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 +13 -6
- data/ext/itsi_server/src/server/mod.rs +1 -0
- data/ext/itsi_server/src/server/process_worker.rs +5 -5
- data/ext/itsi_server/src/server/serve_strategy/acceptor.rs +100 -0
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +87 -31
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +1 -0
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +166 -206
- data/ext/itsi_server/src/server/signal.rs +37 -9
- data/ext/itsi_server/src/server/thread_worker.rs +92 -70
- data/ext/itsi_server/src/services/itsi_http_service.rs +67 -62
- data/ext/itsi_server/src/services/mime_types.rs +185 -183
- data/ext/itsi_server/src/services/rate_limiter.rs +16 -34
- data/ext/itsi_server/src/services/static_file_server.rs +35 -60
- 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/config_helpers.rb +1 -2
- data/lib/itsi/server/config/dsl.rb +5 -4
- data/lib/itsi/server/config/middleware/etag.md +3 -7
- data/lib/itsi/server/config/middleware/etag.rb +2 -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/listen_backlog.rb +1 -1
- 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/send_buffer_size.md +15 -0
- data/lib/itsi/server/config/options/send_buffer_size.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 +43 -31
- 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/route_tester.rb +1 -1
- 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 +10 -1
@@ -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;
|
@@ -126,12 +126,12 @@ impl ItsiGrpcCall {
|
|
126
126
|
nonblocking: bool,
|
127
127
|
) -> itsi_error::Result<HttpResponse> {
|
128
128
|
let (request, mut receiver) = ItsiGrpcCall::new(hyper_request, context).await;
|
129
|
-
let shutdown_channel = context.service.
|
129
|
+
let shutdown_channel = context.service.shutdown_receiver.clone();
|
130
130
|
let response_stream = request.stream.clone();
|
131
131
|
let sender = if nonblocking {
|
132
132
|
&context.nonblocking_sender
|
133
133
|
} else {
|
134
|
-
&context.
|
134
|
+
&context.job_sender
|
135
135
|
};
|
136
136
|
match sender
|
137
137
|
.send(RequestJob::ProcessGrpcRequest(request, app))
|
@@ -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,36 +182,42 @@ 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_channel.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 {
|
188
|
-
&context.
|
189
|
+
&context.job_sender
|
189
190
|
};
|
190
191
|
match sender.try_send(RequestJob::ProcessHttpRequest(request, app)) {
|
191
192
|
Err(err) => match err {
|
192
|
-
async_channel::TrySendError::Full(_) =>
|
193
|
-
|
194
|
-
|
193
|
+
async_channel::TrySendError::Full(_) => Ok(SERVICE_UNAVAILABLE_RESPONSE
|
194
|
+
.to_http_response(context.accept)
|
195
|
+
.await),
|
196
|
+
async_channel::TrySendError::Closed(_) => {
|
197
|
+
error!("Channel closed while sending request job");
|
198
|
+
Ok(INTERNAL_SERVER_ERROR_RESPONSE
|
199
|
+
.to_http_response(context.accept)
|
195
200
|
.await)
|
196
201
|
}
|
197
|
-
|
198
|
-
|
202
|
+
},
|
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");
|
199
216
|
Ok(INTERNAL_SERVER_ERROR_RESPONSE
|
200
|
-
.to_http_response(context.accept
|
217
|
+
.to_http_response(context.accept)
|
201
218
|
.await)
|
202
219
|
}
|
203
220
|
},
|
204
|
-
_ => match receiver.recv().await {
|
205
|
-
Some(first_frame) => Ok(response
|
206
|
-
.build(first_frame, receiver, shutdown_channel)
|
207
|
-
.await),
|
208
|
-
None => Ok(response
|
209
|
-
.build(ByteFrame::Empty, receiver, shutdown_channel)
|
210
|
-
.await),
|
211
|
-
},
|
212
221
|
}
|
213
222
|
}
|
214
223
|
Err(err_resp) => Ok(err_resp),
|
@@ -219,9 +228,18 @@ impl ItsiHttpRequest {
|
|
219
228
|
request: HttpRequest,
|
220
229
|
context: &HttpRequestContext,
|
221
230
|
script_name: String,
|
222
|
-
) -> Result<
|
231
|
+
) -> Result<
|
232
|
+
(
|
233
|
+
ItsiHttpRequest,
|
234
|
+
tokio::sync::oneshot::Receiver<ResponseFrame>,
|
235
|
+
),
|
236
|
+
HttpResponse,
|
237
|
+
> {
|
223
238
|
let (parts, body) = request.into_parts();
|
224
|
-
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 {
|
225
243
|
ItsiBody::Stream(ItsiBodyProxy::new(body))
|
226
244
|
} else {
|
227
245
|
let mut body_bytes = BigBytes::new();
|
@@ -230,7 +248,7 @@ impl ItsiHttpRequest {
|
|
230
248
|
match chunk {
|
231
249
|
Ok(byte_array) => body_bytes.write_all(&byte_array).unwrap(),
|
232
250
|
Err(e) => {
|
233
|
-
let mut err_resp = Response::new(
|
251
|
+
let mut err_resp = Response::new(HttpBody::empty());
|
234
252
|
if e.downcast_ref::<MaxBodySizeReached>().is_some() {
|
235
253
|
*err_resp.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
|
236
254
|
}
|
@@ -240,18 +258,22 @@ impl ItsiHttpRequest {
|
|
240
258
|
}
|
241
259
|
ItsiBody::Buffered(body_bytes)
|
242
260
|
};
|
243
|
-
let
|
261
|
+
let (sender, receiver) = tokio::sync::oneshot::channel::<ResponseFrame>();
|
244
262
|
Ok((
|
245
263
|
Self {
|
246
264
|
context: context.clone(),
|
247
265
|
version: parts.version,
|
248
|
-
response: ItsiHttpResponse::new(
|
266
|
+
response: ItsiHttpResponse::new(
|
267
|
+
parts.clone(),
|
268
|
+
sender,
|
269
|
+
context.service.shutdown_receiver.clone(),
|
270
|
+
),
|
249
271
|
start: Instant::now(),
|
250
272
|
script_name,
|
251
273
|
body,
|
252
274
|
parts,
|
253
275
|
},
|
254
|
-
|
276
|
+
receiver,
|
255
277
|
))
|
256
278
|
}
|
257
279
|
|
@@ -309,7 +331,7 @@ impl ItsiHttpRequest {
|
|
309
331
|
.parts
|
310
332
|
.uri
|
311
333
|
.host()
|
312
|
-
.unwrap_or_else(|| &self.context.
|
334
|
+
.unwrap_or_else(|| &self.context.listener_info.host))
|
313
335
|
}
|
314
336
|
|
315
337
|
pub(crate) fn scheme(&self) -> MagnusResult<&str> {
|
@@ -318,7 +340,7 @@ impl ItsiHttpRequest {
|
|
318
340
|
.uri
|
319
341
|
.scheme()
|
320
342
|
.map(|scheme| scheme.as_str())
|
321
|
-
.unwrap_or_else(|| &self.context.
|
343
|
+
.unwrap_or_else(|| &self.context.listener_info.scheme))
|
322
344
|
}
|
323
345
|
|
324
346
|
pub(crate) fn headers(&self) -> MagnusResult<Vec<(&str, &str)>> {
|
@@ -330,6 +352,13 @@ impl ItsiHttpRequest {
|
|
330
352
|
.collect::<Vec<(&str, &str)>>())
|
331
353
|
}
|
332
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
|
+
|
333
362
|
pub(crate) fn uri(&self) -> MagnusResult<String> {
|
334
363
|
Ok(self.parts.uri.to_string())
|
335
364
|
}
|
@@ -354,7 +383,7 @@ impl ItsiHttpRequest {
|
|
354
383
|
.parts
|
355
384
|
.uri
|
356
385
|
.port_u16()
|
357
|
-
.unwrap_or(self.context.
|
386
|
+
.unwrap_or(self.context.listener_info.port))
|
358
387
|
}
|
359
388
|
|
360
389
|
pub(crate) fn body(&self) -> MagnusResult<Option<Value>> {
|