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.

Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +7 -0
  3. data/Cargo.lock +90 -22
  4. data/README.md +5 -0
  5. data/_index.md +7 -0
  6. data/ext/itsi_error/Cargo.toml +1 -0
  7. data/ext/itsi_error/src/lib.rs +106 -7
  8. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  9. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  10. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  11. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  12. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  13. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  14. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  15. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  16. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  17. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  18. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  19. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  20. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  21. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  22. data/ext/itsi_rb_helpers/Cargo.toml +1 -0
  23. data/ext/itsi_rb_helpers/src/heap_value.rs +18 -0
  24. data/ext/itsi_rb_helpers/src/lib.rs +59 -9
  25. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  26. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  27. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  28. 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
  29. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  30. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  31. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  32. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  33. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  34. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  35. data/ext/itsi_scheduler/src/itsi_scheduler.rs +1 -1
  36. data/ext/itsi_server/Cargo.lock +2956 -0
  37. data/ext/itsi_server/Cargo.toml +72 -28
  38. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  39. data/ext/itsi_server/src/env.rs +43 -0
  40. data/ext/itsi_server/src/lib.rs +113 -75
  41. data/ext/itsi_server/src/prelude.rs +2 -0
  42. data/ext/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  43. data/ext/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +29 -8
  44. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  45. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  46. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +345 -0
  47. data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +84 -40
  48. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
  49. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +375 -0
  50. data/ext/itsi_server/src/ruby_types/itsi_server.rs +83 -0
  51. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  52. data/ext/itsi_server/src/server/{bind.rs → binds/bind.rs} +56 -24
  53. data/ext/itsi_server/src/server/{listener.rs → binds/listener.rs} +218 -113
  54. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  55. data/ext/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +55 -17
  56. data/ext/itsi_server/src/server/{tls.rs → binds/tls.rs} +109 -28
  57. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  58. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  59. data/ext/itsi_server/src/server/io_stream.rs +2 -1
  60. data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
  61. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +165 -0
  62. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +56 -0
  63. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +87 -0
  64. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +86 -0
  65. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +285 -0
  66. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +142 -0
  67. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +289 -0
  68. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +292 -0
  69. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +55 -0
  70. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
  71. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +157 -0
  72. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +195 -0
  73. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  74. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +201 -0
  75. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  76. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  77. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +87 -0
  78. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +414 -0
  79. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +131 -0
  80. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  81. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +44 -0
  82. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +36 -0
  83. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  84. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +180 -0
  85. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  86. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +163 -0
  87. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  88. data/ext/itsi_server/src/server/middleware_stack/mod.rs +347 -0
  89. data/ext/itsi_server/src/server/mod.rs +6 -5
  90. data/ext/itsi_server/src/server/process_worker.rs +65 -14
  91. data/ext/itsi_server/src/server/request_job.rs +11 -0
  92. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +137 -49
  93. data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  94. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +338 -164
  95. data/ext/itsi_server/src/server/signal.rs +32 -26
  96. data/ext/itsi_server/src/server/size_limited_incoming.rs +101 -0
  97. data/ext/itsi_server/src/server/thread_worker.rs +214 -107
  98. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  99. data/ext/itsi_server/src/services/itsi_http_service.rs +239 -0
  100. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  101. data/ext/itsi_server/src/services/mod.rs +6 -0
  102. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  103. data/ext/itsi_server/src/services/rate_limiter.rs +569 -0
  104. data/ext/itsi_server/src/services/static_file_server.rs +1324 -0
  105. data/ext/itsi_tracing/Cargo.toml +1 -0
  106. data/ext/itsi_tracing/src/lib.rs +312 -34
  107. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  108. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  109. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  110. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  111. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  112. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  113. data/lib/itsi/scheduler/version.rb +1 -1
  114. data/lib/itsi/scheduler.rb +2 -2
  115. metadata +93 -21
  116. data/ext/itsi_error/src/from.rs +0 -71
  117. data/ext/itsi_server/extconf.rb +0 -6
  118. data/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  119. data/ext/itsi_server/src/request/itsi_request.rs +0 -277
  120. data/ext/itsi_server/src/request/mod.rs +0 -1
  121. data/ext/itsi_server/src/response/mod.rs +0 -1
  122. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  123. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  124. data/ext/itsi_server/src/server/itsi_server.rs +0 -244
  125. /data/ext/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "itsi-server"
