itsi 0.1.9 → 0.1.12

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1542 -43
  3. data/Itsi.rb +125 -0
  4. data/Rakefile +8 -4
  5. data/crates/itsi_error/src/lib.rs +9 -0
  6. data/crates/itsi_rb_helpers/Cargo.toml +1 -0
  7. data/crates/itsi_rb_helpers/src/heap_value.rs +18 -0
  8. data/crates/itsi_rb_helpers/src/lib.rs +59 -9
  9. data/crates/itsi_server/Cargo.toml +70 -28
  10. data/crates/itsi_server/src/lib.rs +80 -80
  11. data/crates/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  12. data/{gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs → crates/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs} +22 -3
  13. data/crates/itsi_server/src/ruby_types/itsi_grpc_request.rs +147 -0
  14. data/crates/itsi_server/src/ruby_types/itsi_grpc_response.rs +19 -0
  15. data/crates/itsi_server/src/ruby_types/itsi_grpc_stream/mod.rs +216 -0
  16. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +282 -0
  17. data/crates/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +72 -41
  18. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
  19. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +355 -0
  20. data/crates/itsi_server/src/ruby_types/itsi_server.rs +82 -0
  21. data/crates/itsi_server/src/ruby_types/mod.rs +55 -0
  22. data/crates/itsi_server/src/server/bind.rs +29 -17
  23. data/crates/itsi_server/src/server/byte_frame.rs +32 -0
  24. data/crates/itsi_server/src/server/cache_store.rs +74 -0
  25. data/crates/itsi_server/src/server/itsi_service.rs +172 -0
  26. data/crates/itsi_server/src/server/lifecycle_event.rs +3 -0
  27. data/crates/itsi_server/src/server/listener.rs +111 -11
  28. data/crates/itsi_server/src/server/middleware_stack/middleware.rs +153 -0
  29. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +47 -0
  30. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +58 -0
  31. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +82 -0
  32. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +321 -0
  33. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +139 -0
  34. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +300 -0
  35. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +287 -0
  36. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +48 -0
  37. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +127 -0
  38. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +191 -0
  39. data/crates/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +72 -0
  40. data/crates/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +85 -0
  41. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +195 -0
  42. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  43. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +82 -0
  44. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +216 -0
  45. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +124 -0
  46. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +43 -0
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +34 -0
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +93 -0
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +162 -0
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +158 -0
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  53. data/crates/itsi_server/src/server/middleware_stack/mod.rs +315 -0
  54. data/crates/itsi_server/src/server/mod.rs +8 -1
  55. data/crates/itsi_server/src/server/process_worker.rs +44 -11
  56. data/crates/itsi_server/src/server/rate_limiter.rs +565 -0
  57. data/crates/itsi_server/src/server/request_job.rs +11 -0
  58. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +129 -46
  59. data/crates/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  60. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +325 -167
  61. data/crates/itsi_server/src/server/signal.rs +20 -4
  62. data/crates/itsi_server/src/server/static_file_server.rs +984 -0
  63. data/crates/itsi_server/src/server/thread_worker.rs +165 -88
  64. data/crates/itsi_server/src/server/tls.rs +1 -1
  65. data/crates/itsi_server/src/server/types.rs +43 -0
  66. data/crates/itsi_server/test.md +14 -0
  67. data/crates/itsi_tracing/Cargo.toml +1 -0
  68. data/crates/itsi_tracing/src/lib.rs +216 -45
  69. data/docs/.gitignore +7 -0
  70. data/docs/.gitpod.yml +15 -0
  71. data/docs/Itsi.rb +17 -0
  72. data/docs/content/_index.md +17 -0
  73. data/docs/content/about.md +6 -0
  74. data/docs/content/docs/_index.md +18 -0
  75. data/docs/content/docs/first-page.md +9 -0
  76. data/docs/content/docs/folder/_index.md +10 -0
  77. data/docs/content/docs/folder/leaf.md +7 -0
  78. data/docs/go.mod +5 -0
  79. data/docs/go.sum +2 -0
  80. data/docs/hugo.yaml +77 -0
  81. data/examples/static_assets_example.rb +83 -0
  82. data/gems/_index.md +18 -0
  83. data/gems/scheduler/CODE_OF_CONDUCT.md +7 -0
  84. data/gems/scheduler/Cargo.lock +75 -14
  85. data/gems/scheduler/README.md +5 -0
  86. data/gems/scheduler/_index.md +7 -0
  87. data/gems/scheduler/itsi-scheduler.gemspec +4 -1
  88. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  89. data/gems/scheduler/lib/itsi/scheduler.rb +2 -2
  90. data/gems/scheduler/test/test_file_io.rb +0 -1
  91. data/gems/scheduler/test/test_itsi_scheduler.rb +1 -1
  92. data/gems/server/CHANGELOG.md +5 -0
  93. data/gems/server/CODE_OF_CONDUCT.md +7 -0
  94. data/gems/server/Cargo.lock +1543 -43
  95. data/gems/server/README.md +4 -0
  96. data/gems/server/_index.md +6 -0
  97. data/gems/server/exe/itsi +46 -57
  98. data/gems/server/itsi-server.gemspec +3 -2
  99. data/gems/server/lib/itsi/{request.rb → http_request.rb} +29 -5
  100. data/gems/server/lib/itsi/http_response.rb +39 -0
  101. data/gems/server/lib/itsi/server/Itsi.rb +119 -0
  102. data/gems/server/lib/itsi/server/config/dsl.rb +506 -0
  103. data/gems/server/lib/itsi/server/config.rb +131 -0
  104. data/gems/server/lib/itsi/server/default_app/default_app.rb +38 -0
  105. data/gems/server/lib/itsi/server/grpc_interface.rb +213 -0
  106. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +9 -6
  107. data/gems/server/lib/itsi/server/rack_interface.rb +24 -9
  108. data/gems/server/lib/itsi/server/scheduler_interface.rb +1 -1
  109. data/gems/server/lib/itsi/server/scheduler_mode.rb +4 -0
  110. data/gems/server/lib/itsi/server/signal_trap.rb +6 -1
  111. data/gems/server/lib/itsi/server/version.rb +1 -1
  112. data/gems/server/lib/itsi/server.rb +75 -60
  113. data/gems/server/lib/itsi/standard_headers.rb +86 -0
  114. data/gems/server/test/helpers/test_helper.rb +14 -12
  115. data/gems/server/test/test_itsi_server.rb +21 -2
  116. data/lib/itsi/version.rb +1 -1
  117. data/sandbox/itsi_file/Gemfile +11 -0
  118. data/sandbox/itsi_file/Gemfile.lock +69 -0
  119. data/sandbox/itsi_file/Itsi.rb +276 -0
  120. data/sandbox/itsi_file/error.html +2 -0
  121. data/sandbox/itsi_file/organisations_controller.rb +20 -0
  122. data/sandbox/itsi_file/public/assets/image.png +0 -0
  123. data/sandbox/itsi_file/public/assets/index.html +1 -0
  124. data/sandbox/itsi_sandbox_async/Gemfile +1 -1
  125. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +2 -2
  126. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  127. data/sandbox/itsi_sandbox_rack/config.ru +2 -15
  128. data/sandbox/itsi_sandbox_rails/.dockerignore +2 -5
  129. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +1 -1
  130. data/sandbox/itsi_sandbox_rails/.gitignore +2 -1
  131. data/sandbox/itsi_sandbox_rails/Dockerfile +6 -9
  132. data/sandbox/itsi_sandbox_rails/Gemfile +16 -22
  133. data/sandbox/itsi_sandbox_rails/Gemfile.lock +100 -225
  134. data/sandbox/itsi_sandbox_rails/app/assets/config/manifest.js +4 -0
  135. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +11 -6
  136. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/channel.rb +4 -0
  137. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/connection.rb +4 -0
  138. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +7 -8
  139. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +0 -3
  140. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +2 -7
  141. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +3 -4
  142. data/sandbox/itsi_sandbox_rails/bin/setup +8 -5
  143. data/sandbox/itsi_sandbox_rails/config/application.rb +1 -35
  144. data/sandbox/itsi_sandbox_rails/config/cable.yml +3 -10
  145. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -1
  146. data/sandbox/itsi_sandbox_rails/config/database.yml +9 -19
  147. data/sandbox/itsi_sandbox_rails/config/environment.rb +1 -1
  148. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +21 -12
  149. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +49 -34
  150. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +19 -5
  151. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +5 -0
  152. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +1 -1
  153. data/sandbox/itsi_sandbox_rails/config/initializers/permissions_policy.rb +13 -0
  154. data/sandbox/itsi_sandbox_rails/config/puma.rb +2 -9
  155. data/sandbox/itsi_sandbox_rails/config.ru +0 -1
  156. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +1 -1
  157. data/sandbox/itsi_sandbox_rails/db/schema.rb +2 -2
  158. data/sandbox/itsi_sandbox_rails/lib/assets/.keep +0 -0
  159. data/sandbox/itsi_sandbox_rails/public/404.html +66 -113
  160. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +65 -113
  161. data/sandbox/itsi_sandbox_rails/public/422.html +66 -113
  162. data/sandbox/itsi_sandbox_rails/public/500.html +65 -113
  163. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  164. data/sandbox/itsi_sandbox_rails/public/icon.svg +2 -2
  165. data/sandbox/itsi_sandbox_rails/test/channels/application_cable/connection_test.rb +13 -0
  166. data/sandbox/itsi_sandbox_roda/Gemfile.lock +3 -10
  167. data/tasks.txt +72 -12
  168. metadata +94 -139
  169. data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  170. data/crates/itsi_server/src/body_proxy/mod.rs +0 -2
  171. data/crates/itsi_server/src/request/itsi_request.rs +0 -305
  172. data/crates/itsi_server/src/request/mod.rs +0 -1
  173. data/crates/itsi_server/src/response/mod.rs +0 -1
  174. data/crates/itsi_server/src/server/itsi_server.rs +0 -294
  175. data/gems/scheduler/ext/itsi_error/Cargo.lock +0 -368
  176. data/gems/scheduler/ext/itsi_error/Cargo.toml +0 -11
  177. data/gems/scheduler/ext/itsi_error/src/from.rs +0 -68
  178. data/gems/scheduler/ext/itsi_error/src/lib.rs +0 -24
  179. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +0 -15
  180. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +0 -31
  181. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +0 -355
  182. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +0 -10
  183. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  184. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +0 -178
  185. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +0 -24
  186. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +0 -6
  187. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  188. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  189. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  190. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  191. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +0 -38
  192. data/gems/scheduler/ext/itsi_server/Cargo.lock +0 -2956
  193. data/gems/scheduler/ext/itsi_server/Cargo.toml +0 -47
  194. data/gems/scheduler/ext/itsi_server/extconf.rb +0 -6
  195. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  196. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  197. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  198. data/gems/scheduler/ext/itsi_server/src/env.rs +0 -43
  199. data/gems/scheduler/ext/itsi_server/src/lib.rs +0 -112
  200. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +0 -305
  201. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +0 -1
  202. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +0 -357
  203. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +0 -1
  204. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +0 -170
  205. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  206. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +0 -104
  207. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +0 -294
  208. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  209. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +0 -318
  210. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +0 -11
  211. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +0 -196
  212. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  213. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  214. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  215. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +0 -77
  216. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +0 -367
  217. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  218. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +0 -265
  219. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +0 -274
  220. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +0 -16
  221. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +0 -58
  222. data/gems/server/ext/itsi_error/Cargo.lock +0 -368
  223. data/gems/server/ext/itsi_error/Cargo.toml +0 -11
  224. data/gems/server/ext/itsi_error/src/from.rs +0 -68
  225. data/gems/server/ext/itsi_error/src/lib.rs +0 -24
  226. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +0 -15
  227. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +0 -31
  228. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +0 -355
  229. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +0 -10
  230. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  231. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +0 -178
  232. data/gems/server/ext/itsi_scheduler/Cargo.toml +0 -24
  233. data/gems/server/ext/itsi_scheduler/extconf.rb +0 -6
  234. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  235. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  236. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  237. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  238. data/gems/server/ext/itsi_scheduler/src/lib.rs +0 -38
  239. data/gems/server/ext/itsi_server/Cargo.lock +0 -2956
  240. data/gems/server/ext/itsi_server/Cargo.toml +0 -47
  241. data/gems/server/ext/itsi_server/extconf.rb +0 -6
  242. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  243. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  244. data/gems/server/ext/itsi_server/src/env.rs +0 -43
  245. data/gems/server/ext/itsi_server/src/lib.rs +0 -112
  246. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +0 -305
  247. data/gems/server/ext/itsi_server/src/request/mod.rs +0 -1
  248. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +0 -357
  249. data/gems/server/ext/itsi_server/src/response/mod.rs +0 -1
  250. data/gems/server/ext/itsi_server/src/server/bind.rs +0 -170
  251. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  252. data/gems/server/ext/itsi_server/src/server/io_stream.rs +0 -104
  253. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +0 -294
  254. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  255. data/gems/server/ext/itsi_server/src/server/listener.rs +0 -318
  256. data/gems/server/ext/itsi_server/src/server/mod.rs +0 -11
  257. data/gems/server/ext/itsi_server/src/server/process_worker.rs +0 -196
  258. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  259. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  260. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  261. data/gems/server/ext/itsi_server/src/server/signal.rs +0 -77
  262. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +0 -367
  263. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  264. data/gems/server/ext/itsi_server/src/server/tls.rs +0 -265
  265. data/gems/server/ext/itsi_tracing/Cargo.lock +0 -274
  266. data/gems/server/ext/itsi_tracing/Cargo.toml +0 -16
  267. data/gems/server/ext/itsi_tracing/src/lib.rs +0 -58
  268. data/gems/server/lib/itsi/stream_io.rb +0 -38
  269. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +0 -3
  270. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +0 -3
  271. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +0 -14
  272. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +0 -3
  273. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +0 -3
  274. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +0 -51
  275. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +0 -47
  276. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +0 -109
  277. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  278. data/sandbox/itsi_sandbox_rails/.kamal/secrets +0 -17
  279. data/sandbox/itsi_sandbox_rails/bin/dev +0 -2
  280. data/sandbox/itsi_sandbox_rails/bin/jobs +0 -6
  281. data/sandbox/itsi_sandbox_rails/bin/kamal +0 -27
  282. data/sandbox/itsi_sandbox_rails/bin/thrust +0 -5
  283. data/sandbox/itsi_sandbox_rails/config/cache.yml +0 -16
  284. data/sandbox/itsi_sandbox_rails/config/deploy.yml +0 -116
  285. data/sandbox/itsi_sandbox_rails/config/queue.yml +0 -18
  286. data/sandbox/itsi_sandbox_rails/config/recurring.yml +0 -10
  287. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +0 -11
  288. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +0 -14
  289. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +0 -129
  290. data/sandbox/itsi_sandbox_rails/public/400.html +0 -114
  291. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +0 -9
  292. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +0 -7
  293. /data/{sandbox/itsi_sandbox_rails/script/.keep → crates/_index.md} +0 -0
  294. /data/gems/server/lib/itsi/{index.html → server/default_app/index.html} +0 -0
