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
@@ -1,305 +0,0 @@
1
- use crate::{
2
- body_proxy::{
3
- big_bytes::BigBytes,
4
- itsi_body_proxy::{ItsiBody, ItsiBodyProxy},
5
- },
6
- response::itsi_response::ItsiResponse,
7
- server::{
8
- itsi_server::{RequestJob, Server},
9
- listener::{ListenerInfo, SockAddr},
10
- serve_strategy::single_mode::RunningPhase,
11
- },
12
- };
13
- use bytes::Bytes;
14
- use derive_more::Debug;
15
- use futures::StreamExt;
16
- use http::{request::Parts, HeaderValue, Response, StatusCode};
17
- use http_body_util::{combinators::BoxBody, BodyExt, Empty};
18
- use hyper::{body::Incoming, Request};
19
- use itsi_error::from::CLIENT_CONNECTION_CLOSED;
20
- use itsi_tracing::{debug, error};
21
- use magnus::{
22
- error::{ErrorType, Result as MagnusResult},
23
- Error,
24
- };
25
- use magnus::{
26
- value::{LazyId, Opaque, ReprValue},
27
- RClass, Ruby, Value,
28
- };
29
- use std::{convert::Infallible, fmt, io::Write, sync::Arc, time::Instant};
30
- use tokio::sync::{
31
- mpsc::{self},
32
- watch,
33
- };
34
- static ID_CALL: LazyId = LazyId::new("call");
35
- static ID_MESSAGE: LazyId = LazyId::new("message");
36
- static ID_BACKTRACE: LazyId = LazyId::new("backtrace");
37
-
38
- #[derive(Debug)]
39
- #[magnus::wrap(class = "Itsi::Request", free_immediately, size)]
40
- pub struct ItsiRequest {
41
- pub parts: Parts,
42
- #[debug(skip)]
43
- pub body: ItsiBody,
44
- pub remote_addr: String,
45
- pub version: String,
46
- #[debug(skip)]
47
- pub(crate) listener: Arc<ListenerInfo>,
48
- #[debug(skip)]
49
- pub server: Arc<Server>,
50
- pub response: ItsiResponse,
51
- pub start: Instant,
52
- pub content_type: String,
53
- }
54
-
55
- impl fmt::Display for ItsiRequest {
56
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57
- write!(
58
- f,
59
- "{} {} {}",
60
- self.version().unwrap(),
61
- self.method().unwrap(),
62
- self.path().unwrap()
63
- )
64
- }
65
- }
66
-
67
- impl ItsiRequest {
68
- pub fn is_connection_closed_err(ruby: &Ruby, err: &Error) -> bool {
69
- match err.error_type() {
70
- ErrorType::Jump(_) => false,
71
- ErrorType::Error(_, _) => false,
72
- ErrorType::Exception(exception) => {
73
- exception.is_kind_of(ruby.exception_eof_error())
74
- && err
75
- .value()
76
- .map(|v| {
77
- v.funcall::<_, _, String>(*ID_MESSAGE, ())
78
- .unwrap_or("".to_string())
79
- .eq(CLIENT_CONNECTION_CLOSED)
80
- })
81
- .unwrap_or(false)
82
- }
83
- }
84
- }
85
-
86
- pub fn is_json(&self) -> bool {
87
- self.content_type.eq("application/json")
88
- }
89
-
90
- pub fn is_html(&self) -> bool {
91
- self.content_type.eq("text/html")
92
- }
93
-
94
- pub fn process(
95
- self,
96
- ruby: &Ruby,
97
- server: RClass,
98
- app: Opaque<Value>,
99
- ) -> magnus::error::Result<()> {
100
- let req = format!("{}", self);
101
- let response = self.response.clone();
102
- let start = self.start;
103
- debug!("{} Started", req);
104
- let result = server.funcall::<_, _, Value>(*ID_CALL, (app, self));
105
- if let Err(err) = result {
106
- Self::internal_error(ruby, response, err);
107
- }
108
- debug!("{} Finished in {:?}", req, start.elapsed());
109
-
110
- Ok(())
111
- }
112
-
113
- pub fn internal_error(ruby: &Ruby, response: ItsiResponse, err: Error) {
114
- if Self::is_connection_closed_err(ruby, &err) {
115
- debug!("Connection closed by client");
116
- response.close();
117
- } else if let Some(rb_err) = err.value() {
118
- let backtrace = rb_err
119
- .funcall::<_, _, Vec<String>>(*ID_BACKTRACE, ())
120
- .unwrap_or_default();
121
-
122
- error!("Error occurred in Handler: {:?}", rb_err);
123
- for line in backtrace {
124
- error!("{}", line);
125
- }
126
- response.internal_server_error(err.to_string());
127
- } else {
128
- response.internal_server_error(err.to_string());
129
- }
130
- }
131
-
132
- pub fn error(self, message: String) {
133
- self.response.internal_server_error(message);
134
- }
135
-
136
- pub(crate) async fn process_request(
137
- hyper_request: Request<Incoming>,
138
- sender: async_channel::Sender<RequestJob>,
139
- server: Arc<Server>,
140
- listener: Arc<ListenerInfo>,
141
- addr: SockAddr,
142
- shutdown_rx: watch::Receiver<RunningPhase>,
143
- ) -> itsi_error::Result<Response<BoxBody<Bytes, Infallible>>> {
144
- let (request, mut receiver) = ItsiRequest::new(hyper_request, addr, server, listener).await;
145
-
146
- let response = request.response.clone();
147
- match sender.send(RequestJob::ProcessRequest(request)).await {
148
- Err(err) => {
149
- error!("Error occurred: {}", err);
150
- let mut response = Response::new(BoxBody::new(Empty::new()));
151
- *response.status_mut() = StatusCode::BAD_REQUEST;
152
- Ok(response)
153
- }
154
- _ => match receiver.recv().await {
155
- Some(first_frame) => Ok(response.build(first_frame, receiver, shutdown_rx).await),
156
- None => Ok(response.build(None, receiver, shutdown_rx).await),
157
- },
158
- }
159
- }
160
-
161
- pub(crate) async fn new(
162
- request: Request<Incoming>,
163
- sock_addr: SockAddr,
164
- server: Arc<Server>,
165
- listener: Arc<ListenerInfo>,
166
- ) -> (ItsiRequest, mpsc::Receiver<Option<Bytes>>) {
167
- let (parts, body) = request.into_parts();
168
- let body = if server.stream_body.is_some_and(|f| f) {
169
- ItsiBody::Stream(ItsiBodyProxy::new(body))
170
- } else {
171
- let mut body_bytes = BigBytes::new();
172
- let mut stream = body.into_data_stream();
173
- while let Some(chunk) = stream.next().await {
174
- let byte_array = chunk.unwrap().to_vec();
175
- body_bytes.write_all(&byte_array).unwrap();
176
- }
177
- ItsiBody::Buffered(body_bytes)
178
- };
179
- let response_channel = mpsc::channel::<Option<Bytes>>(100);
180
- (
181
- Self {
182
- remote_addr: sock_addr.to_string(),
183
- body,
184
- server,
185
- listener,
186
- version: format!("{:?}", &parts.version),
187
- response: ItsiResponse::new(
188
- parts.clone(),
189
- response_channel.0,
190
- parts
191
- .headers
192
- .get("Accept")
193
- .unwrap_or(&HeaderValue::from_static("text/html"))
194
- .to_str()
195
- .unwrap()
196
- .to_string(),
197
- ),
198
- start: Instant::now(),
199
- content_type: parts
200
- .headers
201
- .get("Content-Type")
202
- .unwrap_or(&HeaderValue::from_static(
203
- "application/x-www-form-urlencoded",
204
- ))
205
- .to_str()
206
- .unwrap()
207
- .to_string(),
208
- parts,
209
- },
210
- response_channel.1,
211
- )
212
- }
213
-
214
- pub(crate) fn path(&self) -> MagnusResult<&str> {
215
- Ok(self
216
- .parts
217
- .uri
218
- .path()
219
- .strip_prefix(&self.server.script_name)
220
- .unwrap_or(self.parts.uri.path()))
221
- }
222
-
223
- pub(crate) fn script_name(&self) -> MagnusResult<&str> {
224
- Ok(&self.server.script_name)
225
- }
226
-
227
- pub(crate) fn query_string(&self) -> MagnusResult<&str> {
228
- Ok(self.parts.uri.query().unwrap_or(""))
229
- }
230
-
231
- pub(crate) fn method(&self) -> MagnusResult<&str> {
232
- Ok(self.parts.method.as_str())
233
- }
234
-
235
- pub(crate) fn version(&self) -> MagnusResult<&str> {
236
- Ok(&self.version)
237
- }
238
-
239
- pub(crate) fn rack_protocol(&self) -> MagnusResult<Vec<&str>> {
240
- Ok(self
241
- .parts
242
- .headers
243
- .get("upgrade")
244
- .or_else(|| self.parts.headers.get("protocol"))
245
- .map(|value| {
246
- value
247
- .to_str()
248
- .unwrap_or("")
249
- .split(',')
250
- .map(|s| s.trim())
251
- .collect::<Vec<&str>>()
252
- })
253
- .unwrap_or_else(|| vec!["http"]))
254
- }
255
-
256
- pub(crate) fn host(&self) -> MagnusResult<String> {
257
- Ok(self
258
- .parts
259
- .uri
260
- .host()
261
- .map(|host| host.to_string())
262
- .unwrap_or_else(|| self.listener.host.clone()))
263
- }
264
-
265
- pub(crate) fn scheme(&self) -> MagnusResult<String> {
266
- Ok(self
267
- .parts
268
- .uri
269
- .scheme()
270
- .map(|scheme| scheme.to_string())
271
- .unwrap_or_else(|| self.listener.scheme.clone()))
272
- }
273
-
274
- pub(crate) fn headers(&self) -> MagnusResult<Vec<(String, &str)>> {
275
- Ok(self
276
- .parts
277
- .headers
278
- .iter()
279
- .map(|(hn, hv)| {
280
- let key = match hn.as_str() {
281
- "content-length" => "CONTENT_LENGTH".to_string(),
282
- "content-type" => "CONTENT_TYPE".to_string(),
283
- _ => format!("HTTP_{}", hn.as_str().to_uppercase().replace("-", "_")),
284
- };
285
- (key, hv.to_str().unwrap_or(""))
286
- })
287
- .collect())
288
- }
289
-
290
- pub(crate) fn remote_addr(&self) -> MagnusResult<&str> {
291
- Ok(&self.remote_addr)
292
- }
293
-
294
- pub(crate) fn port(&self) -> MagnusResult<u16> {
295
- Ok(self.parts.uri.port_u16().unwrap_or(self.listener.port))
296
- }
297
-
298
- pub(crate) fn body(&self) -> MagnusResult<Value> {
299
- Ok(self.body.into_value())
300
- }
301
-
302
- pub(crate) fn response(&self) -> MagnusResult<ItsiResponse> {
303
- Ok(self.response.clone())
304
- }
305
- }
@@ -1 +0,0 @@
1
- pub mod itsi_request;
@@ -1,357 +0,0 @@
1
- use bytes::{Bytes, BytesMut};
2
- use derive_more::Debug;
3
- use futures::stream::{unfold, StreamExt};
4
- use http::{
5
- header::TRANSFER_ENCODING, request::Parts, HeaderMap, HeaderName, HeaderValue, Request,
6
- Response, StatusCode,
7
- };
8
- use http_body_util::{combinators::BoxBody, Empty, Full, StreamBody};
9
- use hyper::{body::Frame, upgrade::Upgraded};
10
- use hyper_util::rt::TokioIo;
11
- use itsi_error::Result;
12
- use itsi_tracing::error;
13
- use magnus::error::Result as MagnusResult;
14
- use parking_lot::RwLock;
15
- use std::{
16
- convert::Infallible,
17
- io,
18
- os::{fd::FromRawFd, unix::net::UnixStream},
19
- str::FromStr,
20
- sync::Arc,
21
- };
22
- use tokio::{
23
- io::AsyncReadExt,
24
- net::UnixStream as TokioUnixStream,
25
- sync::{
26
- mpsc::{self},
27
- watch,
28
- },
29
- };
30
- use tokio_stream::wrappers::ReceiverStream;
31
- use tokio_util::io::ReaderStream;
32
- use tracing::warn;
33
-
34
- use crate::server::serve_strategy::single_mode::RunningPhase;
35
-
36
- #[magnus::wrap(class = "Itsi::Response", free_immediately, size)]
37
- #[derive(Debug, Clone)]
38
- pub struct ItsiResponse {
39
- pub data: Arc<ResponseData>,
40
- pub accept: String,
41
- }
42
-
43
- #[derive(Debug)]
44
- pub struct ResponseData {
45
- pub response: RwLock<Option<Response<BoxBody<Bytes, Infallible>>>>,
46
- pub response_writer: RwLock<Option<mpsc::Sender<Option<Bytes>>>>,
47
- pub response_buffer: RwLock<BytesMut>,
48
- pub hijacked_socket: RwLock<Option<UnixStream>>,
49
- pub parts: Parts,
50
- }
51
-
52
- impl ItsiResponse {
53
- pub async fn build(
54
- &self,
55
- first_frame: Option<Bytes>,
56
- receiver: mpsc::Receiver<Option<Bytes>>,
57
- shutdown_rx: watch::Receiver<RunningPhase>,
58
- ) -> Response<BoxBody<Bytes, Infallible>> {
59
- if self.is_hijacked() {
60
- return match self.process_hijacked_response().await {
61
- Ok(result) => result,
62
- Err(e) => {
63
- error!("Error processing hijacked response: {}", e);
64
- Response::new(BoxBody::new(Empty::new()))
65
- }
66
- };
67
- }
68
-
69
- let mut response = self.data.response.write().take().unwrap();
70
- *response.body_mut() = if first_frame.is_none() {
71
- BoxBody::new(Empty::new())
72
- } else if receiver.is_closed() && receiver.is_empty() {
73
- BoxBody::new(Full::new(first_frame.unwrap()))
74
- } else {
75
- let initial_frame = tokio_stream::once(Ok(Frame::data(first_frame.unwrap())));
76
- let frame_stream = unfold(
77
- (ReceiverStream::new(receiver), shutdown_rx),
78
- |(mut receiver, mut shutdown_rx)| async move {
79
- if let RunningPhase::ShutdownPending = *shutdown_rx.borrow() {
80
- warn!("Disconnecting streaming client.");
81
- return None;
82
- }
83
- loop {
84
- tokio::select! {
85
- maybe_bytes = receiver.next() => {
86
- if let Some(bytes) = maybe_bytes {
87
- // We assume `bytes` is Some(Bytes) here.
88
- return Some((Ok(Frame::data(bytes.unwrap())), (receiver, shutdown_rx)));
89
- } else {
90
- // Receiver closed, end the stream.
91
- return None;
92
- }
93
- },
94
- _ = shutdown_rx.changed() => {
95
- match *shutdown_rx.borrow() {
96
- RunningPhase::ShutdownPending => {
97
- warn!("Disconnecting streaming client.");
98
- return None;
99
- },
100
- _ => continue,
101
- }
102
- }
103
- }
104
- }
105
- },
106
- );
107
-
108
- let combined_stream = initial_frame.chain(frame_stream);
109
- BoxBody::new(StreamBody::new(combined_stream))
110
- };
111
- response
112
- }
113
-
114
- pub fn close(&self) {
115
- self.data.response_writer.write().take();
116
- }
117
-
118
- async fn two_way_bridge(upgraded: Upgraded, local: TokioUnixStream) -> io::Result<()> {
119
- let client_io = TokioIo::new(upgraded);
120
-
121
- // Split each side
122
- let (mut lr, mut lw) = tokio::io::split(local);
123
- let (mut cr, mut cw) = tokio::io::split(client_io);
124
-
125
- let to_ruby = tokio::spawn(async move {
126
- if let Err(e) = tokio::io::copy(&mut cr, &mut lw).await {
127
- eprintln!("Error copying upgraded->local: {:?}", e);
128
- }
129
- });
130
- let from_ruby = tokio::spawn(async move {
131
- if let Err(e) = tokio::io::copy(&mut lr, &mut cw).await {
132
- eprintln!("Error copying upgraded->local: {:?}", e);
133
- }
134
- });
135
-
136
- let _ = to_ruby.await;
137
- let _ = from_ruby.await;
138
- Ok(())
139
- }
140
-
141
- async fn read_response_headers(&self, reader: &mut TokioUnixStream) -> Result<Vec<u8>> {
142
- let mut buf = [0u8; 1];
143
- let mut collected = Vec::new();
144
- loop {
145
- let n = reader.read(&mut buf).await?;
146
- if n == 0 {
147
- // EOF reached unexpectedly
148
- break;
149
- }
150
- collected.push(buf[0]);
151
- if collected.ends_with(b"\r\n\r\n") {
152
- break;
153
- }
154
- }
155
-
156
- Ok(collected)
157
- }
158
-
159
- pub async fn read_hijacked_headers(
160
- &self,
161
- ) -> Result<(HeaderMap, StatusCode, bool, TokioUnixStream)> {
162
- let hijacked_socket =
163
- self.data
164
- .hijacked_socket
165
- .write()
166
- .take()
167
- .ok_or(itsi_error::ItsiError::InvalidInput(
168
- "Couldn't hijack stream".to_owned(),
169
- ))?;
170
- let mut reader = TokioUnixStream::from_std(hijacked_socket).unwrap();
171
- let response_headers = self.read_response_headers(&mut reader).await?;
172
- let mut headers = [httparse::EMPTY_HEADER; 64];
173
- let mut resp = httparse::Response::new(&mut headers);
174
- resp.parse(&response_headers)?;
175
-
176
- let status = StatusCode::from_u16(resp.code.unwrap_or(200)).unwrap_or(StatusCode::OK);
177
- let mut headers = HeaderMap::new();
178
- for header in resp.headers.iter() {
179
- headers.insert(
180
- HeaderName::from_str(header.name).unwrap(),
181
- HeaderValue::from_bytes(header.value).unwrap(),
182
- );
183
- }
184
- let requires_upgrade = status == StatusCode::SWITCHING_PROTOCOLS;
185
- Ok((headers, status, requires_upgrade, reader))
186
- }
187
-
188
- pub async fn process_hijacked_response(&self) -> Result<Response<BoxBody<Bytes, Infallible>>> {
189
- let (headers, status, requires_upgrade, reader) = self.read_hijacked_headers().await?;
190
- let mut response = if requires_upgrade {
191
- let parts = self.data.parts.clone();
192
- tokio::spawn(async move {
193
- let mut req = Request::from_parts(parts, Empty::<Bytes>::new());
194
- match hyper::upgrade::on(&mut req).await {
195
- Ok(upgraded) => {
196
- Self::two_way_bridge(upgraded, reader)
197
- .await
198
- .expect("Error in creating two way bridge");
199
- }
200
- Err(e) => eprintln!("upgrade error: {:?}", e),
201
- }
202
- });
203
- Response::new(BoxBody::new(Empty::new()))
204
- } else {
205
- let stream = ReaderStream::new(reader);
206
- let boxed_body = if headers
207
- .get(TRANSFER_ENCODING)
208
- .is_some_and(|h| h == "chunked")
209
- {
210
- BoxBody::new(StreamBody::new(unfold(
211
- (stream, Vec::new()),
212
- |(mut stream, mut buf)| async move {
213
- loop {
214
- if let Some(pos) = buf.iter().position(|&b| b == b'\n') {
215
- let line = buf.drain(..=pos).collect::<Vec<u8>>();
216
- let line = std::str::from_utf8(&line).ok()?.trim();
217
- let chunk_size = usize::from_str_radix(line, 16).ok()?;
218
- if chunk_size == 0 {
219
- return None;
220
- }
221
- while buf.len() < chunk_size {
222
- match stream.next().await {
223
- Some(Ok(chunk)) => buf.extend_from_slice(&chunk),
224
- _ => return None,
225
- }
226
- }
227
- let data = buf.drain(..chunk_size).collect::<Vec<u8>>();
228
- if buf.starts_with(b"\r\n") {
229
- buf.drain(..2);
230
- }
231
- return Some((Ok(Frame::data(Bytes::from(data))), (stream, buf)));
232
- }
233
- match stream.next().await {
234
- Some(Ok(chunk)) => buf.extend_from_slice(&chunk),
235
- _ => return None,
236
- }
237
- }
238
- },
239
- )))
240
- } else {
241
- BoxBody::new(StreamBody::new(stream.map(
242
- |result: std::result::Result<Bytes, io::Error>| {
243
- result
244
- .map(Frame::data)
245
- .map_err(|e| unreachable!("unexpected io error: {:?}", e))
246
- },
247
- )))
248
- };
249
- Response::new(boxed_body)
250
- };
251
-
252
- *response.status_mut() = status;
253
- *response.headers_mut() = headers;
254
- Ok(response)
255
- }
256
-
257
- pub fn internal_server_error(&self, message: String) {
258
- error!(message);
259
- self.data.response_writer.write().take();
260
- if let Some(ref mut response) = *self.data.response.write() {
261
- *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
262
- }
263
- }
264
-
265
- pub fn send_frame(&self, frame: Bytes) -> MagnusResult<usize> {
266
- self.send_frame_into(frame, &self.data.response_writer)
267
- }
268
-
269
- pub fn send_and_close(&self, frame: Bytes) -> MagnusResult<usize> {
270
- let result = self.send_frame_into(frame, &self.data.response_writer);
271
- self.data.response_writer.write().take();
272
- result
273
- }
274
-
275
- pub fn send_frame_into(
276
- &self,
277
- frame: Bytes,
278
- writer: &RwLock<Option<mpsc::Sender<Option<Bytes>>>>,
279
- ) -> MagnusResult<usize> {
280
- if let Some(writer) = writer.write().as_ref() {
281
- writer
282
- .blocking_send(Some(frame))
283
- .map_err(|_| itsi_error::ItsiError::ClientConnectionClosed)?;
284
- }
285
- Ok(0)
286
- }
287
-
288
- pub fn is_hijacked(&self) -> bool {
289
- self.data.hijacked_socket.read().is_some()
290
- }
291
-
292
- pub fn close_write(&self) -> MagnusResult<bool> {
293
- self.data.response_writer.write().take();
294
- Ok(true)
295
- }
296
-
297
- pub fn is_html(&self) -> bool {
298
- self.accept.starts_with("text/html")
299
- }
300
-
301
- pub fn is_json(&self) -> bool {
302
- self.accept.starts_with("application/json")
303
- }
304
-
305
- pub fn close_read(&self) -> MagnusResult<bool> {
306
- Ok(true)
307
- }
308
-
309
- pub fn new(parts: Parts, response_writer: mpsc::Sender<Option<Bytes>>, accept: String) -> Self {
310
- Self {
311
- data: Arc::new(ResponseData {
312
- response: RwLock::new(Some(Response::new(BoxBody::new(Empty::new())))),
313
- response_writer: RwLock::new(Some(response_writer)),
314
- response_buffer: RwLock::new(BytesMut::new()),
315
- hijacked_socket: RwLock::new(None),
316
- parts,
317
- }),
318
- accept,
319
- }
320
- }
321
-
322
- pub fn add_header(&self, name: Bytes, value: Bytes) -> MagnusResult<()> {
323
- let header_name: HeaderName = HeaderName::from_bytes(&name).map_err(|e| {
324
- itsi_error::ItsiError::InvalidInput(format!("Invalid header name {:?}: {:?}", name, e))
325
- })?;
326
- let header_value = unsafe { HeaderValue::from_maybe_shared_unchecked(value) };
327
- if let Some(ref mut resp) = *self.data.response.write() {
328
- resp.headers_mut().insert(header_name, header_value);
329
- }
330
- Ok(())
331
- }
332
-
333
- pub fn set_status(&self, status: u16) -> MagnusResult<()> {
334
- if let Some(ref mut resp) = *self.data.response.write() {
335
- *resp.status_mut() = StatusCode::from_u16(status).map_err(|e| {
336
- itsi_error::ItsiError::InvalidInput(format!(
337
- "Invalid status code {:?}: {:?}",
338
- status, e
339
- ))
340
- })?;
341
- }
342
- Ok(())
343
- }
344
-
345
- pub fn hijack(&self, fd: i32) -> MagnusResult<()> {
346
- let stream = unsafe { UnixStream::from_raw_fd(fd) };
347
-
348
- *self.data.hijacked_socket.write() = Some(stream);
349
- if let Some(writer) = self.data.response_writer.write().as_ref() {
350
- writer
351
- .blocking_send(None)
352
- .map_err(|_| itsi_error::ItsiError::ClientConnectionClosed)?;
353
- }
354
- self.close();
355
- Ok(())
356
- }
357
- }
@@ -1 +0,0 @@
1
- pub mod itsi_response;