itsi 0.1.14 → 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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +126 -272
  3. data/Cargo.toml +6 -0
  4. data/crates/itsi_error/Cargo.toml +1 -0
  5. data/crates/itsi_error/src/lib.rs +100 -10
  6. data/crates/itsi_scheduler/src/itsi_scheduler.rs +1 -1
  7. data/crates/itsi_server/Cargo.toml +12 -11
  8. data/crates/itsi_server/src/default_responses/html/401.html +68 -0
  9. data/crates/itsi_server/src/default_responses/html/403.html +68 -0
  10. data/crates/itsi_server/src/default_responses/html/404.html +68 -0
  11. data/crates/itsi_server/src/default_responses/html/413.html +71 -0
  12. data/crates/itsi_server/src/default_responses/html/429.html +68 -0
  13. data/crates/itsi_server/src/default_responses/html/500.html +71 -0
  14. data/crates/itsi_server/src/default_responses/html/502.html +71 -0
  15. data/crates/itsi_server/src/default_responses/html/503.html +68 -0
  16. data/crates/itsi_server/src/default_responses/html/504.html +69 -0
  17. data/crates/itsi_server/src/default_responses/html/index.html +238 -0
  18. data/crates/itsi_server/src/default_responses/json/401.json +6 -0
  19. data/crates/itsi_server/src/default_responses/json/403.json +6 -0
  20. data/crates/itsi_server/src/default_responses/json/404.json +6 -0
  21. data/crates/itsi_server/src/default_responses/json/413.json +6 -0
  22. data/crates/itsi_server/src/default_responses/json/429.json +6 -0
  23. data/crates/itsi_server/src/default_responses/json/500.json +6 -0
  24. data/crates/itsi_server/src/default_responses/json/502.json +6 -0
  25. data/crates/itsi_server/src/default_responses/json/503.json +6 -0
  26. data/crates/itsi_server/src/default_responses/json/504.json +6 -0
  27. data/crates/itsi_server/src/default_responses/mod.rs +11 -0
  28. data/crates/itsi_server/src/lib.rs +58 -26
  29. data/crates/itsi_server/src/prelude.rs +2 -0
  30. data/crates/itsi_server/src/ruby_types/README.md +21 -0
  31. data/crates/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +8 -6
  32. data/crates/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  33. data/crates/itsi_server/src/ruby_types/{itsi_grpc_stream → itsi_grpc_response_stream}/mod.rs +121 -73
  34. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +103 -40
  35. data/crates/itsi_server/src/ruby_types/itsi_http_response.rs +8 -5
  36. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +4 -4
  37. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +37 -17
  38. data/crates/itsi_server/src/ruby_types/itsi_server.rs +4 -3
  39. data/crates/itsi_server/src/ruby_types/mod.rs +6 -13
  40. data/crates/itsi_server/src/server/{bind.rs → binds/bind.rs} +23 -4
  41. data/crates/itsi_server/src/server/{listener.rs → binds/listener.rs} +24 -10
  42. data/crates/itsi_server/src/server/binds/mod.rs +4 -0
  43. data/crates/itsi_server/src/server/{tls.rs → binds/tls.rs} +9 -4
  44. data/crates/itsi_server/src/server/http_message_types.rs +97 -0
  45. data/crates/itsi_server/src/server/io_stream.rs +2 -1
  46. data/crates/itsi_server/src/server/middleware_stack/middleware.rs +28 -16
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +17 -8
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +47 -18
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +13 -9
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +50 -29
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +5 -2
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +37 -48
  53. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +25 -20
  54. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +14 -7
  55. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
  56. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +125 -95
  57. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +9 -5
  58. data/crates/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +1 -4
  59. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +25 -19
  60. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +4 -4
  61. data/crates/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  62. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +9 -4
  63. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +260 -62
  64. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +29 -22
  65. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +6 -6
  66. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +6 -5
  67. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +4 -2
  68. data/crates/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +51 -18
  69. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +31 -13
  70. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  71. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +13 -8
  72. data/crates/itsi_server/src/server/middleware_stack/mod.rs +101 -69
  73. data/crates/itsi_server/src/server/mod.rs +3 -9
  74. data/crates/itsi_server/src/server/process_worker.rs +21 -3
  75. data/crates/itsi_server/src/server/request_job.rs +2 -2
  76. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +8 -3
  77. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +26 -26
  78. data/crates/itsi_server/src/server/signal.rs +24 -41
  79. data/crates/itsi_server/src/server/size_limited_incoming.rs +101 -0
  80. data/crates/itsi_server/src/server/thread_worker.rs +59 -28
  81. data/crates/itsi_server/src/services/itsi_http_service.rs +239 -0
  82. data/crates/itsi_server/src/services/mime_types.rs +1416 -0
  83. data/crates/itsi_server/src/services/mod.rs +6 -0
  84. data/crates/itsi_server/src/services/password_hasher.rs +83 -0
  85. data/crates/itsi_server/src/{server → services}/rate_limiter.rs +35 -31
  86. data/crates/itsi_server/src/{server → services}/static_file_server.rs +521 -181
  87. data/crates/itsi_tracing/src/lib.rs +145 -55
  88. data/{Itsi.rb → foo/Itsi.rb} +6 -9
  89. data/gems/scheduler/Cargo.lock +7 -0
  90. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  91. data/gems/scheduler/test/helpers/test_helper.rb +0 -1
  92. data/gems/scheduler/test/test_address_resolve.rb +0 -1
  93. data/gems/scheduler/test/test_network_io.rb +1 -1
  94. data/gems/scheduler/test/test_process_wait.rb +0 -1
  95. data/gems/server/Cargo.lock +126 -272
  96. data/gems/server/exe/itsi +65 -19
  97. data/gems/server/itsi-server.gemspec +4 -3
  98. data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +74 -0
  99. data/gems/server/lib/itsi/http_request.rb +117 -17
  100. data/gems/server/lib/itsi/http_response.rb +2 -0
  101. data/gems/server/lib/itsi/passfile.rb +109 -0
  102. data/gems/server/lib/itsi/server/config/dsl.rb +171 -99
  103. data/gems/server/lib/itsi/server/config.rb +58 -23
  104. data/gems/server/lib/itsi/server/default_app/default_app.rb +25 -29
  105. data/gems/server/lib/itsi/server/default_app/index.html +113 -89
  106. data/gems/server/lib/itsi/server/{Itsi.rb → default_config/Itsi-rackup.rb} +1 -1
  107. data/gems/server/lib/itsi/server/default_config/Itsi.rb +107 -0
  108. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +246 -0
  109. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +100 -0
  110. data/gems/server/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
  111. data/gems/server/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
  112. data/gems/server/lib/itsi/server/route_tester.rb +107 -0
  113. data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +200 -0
  114. data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +55 -0
  115. data/gems/server/lib/itsi/server/typed_handlers.rb +17 -0
  116. data/gems/server/lib/itsi/server/version.rb +1 -1
  117. data/gems/server/lib/itsi/server.rb +82 -12
  118. data/gems/server/lib/ruby_lsp/itsi/addon.rb +111 -0
  119. data/gems/server/lib/shell_completions/completions.rb +26 -0
  120. data/gems/server/test/helpers/test_helper.rb +2 -1
  121. data/lib/itsi/version.rb +1 -1
  122. data/sandbox/README.md +5 -0
  123. data/sandbox/itsi_file/Gemfile +4 -2
  124. data/sandbox/itsi_file/Gemfile.lock +48 -6
  125. data/sandbox/itsi_file/Itsi.rb +327 -129
  126. data/sandbox/itsi_file/call.json +1 -0
  127. data/sandbox/itsi_file/echo_client/Gemfile +10 -0
  128. data/sandbox/itsi_file/echo_client/Gemfile.lock +27 -0
  129. data/sandbox/itsi_file/echo_client/README.md +95 -0
  130. data/sandbox/itsi_file/echo_client/echo_client.rb +164 -0
  131. data/sandbox/itsi_file/echo_client/gen_proto.sh +17 -0
  132. data/sandbox/itsi_file/echo_client/lib/echo_pb.rb +16 -0
  133. data/sandbox/itsi_file/echo_client/lib/echo_services_pb.rb +29 -0
  134. data/sandbox/itsi_file/echo_client/run_client.rb +64 -0
  135. data/sandbox/itsi_file/echo_client/test_compressions.sh +20 -0
  136. data/sandbox/itsi_file/echo_service_nonitsi/Gemfile +10 -0
  137. data/sandbox/itsi_file/echo_service_nonitsi/Gemfile.lock +79 -0
  138. data/sandbox/itsi_file/echo_service_nonitsi/echo.proto +26 -0
  139. data/sandbox/itsi_file/echo_service_nonitsi/echo_pb.rb +16 -0
  140. data/sandbox/itsi_file/echo_service_nonitsi/echo_services_pb.rb +29 -0
  141. data/sandbox/itsi_file/echo_service_nonitsi/server.rb +52 -0
  142. data/sandbox/itsi_sandbox_async/config.ru +0 -1
  143. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  144. data/sandbox/itsi_sandbox_rails/Gemfile +2 -2
  145. data/sandbox/itsi_sandbox_rails/Gemfile.lock +76 -2
  146. data/sandbox/itsi_sandbox_rails/app/controllers/home_controller.rb +15 -0
  147. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +1 -0
  148. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +1 -0
  149. data/sandbox/itsi_sandbox_rails/config/routes.rb +2 -0
  150. data/sandbox/itsi_sinatra/app.rb +0 -1
  151. data/sandbox/static_files/.env +1 -0
  152. data/sandbox/static_files/404.html +25 -0
  153. data/sandbox/static_files/_DSC0102.NEF.jpg +0 -0
  154. data/sandbox/static_files/about.html +68 -0
  155. data/sandbox/static_files/tiny.html +1 -0
  156. data/sandbox/static_files/writebook.zip +0 -0
  157. data/tasks.txt +28 -33
  158. metadata +87 -26
  159. data/crates/itsi_error/src/from.rs +0 -68
  160. data/crates/itsi_server/src/ruby_types/itsi_grpc_request.rs +0 -147
  161. data/crates/itsi_server/src/ruby_types/itsi_grpc_response.rs +0 -19
  162. data/crates/itsi_server/src/server/itsi_service.rs +0 -172
  163. data/crates/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +0 -72
  164. data/crates/itsi_server/src/server/types.rs +0 -43
  165. data/gems/server/lib/itsi/server/grpc_interface.rb +0 -213
  166. data/sandbox/itsi_file/public/assets/index.html +0 -1
  167. /data/crates/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
  168. /data/crates/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +0 -0
  169. /data/crates/itsi_server/src/{server → services}/cache_store.rs +0 -0