@@ -0,0 +1,213 @@
1
+ module Itsi
2
+ class Server
3
+ class GrpcActiveCall
4
+ attr_reader :stream, :method_rpc, :output_metadata, :method_name
5
+
6
+ def initialize(stream, method_rpc, service_class, method_name)
7
+ @stream = stream
8
+ @method_rpc = method_rpc
9
+ @service_class = service_class
10
+ @output_metadata = {}
11
+ @method_name = method_name
12
+ end
13
+ end
14
+
15
+ class GrpcInterface
16
+ def self.for(services)
17
+ interface = new(services)
18
+ lambda do |request|
19
+ interface.handle_request(request)
20
+ end
21
+ end
22
+
23
+ def initialize(services = [])
24
+ @services = {}
25
+ register_services(services)
26
+ end
27
+
28
+ def register_services(services)
29
+ services.each do |service|
30
+ service_class = service.class
31
+ @services[service_class.service_name] = {
32
+ implementation: service,
33
+ class: service_class
34
+ }
35
+ end
36
+ end
37
+
38
+ def handle_request(request)
39
+ service_info = @services[request.service_name]
40
+ raise "Unknown service: #{request.service_name}" unless service_info
41
+
42
+ service_impl = service_info[:implementation]
43
+ service_class = service_info[:class]
44
+
45
+ method_rpc = RpcDescWrapper.new(service_class, request.content_type, request.method_name)
46
+
47
+ active_call = GrpcActiveCall.new(request.stream, method_rpc, service_class, request.method_name)
48
+
49
+ if method_rpc.bidi_streamer?
50
+ puts "Calling bidirectional streaming handler"
51
+ handle_bidi_streaming(active_call, service_impl)
52
+ elsif method_rpc.client_streamer?
53
+ puts "Calling client streaming handler"
54
+ handle_client_streaming(active_call, service_impl)
55
+ elsif method_rpc.server_streamer?
56
+ puts "Calling server streaming handler"
57
+ handle_server_streaming(active_call, service_impl)
58
+ elsif method_rpc.request_response?
59
+ handle_unary(active_call, service_impl)
60
+ end
61
+ active_call.stream.send_trailers({ "grpc-status" => "0" })
62
+ rescue StandardError => e
63
+ active_call.stream.send_trailers({ "grpc-status" => "13", "grpc-message" => e.message })
64
+ end
65
+
66
+ private
67
+
68
+ # Read a framed message from the stream
69
+ def read_message(stream)
70
+ # Read the gRPC frame header (5 bytes)
71
+ header = stream.read(5)
72
+ return nil if header.nil? || header.bytesize < 5
73
+
74
+ compressed = header.bytes[0] == 1
75
+ length = header[1..4].unpack1("N")
76
+
77
+ # Read the message body
78
+ stream.read(length)
79
+ end
80
+
81
+ # Send a response
82
+ def send_response(active_call, response)
83
+ response_data = active_call.method_rpc.marshal_response(response)
84
+ send_framed_message(active_call.stream, response_data)
85
+ end
86
+
87
+ # Send a framed message
88
+ def send_framed_message(stream, message_data, compressed = false)
89
+ compressed_flag = compressed ? 1 : 0
90
+ header = [compressed_flag, message_data.bytesize].pack("CN")
91
+
92
+ stream.write(header)
93
+ stream.write(message_data)
94
+ stream.flush
95
+ end
96
+
97
+ # Create an enumerator for client streaming requests
98
+ def create_request_enum(active_call)
99
+ Enumerator.new do |yielder|
100
+ loop do
101
+ message_data = read_message(active_call.stream)
102
+ break if message_data.nil?
103
+
104
+ request = active_call.method_rpc.unmarshal_request(message_data)
105
+ yielder << request
106
+ end
107
+ end
108
+ end
109
+
110
+ # Handlers for different RPC types
111
+
112
+ def handle_unary(active_call, service)
113
+ # Read the request message
114
+ message_data = read_message(active_call.stream)
115
+ request = active_call.method_rpc.unmarshal_request(message_data)
116
+
117
+ # Call the service implementation
118
+ underscore_method = GRPC::GenericService.underscore(active_call.method_name)
119
+ response = service.send(underscore_method, request, active_call)
120
+
121
+ # Send response
122
+ send_response(active_call, response)
123
+ end
124
+
125
+ def handle_client_streaming(active_call, service)
126
+ # Create an enumerable to read the incoming stream
127
+ request_enum = create_request_enum(active_call)
128
+
129
+ # Call the service implementation
130
+ underscore_method = GRPC::GenericService.underscore(active_call.method_name)
131
+ response = service.send(underscore_method, request_enum, active_call)
132
+
133
+ # Send response
134
+ send_response(active_call, response)
135
+ end
136
+
137
+ def handle_server_streaming(active_call, service)
138
+ # Read the request message
139
+ message_data = read_message(active_call.stream)
140
+ request = active_call.method_rpc.unmarshal_request(message_data)
141
+
142
+ # Call the service implementation with a block to handle streaming
143
+ underscore_method = GRPC::GenericService.underscore(active_call.method_name)
144
+ service.send(underscore_method, request, active_call) do |response|
145
+ send_response(active_call, response)
146
+ end
147
+ end
148
+
149
+ def handle_bidi_streaming(active_call, service)
150
+ # Create an enumerable to read the incoming stream
151
+ request_enum = create_request_enum(active_call)
152
+
153
+ # Call the service implementation with a block
154
+ underscore_method = GRPC::GenericService.underscore(active_call.method_name)
155
+ service.send(underscore_method, request_enum, active_call) do |response|
156
+ send_response(active_call, response)
157
+ end
158
+ end
159
+ end
160
+
161
+ class RpcDescWrapper
162
+ def initialize(service_class, content_type, method_name)
163
+ rpc_descs = service_class.rpc_descs
164
+ @rpc_desc = rpc_descs[method_name.to_sym]
165
+ raise "Method not found: #{method_name}" unless @rpc_desc
166
+
167
+ @input_type = @rpc_desc.input
168
+ @content_type = content_type
169
+ @input_is_stream = @input_type.is_a?(GRPC::RpcDesc::Stream)
170
+ @input_type = @input_type.type if @input_is_stream
171
+
172
+ @output_type = @rpc_desc.output
173
+ @output_is_stream = @output_type.is_a?(GRPC::RpcDesc::Stream)
174
+ @output_type = @output_type.type if @output_is_stream
175
+
176
+ @client_streamer = @input_is_stream
177
+ @server_streamer = @output_is_stream
178
+ end
179
+
180
+ def client_streamer?
181
+ @client_streamer
182
+ end
183
+
184
+ def server_streamer?
185
+ @server_streamer
186
+ end
187
+
188
+ def bidi_streamer?
189
+ @client_streamer && @server_streamer
190
+ end
191
+
192
+ def request_response?
193
+ !@client_streamer && !@server_streamer
194
+ end
195
+
196
+ def unmarshal_request(data)
197
+ if @content_type == "application/json"
198
+ @input_type.decode_json(data)
199
+ else
200
+ @input_type.decode(data)
201
+ end
202
+ end
203
+
204
+ def marshal_response(response)
205
+ if @content_type == "application/json"
206
+ response.to_json
207
+ else
208
+ response.to_proto
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -4,12 +4,15 @@ module Rack
4
4
  module Handler
