wrap_it_ruby 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/wrap_it_ruby/interception.js +54 -31
- data/app/assets/stylesheets/wrap_it_ruby/application.css +71 -1
- data/app/controllers/wrap_it_ruby/menu_settings_controller.rb +64 -0
- data/app/controllers/wrap_it_ruby/proxy_controller.rb +2 -1
- data/app/helpers/wrap_it_ruby/menu_helper.rb +298 -22
- data/app/javascript/wrap_it_ruby/controllers/sortable_tree_controller.js +198 -0
- data/app/views/wrap_it_ruby/menu_settings/_tree.html.erb +1 -0
- data/app/views/wrap_it_ruby/menu_settings/index.html.erb +1 -0
- data/config/importmap.rb +7 -3
- data/config/routes.rb +7 -1
- data/lib/wrap_it_ruby/engine.rb +14 -13
- data/lib/wrap_it_ruby/middleware/proxy_middleware.rb +159 -62
- data/lib/wrap_it_ruby/middleware/root_relative_proxy_middleware.rb +10 -2
- data/lib/wrap_it_ruby/middleware/script_injection_middleware.rb +7 -1
- data/lib/wrap_it_ruby/middleware/websocket_proxy.rb +92 -0
- data/lib/wrap_it_ruby/version.rb +1 -1
- data/lib/wrap_it_ruby.rb +2 -2
- metadata +6 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "async/http/client"
|
|
4
|
+
require "async/http/endpoint"
|
|
5
|
+
|
|
6
|
+
module WrapItRuby
|
|
7
|
+
module Middleware
|
|
8
|
+
# Protocol::HTTP middleware that intercepts WebSocket upgrade requests
|
|
9
|
+
# BEFORE the Rack adapter, proxying them directly at the HTTP protocol
|
|
10
|
+
# level. This preserves the Upgrade/Connection headers that Rack strips.
|
|
11
|
+
#
|
|
12
|
+
# Must be inserted as Falcon middleware, not as Rack middleware.
|
|
13
|
+
# For non-WebSocket requests, passes through to the Rack app.
|
|
14
|
+
#
|
|
15
|
+
class WebSocketProxy < Protocol::HTTP::Middleware
|
|
16
|
+
PROXY_PATTERN = %r{\A/_proxy/(?<host>[^/]+)(?<path>/.*)?\z}
|
|
17
|
+
|
|
18
|
+
HOP_HEADERS = %w[
|
|
19
|
+
connection keep-alive proxy-authenticate proxy-authorization
|
|
20
|
+
te trailers transfer-encoding upgrade
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
def initialize(app)
|
|
24
|
+
super(app)
|
|
25
|
+
@clients = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call(request)
|
|
29
|
+
if websocket?(request) && (match = PROXY_PATTERN.match(request.path))
|
|
30
|
+
host = match[:host].delete_suffix(".")
|
|
31
|
+
proxy_websocket(request, host)
|
|
32
|
+
else
|
|
33
|
+
super(request)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def websocket?(request)
|
|
40
|
+
# HTTP/2: protocol pseudo-header
|
|
41
|
+
if Array(request.protocol).any? { |p| p.casecmp?("websocket") }
|
|
42
|
+
return true
|
|
43
|
+
end
|
|
44
|
+
# HTTP/1.1: Upgrade header
|
|
45
|
+
if upgrade = request.headers["upgrade"]
|
|
46
|
+
return Array(upgrade).any? { |u| u.casecmp?("websocket") }
|
|
47
|
+
end
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def proxy_websocket(request, host)
|
|
52
|
+
# Strip /_proxy/{host} prefix from the path
|
|
53
|
+
match = PROXY_PATTERN.match(request.path)
|
|
54
|
+
request.path = match[:path] || "/"
|
|
55
|
+
|
|
56
|
+
# Rewrite authority/host to upstream — write_request adds host
|
|
57
|
+
# from authority automatically, so just delete it from headers.
|
|
58
|
+
request.authority = host
|
|
59
|
+
request.headers.delete("host")
|
|
60
|
+
|
|
61
|
+
# Set protocol as string (not array) for write_upgrade_body,
|
|
62
|
+
# and remove upgrade/connection headers to avoid duplicates.
|
|
63
|
+
request.protocol = "websocket"
|
|
64
|
+
request.headers.delete("upgrade")
|
|
65
|
+
request.headers.delete("connection")
|
|
66
|
+
|
|
67
|
+
# Rewrite origin
|
|
68
|
+
if request.headers["origin"]
|
|
69
|
+
request.headers.delete("origin")
|
|
70
|
+
request.headers.add("origin", "https://#{host}")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
client = client_for(host)
|
|
74
|
+
client.call(request)
|
|
75
|
+
rescue => error
|
|
76
|
+
$stderr.puts "[ws-proxy] upstream error: #{error.class}: #{error.message}"
|
|
77
|
+
Protocol::HTTP::Response[502, {}, ["WebSocket proxy error: #{error.message}"]]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def client_for(host)
|
|
81
|
+
# Force HTTP/1.1 — upstream (Traefik/code-server) returns 405
|
|
82
|
+
# for HTTP/2 WebSocket CONNECT but accepts HTTP/1.1 Upgrade.
|
|
83
|
+
@clients[host] ||= Async::HTTP::Client.new(
|
|
84
|
+
Async::HTTP::Endpoint.parse("https://#{host}",
|
|
85
|
+
alpn_protocols: Async::HTTP::Protocol::HTTP11.names
|
|
86
|
+
),
|
|
87
|
+
retries: 0
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/wrap_it_ruby/version.rb
CHANGED
data/lib/wrap_it_ruby.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wrap_it_ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Kidd
|
|
@@ -105,10 +105,14 @@ files:
|
|
|
105
105
|
- Rakefile
|
|
106
106
|
- app/assets/javascripts/wrap_it_ruby/interception.js
|
|
107
107
|
- app/assets/stylesheets/wrap_it_ruby/application.css
|
|
108
|
+
- app/controllers/wrap_it_ruby/menu_settings_controller.rb
|
|
108
109
|
- app/controllers/wrap_it_ruby/proxy_controller.rb
|
|
109
110
|
- app/helpers/wrap_it_ruby/iframe_helper.rb
|
|
110
111
|
- app/helpers/wrap_it_ruby/menu_helper.rb
|
|
111
112
|
- app/javascript/wrap_it_ruby/controllers/iframe_proxy_controller.js
|
|
113
|
+
- app/javascript/wrap_it_ruby/controllers/sortable_tree_controller.js
|
|
114
|
+
- app/views/wrap_it_ruby/menu_settings/_tree.html.erb
|
|
115
|
+
- app/views/wrap_it_ruby/menu_settings/index.html.erb
|
|
112
116
|
- app/views/wrap_it_ruby/proxy/show.html.ruby
|
|
113
117
|
- config/importmap.rb
|
|
114
118
|
- config/routes.rb
|
|
@@ -119,6 +123,7 @@ files:
|
|
|
119
123
|
- lib/wrap_it_ruby/middleware/proxy_middleware.rb
|
|
120
124
|
- lib/wrap_it_ruby/middleware/root_relative_proxy_middleware.rb
|
|
121
125
|
- lib/wrap_it_ruby/middleware/script_injection_middleware.rb
|
|
126
|
+
- lib/wrap_it_ruby/middleware/websocket_proxy.rb
|
|
122
127
|
- lib/wrap_it_ruby/version.rb
|
|
123
128
|
- lib/wrap_it_ruby/version.rb.erb
|
|
124
129
|
homepage: https://github.com/n-at-han-k/wrap-it-ruby
|