itsi 0.1.0 → 0.1.3

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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +524 -44
  3. data/Rakefile +22 -33
  4. data/crates/itsi_error/Cargo.toml +2 -0
  5. data/crates/itsi_error/src/from.rs +70 -0
  6. data/crates/itsi_error/src/lib.rs +10 -37
  7. data/crates/itsi_instrument_entry/Cargo.toml +15 -0
  8. data/crates/itsi_instrument_entry/src/lib.rs +31 -0
  9. data/crates/itsi_rb_helpers/Cargo.toml +2 -0
  10. data/crates/itsi_rb_helpers/src/heap_value.rs +121 -0
  11. data/crates/itsi_rb_helpers/src/lib.rs +90 -10
  12. data/crates/itsi_scheduler/Cargo.toml +9 -1
  13. data/crates/itsi_scheduler/extconf.rb +1 -1
  14. data/crates/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  15. data/crates/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  16. data/crates/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  17. data/crates/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  18. data/crates/itsi_scheduler/src/lib.rs +31 -10
  19. data/crates/itsi_server/Cargo.toml +14 -2
  20. data/crates/itsi_server/extconf.rb +1 -1
  21. data/crates/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  22. data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  23. data/crates/itsi_server/src/body_proxy/mod.rs +2 -0
  24. data/crates/itsi_server/src/lib.rs +58 -7
  25. data/crates/itsi_server/src/request/itsi_request.rs +238 -104
  26. data/crates/itsi_server/src/response/itsi_response.rs +347 -0
  27. data/crates/itsi_server/src/response/mod.rs +1 -0
  28. data/crates/itsi_server/src/server/bind.rs +50 -20
  29. data/crates/itsi_server/src/server/bind_protocol.rs +37 -0
  30. data/crates/itsi_server/src/server/io_stream.rs +104 -0
  31. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
  32. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
  33. data/crates/itsi_server/src/server/itsi_server.rs +196 -134
  34. data/crates/itsi_server/src/server/lifecycle_event.rs +9 -0
  35. data/crates/itsi_server/src/server/listener.rs +184 -127
  36. data/crates/itsi_server/src/server/mod.rs +7 -1
  37. data/crates/itsi_server/src/server/process_worker.rs +196 -0
  38. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  39. data/crates/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  40. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  41. data/crates/itsi_server/src/server/signal.rs +70 -0
  42. data/crates/itsi_server/src/server/thread_worker.rs +368 -0
  43. data/crates/itsi_server/src/server/tls.rs +42 -28
  44. data/crates/itsi_tracing/Cargo.toml +4 -0
  45. data/crates/itsi_tracing/src/lib.rs +36 -6
  46. data/gems/scheduler/Cargo.lock +219 -23
  47. data/gems/scheduler/Rakefile +7 -1
  48. data/gems/scheduler/ext/itsi_error/Cargo.toml +2 -0
  49. data/gems/scheduler/ext/itsi_error/src/from.rs +70 -0
  50. data/gems/scheduler/ext/itsi_error/src/lib.rs +10 -37
  51. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +15 -0
  52. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +31 -0
  53. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +2 -0
  54. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  55. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +90 -10
  56. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +9 -1
  57. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +1 -1
  58. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  59. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  60. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  61. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  62. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +31 -10
  63. data/gems/scheduler/ext/itsi_server/Cargo.toml +41 -0
  64. data/gems/scheduler/ext/itsi_server/extconf.rb +6 -0
  65. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  66. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  67. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  68. data/gems/scheduler/ext/itsi_server/src/lib.rs +103 -0
  69. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +277 -0
  70. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +1 -0
  71. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +347 -0
  72. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +1 -0
  73. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +168 -0
  74. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  75. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +104 -0
  76. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +13 -0
  77. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +5 -0
  78. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +244 -0
  79. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
  80. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +275 -0
  81. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +11 -0
  82. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +196 -0
  83. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  84. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  85. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  86. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +70 -0
  87. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +368 -0
  88. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +152 -0
  89. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +4 -0
  90. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +36 -6
  91. data/gems/scheduler/itsi-scheduler.gemspec +2 -3
  92. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  93. data/gems/scheduler/lib/itsi/scheduler.rb +137 -1
  94. data/gems/scheduler/test/helpers/test_helper.rb +24 -0
  95. data/gems/scheduler/test/test_active_record.rb +158 -0
  96. data/gems/scheduler/test/test_address_resolve.rb +23 -0
  97. data/gems/scheduler/test/test_block_unblock.rb +229 -0
  98. data/gems/scheduler/test/test_file_io.rb +193 -0
  99. data/gems/scheduler/test/test_itsi_scheduler.rb +24 -1
  100. data/gems/scheduler/test/test_kernel_sleep.rb +91 -0
  101. data/gems/scheduler/test/test_nested_fibers.rb +286 -0
  102. data/gems/scheduler/test/test_network_io.rb +274 -0
  103. data/gems/scheduler/test/test_process_wait.rb +26 -0
  104. data/gems/server/exe/itsi +88 -28
  105. data/gems/server/ext/itsi_error/Cargo.toml +2 -0
  106. data/gems/server/ext/itsi_error/src/from.rs +70 -0
  107. data/gems/server/ext/itsi_error/src/lib.rs +10 -37
  108. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +15 -0
  109. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +31 -0
  110. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +2 -0
  111. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  112. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +90 -10
  113. data/gems/server/ext/itsi_scheduler/Cargo.toml +24 -0
  114. data/gems/server/ext/itsi_scheduler/extconf.rb +6 -0
  115. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  116. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  117. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  118. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  119. data/gems/server/ext/itsi_scheduler/src/lib.rs +38 -0
  120. data/gems/server/ext/itsi_server/Cargo.toml +14 -2
  121. data/gems/server/ext/itsi_server/extconf.rb +1 -1
  122. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  123. data/gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  124. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  125. data/gems/server/ext/itsi_server/src/lib.rs +58 -7
  126. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +238 -104
  127. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +347 -0
  128. data/gems/server/ext/itsi_server/src/response/mod.rs +1 -0
  129. data/gems/server/ext/itsi_server/src/server/bind.rs +50 -20
  130. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  131. data/gems/server/ext/itsi_server/src/server/io_stream.rs +104 -0
  132. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
  133. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
  134. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +196 -134
  135. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
  136. data/gems/server/ext/itsi_server/src/server/listener.rs +184 -127
  137. data/gems/server/ext/itsi_server/src/server/mod.rs +7 -1
  138. data/gems/server/ext/itsi_server/src/server/process_worker.rs +196 -0
  139. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  140. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  141. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  142. data/gems/server/ext/itsi_server/src/server/signal.rs +70 -0
  143. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +368 -0
  144. data/gems/server/ext/itsi_server/src/server/tls.rs +42 -28
  145. data/gems/server/ext/itsi_tracing/Cargo.toml +4 -0
  146. data/gems/server/ext/itsi_tracing/src/lib.rs +36 -6
  147. data/gems/server/itsi-server.gemspec +4 -5
  148. data/gems/server/lib/itsi/request.rb +30 -14
  149. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +25 -0
  150. data/gems/server/lib/itsi/server/scheduler_mode.rb +6 -0
  151. data/gems/server/lib/itsi/server/version.rb +1 -1
  152. data/gems/server/lib/itsi/server.rb +82 -2
  153. data/gems/server/lib/itsi/signals.rb +23 -0
  154. data/gems/server/lib/itsi/stream_io.rb +38 -0
  155. data/gems/server/test/test_helper.rb +2 -0
  156. data/gems/server/test/test_itsi_server.rb +1 -1
  157. data/lib/itsi/version.rb +1 -1
  158. data/tasks.txt +18 -0
  159. metadata +102 -12
  160. data/crates/itsi_server/src/server/transfer_protocol.rs +0 -23
  161. data/crates/itsi_server/src/stream_writer/mod.rs +0 -21
  162. data/gems/scheduler/test/test_helper.rb +0 -6
  163. data/gems/server/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  164. data/gems/server/ext/itsi_server/src/stream_writer/mod.rs +0 -21