5
5
  module Itsi
6
6
  def self.run(app, options = {})
7
- ::Itsi::Server.new(
8
- app: -> { app },
9
- binds: ["http://#{options.fetch(:host, "127.0.0.1")}:#{options.fetch(:Port, 3001)}"],
10
- workers: options.fetch(:workers, 1),
11
- threads: options.fetch(:threads, 1)
12
- ).start
7
+ host = options.fetch(:host, "127.0.0.1")
8
+ port = options.fetch(:Port, 3001)
9
+ Itsi::Server.start(
10
+ {
11
+ app: app,
12
+ binds: ["http://#{host}:#{port}"]
13
+ },
14
+ Itsi::Server::Config.config_file_path
15
+ )
13
16
  end
14
17
  end
15
18
  end
@@ -1,6 +1,22 @@
1
1
  module Itsi
2
2
  class Server
3
3
  module RackInterface
4
+
5
+ # Builds a handler proc that is compatible with Rack applications.
6
+ def self.for(app)
7
+ require "rack"
8
+ if app.is_a?(String)
9
+ dir = File.expand_path(File.dirname(app))
10
+ Dir.chdir(dir) do
11
+ loaded_app = ::Rack::Builder.parse_file(app)
12
+ app = loaded_app.is_a?(Array) ? loaded_app.first : loaded_app
13
+ end
14
+ end
15
+ lambda do |request|
16
+ Server.respond(request, app.call(request.to_rack_env))
17
+ end
18
+ end
19
+
4
20
  # Interface to Rack applications.