@@ -0,0 +1,71 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Bad Gateway</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #f0f2f5;
10
+ --text-color: #333;
11
+ --accent-color: #0052cc;
12
+ --link-color: #0052cc;
13
+ }
14
+ body {
15
+ margin: 0;
16
+ font-family: "Helvetica Neue", Arial, sans-serif;
17
+ background: var(--bg-color);
18
+ color: var(--text-color);
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ min-height: 100vh;
23
+ padding: 2rem;
24
+ }
25
+ .error-container {
26
+ text-align: center;
27
+ max-width: 800px;
28
+ width: 100%;
29
+ }
30
+ h1 {
31
+ font-size: 5rem;
32
+ font-weight: 300;
33
+ margin-bottom: 0.5rem;
34
+ }
35
+ p {
36
+ font-size: 1.5rem;
37
+ line-height: 1.6;
38
+ margin-bottom: 2rem;
39
+ }
40
+ a {
41
+ font-size: 1rem;
42
+ text-decoration: none;
43
+ color: var(--link-color);
44
+ border-bottom: 1px solid transparent;
45
+ transition: border-color 0.2s ease-in-out;
46
+ }
47
+ a:hover {
48
+ border-color: var(--link-color);
49
+ }
50
+ @media (max-width: 480px) {
51
+ h1 {
52
+ font-size: 3.5rem;
53
+ }
54
+ p {
55
+ font-size: 1.2rem;
56
+ }
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <div class="error-container">
62
+ <h1>502</h1>
63
+ <p>
64
+ The server encountered an unexpected upstream error that prevented it
65
+ from fulfilling the request.
66
+ </p>
67
+ <p><a href="/">Return Home</a></p>
68
+ <p><a href="javascript:history.back()">Go Back</a></p>
69
+ </div>
70
+ </body>
71
+ </html>
@@ -0,0 +1,68 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Service Unavailable</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #f0f2f5;
10
+ --text-color: #333;
11
+ --accent-color: #0052cc;
12
+ --link-color: #0052cc;
13
+ }
14
+ body {
15
+ margin: 0;
16
+ font-family: "Helvetica Neue", Arial, sans-serif;
17
+ background: var(--bg-color);
18
+ color: var(--text-color);
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ min-height: 100vh;
23
+ padding: 2rem;
24
+ }
25
+ .error-container {
26
+ text-align: center;
27
+ max-width: 800px;
28
+ width: 100%;
29
+ }
30
+ h1 {
31
+ font-size: 5rem;
32
+ font-weight: 300;
33
+ margin-bottom: 0.5rem;
34
+ }
35
+ p {
36
+ font-size: 1.5rem;
37
+ line-height: 1.6;
38
+ margin-bottom: 2rem;
39
+ }
40
+ a {
41
+ font-size: 1rem;
42
+ text-decoration: none;
43
+ color: var(--link-color);
44
+ border-bottom: 1px solid transparent;
45
+ transition: border-color 0.2s ease-in-out;
46
+ }
47
+ a:hover {
48
+ border-color: var(--link-color);
49
+ }
50
+ @media (max-width: 480px) {
51
+ h1 {
52
+ font-size: 3.5rem;
53
+ }
54
+ p {
55
+ font-size: 1.2rem;
56
+ }
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <div class="error-container">
62
+ <h1>503</h1>
63
+ <p>The service is currently unavailable. Please try again later.</p>
64
+ <p><a href="/">Return Home</a></p>
65
+ <p><a href="javascript:history.back()">Go Back</a></p>
66
+ </div>
67
+ </body>
68
+ </html>
@@ -0,0 +1,69 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Gateway Timeout</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #f0f2f5;
10
+ --text-color: #333;
11
+ --accent-color: #0052cc;
12
+ --link-color: #0052cc;
13
+ }
14
+ body {
15
+ margin: 0;
16
+ font-family: "Helvetica Neue", Arial, sans-serif;
17
+ background: var(--bg-color);
18
+ color: var(--text-color);
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ min-height: 100vh;
23
+ padding: 2rem;
24
+ }
25
+ .error-container {
26
+ text-align: center;
27
+ max-width: 800px;
28
+ width: 100%;
29
+ }
30
+ h1 {
31
+ font-size: 5rem;
32
+ font-weight: 300;
33
+ margin-bottom: 0.5rem;
34
+ }
35
+ p {
36
+ font-size: 1.5rem;
37
+ line-height: 1.6;
38
+ margin-bottom: 2rem;
39
+ }
40
+ a {
41
+ font-size: 1rem;
42
+ text-decoration: none;
43
+ color: var(--link-color);
44
+ border-bottom: 1px solid transparent;
45
+ transition: border-color 0.2s ease-in-out;
46
+ }
47
+ a:hover {
48
+ border-color: var(--link-color);
49
+ }
50
+ @media (max-width: 480px) {
51
+ h1 {
52
+ font-size: 3.5rem;
53
+ }
54
+ p {
55
+ font-size: 1.2rem;
56
+ }
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <div class="error-container">
62
+ <h1>504</h1>
63
+ <p>The service did not respond within the expected time frame.</p>
64
+ <p>Please try again later.</p>
65
+ <p><a href="/">Return Home</a></p>
66
+ <p><a href="javascript:history.back()">Go Back</a></p>
67
+ </div>
68
+ </body>
69
+ </html>
@@ -0,0 +1,238 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>{{title}}</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #f0f2f5;
10
+ --text-color: #333;
11
+ --link-color: #0052cc;
12
+ --accent-color: #0052cc;
13
+ }
14
+ * {
15
+ box-sizing: border-box;
16
+ }
17
+ body {
18
+ margin: 0;
19
+ font-family: "Helvetica Neue", Arial, sans-serif;
20
+ background: var(--bg-color);
21
+ color: var(--text-color);
22
+ padding: 2rem;
23
+ }
24
+ h1 {
25
+ font-size: 2.5rem;
26
+ margin-bottom: 1rem;
27
+ text-align: center;
28
+ }
29
+ table {
30
+ width: 100%;
31
+ border-collapse: collapse;
32
+ margin-top: 1rem;
33
+ }
34
+ th,
35
+ td {
36
+ padding: 0.5rem;
37
+ text-align: left;
38
+ }
39
+ tr:nth-child(even) {
40
+ background-color: #e9ecef;
41
+ }
42
+ th {
43
+ border-bottom: 2px solid #ccc;
44
+ position: relative;
45
+ cursor: pointer;
46
+ }
47
+ /* Sorted header arrow */
48
+ th .sort-arrow {
49
+ font-size: 0.8rem;
50
+ display: none;
51
+ }
52
+ th.sorted .sort-arrow {
53
+ display: inline;
54
+ }
55
+ a {
56
+ color: var(--link-color);
57
+ text-decoration: none;
58
+ }
59
+ a:hover {
60
+ text-decoration: underline;
61
+ }
62
+ .size {
63
+ text-align: right;
64
+ }
65
+ .date {
66
+ white-space: nowrap;
67
+ }
68
+ footer {
69
+ margin-top: 2rem;
70
+ text-align: center;
71
+ font-size: 0.9rem;
72
+ color: #555;
73
+ }
74
+ th.name-header > span {
75
+ display: inline-block;
76
+ width: 100%;
77
+ }
78
+ th.name-header input {
79
+ margin-top: 0.3rem;
80
+ font-size: 0.8rem;
81
+ width: 100%;
82
+ max-width: 200px;
83
+ border: 1px solid #ccc;
84
+ background: none;
85
+ border-radius: 12px;
86
+ padding: 5px 15px;
87
+ }
88
+ /* Responsive adjustments */
89
+ @media (max-width: 480px) {
90
+ h1 {
91
+ font-size: 2.5rem;
92
+ }
93
+ th,
94
+ td {
95
+ padding: 0.4rem;
96
+ }
97
+ th {
98
+ vertical-align: top;
99
+ }
100
+ th.name-header input {
101
+ max-width: 150px;
102
+ font-size: 0.75rem;
103
+ }
104
+ }
105
+ </style>
106
+ </head>
107
+ <body>
108
+ <h1>Directory listing for {{directory}}</h1>
109
+ <table data-sort-asc="true" data-sorted-column="0">
110
+ <thead>
111
+ <tr>
112
+ <th data-type="text" data-column="0" class="name-header">
113
+ <span>Name <span class="sort-arrow">▲</span></span>
114
+ <input type="text" id="nameFilter" placeholder="Filter names" />
115
+ </th>
116
+ <th data-type="size" data-column="1">
117
+ Size <span class="sort-arrow"></span>
118
+ </th>
119
+ <th data-type="text" data-column="2">
120
+ Last Modified <span class="sort-arrow"></span>
121
+ </th>
122
+ </tr>
123
+ </thead>
124
+ <tbody>
125
+ {{rows}}
126
+ </tbody>
127
+ </table>
128
+ <footer>
129
+ <p>Served by Itsi Static Assets</p>
130
+ </footer>
131
+ <script>
132
+ document.addEventListener("DOMContentLoaded", function () {
133
+ const table = document.querySelector("table");
134
+ const headers = table.querySelectorAll("th");
135
+ const nameFilter = document.getElementById("nameFilter");
136
+ let currentSortedColumn = 0;
137
+ let ascending = true;
138
+
139
+ // Add sorting listeners
140
+ headers.forEach((header, index) => {
141
+ header.addEventListener("click", function (e) {
142
+ // Prevent clicks on the filter input from triggering a sort.
143
+ if (e.target.tagName.toLowerCase() === "input") return;
144
+ sortTable(index);
145
+ updateSortArrows(index, ascending);
146
+ });
147
+ });
148
+
149
+ // Filter rows as the user types.
150
+ nameFilter.addEventListener("input", function () {
151
+ filterTable(this.value);
152
+ });
153
+
154
+ function sortTable(columnIndex) {
155
+ const tbody = table.querySelector("tbody");
156
+ let rows = Array.from(tbody.querySelectorAll("tr"));
157
+
158
+ // If sorting on a new column, default to ascending.
159
+ if (currentSortedColumn !== columnIndex) {
160
+ ascending = true;
161
+ currentSortedColumn = columnIndex;
162
+ } else {
163
+ ascending = !ascending;
164
+ }
165
+
166
+ rows.sort((a, b) => {
167
+ let aText = a.cells[columnIndex].textContent.trim().toLowerCase();
168
+ let bText = b.cells[columnIndex].textContent.trim().toLowerCase();
169
+
170
+ // If sorting the file size column, convert sizes to bytes.
171
+ if (headers[columnIndex].getAttribute("data-type") === "size") {
172
+ aText = parseSize(aText);
173
+ bText = parseSize(bText);
174
+ }
175
+
176
+ if (aText < bText) return ascending ? -1 : 1;
177
+ if (aText > bText) return ascending ? 1 : -1;
178
+ return 0;
179
+ });
180
+
181
+ rows.forEach((row) => tbody.appendChild(row));
182
+ table.setAttribute("data-sort-asc", ascending.toString());
183
+ table.setAttribute("data-sorted-column", columnIndex.toString());
184
+ }
185
+
186
+ function updateSortArrows(sortedIndex, ascending) {
187
+ headers.forEach((header, index) => {
188
+ header.classList.remove("sorted");
189
+ const arrow = header.querySelector(".sort-arrow");
190
+ if (index === sortedIndex) {
191
+ header.classList.add("sorted");
192
+ arrow.textContent = ascending ? "▲" : "▼";
193
+ } else {
194
+ arrow.textContent = "";
195
+ }
196
+ });
197
+ }
198
+
199
+ function filterTable(filterValue) {
200
+ const tbody = table.querySelector("tbody");
201
+ const rows = Array.from(tbody.querySelectorAll("tr"));
202
+ const lowerFilter = filterValue.toLowerCase();
203
+
204
+ rows.forEach((row) => {
205
+ const nameCell = row.cells[0];
206
+ row.style.display = nameCell.textContent
207
+ .toLowerCase()
208
+ .includes(lowerFilter)
209
+ ? ""
210
+ : "none";
211
+ });
212
+ }
213
+
214
+ // Parse file size string (e.g., "12.3 KB") into a number (bytes)
215
+ function parseSize(sizeStr) {
216
+ sizeStr = sizeStr.trim();
217
+ if (sizeStr === "-" || sizeStr === "") return 0;
218
+ const parts = sizeStr.split(" ");
219
+ if (parts.length < 2) return parseFloat(parts[0]);
220
+ const value = parseFloat(parts[0]);
221
+ const unit = parts[1].toLowerCase();
222
+ switch (unit) {
223
+ case "b":
224
+ return value;
225
+ case "kb":
226
+ return value * 1024;
227
+ case "mb":
228
+ return value * 1024 * 1024;
229
+ case "gb":
230
+ return value * 1024 * 1024 * 1024;
231
+ default:
232
+ return value;
233
+ }
234
+ }
235
+ });
236
+ </script>
237
+ </body>
238
+ </html>
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Unauthorized",
3
+ "message": "You are not authorized to access this resource.",
4
+ "code": 401,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Forbidden",
3
+ "message": "You are forbidden to access this resource.",
4
+ "code": 403,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Not Found",
3
+ "message": "The requested resource could not be found.",
4
+ "code": 404,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Payload Too Large",
3
+ "message": "The request entity is larger than the server is willing or able to process.",
4
+ "code": 413,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Too Many Requests",
3
+ "message": "Too many requests within a limited time frame.",
4
+ "code": 429,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Internal Server Error",
3
+ "message": "The server encountered an unexpected condition that prevented it from fulfilling the request.",
4
+ "code": 500,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Bad Gateway",
3
+ "message": "The server was acting as a gateway or proxy and received an invalid response from the upstream server.",
4
+ "code": 502,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Service Unavailable",
3
+ "message": "The server is currently unable to handle the request.",
4
+ "code": 503,
5
+ "status": "error"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": "Gateway Timeout",
3
+ "message": "The server did not respond in time.",
4
+ "code": 504,
5
+ "status": "error"
6
+ }
@@ -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);
@@ -1,16 +1,21 @@
1
+ #![deny(unused_crate_dependencies)]
2
+ pub mod default_responses;
3
+ pub mod env;
4
+ pub mod prelude;
5
+ pub mod ruby_types;
6
+ pub mod server;
7
+ pub mod services;
8
+
1
9
  use magnus::{error::Result, function, method, Module, Object, Ruby};