3
- version = "0.1.0"
3
+ version = "0.1.19"
4
4
  edition = "2021"
5
5
  authors = ["Wouter Coppieters <wc@pico.net.nz>"]
6
6
  license = "MIT"
@@ -10,37 +10,81 @@ publish = false
10
10
  crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
- magnus = { version = "0.7.1", features = ["bytes", "rb-sys"] }
14
- itsi_tracing = { path = "../itsi_tracing" }
15
- itsi_rb_helpers = { path = "../itsi_rb_helpers" }
16
- itsi_error = { path = "../itsi_error" }
17
- socket2 = "0.5.8"
18
- parking_lot = "0.12.3"
19
- rustls-pemfile = "2.2.0"
20
- tokio-rustls = "0.26.2"
21
- bytes = "1.3"
22
- rcgen = { version = "0.13.2", features = ["x509-parser", "pem"] }
13
+ async-compression = { version = "0.4.21", features = [
14
+ "futures-io",
15
+ "tokio",
16
+ "zstd",
17
+ "brotli",
18
+ "deflate",
19
+ "gzip",
20
+ "zlib",
21
+ ] }
22
+ async-channel = "2.3.1"
23
+ async-trait = "0.1.87"
24
+ bcrypt = "0.17.0"
23
25
  base64 = "0.22.1"
26
+ bytes = "1.3"
27
+ chrono = "0.4.35"
28
+ derive_more = { version = "2.0.1", features = ["debug"] }
29
+ dirs = "6.0.0"
30
+ either = "1.15.0"
31
+ fs2 = "0.4.3"
32
+ futures = "0.3.31"
33
+ globset = "0.4.16"
34
+ http = "1.3.1"
24
35
  http-body-util = "0.1.2"
36
+ httpdate = "1.0.3"
37
+ httparse = "1.10.1"
25
38
  hyper = { version = "1.5.0", features = ["full", "server", "http1", "http2"] }
26
- tokio = { version = "1", features = ["full"] }
27
39
  hyper-util = { version = "0.1.10", features = ["full"] }
28
- derive_more = { version = "2.0.1", features = ["debug"] }
29
- http = "1.3.1"
30
- crossbeam = "0.8.4"
31
- futures = "0.3.31"
32
- nix = { version = "0.29.0", features = ["socket", "uio", "signal"] }
40
+ itsi_error = { path = "../itsi_error" }
41
+ itsi_rb_helpers = { path = "../itsi_rb_helpers" }
42
+ itsi_tracing = { path = "../itsi_tracing" }
43
+ jsonwebtoken = "9.3.1"
44
+ magnus = { version = "0.7.1", features = ["bytes", "rb-sys"] }
45
+ moka = { version = "0.12.10", features = ["sync"] }
46
+ notify = { version = "8.0.0" }
47
+ nix = { version = "0.29.0", features = [
48
+ "socket",
49
+ "uio",
50
+ "signal",
51
+ "fs",
52
+ "process",
53
+ ] }
54
+ num_cpus = "1.16.0"
55
+ parking_lot = "0.12.3"
33
56
  pin-project = "1.1.9"
34
- rb-sys = "0.9.111"
35
- tracing = "0.1.41"
36
- tokio-util = "0.7.13"
37
- tokio-stream = "0.1.17"
38
- httparse = "1.10.1"
39
- async-channel = "2.3.1"
40
- tempfile = "3.18.0"
57
+ rand = "0.9.0"
58
+ rcgen = { version = "0.13.2", features = ["x509-parser", "pem"] }
59
+ regex = "1.11.1"
60
+ reqwest = { version = "0.12.15", features = [
61
+ "stream",
62
+ "rustls-tls",
63
+ ], default-features = false }
64
+ redis = { version = "0.29.2", features = [
65
+ "tokio-comp",
66
+ "r2d2",
67
+ "tokio-rustls-comp",
68
+ "connection-manager",
69
+ ] }
70
+ rustls = "0.23.23"
71
+ rustls-pemfile = "2.2.0"
72
+ serde = "1.0.219"
73
+ serde_json = "1.0.140"
74
+ serde_magnus = "0.9.0"
75
+ sha2 = "0.10.8"
76
+ socket2 = "0.5.8"
41
77
  sysinfo = "0.33.1"