5
21
  # Here we build the env, and invoke the Rack app's call method.
6
22
  # We then turn the Rack response into something Itsi server understands.
@@ -25,10 +41,13 @@ module Itsi
25
41
  # 2. Set Headers
26
42
  body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack")
27
43
  headers.each do |key, value|
28
- next response.add_header(key, value) unless value.is_a?(Array)
44
+ unless value.is_a?(Array)
45
+ response[key] = value
46
+ next
47
+ end
29
48
 
30
49
  value.each do |v|
31
- response.add_header(key, v)
50
+ response[key] = v
32
51
  end
33
52
  end
34
53
 
@@ -40,7 +59,7 @@ module Itsi
40
59
  # stream this response.
41
60
 
42
61
  if body_streamer
43
- body_streamer.call(StreamIO.new(response))
62
+ body_streamer.call(response)
44
63
 
45
64
  # If we're enumerable with more than one chunk
46
65
  # also stream, otherwise write in a single chunk
@@ -53,15 +72,11 @@ module Itsi
53
72
  # to optimize for the case where there's only one chunk.
54
73
  buffer = nil
55
74
  body.each do |part|
56
- response.send_frame(buffer.to_s) if buffer
75
+ response << buffer.to_s if buffer
57
76
  buffer = part
58
77
  end