@@ -0,0 +1,103 @@
1
+ use body_proxy::itsi_body_proxy::ItsiBodyProxy;
2
+ use magnus::{error::Result, function, method, value::Lazy, Module, Object, RClass, RModule, Ruby};
3
+ use request::itsi_request::ItsiRequest;
4
+ use response::itsi_response::ItsiResponse;
5
+ use server::{itsi_server::Server, signal::reset_signal_handlers};
6
+ use tracing::*;
7
+
8
+ pub mod body_proxy;
9
+ pub mod request;
10
+ pub mod response;
11
+ pub mod server;
12
+
13
+ pub static ITSI_MODULE: Lazy<RModule> = Lazy::new(|ruby| ruby.define_module("Itsi").unwrap());
14
+ pub static ITSI_SERVER: Lazy<RClass> = Lazy::new(|ruby| {
15
+ ruby.get_inner(&ITSI_MODULE)
16
+ .define_class("Server", ruby.class_object())
17
+ .unwrap()
18
+ });
19
+ pub static ITSI_REQUEST: Lazy<RClass> = Lazy::new(|ruby| {
20
+ ruby.get_inner(&ITSI_MODULE)
21
+ .define_class("Request", ruby.class_object())
22
+ .unwrap()
23
+ });
24
+
25
+ pub static ITSI_RESPONSE: Lazy<RClass> = Lazy::new(|ruby| {
26
+ ruby.get_inner(&ITSI_MODULE)
27
+ .define_class("Response", ruby.class_object())
28
+ .unwrap()
29
+ });
30
+
31
+ pub static ITSI_BODY_PROXY: Lazy<RClass> = Lazy::new(|ruby| {
32
+ ruby.get_inner(&ITSI_MODULE)
33
+ .define_class("BodyProxy", ruby.class_object())
34
+ .unwrap()
35
+ });
36
+
37
+ pub static ITSI_SERVER_SCHEDULER_TASK: Lazy<RClass> = Lazy::new(|ruby| {
38
+ ruby.get_inner(&ITSI_MODULE)
39
+ .define_class("ServerSchedulerTask", ruby.class_object())
40
+ .unwrap()
41
+ });
42
+
43
+ pub fn log_debug(msg: String) {
44
+ debug!(msg);
45
+ }
46
+ pub fn log_info(msg: String) {
47
+ info!(msg);
48
+ }
49
+ pub fn log_warn(msg: String) {
50
+ warn!(msg);
51
+ }
52
+ pub fn log_error(msg: String) {
53
+ error!(msg);
54
+ }
55
+
56
+ #[magnus::init]
57
+ fn init(ruby: &Ruby) -> Result<()> {
58
+ itsi_tracing::init();
59
+
60
+ let itsi = ruby.get_inner(&ITSI_MODULE);
61
+ itsi.define_singleton_method("log_debug", function!(log_debug, 1))?;
62
+ itsi.define_singleton_method("log_info", function!(log_info, 1))?;
63
+ itsi.define_singleton_method("log_warn", function!(log_warn, 1))?;
64
+ itsi.define_singleton_method("log_error", function!(log_error, 1))?;
65
+
66
+ let server = ruby.get_inner(&ITSI_SERVER);
67
+ server.define_singleton_method("new", function!(Server::new, -1))?;
68
+ server.define_singleton_method("reset_signal_handlers", function!(reset_signal_handlers, 0))?;
69
+ server.define_method("start", method!(Server::start, 0))?;
70
+
71
+ let request = ruby.get_inner(&ITSI_REQUEST);
72
+ request.define_method("path", method!(ItsiRequest::path, 0))?;
73
+ request.define_method("script_name", method!(ItsiRequest::script_name, 0))?;
74
+ request.define_method("query_string", method!(ItsiRequest::query_string, 0))?;
75
+ request.define_method("method", method!(ItsiRequest::method, 0))?;
76
+ request.define_method("version", method!(ItsiRequest::version, 0))?;
77
+ request.define_method("rack_protocol", method!(ItsiRequest::rack_protocol, 0))?;
78
+ request.define_method("host", method!(ItsiRequest::host, 0))?;
79
+ request.define_method("headers", method!(ItsiRequest::headers, 0))?;
80
+ request.define_method("scheme", method!(ItsiRequest::scheme, 0))?;
81
+ request.define_method("remote_addr", method!(ItsiRequest::remote_addr, 0))?;
82
+ request.define_method("port", method!(ItsiRequest::port, 0))?;
83
+ request.define_method("body", method!(ItsiRequest::body, 0))?;
84
+ request.define_method("response", method!(ItsiRequest::response, 0))?;
85
+
86
+ let body_proxy = ruby.get_inner(&ITSI_BODY_PROXY);
87
+ body_proxy.define_method("gets", method!(ItsiBodyProxy::gets, 0))?;
88
+ body_proxy.define_method("each", method!(ItsiBodyProxy::each, 0))?;
89
+ body_proxy.define_method("read", method!(ItsiBodyProxy::read, -1))?;
90
+ body_proxy.define_method("close", method!(ItsiBodyProxy::close, 0))?;
91
+
92
+ let response = ruby.get_inner(&ITSI_RESPONSE);
93
+ response.define_method("add_header", method!(ItsiResponse::add_header, 2))?;
94
+ response.define_method("status=", method!(ItsiResponse::set_status, 1))?;
95
+ response.define_method("send_frame", method!(ItsiResponse::send_frame, 1))?;
96
+ response.define_method("send_and_close", method!(ItsiResponse::send_and_close, 1))?;
97
+ response.define_method("close_write", method!(ItsiResponse::close_write, 0))?;
98
+ response.define_method("close_read", method!(ItsiResponse::close_read, 0))?;
99
+ response.define_method("close", method!(ItsiResponse::close, 0))?;
100
+ response.define_method("hijack", method!(ItsiResponse::hijack, 1))?;
101
+
102
+ Ok(())
103
+ }
@@ -0,0 +1,277 @@
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::{SockAddr, TokioListener},
10
+ serve_strategy::single_mode::RunningPhase,
11
+ },
12
+ };
13
+ use bytes::Bytes;
14
+ use derive_more::Debug;
15
+ use futures::StreamExt;
16
+ use http::{request::Parts, Response, StatusCode};
17
+ use http_body_util::{combinators::BoxBody, BodyExt, Empty};
18
+ use hyper::{body::Incoming, Request};
19
+ use itsi_error::from::CLIENT_CONNECTION_CLOSED;
20
+ use itsi_tracing::{debug, error};
21
+ use magnus::{
22
+ error::{ErrorType, Result as MagnusResult},
23
+ Error,
24
+ };
25
+ use magnus::{
26
+ value::{LazyId, Opaque, ReprValue},
27
+ RClass, Ruby, Value,
28
+ };
29
+ use std::{convert::Infallible, fmt, io::Write, sync::Arc, time::Instant};
30
+ use tokio::sync::{
31
+ mpsc::{self},
32
+ watch,
33
+ };
34
+ static ID_CALL: LazyId = LazyId::new("call");
35
+ static ID_MESSAGE: LazyId = LazyId::new("message");
36
+ static ID_BACKTRACE: LazyId = LazyId::new("backtrace");
37
+
38
+ #[derive(Debug)]
39
+ #[magnus::wrap(class = "Itsi::Request", free_immediately, size)]
40
+ pub struct ItsiRequest {
41
+ pub parts: Parts,
42
+ #[debug(skip)]
43
+ pub body: ItsiBody,
44
+ pub remote_addr: String,
45
+ pub version: String,
46
+ #[debug(skip)]
47
+ pub(crate) listener: Arc<TokioListener>,
48
+ #[debug(skip)]
49
+ pub server: Arc<Server>,
50
+ pub response: ItsiResponse,
51
+ pub start: Instant,
52
+ }
53
+
54
+ impl fmt::Display for ItsiRequest {
55
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56
+ write!(
57
+ f,
58
+ "{} {} {}",
59
+ self.version().unwrap(),
60
+ self.method().unwrap(),
61
+ self.path().unwrap()
62
+ )
63
+ }
64
+ }
65
+
66
+ impl ItsiRequest {
67
+ pub fn is_connection_closed_err(ruby: &Ruby, err: &Error) -> bool {
68
+ match err.error_type() {
69
+ ErrorType::Jump(_) => false,
70
+ ErrorType::Error(_, _) => false,
71
+ ErrorType::Exception(exception) => {
72
+ exception.is_kind_of(ruby.exception_eof_error())
73
+ && err
74
+ .value()
75
+ .map(|v| {
76
+ v.funcall::<_, _, String>(*ID_MESSAGE, ())
77
+ .unwrap_or("".to_string())
78
+ .eq(CLIENT_CONNECTION_CLOSED)
79
+ })
80
+ .unwrap_or(false)
81
+ }
82
+ }
83
+ }
84
+
85
+ pub fn process(
86
+ self,
87
+ ruby: &Ruby,
88
+ server: RClass,
89
+ app: Opaque<Value>,
90
+ ) -> magnus::error::Result<()> {
91
+ let req = format!("{}", self);
92
+ let response = self.response.clone();
93
+ let start = self.start;
94
+ debug!("{} Started", req);
95
+ let result = server.funcall::<_, _, Value>(*ID_CALL, (app, self));
96
+ if let Err(err) = result {
97
+ Self::internal_error(ruby, response, err);
98
+ }
99
+ debug!("{} Finished in {:?}", req, start.elapsed());
100
+
101
+ Ok(())
102
+ }
103
+
104
+ pub fn internal_error(ruby: &Ruby, response: ItsiResponse, err: Error) {
105
+ if Self::is_connection_closed_err(ruby, &err) {
106
+ debug!("Connection closed by client");
107
+ response.close();
108
+ } else if let Some(rb_err) = err.value() {
109
+ let backtrace = rb_err
110
+ .funcall::<_, _, Vec<String>>(*ID_BACKTRACE, ())
111
+ .unwrap_or_default();
112
+
113
+ error!("Error occurred in Handler: {:?}", rb_err);
114
+ for line in backtrace {
115
+ error!("{}", line);
116
+ }
117
+ response.internal_server_error(err.to_string());
118
+ } else {
119
+ response.internal_server_error(err.to_string());
120
+ }
121
+ }
122
+
123
+ pub fn error(self, message: String) {
124
+ self.response.internal_server_error(message);
125
+ }
126
+
127
+ pub(crate) async fn process_request(
128
+ hyper_request: Request<Incoming>,
129
+ sender: async_channel::Sender<RequestJob>,
130
+ server: Arc<Server>,
131
+ listener: Arc<TokioListener>,
132
+ addr: SockAddr,
133
+ shutdown_rx: watch::Receiver<RunningPhase>,
134
+ ) -> itsi_error::Result<Response<BoxBody<Bytes, Infallible>>> {
135
+ let (request, mut receiver) = ItsiRequest::new(hyper_request, addr, server, listener).await;
136
+
137
+ let response = request.response.clone();
138
+ match sender.send(RequestJob::ProcessRequest(request)).await {
139
+ Err(err) => {
140
+ error!("Error occurred: {}", err);
141
+ let mut response = Response::new(BoxBody::new(Empty::new()));
142
+ *response.status_mut() = StatusCode::BAD_REQUEST;
143
+ Ok(response)
144
+ }
145
+ _ => match receiver.recv().await {
146
+ Some(first_frame) => Ok(response.build(first_frame, receiver, shutdown_rx).await),
147
+ None => Ok(response.build(None, receiver, shutdown_rx).await),
148
+ },
149
+ }
150
+ }
151
+
152
+ pub(crate) async fn new(
153
+ request: Request<Incoming>,
154
+ sock_addr: SockAddr,
155
+ server: Arc<Server>,
156
+ listener: Arc<TokioListener>,
157
+ ) -> (ItsiRequest, mpsc::Receiver<Option<Bytes>>) {
158
+ let (parts, body) = request.into_parts();
159
+ let body = if server.stream_body.is_some_and(|f| f) {
160
+ ItsiBody::Stream(ItsiBodyProxy::new(body))
161
+ } else {
162
+ let mut body_bytes = BigBytes::new();
163
+ let mut stream = body.into_data_stream();
164
+ while let Some(chunk) = stream.next().await {
165
+ let byte_array = chunk.unwrap().to_vec();
166
+ body_bytes.write_all(&byte_array).unwrap();
167
+ }
168
+ ItsiBody::Buffered(body_bytes)
169
+ };
170
+ let response_channel = mpsc::channel::<Option<Bytes>>(100);
171
+ (
172
+ Self {
173
+ remote_addr: sock_addr.to_string(),
174
+ body,
175
+ server,
176
+ listener,
177
+ version: format!("{:?}", &parts.version),
178
+ response: ItsiResponse::new(parts.clone(), response_channel.0),
179
+ start: Instant::now(),
180
+ parts,
181
+ },
182
+ response_channel.1,
183
+ )
184
+ }
185
+
186
+ pub(crate) fn path(&self) -> MagnusResult<&str> {
187
+ Ok(self
188
+ .parts
189
+ .uri
190
+ .path()
191
+ .strip_prefix(&self.server.script_name)
192
+ .unwrap_or(self.parts.uri.path()))
193
+ }
194
+
195
+ pub(crate) fn script_name(&self) -> MagnusResult<&str> {
196
+ Ok(&self.server.script_name)
197
+ }
198
+
199
+ pub(crate) fn query_string(&self) -> MagnusResult<&str> {
200
+ Ok(self.parts.uri.query().unwrap_or(""))
201
+ }
202
+
203
+ pub(crate) fn method(&self) -> MagnusResult<&str> {
204
+ Ok(self.parts.method.as_str())
205
+ }
206
+
207
+ pub(crate) fn version(&self) -> MagnusResult<&str> {
208
+ Ok(&self.version)
209
+ }
210
+
211
+ pub(crate) fn rack_protocol(&self) -> MagnusResult<Vec<&str>> {
212
+ Ok(self
213
+ .parts
214
+ .headers
215
+ .get("upgrade")
216
+ .or_else(|| self.parts.headers.get("protocol"))
217
+ .map(|value| {
218
+ value
219
+ .to_str()
220
+ .unwrap_or("")
221
+ .split(',')
222
+ .map(|s| s.trim())
223
+ .collect::<Vec<&str>>()
224
+ })
225
+ .unwrap_or_else(|| vec!["http"]))
226
+ }
227
+
228
+ pub(crate) fn host(&self) -> MagnusResult<String> {
229
+ Ok(self
230
+ .parts
231
+ .uri
232
+ .host()
233
+ .map(|host| host.to_string())
234
+ .unwrap_or_else(|| self.listener.host()))
235
+ }
236
+
237
+ pub(crate) fn scheme(&self) -> MagnusResult<String> {
238
+ Ok(self
239
+ .parts
240
+ .uri
241
+ .scheme()
242
+ .map(|scheme| scheme.to_string())
243
+ .unwrap_or_else(|| self.listener.scheme()))
244
+ }
245
+
246
+ pub(crate) fn headers(&self) -> MagnusResult<Vec<(String, &str)>> {
247
+ Ok(self
248
+ .parts
249
+ .headers
250
+ .iter()
251
+ .map(|(hn, hv)| {
252
+ let key = match hn.as_str() {
253
+ "content-length" => "CONTENT_LENGTH".to_string(),
254
+ "content-type" => "CONTENT_TYPE".to_string(),
255
+ _ => format!("HTTP_{}", hn.as_str().to_uppercase().replace("-", "_")),
256
+ };
257
+ (key, hv.to_str().unwrap_or(""))
258
+ })
259
+ .collect())
260
+ }
261
+
262
+ pub(crate) fn remote_addr(&self) -> MagnusResult<&str> {
263
+ Ok(&self.remote_addr)
264
+ }
265
+
266
+ pub(crate) fn port(&self) -> MagnusResult<u16> {
267
+ Ok(self.parts.uri.port_u16().unwrap_or(self.listener.port()))
268
+ }
269
+
270
+ pub(crate) fn body(&self) -> MagnusResult<Value> {
271
+ Ok(self.body.into_value())
272
+ }
273
+
274
+ pub(crate) fn response(&self) -> MagnusResult<ItsiResponse> {
275
+ Ok(self.response.clone())
276
+ }
277
+ }
@@ -0,0 +1 @@
1
+ pub mod itsi_request;