mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-11 11:46:37 +08:00
chore: improve websocket wss->ws fallback diagnostics
This commit is contained in:
@@ -266,7 +266,7 @@ func (w *WebSocketReporter) connect() error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Printf("✅ WebSocket连接建立成功 (%s, http=%d, tls=%d, socks=%d)\n", usedURL, cfg.Http, cfg.Tls, cfg.Socks)
|
fmt.Printf("✅ WebSocket连接建立成功 (%s, http=%d, tls=%d, socks=%d)\n", sanitizeWebSocketURL(usedURL), cfg.Http, cfg.Tls, cfg.Socks)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,20 +345,64 @@ func dialWebSocketWithFallback(dialer *websocket.Dialer, candidates []string) (*
|
|||||||
|
|
||||||
var errs []string
|
var errs []string
|
||||||
for i, targetURL := range candidates {
|
for i, targetURL := range candidates {
|
||||||
conn, _, err := wsDial(dialer, targetURL)
|
conn, resp, err := wsDial(dialer, targetURL)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Printf("↪️ WebSocket已自动回退到: %s\n", targetURL)
|
fmt.Printf("↪️ WebSocket已自动回退成功: %s\n", sanitizeWebSocketURL(targetURL))
|
||||||
}
|
}
|
||||||
return conn, targetURL, nil
|
return conn, targetURL, nil
|
||||||
}
|
}
|
||||||
errs = append(errs, fmt.Sprintf("%s => %v", targetURL, err))
|
errMsg := formatWebSocketDialError(err, resp)
|
||||||
|
errs = append(errs, fmt.Sprintf("%s => %s", sanitizeWebSocketURL(targetURL), errMsg))
|
||||||
if i < len(candidates)-1 {
|
if i < len(candidates)-1 {
|
||||||
fmt.Printf("⚠️ WebSocket连接尝试失败,准备回退: %s => %v\n", targetURL, err)
|
fmt.Printf(
|
||||||
|
"⚠️ WebSocket连接失败,准备从 %s 回退到 %s: %s\n",
|
||||||
|
strings.ToUpper(detectWebSocketScheme(targetURL)),
|
||||||
|
strings.ToUpper(detectWebSocketScheme(candidates[i+1])),
|
||||||
|
errMsg,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, "", fmt.Errorf("连接WebSocket失败: %s", strings.Join(errs, " | "))
|
return nil, "", fmt.Errorf("连接WebSocket失败(已尝试%d种协议): %s", len(candidates), strings.Join(errs, " | "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeWebSocketURL(rawURL string) string {
|
||||||
|
u, err := url.Parse(rawURL)
|
||||||
|
if err != nil {
|
||||||
|
return rawURL
|
||||||
|
}
|
||||||
|
|
||||||
|
q := u.Query()
|
||||||
|
if q.Get("secret") != "" {
|
||||||
|
q.Set("secret", "***")
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatWebSocketDialError(err error, resp *http.Response) string {
|
||||||
|
if err == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s (HTTP %s)", err, resp.Status)
|
||||||
|
if resp.Body == nil {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 256))
|
||||||
|
if readErr != nil {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
bodyText := strings.TrimSpace(string(body))
|
||||||
|
if bodyText == "" {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s, body=%q", msg, bodyText)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleConnection 处理WebSocket连接
|
// handleConnection 处理WebSocket连接
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package socket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -96,3 +97,31 @@ func TestDetectWebSocketScheme(t *testing.T) {
|
|||||||
t.Fatalf("expected empty detection for non-websocket scheme")
|
t.Fatalf("expected empty detection for non-websocket scheme")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitizeWebSocketURL(t *testing.T) {
|
||||||
|
raw := "wss://panel.example.com/system-info?type=1&secret=abc&version=2.0.2"
|
||||||
|
sanitized := sanitizeWebSocketURL(raw)
|
||||||
|
|
||||||
|
if strings.Contains(sanitized, "secret=abc") {
|
||||||
|
t.Fatalf("expected secret to be masked, got %s", sanitized)
|
||||||
|
}
|
||||||
|
if !strings.Contains(sanitized, "secret=%2A%2A%2A") {
|
||||||
|
t.Fatalf("expected masked secret in url, got %s", sanitized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatWebSocketDialErrorIncludesHTTPStatus(t *testing.T) {
|
||||||
|
err := errors.New("websocket: bad handshake")
|
||||||
|
resp := &http.Response{
|
||||||
|
Status: "403 Forbidden",
|
||||||
|
Body: io.NopCloser(strings.NewReader("forbidden")),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := formatWebSocketDialError(err, resp)
|
||||||
|
if !strings.Contains(msg, "HTTP 403 Forbidden") {
|
||||||
|
t.Fatalf("expected status in message, got %s", msg)
|
||||||
|
}
|
||||||
|
if !strings.Contains(msg, "forbidden") {
|
||||||
|
t.Fatalf("expected response body in message, got %s", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user