59
78
 
60
- begin
61
- response.send_and_close(buffer.to_s)
62
- rescue StandardError
63
- binding.b
64
- end
79
+ response.send_and_close(buffer.to_s)
65
80
  else
66
81
  response.send_and_close(body.to_s)
67
82
  end
@@ -13,7 +13,7 @@ module Itsi
13
13
  # each request is wrapped in a Fiber.
14
14
  def schedule(app, request)
15
15
  Fiber.schedule do
16
- call(app, request)
16
+ app.call(request)
17
17
  end
18
18
  end
19
19
  end
@@ -1,3 +1,7 @@
1
+ # Running with a Fiber scheduler enabled but with an ActiveSupport isolation_level set to Thread
2
+ # can be dangerous. A thread isolation level means that all fibers sharing a thread can content
3
+ # for the same resources, which can lead to race conditions.
4
+ # This hook should *only* be disabled if you know there are no such shared resources.
1
5
  if defined?(ActiveSupport::IsolatedExecutionState) && !ENV["ITSI_DISABLE_AS_AUTO_FIBER_ISOLATION_LEVEL"]
2
6
  Itsi.log_info \
3
7
  "ActiveSupport Isolated Execution state detected. Automatically switching to :fiber mode. "\
@@ -1,6 +1,11 @@
1
1
  module Itsi
