itsi-server 0.1.1

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.
@@ -0,0 +1,138 @@
1
+ use base64::{engine::general_purpose, Engine as _};
2
+ use itsi_error::Result;
3
+ use itsi_tracing::{info, warn};
4
+ use rcgen::{CertificateParams, DnType, KeyPair, SanType};
5
+ use rustls_pemfile::{certs, pkcs8_private_keys};
6
+ use std::{collections::HashMap, fs, io::BufReader};
7
+ use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
8
+
9
+ const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
10
+ const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
11
+
12
+ // Generates a TLS configuration based on either :
13
+ // * Input "cert" and "key" options (either paths or Base64-encoded strings) or
14
+ // * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
15
+ // If a non-local host or optional domain parameter is provided,
16
+ // an automated certificate will attempt to be fetched using let's encrypt.
17
+ pub fn configure_tls(host: &str, query_params: &HashMap<String, String>) -> Result<ServerConfig> {
18
+ let (certs, key) = if let (Some(cert_path), Some(key_path)) =
19
+ (query_params.get("cert"), query_params.get("key"))
20
+ {
21
+ // Load from file or Base64
22
+ let certs = load_certs(cert_path);
23
+ let key = load_private_key(key_path);
24
+ (certs, key)
25
+ } else if query_params
26
+ .get("cert")
27
+ .map(|v| v == "auto")
28
+ .unwrap_or(false)
29
+ {
30
+ let domain_param = query_params.get("domain");
31
+ let host_string = host.to_string();
32
+ let domain = domain_param.or_else(|| {
33
+ if host_string != "localhost" {
34
+ Some(&host_string)
35
+ } else {
36
+ None
37
+ }
38
+ });
39
+
40
+ if let Some(domain) = domain {
41
+ retrieve_acme_cert(domain)?
42
+ } else {
43
+ generate_ca_signed_cert(host)?
44
+ }
45
+ } else {
46
+ generate_ca_signed_cert(host)?
47
+ };
48
+
49
+ let mut config = ServerConfig::builder()
50
+ .with_safe_defaults()
51
+ .with_no_client_auth()
52
+ .with_single_cert(certs, key)
53
+ .expect("Failed to build TLS config");
54
+
55
+ config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
56
+ Ok(config)
57
+ }
58
+
59
+ pub fn load_certs(path: &str) -> Vec<Certificate> {
60
+ let data = if let Some(stripped) = path.strip_prefix("base64:") {
61
+ general_purpose::STANDARD
62
+ .decode(stripped)
63
+ .expect("Invalid base64 certificate")
64
+ } else {
65
+ fs::read(path).expect("Failed to read certificate file")
66
+ };
67
+
68
+ if data.starts_with(b"-----BEGIN ") {
69
+ let mut reader = BufReader::new(&data[..]);
70
+ let certs_der: Vec<Vec<u8>> = certs(&mut reader)
71
+ .map(|r| {
72
+ r.map(|der| der.as_ref().to_vec())
73
+ .map_err(itsi_error::ItsiError::from)
74
+ })
75
+ .collect::<Result<_>>()
76
+ .expect("Failed to parse certificate file");
77
+ certs_der.into_iter().map(Certificate).collect()
78
+ } else {
79
+ vec![Certificate(data)]
80
+ }
81
+ }
82
+
83
+ /// Loads a private key from a file or Base64.
84
+ pub fn load_private_key(path: &str) -> PrivateKey {
85
+ let key_data = if let Some(stripped) = path.strip_prefix("base64:") {
86
+ general_purpose::STANDARD
87
+ .decode(stripped)
88
+ .expect("Invalid base64 private key")
89
+ } else {
90
+ fs::read(path).expect("Failed to read private key file")
91
+ };
92
+
93
+ if key_data.starts_with(b"-----BEGIN ") {
94
+ let mut reader = BufReader::new(&key_data[..]);
95
+ let keys: Vec<Vec<u8>> = pkcs8_private_keys(&mut reader)
96
+ .map(|r| {
97
+ r.map(|key| key.secret_pkcs8_der().to_vec())
98
+ .map_err(itsi_error::ItsiError::from)
99
+ })
100
+ .collect::<Result<_>>()
101
+ .expect("Failed to parse private key");
102
+ if !keys.is_empty() {
103
+ return PrivateKey(keys[0].clone());
104
+ }
105
+ }
106
+ PrivateKey(key_data)
107
+ }
108
+
109
+ pub fn generate_ca_signed_cert(domain: &str) -> Result<(Vec<Certificate>, PrivateKey)> {
110
+ info!("Generating New Itsi CA - Self signed Certificate. Use `itsi ca export` to export the CA certificate for import into your local trust store.");
111
+
112
+ let ca_kp = KeyPair::from_pem(ITS_CA_KEY).unwrap();
113
+ let params = CertificateParams::from_ca_cert_pem(ITS_CA_CERT).unwrap();
114
+
115
+ let ca_cert = params.self_signed(&ca_kp).unwrap();
116
+ let ee_key = KeyPair::generate().unwrap();
117
+ let mut ee_params = CertificateParams::default();
118
+
119
+ // Set the domain in the subject alternative names (SAN)
120
+ ee_params.subject_alt_names = vec![SanType::DnsName(domain.try_into()?)];
121
+ // Optionally, set the Common Name (CN) in the distinguished name:
122
+ ee_params
123
+ .distinguished_name
124
+ .push(DnType::CommonName, domain);
125
+
126
+ ee_params.use_authority_key_identifier_extension = true;
127
+
128
+ let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ee_key).unwrap();
129
+ let ee_cert_der = ee_cert.der().to_vec();
130
+ let ee_cert = Certificate(ee_cert_der);
131
+ Ok((vec![ee_cert], PrivateKey(ee_key.serialize_der())))
132
+ }
133
+
134
+ /// Retrieves an ACME certificate for a given domain.
135
+ pub fn retrieve_acme_cert(domain: &str) -> Result<(Vec<Certificate>, PrivateKey)> {
136
+ warn!("Retrieving ACME cert for {}", domain);
137
+ generate_ca_signed_cert(domain)
138
+ }
@@ -0,0 +1,23 @@
1
+ use itsi_error::ItsiError;
2
+ use std::str::FromStr;
3
+
4
+ #[derive(Debug, Default, Clone)]
5
+ pub enum TransferProtocol {
6
+ #[default]
7
+ Https,
8
+ Http,
9
+ Unix,
10
+ }
11
+
12
+ impl FromStr for TransferProtocol {
13
+ type Err = ItsiError;
14
+
15
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
16
+ match s {
17
+ "http" => Ok(TransferProtocol::Http),
18
+ "https" => Ok(TransferProtocol::Https),
19
+ "unix" => Ok(TransferProtocol::Unix),
20
+ _ => Err(ItsiError::UnsupportedProtocol(s.to_string())),
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,21 @@
1
+ use bytes::Bytes;
2
+ use magnus::{error::Result as MagnusResult, exception::io_error, Error};
3
+ use tokio::sync::mpsc::Sender;
4
+
5
+ #[magnus::wrap(class = "Itsi::StreamWriter", free_immediately, size)]
6
+ pub struct StreamWriter {
7
+ sender: Sender<Bytes>,
8
+ }
9
+
10
+ impl StreamWriter {
11
+ pub fn new(sender: Sender<Bytes>) -> Self {
12
+ StreamWriter { sender }
13
+ }
14
+
15
+ pub fn write(&self, bytes: Bytes) -> MagnusResult<()> {
16
+ self.sender
17
+ .blocking_send(bytes)
18
+ .map_err(|e| Error::new(io_error(), format!("{:?}", e)))?;
19
+ Ok(())
20
+ }
21
+ }
@@ -0,0 +1,274 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "aho-corasick"
7
+ version = "1.1.3"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
10
+ dependencies = [
11
+ "memchr",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "cfg-if"
16
+ version = "1.0.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
19
+
20
+ [[package]]
21
+ name = "itsi_tracing"
22
+ version = "0.1.0"
23
+ dependencies = [
24
+ "tracing",
25
+ "tracing-subscriber",
26
+ ]
27
+
28
+ [[package]]
29
+ name = "lazy_static"
30
+ version = "1.5.0"
31
+ source = "registry+https://github.com/rust-lang/crates.io-index"
32
+ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
33
+
34
+ [[package]]
35
+ name = "log"
36
+ version = "0.4.26"
37
+ source = "registry+https://github.com/rust-lang/crates.io-index"
38
+ checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
39
+
40
+ [[package]]
41
+ name = "matchers"
42
+ version = "0.1.0"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
45
+ dependencies = [
46
+ "regex-automata 0.1.10",
47
+ ]
48
+
49
+ [[package]]
50
+ name = "memchr"
51
+ version = "2.7.4"
52
+ source = "registry+https://github.com/rust-lang/crates.io-index"
53
+ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
54
+
55
+ [[package]]
56
+ name = "nu-ansi-term"
57
+ version = "0.46.0"
58
+ source = "registry+https://github.com/rust-lang/crates.io-index"
59
+ checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
60
+ dependencies = [
61
+ "overload",
62
+ "winapi",
63
+ ]
64
+
65
+ [[package]]
66
+ name = "once_cell"
67
+ version = "1.20.3"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
70
+
71
+ [[package]]
72
+ name = "overload"
73
+ version = "0.1.1"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
76
+
77
+ [[package]]
78
+ name = "pin-project-lite"
79
+ version = "0.2.16"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
82
+
83
+ [[package]]
84
+ name = "proc-macro2"
85
+ version = "1.0.93"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
88
+ dependencies = [
89
+ "unicode-ident",
90
+ ]
91
+
92
+ [[package]]
93
+ name = "quote"
94
+ version = "1.0.38"
95
+ source = "registry+https://github.com/rust-lang/crates.io-index"
96
+ checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
97
+ dependencies = [
98
+ "proc-macro2",
99
+ ]
100
+
101
+ [[package]]
102
+ name = "regex"
103
+ version = "1.11.1"
104
+ source = "registry+https://github.com/rust-lang/crates.io-index"
105
+ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
106
+ dependencies = [
107
+ "aho-corasick",
108
+ "memchr",
109
+ "regex-automata 0.4.9",
110
+ "regex-syntax 0.8.5",
111
+ ]
112
+
113
+ [[package]]
114
+ name = "regex-automata"
115
+ version = "0.1.10"
116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
117
+ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
118
+ dependencies = [
119
+ "regex-syntax 0.6.29",
120
+ ]
121
+
122
+ [[package]]
123
+ name = "regex-automata"
124
+ version = "0.4.9"
125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
126
+ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
127
+ dependencies = [
128
+ "aho-corasick",
129
+ "memchr",
130
+ "regex-syntax 0.8.5",
131
+ ]
132
+
133
+ [[package]]
134
+ name = "regex-syntax"
135
+ version = "0.6.29"
136
+ source = "registry+https://github.com/rust-lang/crates.io-index"
137
+ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
138
+
139
+ [[package]]
140
+ name = "regex-syntax"
141
+ version = "0.8.5"
142
+ source = "registry+https://github.com/rust-lang/crates.io-index"
143
+ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
144
+
145
+ [[package]]
146
+ name = "sharded-slab"
147
+ version = "0.1.7"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
150
+ dependencies = [
151
+ "lazy_static",
152
+ ]
153
+
154
+ [[package]]
155
+ name = "smallvec"
156
+ version = "1.14.0"
157
+ source = "registry+https://github.com/rust-lang/crates.io-index"
158
+ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
159
+
160
+ [[package]]
161
+ name = "syn"
162
+ version = "2.0.98"
163
+ source = "registry+https://github.com/rust-lang/crates.io-index"
164
+ checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
165
+ dependencies = [
166
+ "proc-macro2",
167
+ "quote",
168
+ "unicode-ident",
169
+ ]
170
+
171
+ [[package]]
172
+ name = "thread_local"
173
+ version = "1.1.8"
174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
175
+ checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
176
+ dependencies = [
177
+ "cfg-if",
178
+ "once_cell",
179
+ ]
180
+
181
+ [[package]]
182
+ name = "tracing"
183
+ version = "0.1.41"
184
+ source = "registry+https://github.com/rust-lang/crates.io-index"
185
+ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
186
+ dependencies = [
187
+ "pin-project-lite",
188
+ "tracing-attributes",
189
+ "tracing-core",
190
+ ]
191
+
192
+ [[package]]
193
+ name = "tracing-attributes"
194
+ version = "0.1.28"
195
+ source = "registry+https://github.com/rust-lang/crates.io-index"
196
+ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
197
+ dependencies = [
198
+ "proc-macro2",
199
+ "quote",
200
+ "syn",
201
+ ]
202
+
203
+ [[package]]
204
+ name = "tracing-core"
205
+ version = "0.1.33"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
208
+ dependencies = [
209
+ "once_cell",
210
+ "valuable",
211
+ ]
212
+
213
+ [[package]]
214
+ name = "tracing-log"
215
+ version = "0.2.0"
216
+ source = "registry+https://github.com/rust-lang/crates.io-index"
217
+ checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
218
+ dependencies = [
219
+ "log",
220
+ "once_cell",
221
+ "tracing-core",
222
+ ]
223
+
224
+ [[package]]
225
+ name = "tracing-subscriber"
226
+ version = "0.3.19"
227
+ source = "registry+https://github.com/rust-lang/crates.io-index"
228
+ checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
229
+ dependencies = [
230
+ "matchers",
231
+ "nu-ansi-term",
232
+ "once_cell",
233
+ "regex",
234
+ "sharded-slab",
235
+ "smallvec",
236
+ "thread_local",
237
+ "tracing",
238
+ "tracing-core",
239
+ "tracing-log",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "unicode-ident"
244
+ version = "1.0.17"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
247
+
248
+ [[package]]
249
+ name = "valuable"
250
+ version = "0.1.1"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
253
+
254
+ [[package]]
255
+ name = "winapi"
256
+ version = "0.3.9"
257
+ source = "registry+https://github.com/rust-lang/crates.io-index"
258
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
259
+ dependencies = [
260
+ "winapi-i686-pc-windows-gnu",
261
+ "winapi-x86_64-pc-windows-gnu",
262
+ ]
263
+
264
+ [[package]]
265
+ name = "winapi-i686-pc-windows-gnu"
266
+ version = "0.4.0"
267
+ source = "registry+https://github.com/rust-lang/crates.io-index"
268
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
269
+
270
+ [[package]]
271
+ name = "winapi-x86_64-pc-windows-gnu"
272
+ version = "0.4.0"
273
+ source = "registry+https://github.com/rust-lang/crates.io-index"
274
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
@@ -0,0 +1,12 @@
1
+ [package]
2
+ name = "itsi_tracing"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+
6
+ [dependencies]
7
+ tracing = { version = "0.1.41", features = ["attributes"] }
8
+ tracing-subscriber = { version = "0.3.19", features = [
9
+ "env-filter",
10
+ "std",
11
+ "fmt",
12
+ ] }
@@ -0,0 +1,11 @@
1
+ pub use tracing::{debug, error, info, trace, warn};
2
+ use tracing_subscriber::{EnvFilter, fmt};
3
+
4
+ pub fn init() {
5
+ let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
6
+ let format = fmt::format().with_level(true).with_target(false).compact();
7
+ tracing_subscriber::fmt()
8
+ .with_env_filter(env_filter)
9
+ .event_format(format)
10
+ .init();
11
+ }
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Itsi
6
+ class Request
7
+ def to_env
8
+ {
9
+ "SERVER_SOFTWARE" => "Itsi",
10
+ "SCRIPT_NAME" => script_name,
11
+ "REQUEST_METHOD" => method,
12
+ "PATH_INFO" => path,
13
+ "REQUEST_PATH" => path,
14
+ "QUERY_STRING" => query_string,
15
+ "REMOTE_ADDR" => remote_addr,
16
+ "SERVER_NAME" => host,
17
+ "SERVER_PORT" => port.to_s,
18
+ "SERVER_PROTOCOL" => version,
19
+ "HTTP_VERSION" => version,
20
+ "HTTP_HOST" => host,
21
+ "rack.input" => StringIO.new(body),
22
+ "rack.errors" => $stderr,
23
+ "rack.version" => version,
24
+ "rack.multithread" => true,
25
+ "rack.multiprocess" => true,
26
+ "rack.run_once" => false,
27
+ "rack.multipart.buffer_size" => 16_384
28
+ }.merge(
29
+ headers.transform_keys do |k|
30
+ case k
31
+ when "content-length" then "CONTENT_LENGTH"
32
+ when "content-type" then "CONTENT_TYPE"
33
+ else "HTTP_#{k.upcase.tr("-", "_")}"
34
+ end
35
+ end
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Itsi
4
+ class Server
5
+ VERSION = "0.1.1"
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "server/version"
4
+ require_relative "server/itsi_server"
5
+
6
+ module Itsi
7
+ class Server
8
+ # Call our Rack app with our request ENV.
9
+ def self.call(app, request)
10
+ app.call(request.to_env)
11
+ end
12
+
13
+ # If scheduler is enabled
14
+ # Each request is wrapped in a Fiber.
15
+ def self.schedule(app, request)
16
+ Fiber.schedule do
17
+ call(app, request)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module ItsiServer
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itsi-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Wouter Coppieters
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-03-01 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: libclang
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '14.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '14.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rb_sys
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.91
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.91
40
+ - !ruby/object:Gem::Dependency
41
+ name: rack
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2'
54
+ description: Itsi Server - A light-weight Rack Server implementation for Ruby
55
+ email:
56
+ - wc@pico.net.nz
57
+ executables:
58
+ - itsi
59
+ extensions:
60
+ - ext/itsi_server/extconf.rb
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".rubocop.yml"
64
+ - CHANGELOG.md
65
+ - CODE_OF_CONDUCT.md
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - exe/itsi
70
+ - ext/itsi_error/Cargo.lock
71
+ - ext/itsi_error/Cargo.toml
72
+ - ext/itsi_error/src/lib.rs
73
+ - ext/itsi_rb_helpers/Cargo.lock
74
+ - ext/itsi_rb_helpers/Cargo.toml
75
+ - ext/itsi_rb_helpers/src/lib.rs
76
+ - ext/itsi_server/Cargo.toml
77
+ - ext/itsi_server/extconf.rb
78
+ - ext/itsi_server/src/lib.rs
79
+ - ext/itsi_server/src/request/itsi_request.rs
80
+ - ext/itsi_server/src/request/mod.rs
81
+ - ext/itsi_server/src/server/bind.rs
82
+ - ext/itsi_server/src/server/itsi_ca/itsi_ca.crt
83
+ - ext/itsi_server/src/server/itsi_ca/itsi_ca.key
84
+ - ext/itsi_server/src/server/itsi_server.rs
85
+ - ext/itsi_server/src/server/listener.rs
86
+ - ext/itsi_server/src/server/mod.rs
87
+ - ext/itsi_server/src/server/tls.rs
88
+ - ext/itsi_server/src/server/transfer_protocol.rs
89
+ - ext/itsi_server/src/stream_writer/mod.rs
90
+ - ext/itsi_tracing/Cargo.lock
91
+ - ext/itsi_tracing/Cargo.toml
92
+ - ext/itsi_tracing/src/lib.rs
93
+ - lib/itsi/request.rb
94
+ - lib/itsi/server.rb
95
+ - lib/itsi/server/version.rb
96
+ - sig/itsi_server.rbs
97
+ homepage: https://itsi.fyi
98
+ licenses:
99
+ - MIT
100
+ metadata:
101
+ homepage_uri: https://itsi.fyi
102
+ source_code_uri: https://github.com/wouterken/itsi/server
103
+ changelog_uri: https://github.com/wouterken/itsi/server/blob/main/CHANGELOG.md
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 3.1.0
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 3.3.11
117
+ requirements: []
118
+ rubygems_version: 3.6.2
119
+ specification_version: 4
120
+ summary: Itsi Server - A light-weight Rack Server implementation for Ruby.
121
+ test_files: []