From d2a80f5f803bc155b572c1920116f810f77b6b44 Mon Sep 17 00:00:00 2001 From: kazeyukiro Date: Wed, 30 Sep 2026 08:01:44 +0000 Subject: [PATCH] fix(protocol): strip ws-headers from VLESS/VMess listeners Mihomo inbound only supports ws-path for WebSocket; headers are client-side. Keep ws-headers in panel config for share/export. --- backend/internal/protocol/compile.go | 5 ++- .../protocol/compile_ws_headers_test.go | 35 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 backend/internal/protocol/compile_ws_headers_test.go diff --git a/backend/internal/protocol/compile.go b/backend/internal/protocol/compile.go index f751c18..aa350a4 100644 --- a/backend/internal/protocol/compile.go +++ b/backend/internal/protocol/compile.go @@ -155,7 +155,10 @@ func clientOnlyListenerKey(k string) bool { "grpc-user-agent", "ping-interval", "max-connections", "min-streams", "max-streams", // Client-only TUIC/Hy2 hints sometimes stored in panel JSON. "udp-relay-mode", "reduce-rtt", "request-timeout", "heartbeat-interval", - "fast-open", "max-open-streams", "disable-sni", "ip": + "fast-open", "max-open-streams", "disable-sni", "ip", + // Listener WS is only ws-path (wiki inbound VLESS/VMess). Headers belong on + // the client as ws-opts.headers / share URI — not on the serving listener. + "ws-headers", "ws-opts", "headers", "network": return true default: return false diff --git a/backend/internal/protocol/compile_ws_headers_test.go b/backend/internal/protocol/compile_ws_headers_test.go new file mode 100644 index 0000000..2cafefa --- /dev/null +++ b/backend/internal/protocol/compile_ws_headers_test.go @@ -0,0 +1,35 @@ +package protocol + +import "testing" + +// Official VLESS/VMess listeners only accept ws-path for WebSocket, not +// ws-headers (client-side Host goes in share URI / ws-opts.headers). +func TestCompileVLESSStripsWSHeaders(t *testing.T) { + cfg := map[string]interface{}{ + "ws-path": "/ws", + "ws-headers": map[string]interface{}{"Host": "cdn.example.com"}, + "allow-insecure": true, + } + reg := DefaultCompileRegistry() + m, err := reg.Compile(CompileInput{ + Name: "VLESS-WS", + Protocol: "vless", + Listen: "0.0.0.0", + Port: 10000, + Config: cfg, + Users: []UserCred{{UUID: "9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68", Username: "u1"}}, + }) + if err != nil { + t.Fatal(err) + } + if _, ok := m["ws-headers"]; ok { + t.Fatalf("ws-headers must not appear on listener: %#v", m) + } + if m["ws-path"] != "/ws" { + t.Fatalf("ws-path should remain: %#v", m["ws-path"]) + } + // Panel config keeps headers for share/export. + if cfg["ws-headers"] == nil { + t.Fatal("input ws-headers must stay for client export") + } +}