2
+ # This trap is necessary for debuggers and similar which intercept certain signals
3
+ # then attempt to restore these to the previous signal when finished.
4
+ # If the previous signal handler was registered in native code, this restoration doesn't
5
+ # work as expected and the native signal handler is lost.
6
+ # We intercept restored signals here and reinstate the Itsi server signal handlers
7
+ # (if the server is still running).
2
8
  module SignalTrap
3
-
4
9
  DEFAULT_SIGNALS = ["DEFAULT", "", nil].freeze
5
10
  INTERCEPTED_SIGNALS = ["INT"].freeze
6
11
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.1.9"
5
+ VERSION = "0.1.12"
6
6
  end
7
7
  end
@@ -3,45 +3,14 @@
3
3
  require_relative "server/version"
4
4
  require_relative "server/itsi_server"
5
5
  require_relative "server/rack_interface"
6
- require_relative "server/signal_trap"
6
+ require_relative "server/grpc_interface"
7
7
  require_relative "server/scheduler_interface"
8
+ require_relative "server/signal_trap"
8
9
  require_relative "server/rack/handler/itsi"
9
- require_relative "request"
10
- require_relative "stream_io"
11
-
12
- # When you Run Itsi without a Rack app,
13
- # we start a tiny
14
- DEFAULT_INDEX = IO.read("#{__dir__}/index.html").freeze
15
- DEFAULT_BINDS = ["http://0.0.0.0:3000"].freeze
16
- DEFAULT_APP = lambda {
17
- require "json"
18
- lambda do |env|
19
- headers, body = \
20
- if env["itsi.response"].json?
21
- [
22
- { "Content-Type" => "application/json" },
23
- [{ "message" => "You're running on Itsi!", "rack_env" => env,
24
- "version" => Itsi::Server::VERSION }.to_json]
25
- ]
26
- else
27
- [
28
- { "Content-Type" => "text/html" },
29
- [
30
- format(
31
- DEFAULT_INDEX,
32
- REQUEST_METHOD: env["REQUEST_METHOD"],
33
- PATH_INFO: env["PATH_INFO"],
34
- SERVER_NAME: env["SERVER_NAME"],
35
- SERVER_PORT: env["SERVER_PORT"],
36
- REMOTE_ADDR: env["REMOTE_ADDR"],
37
- HTTP_USER_AGENT: env["HTTP_USER_AGENT"]
38
- )
39
- ]
40
- ]
41
- end
42
- [200, headers, body]
43
- end
44
- }
10
+ require_relative "server/config"
11
+ require_relative "standard_headers"
12
+ require_relative "http_request"
13
+ require_relative "http_response"
45
14
 
46
15
  module Itsi
47
16
  class Server
@@ -53,34 +22,80 @@ module Itsi
53
22
  !!@running
54
23
  end
55
24
 
56
- def build(
57
- app: DEFAULT_APP[],
58
- binds: DEFAULT_BINDS,
59
- **opts
60
- )
61
- new(app: -> { app }, binds: binds, **opts)
25
+ def start_in_background_thread(cli_params={}, itsi_file = Itsi::Server::Config.config_file_path, &blk)
26
+ @background_thread = start(cli_params, itsi_file, background: true, &blk)
27
+ end
28
+
29
+ def start(cli_params, itsi_file = Itsi::Server::Config.config_file_path, background: false, &blk)
30
+ server = new(cli_params, itsi_file, blk)
31
+ previous_handler = Signal.trap(:INT, :DEFAULT)
32
+ run = lambda do
33
+ write_pid
34
+ @running = server
35
+ server.start
36
+ Signal.trap(:INT, previous_handler)
37
+ server
38
+ end
39
+ background ? Thread.new(&run) : run[]
40
+ end
41
+
42
+ def stop_background_thread
43
+ @running&.stop
44
+ @running = nil
45
+ @background_thread&.join
62
46
  end