10
+ use prelude::*;
2
11
  use ruby_types::{
3
- itsi_body_proxy::ItsiBodyProxy, itsi_grpc_request::ItsiGrpcRequest,
4
- itsi_grpc_stream::ItsiGrpcStream, itsi_http_request::ItsiHttpRequest,
5
- itsi_http_response::ItsiHttpResponse, itsi_server::ItsiServer, ITSI_BODY_PROXY,
6
- ITSI_GRPC_REQUEST, ITSI_GRPC_RESPONSE, ITSI_GRPC_STREAM, ITSI_MODULE, ITSI_REQUEST,
7
- ITSI_RESPONSE, ITSI_SERVER,
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,
8
16
  };
9
17
  use server::signal::reset_signal_handlers;
10
- use tracing::*;
11
- pub mod env;
12
- pub mod ruby_types;
13
- pub mod server;
18
+ use services::password_hasher;
14
19
 
15
20
  #[magnus::init]
16
21
  fn init(ruby: &Ruby) -> Result<()> {
@@ -24,6 +29,10 @@ fn init(ruby: &Ruby) -> Result<()> {
24
29
  itsi.define_singleton_method("log_info", function!(log_info, 1))?;
25
30
  itsi.define_singleton_method("log_warn", function!(log_warn, 1))?;
26
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
+ )?;
27
36
 
28
37
  let server = ruby.get_inner(&ITSI_SERVER);
29
38
  server.define_singleton_method("new", function!(ItsiServer::new, 3))?;
@@ -35,7 +44,15 @@ fn init(ruby: &Ruby) -> Result<()> {
35
44
  request.define_method("path", method!(ItsiHttpRequest::path, 0))?;
36
45
  request.define_method("script_name", method!(ItsiHttpRequest::script_name, 0))?;
37
46
  request.define_method("query_string", method!(ItsiHttpRequest::query_string, 0))?;
38
- request.define_method("method", method!(ItsiHttpRequest::method, 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))?;
39
56
  request.define_method("version", method!(ItsiHttpRequest::version, 0))?;
40
57
  request.define_method("rack_protocol", method!(ItsiHttpRequest::rack_protocol, 0))?;
41
58
  request.define_method("host", method!(ItsiHttpRequest::host, 0))?;
@@ -49,6 +66,9 @@ fn init(ruby: &Ruby) -> Result<()> {
49
66
  request.define_method("response", method!(ItsiHttpRequest::response, 0))?;
50
67
  request.define_method("json?", method!(ItsiHttpRequest::is_json, 0))?;
51
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))?;
52
72
 
53
73
  let body_proxy = ruby.get_inner(&ITSI_BODY_PROXY);
54
74
  body_proxy.define_method("gets", method!(ItsiBodyProxy::gets, 0))?;
@@ -73,27 +93,39 @@ fn init(ruby: &Ruby) -> Result<()> {
73
93
  response.define_method("close_read", method!(ItsiHttpResponse::close_read, 0))?;
74
94
  response.define_method("close", method!(ItsiHttpResponse::close, 0))?;
75
95
  response.define_method("hijack", method!(ItsiHttpResponse::hijack, 1))?;
96
+ response.define_method("accept", method!(ItsiHttpResponse::accept_str, 0))?;
76
97
  response.define_method("json?", method!(ItsiHttpResponse::is_json, 0))?;
77
98
  response.define_method("html?", method!(ItsiHttpResponse::is_html, 0))?;
78
99
 
79
- let grpc_request = ruby.get_inner(&ITSI_GRPC_REQUEST);
80
-
81
- grpc_request.define_method("service_name", method!(ItsiGrpcRequest::service_name, 0))?;
82
- grpc_request.define_method("method_name", method!(ItsiGrpcRequest::method_name, 0))?;
83
- grpc_request.define_method("stream", method!(ItsiGrpcRequest::stream, 0))?;
84
- grpc_request.define_method("json?", method!(ItsiGrpcRequest::is_json, 0))?;
85
- grpc_request.define_method(
86
- "content_type",
87
- method!(ItsiGrpcRequest::content_type_str, 0),
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),
88
117
  )?;
89
118
 
90
- let grpc_stream = ruby.get_inner(&ITSI_GRPC_STREAM);
91
- grpc_stream.define_method("read", method!(ItsiGrpcStream::read, 1))?;
92
- grpc_stream.define_method("write", method!(ItsiGrpcStream::write, 1))?;
93
- grpc_stream.define_method("flush", method!(ItsiGrpcStream::flush, 0))?;
94
- grpc_stream.define_method("send_trailers", method!(ItsiGrpcStream::send_trailers, 1))?;
95
-
96
- let _grpc_response = ruby.get_inner(&ITSI_GRPC_RESPONSE);
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))?;
97
129
 
98
130
  Ok(())
99
131
  }
@@ -0,0 +1,2 @@
1
+ pub use itsi_error::*;
2
+ pub use itsi_tracing::{debug, error, info, trace, warn};
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Itsi Server Twp
3
+ type: docs
4
+ prev: /crates/itsi_server/test
5
+ next: docs/folder/
6
+ ---
7
+ # Deep nested Foo
8
+
9
+ This is a demo of the theme's documentation layout.
10
+
11
+ ## Hello, World!
12
+
13
+ ```go {filename="main.go"}
14
+ package main
15
+
16
+ import "fmt"
17
+
18
+ func main() {
19
+ fmt.Println("Hello, World!")
20
+ }
21
+ ```