78
+ tempfile = "3.18.0"
79
+ tokio = { version = "1.44.1", features = ["full"] }
80
+ tokio-rustls = "0.26.2"
42
81
  tokio-rustls-acme = "0.6.0"
43
- rustls = "0.23.23"
44
- fs2 = "0.4.3"
45
- ring = "0.17.14"
46
- async-trait = "0.1.87"
82
+ tokio-stream = "0.1.17"
83
+ tokio-util = "0.7.13"
84
+ tracing = "0.1.41"
85
+ url = "2.5.4"
86
+ md5 = "0.7.0"
87
+ percent-encoding = "2.3.1"
88
+ sha-crypt = "0.5.0"
89
+ argon2 = "0.5.3"
90
+ core_affinity = "0.8.3"
@@ -0,0 +1,11 @@
1
+ use std::sync::LazyLock;
2
+
3
+ use crate::server::middleware_stack::ErrorResponse;
4
+
5
+ pub static TIMEOUT_RESPONSE: LazyLock<ErrorResponse> =
6
+ LazyLock::new(ErrorResponse::gateway_timeout);
7
+
8
+ pub static NOT_FOUND_RESPONSE: LazyLock<ErrorResponse> = LazyLock::new(ErrorResponse::not_found);
9
+
10
+ pub static INTERNAL_SERVER_ERROR_RESPONSE: LazyLock<ErrorResponse> =
11
+ LazyLock::new(ErrorResponse::internal_server_error);
@@ -0,0 +1,43 @@
1
+ use std::{
2
+ env::{var, VarError},
3
+ path::PathBuf,
4
+ sync::LazyLock,
5
+ };
6
+
7
+ type StringVar = LazyLock<String>;
8
+ type MaybeStringVar = LazyLock<Result<String, VarError>>;
9
+ type PathVar = LazyLock<PathBuf>;
10
+
11
+ /// ACME Configuration for auto-generating production certificates
12
+ /// *ITSI_ACME_CACHE_DIR* - Directory to store cached certificates
13
+ /// so that these are not regenerated every time the server starts
14
+ pub static ITSI_ACME_CACHE_DIR: StringVar = LazyLock::new(|| {
15
+ var("ITSI_ACME_CACHE_DIR").unwrap_or_else(|_| "./.rustls_acme_cache".to_string())
16
+ });
17
+
18
+ /// *ITSI_ACME_CONTACT_EMAIL* - Contact Email address to provide to ACME server during certificate renewal
19
+ pub static ITSI_ACME_CONTACT_EMAIL: MaybeStringVar =
20
+ LazyLock::new(|| var("ITSI_ACME_CONTACT_EMAIL"));
21
+
22
+ /// *ITSI_ACME_CA_PEM_PATH* - Optional CA Pem path, used for testing with non-trusted CAs for certifcate generation.
23
+ pub static ITSI_ACME_CA_PEM_PATH: MaybeStringVar = LazyLock::new(|| var("ITSI_ACME_CA_PEM_PATH"));
24
+
25
+ /// *ITSI_ACME_DIRECTORY_URL* - Directory URL to use for ACME certificate generation.
26
+ pub static ITSI_ACME_DIRECTORY_URL: StringVar = LazyLock::new(|| {
27
+ var("ITSI_ACME_DIRECTORY_URL")
28
+ .unwrap_or_else(|_| "https://acme-v02.api.letsencrypt.org/directory".to_string())
29
+ });
30
+
31
+ /// *ITSI_ACME_LOCK_FILE_NAME* - Name of the lock file used to prevent concurrent certificate generation.
32
+ pub static ITSI_ACME_LOCK_FILE_NAME: StringVar =
33
+ LazyLock::new(|| var("ITSI_ACME_LOCK_FILE_NAME").unwrap_or(".acme.lock".to_string()));
34
+
35
+ pub static ITSI_LOCAL_CA_DIR: PathVar = LazyLock::new(|| {
36
+ var("ITSI_LOCAL_CA_DIR")
37
+ .map(PathBuf::from)
38
+ .unwrap_or_else(|_| {
39
+ dirs::home_dir()
40
+ .expect("Failed to find HOME directory when initializing ITSI_LOCAL_CA_DIR")
41
+ .join(".itsi")
42
+ })
43
+ });
@@ -1,57 +1,21 @@
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;
1
+ #![deny(unused_crate_dependencies)]
2
+ pub mod default_responses;
3
+ pub mod env;
4
+ pub mod prelude;
5
+ pub mod ruby_types;
11
6
  pub mod server;