63
47
 
64
- def start_in_background_thread(silence: true, **opts)
65
- start(background: true, silence: silence, **opts)
48
+ def write_pid
49
+ File.write(Itsi::Server::Config.pid_file_path, Process.pid)
66
50
  end
67
51
 
68
- def start(background: false, **opts)
69
- build(**opts).tap do |server|
70
- previous_handler = Signal.trap("INT", "DEFAULT")
71
- @running = true
72
- if background
73
- Thread.new do
74
- server.start
75
- @running = false
76
- Signal.trap("INT", previous_handler)
77
- end
78
- else
79
- server.start
80
- @running = false
81
- Signal.trap("INT", previous_handler)
82
- end
52
+ def get_pid
53
+ pid = File.read(Itsi::Server::Config.pid_file_path).to_i
54
+ if Process.kill(0, pid)
55
+ pid
56
+ else
57
+ nil
83
58
  end
59
+ rescue StandardError
60
+ nil
61
+ end
62
+
63
+ def reload
64
+ return unless pid = get_pid
65
+
66
+ Process.kill(:USR2, pid)
67
+ end
68
+
69
+ def restart
70
+ return unless pid = get_pid
71
+
72
+ Process.kill(:USR1, pid)
73
+ end
74
+
75
+ def down
76
+ puts :down
77
+ end
78
+
79
+ def up
80
+ puts :up
81
+ end
82
+
83
+ def add_worker
84
+ return unless pid = get_pid
85
+
86
+ Process.kill(:TTIN, pid)
87
+ end
88
+
89
+ def remove_worker
90
+ return unless pid = get_pid
91
+
92
+ Process.kill(:TTOU, pid)
93
+ end
94
+
95
+ def status
96
+ return unless pid = get_pid
97
+
98
+ Process.kill(:INFO, pid)
84
99
  end
85
100
  end
86
101
  end
@@ -0,0 +1,86 @@
1
+ module Itsi
2
+ module StandardHeaders
3
+ ALL = [
4
+ ACCEPT = "accept",
5
+ ACCEPT_CHARSET = "accept-charset",
6
+ ACCEPT_ENCODING = "accept-encoding",
7
+ ACCEPT_LANGUAGE = "accept-language",
8
+ ACCEPT_RANGES = "accept-ranges",
9
+ ACCESS_CONTROL_ALLOW_CREDENTIALS = "access-control-allow-credentials",
10
+ ACCESS_CONTROL_ALLOW_HEADERS = "access-control-allow-headers",
11
+ ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods",
12
+ ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin",
13
+ ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers",
14
+ ACCESS_CONTROL_MAX_AGE = "access-control-max-age",
15
+ ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers",
16
+ ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method",
17
+ AGE = "age",
18
+ ALLOW = "allow",
19
+ ALT_SVC = "alt-svc",
20
+ AUTHORIZATION = "authorization",
21
+ CACHE_CONTROL = "cache-control",
22
+ CACHE_STATUS = "cache-status",
23
+ CDN_CACHE_CONTROL = "cdn-cache-control",
24
+ CONNECTION = "connection",
25
+ CONTENT_DISPOSITION = "content-disposition",
26
+ CONTENT_ENCODING = "content-encoding",
27
+ CONTENT_LANGUAGE = "content-language",
28
+ CONTENT_LENGTH = "content-length",
29
+ CONTENT_LOCATION = "content-location",
30
+ CONTENT_RANGE = "content-range",
31
+ CONTENT_SECURITY_POLICY_REPORT_ONLY = "content-security-policy-report-only",
32
+ CONTENT_TYPE = "content-type",
33
+ COOKIE = "cookie",
34
+ DNT = "dnt",
35
+ DATE = "date",
36
+ ETAG = "etag",
37
+ EXPECT = "expect",
38
+ EXPIRES = "expires",
39
+ FORWARDED = "forwarded",
40
+ FROM = "from",
41
+ HOST = "host",
42
+ IF_MATCH = "if-match",
43
+ IF_MODIFIED_SINCE = "if-modified-since",
44
+ IF_NONE_MATCH = "if-none-match",
45
+ IF_RANGE = "if-range",
46
+ IF_UNMODIFIED_SINCE = "if-unmodified-since",
47
+ LAST_MODIFIED = "last-modified",
48
+ LINK = "link",
49
+ LOCATION = "location",
50
+ MAX_FORWARDS = "max-forwards",
51
+ ORIGIN = "origin",
52
+ PRAGMA = "pragma",
53
+ PROXY_AUTHENTICATE = "proxy-authenticate",
54
+ PROXY_AUTHORIZATION = "proxy-authorization",
55
+ PUBLIC_KEY_PINS = "public-key-pins",
56
+ PUBLIC_KEY_PINS_REPORT_ONLY = "public-key-pins-report-only",
57
+ RANGE = "range",
58
+ REFERER = "referer",
59
+ REFERRER_POLICY = "referrer-policy",
60
+ REFRESH = "refresh",
61
+ RETRY_AFTER = "retry-after",
62
+ SEC_WEBSOCKET_ACCEPT = "sec-websocket-accept",
63
+ SEC_WEBSOCKET_EXTENSIONS = "sec-websocket-extensions",
64
+ SEC_WEBSOCKET_KEY = "sec-websocket-key",
65
+ SEC_WEBSOCKET_PROTOCOL = "sec-websocket-protocol",
66
+ SEC_WEBSOCKET_VERSION = "sec-websocket-version",
67
+ SERVER = "server",
68
+ SET_COOKIE = "set-cookie",
69
+ STRICT_TRANSPORT_SECURITY = "strict-transport-security",
70
+ TE = "te",
71
+ TRAILER = "trailer",
72
+ TRANSFER_ENCODING = "transfer-encoding",
73
+ USER_AGENT = "user-agent",
74
+ UPGRADE = "upgrade",
75
+ UPGRADE_INSECURE_REQUESTS = "upgrade-insecure-requests",
76
+ VARY = "vary",
77
+ VIA = "via",
78
+ WARNING = "warning",
79
+ WWW_AUTHENTICATE = "www-authenticate",
80
+ X_CONTENT_TYPE_OPTIONS = "x-content-type-options",
81
+ X_DNS_PREFETCH_CONTROL = "x-dns-prefetch-control",
82
+ X_FRAME_OPTIONS = "x-frame-options",
83
+ X_XSS_PROTECTION = "x-xss-protection",
84
+ ]
85
+ end
86
+ end
@@ -6,23 +6,25 @@ require "itsi/scheduler"
6
6
 
7
7
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
8
8
 
9
- def free_bind
9
+ def free_bind(protocol)
10
10
  server = TCPServer.new("0.0.0.0", 0)
11
11
  port = server.addr[1]
12
12
  server.close
13
- "http://0.0.0.0:#{port}"
13
+ "#{protocol}://0.0.0.0:#{port}"
14
14
  end
15
15
 
16
- def run_app(app, **opts)
17
- bind = free_bind
18
- server = Itsi::Server.start_in_background_thread(
19
- app: app,
20
- binds: [bind],
21
- **opts
22
- )
16
+ def run_app(app, protocol: "http", bind: free_bind(protocol), scheduler_class: nil)
17
+ Itsi::Server.start_in_background_thread do
18
+ # Inline Itsi.rb
19
+ bind bind
20
+ workers 1
21
+ threads 1
22
+ fiber_scheduler scheduler_class
23
+ log_level :error
24
+ run app
25
+ end
23
26
 
24
- sleep 0.1
25
- yield URI(bind), server
27
+ yield URI(bind)
26
28
  ensure
27
- server&.stop
29
+ Itsi::Server.stop_background_thread
28
30
  end
@@ -80,14 +80,20 @@ class TestItsiServer < Minitest::Test
80
80
  run_app(
81
81
  lambda do |env|
82
82
  sleep 0.25
83
- [200, { "Content-Type" => "text/plain" }, "Hello, World!"]
83
+ [200, { "Content-Type" => "text/plain" }, "Response: #{env["PATH_INFO"][1..-1]}"]
84
84
  end,
85
85
  scheduler_class: "Itsi::Scheduler"
86
86
  ) do |uri|
87
87
  start_time = Time.now
88
88
  20.times.map do
89
89
  Thread.new do
90
- assert_equal "Hello, World!", Net::HTTP.get(uri)
90
+ payload = SecureRandom.hex(16)
91
+ local_uri = uri.dup
92
+ local_uri.path = "/#{payload}"
93
+ response = Net::HTTP.start(local_uri.hostname, local_uri.port) do |http|
94
+ http.request(Net::HTTP::Get.new(local_uri))
95
+ end
96
+ assert_equal "Response: #{payload}", response.body
91
97
  end
92
98
  end.each(&:join)
93
99
  assert_in_delta 0.25, Time.now - start_time, 0.5
@@ -278,4 +284,17 @@ class TestItsiServer < Minitest::Test
278
284
  assert_equal "param=%C3%A9", Net::HTTP.get(uri)
279
285
  end
280
286
  end
287
+
288
+ def test_https
289
+ run_app(lambda do |env|
290
+ [200, { "Content-Type" => "text/plain" }, ["Hello, HTTPS!"]]
291
+ end, protocol: "https") do |uri|
292
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true,
293
+ verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
294
+ http.request(Net::HTTP::Get.new(uri))
295
+ end
296
+ assert_equal "200", response.code
297
+ assert_equal "Hello, HTTPS!", response.body
298
+ end
299
+ end
281
300
  end
data/lib/itsi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Itsi
2
- VERSION = '0.1.9'
2
+ VERSION = '0.1.12'
3
3
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # gem "rails"
6
+
7
+ gem 'itsi-scheduler', path: '../../gems/scheduler'
8
+ gem 'itsi-server', path: '../../gems/server'
9
+
10
+ gem 'debug'
11
+ gem 'grpc'