7
+ pub mod services;
12
8
 
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
- }
9
+ use magnus::{error::Result, function, method, Module, Object, Ruby};
10
+ use prelude::*;
11
+ use ruby_types::{
12
+ itsi_body_proxy::ItsiBodyProxy, itsi_grpc_call::ItsiGrpcCall,
13
+ itsi_grpc_response_stream::ItsiGrpcResponseStream, itsi_http_request::ItsiHttpRequest,
14
+ itsi_http_response::ItsiHttpResponse, itsi_server::ItsiServer, ITSI_BODY_PROXY, ITSI_GRPC_CALL,
15
+ ITSI_GRPC_RESPONSE_STREAM, ITSI_MODULE, ITSI_REQUEST, ITSI_RESPONSE, ITSI_SERVER,
16
+ };
17
+ use server::signal::reset_signal_handlers;
18
+ use services::password_hasher;
55
19
 
56
20
  #[magnus::init]
57
21
  fn init(ruby: &Ruby) -> Result<()> {
@@ -65,26 +29,46 @@ fn init(ruby: &Ruby) -> Result<()> {
65
29
  itsi.define_singleton_method("log_info", function!(log_info, 1))?;
66
30
  itsi.define_singleton_method("log_warn", function!(log_warn, 1))?;
67
31
  itsi.define_singleton_method("log_error", function!(log_error, 1))?;
32
+ itsi.define_singleton_method(
33
+ "create_password_hash",
34
+ function!(password_hasher::create_password_hash, 2),
35
+ )?;
68
36
 
69
37
  let server = ruby.get_inner(&ITSI_SERVER);
70
- server.define_singleton_method("new", function!(Server::new, -1))?;
38
+ server.define_singleton_method("new", function!(ItsiServer::new, 3))?;
71
39
  server.define_singleton_method("reset_signal_handlers", function!(reset_signal_handlers, 0))?;
72
- server.define_method("start", method!(Server::start, 0))?;
40
+ server.define_method("start", method!(ItsiServer::start, 0))?;
41
+ server.define_method("stop", method!(ItsiServer::stop, 0))?;
73
42
 
74
43
  let request = ruby.get_inner(&ITSI_REQUEST);
75
- request.define_method("path", method!(ItsiRequest::path, 0))?;
76
- request.define_method("script_name", method!(ItsiRequest::script_name, 0))?;
77
- request.define_method("query_string", method!(ItsiRequest::query_string, 0))?;
78
- request.define_method("method", method!(ItsiRequest::method, 0))?;
79
- request.define_method("version", method!(ItsiRequest::version, 0))?;
80
- request.define_method("rack_protocol", method!(ItsiRequest::rack_protocol, 0))?;
81
- request.define_method("host", method!(ItsiRequest::host, 0))?;
82
- request.define_method("headers", method!(ItsiRequest::headers, 0))?;
83
- request.define_method("scheme", method!(ItsiRequest::scheme, 0))?;
84
- request.define_method("remote_addr", method!(ItsiRequest::remote_addr, 0))?;
85
- request.define_method("port", method!(ItsiRequest::port, 0))?;
86
- request.define_method("body", method!(ItsiRequest::body, 0))?;
87
- request.define_method("response", method!(ItsiRequest::response, 0))?;
44
+ request.define_method("path", method!(ItsiHttpRequest::path, 0))?;
45
+ request.define_method("script_name", method!(ItsiHttpRequest::script_name, 0))?;
46
+ request.define_method("query_string", method!(ItsiHttpRequest::query_string, 0))?;
47
+ request.define_method(
48
+ "content_type",
49
+ method!(ItsiHttpRequest::content_type_str, 0),
50
+ )?;
51
+ request.define_method(
52
+ "content_length",
53
+ method!(ItsiHttpRequest::content_length, 0),
54
+ )?;
55
+ request.define_method("request_method", method!(ItsiHttpRequest::method, 0))?;
56
+ request.define_method("version", method!(ItsiHttpRequest::version, 0))?;
57
+ request.define_method("rack_protocol", method!(ItsiHttpRequest::rack_protocol, 0))?;
58
+ request.define_method("host", method!(ItsiHttpRequest::host, 0))?;
59
+ request.define_method("headers", method!(ItsiHttpRequest::headers, 0))?;
60
+ request.define_method("header", method!(ItsiHttpRequest::header, 1))?;
61
+ request.define_method("[]", method!(ItsiHttpRequest::header, 1))?;
62
+ request.define_method("scheme", method!(ItsiHttpRequest::scheme, 0))?;
63
+ request.define_method("remote_addr", method!(ItsiHttpRequest::remote_addr, 0))?;
64
+ request.define_method("port", method!(ItsiHttpRequest::port, 0))?;
65
+ request.define_method("body", method!(ItsiHttpRequest::body, 0))?;
66
+ request.define_method("response", method!(ItsiHttpRequest::response, 0))?;
67
+ request.define_method("json?", method!(ItsiHttpRequest::is_json, 0))?;
68
+ request.define_method("html?", method!(ItsiHttpRequest::is_html, 0))?;
69
+ request.define_method("url_encoded?", method!(ItsiHttpRequest::is_url_encoded, 0))?;
70
+ request.define_method("multipart?", method!(ItsiHttpRequest::is_multipart, 0))?;
71
+ request.define_method("url_params", method!(ItsiHttpRequest::url_params, 0))?;
88
72
 
89
73
  let body_proxy = ruby.get_inner(&ITSI_BODY_PROXY);
90
74
  body_proxy.define_method("gets", method!(ItsiBodyProxy::gets, 0))?;
@@ -93,14 +77,68 @@ fn init(ruby: &Ruby) -> Result<()> {
93
77
  body_proxy.define_method("close", method!(ItsiBodyProxy::close, 0))?;
94
78
 
95
79
  let response = ruby.get_inner(&ITSI_RESPONSE);
96
- response.define_method("add_header", method!(ItsiResponse::add_header, 2))?;
97
- response.define_method("status=", method!(ItsiResponse::set_status, 1))?;
98
- response.define_method("send_frame", method!(ItsiResponse::send_frame, 1))?;
99
- response.define_method("send_and_close", method!(ItsiResponse::send_and_close, 1))?;
100
- response.define_method("close_write", method!(ItsiResponse::close_write, 0))?;
101
- response.define_method("close_read", method!(ItsiResponse::close_read, 0))?;
102
- response.define_method("close", method!(ItsiResponse::close, 0))?;
103
- response.define_method("hijack", method!(ItsiResponse::hijack, 1))?;
80
+ response.define_method("[]=", method!(ItsiHttpResponse::add_header, 2))?;
81
+ response.define_method("add_header", method!(ItsiHttpResponse::add_header, 2))?;
82
+ response.define_method("add_headers", method!(ItsiHttpResponse::add_headers, 1))?;
83
+ response.define_method("status=", method!(ItsiHttpResponse::set_status, 1))?;
84
+ response.define_method("send_frame", method!(ItsiHttpResponse::send_frame, 1))?;
85
+ response.define_method("<<", method!(ItsiHttpResponse::send_frame, 1))?;
86
+ response.define_method("write", method!(ItsiHttpResponse::send_frame, 1))?;
87
+ response.define_method("read", method!(ItsiHttpResponse::recv_frame, 0))?;
88
+ response.define_method(
89
+ "send_and_close",
90
+ method!(ItsiHttpResponse::send_and_close, 1),
91
+ )?;
92
+ response.define_method("close_write", method!(ItsiHttpResponse::close_write, 0))?;
93
+ response.define_method("close_read", method!(ItsiHttpResponse::close_read, 0))?;
94
+ response.define_method("close", method!(ItsiHttpResponse::close, 0))?;
95
+ response.define_method("hijack", method!(ItsiHttpResponse::hijack, 1))?;
96
+ response.define_method("accept", method!(ItsiHttpResponse::accept_str, 0))?;
97
+ response.define_method("json?", method!(ItsiHttpResponse::is_json, 0))?;
98
+ response.define_method("html?", method!(ItsiHttpResponse::is_html, 0))?;
99
+
100
+ let grpc_call = ruby.get_inner(&ITSI_GRPC_CALL);
101
+ grpc_call.define_method("service_name", method!(ItsiGrpcCall::service_name, 0))?;
102
+ grpc_call.define_method("method_name", method!(ItsiGrpcCall::method_name, 0))?;
103
+ grpc_call.define_method("stream", method!(ItsiGrpcCall::stream, 0))?;
104
+ grpc_call.define_method("json?", method!(ItsiGrpcCall::is_json, 0))?;
105
+ grpc_call.define_method("content_type", method!(ItsiGrpcCall::content_type_str, 0))?;
106
+ grpc_call.define_method("timeout", method!(ItsiGrpcCall::timeout, 0))?;
107
+ grpc_call.define_method("cancelled?", method!(ItsiGrpcCall::is_cancelled, 0))?;
108
+ grpc_call.define_method("add_headers", method!(ItsiGrpcCall::add_headers, 1))?;
109
+ grpc_call.define_method("compress_output", method!(ItsiGrpcCall::compress_output, 1))?;
110
+ grpc_call.define_method(
111
+ "decompress_input",
112
+ method!(ItsiGrpcCall::decompress_input, 1),
113
+ )?;
114
+ grpc_call.define_method(
115
+ "should_compress_output?",
116
+ method!(ItsiGrpcCall::should_compress_output, 1),
117
+ )?;
118
+
119
+ let grpc_response_stream = ruby.get_inner(&ITSI_GRPC_RESPONSE_STREAM);
120
+ grpc_response_stream
121
+ .define_method("reader_fileno", method!(ItsiGrpcResponseStream::reader, 0))?;
122
+ grpc_response_stream.define_method("write", method!(ItsiGrpcResponseStream::write, 1))?;
123
+ grpc_response_stream.define_method("flush", method!(ItsiGrpcResponseStream::flush, 0))?;
124
+ grpc_response_stream.define_method(
125
+ "send_trailers",
126
+ method!(ItsiGrpcResponseStream::send_trailers, 1),
127
+ )?;
128
+ grpc_response_stream.define_method("close", method!(ItsiGrpcResponseStream::close, 0))?;
104
129
 
105
130
  Ok(())
106
131
  }
132
+
133
+ pub fn log_debug(msg: String) {
134
+ debug!(msg);
135
+ }
136
+ pub fn log_info(msg: String) {
137
+ info!(msg);
138
+ }
139
+ pub fn log_warn(msg: String) {
140
+ warn!(msg);
141
+ }
142
+ pub fn log_error(msg: String) {
143
+ error!(msg);
144
+ }
@@ -0,0 +1,2 @@
1
+ pub use itsi_error::*;
2
+ pub use itsi_tracing::{debug, error, info, trace, warn};
@@ -6,7 +6,7 @@ use tempfile::NamedTempFile;
6
6
 
7
7
  const THRESHOLD: usize = 1024 * 1024; // 1 MB
8
8
 
9
- /// An container that holds data in memory if it’s small, or in a temporary file on disk if it exceeds THRESHOLD.
9
+ /// A container that will hold data in memory if it’s small, or in a temporary file on disk if it exceeds THRESHOLD.
10
10
  /// Used for providing Rack input data.
11
11
  pub enum BigBytes {
12
12
  InMemory(Vec<u8>),
@@ -27,7 +27,7 @@ impl BigBytes {
27
27
  BigBytes::InMemory(Vec::new())
28
28
  }
29
29
 
30
- /// Reads the entire contents that have been written.
30
+ /// Returns either the raw bytes, or the file path of the BigBytes
31
31
  ///
32
32
  /// - If stored in memory, returns a clone of the bytes.
33
33
  /// - If stored on disk, returns the file path of the temporary file.
@@ -42,17 +42,22 @@ impl BigBytes {
42
42
  }
43
43
  }
44
44
 
45
- pub fn as_value(&self) -> Value {
45
+ /// Turn this into a value that can be used in Ruby.
46
+ pub fn as_value(&self) -> Option<Value> {
46
47
  match self {
47
48
  BigBytes::InMemory(bytes) => {
48
49
  let bytes = Bytes::from(bytes.to_owned());
49
- bytes.into_value()
50
+ if bytes.is_empty() {
51
+ None
52
+ } else {
53
+ Some(bytes.into_value())
54
+ }
50
55
  }
51
56
  BigBytes::OnDisk(path) => {
52
57
  let ruby = Ruby::get().unwrap();
53
58
  let rarray = ruby.ary_new();
54
59
  rarray.push(path.path().to_str().unwrap().into_value()).ok();
55
- rarray.into_value()
60
+ Some(rarray.into_value())
56
61
  }
57
62
  }
58
63
  }
@@ -1,4 +1,5 @@
1
- use super::big_bytes::BigBytes;
1
+ pub mod big_bytes;
2
+ use big_bytes::BigBytes;
2
3
  use bytes::Bytes;
3
4
  use futures::executor::block_on;
4
5
  use http_body_util::{BodyDataStream, BodyExt};
@@ -11,10 +12,12 @@ use std::sync::{
11
12
  };
12
13
  use tokio_stream::StreamExt;
13
14
 
15
+ use crate::server::size_limited_incoming::SizeLimitedIncoming;
16
+
14
17
  #[magnus::wrap(class = "Itsi::BodyProxy", free_immediately, size)]
15
18
  #[derive(Debug, Clone)]
16
19
  pub struct ItsiBodyProxy {
17
- pub incoming: Arc<Mutex<BodyDataStream<Incoming>>>,
20
+ pub incoming: Arc<Mutex<BodyDataStream<SizeLimitedIncoming<Incoming>>>>,
18
21
  pub closed: Arc<AtomicBool>,
19
22
  pub buf: Arc<Mutex<Vec<u8>>>,
20
23
  }
@@ -25,15 +28,15 @@ pub enum ItsiBody {
25
28
  }
26
29
 
27
30
  impl ItsiBody {
28
- pub fn into_value(&self) -> Value {
31
+ pub fn into_value(&self) -> Option<Value> {
29
32
  match self {
30
33
  ItsiBody::Buffered(bytes) => bytes.as_value(),
31
- ItsiBody::Stream(proxy) => proxy.clone().into_value(),
34
+ ItsiBody::Stream(proxy) => Some(proxy.clone().into_value()),
32
35
  }
33
36
  }
34
37
  }
35
38
  impl ItsiBodyProxy {
36
- pub fn new(incoming: Incoming) -> Self {
39
+ pub fn new(incoming: SizeLimitedIncoming<Incoming>) -> Self {
37
40
  ItsiBodyProxy {
38
41
  incoming: Arc::new(Mutex::new(incoming.into_data_stream())),
39
42
  closed: Arc::new(AtomicBool::new(false)),
@@ -49,7 +52,7 @@ impl ItsiBodyProxy {
49
52
  if let Some(chunk) = block_on(stream.next()) {
50
53
  let chunk = chunk.map_err(|err| {
51
54
  magnus::Error::new(
52
- magnus::exception::exception(),
55
+ magnus::exception::standard_error(),
53
56
  format!("Error reading body {:?}", err),
54
57
  )
55
58
  })?;
@@ -81,7 +84,7 @@ impl ItsiBodyProxy {
81
84
  if let Some(chunk) = block_on(stream.next()) {
82
85
  let chunk = chunk.map_err(|err| {
83
86
  magnus::Error::new(
84
- magnus::exception::exception(),
87
+ magnus::exception::standard_error(),
85
88
  format!("Error reading body {:?}", err),
86
89
  )
87
90
  })?;
@@ -98,6 +101,24 @@ impl ItsiBodyProxy {
98
101
  Ok(Some(output_string))
99
102
  }
100
103
 
104
+ pub fn to_bytes(&self) -> MagnusResult<Vec<u8>> {
105
+ self.verify_open()?;
106
+ let mut stream = self.incoming.lock();
107
+ let mut buf = self.buf.lock();
108
+
109
+ while let Some(chunk) = block_on(stream.next()) {
110
+ let chunk = chunk.map_err(|err| {
111
+ magnus::Error::new(
112
+ magnus::exception::standard_error(),
113
+ format!("Error reading body {:?}", err),
114
+ )
115
+ })?;
116
+ buf.extend_from_slice(&chunk);
117
+ }
118
+
119
+ Ok(buf.clone())
120
+ }
121
+
101
122
  /// Equivalent to calling gets and yielding it, until we reach EOF
102
123
  pub fn each(ruby: &Ruby, rbself: &Self) -> MagnusResult<()> {
103
124
  let proc = ruby.block_proc()?;
@@ -110,7 +131,7 @@ impl ItsiBodyProxy {
110
131
  fn verify_open(&self) -> MagnusResult<()> {
111
132
  if self.closed.load(atomic::Ordering::SeqCst) {
112
133
  return Err(magnus::Error::new(
113
- magnus::exception::exception(),
134
+ magnus::exception::standard_error(),
114
135
  "Body stream is closed",
115
136
  ));
116
137
  }