From 6d3312fe89b1ec333accb4f8c78c50ea046ffbad Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 9 Jun 2026 16:01:45 -0700 Subject: [PATCH] Add some preflight check for vnc reachability --- browsergateway/vnc.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/browsergateway/vnc.go b/browsergateway/vnc.go index 62f4065..f104a8d 100644 --- a/browsergateway/vnc.go +++ b/browsergateway/vnc.go @@ -2,6 +2,7 @@ package browsergateway import ( "context" + "fmt" "io" "net" "net/http" @@ -44,6 +45,18 @@ func (g *Gateway) handleVNC(w http.ResponseWriter, r *http.Request) { } target := net.JoinHostPort(host, port) + // Optional HTTP probe used by the web UI to surface backend reachability + // failures before attempting a WebSocket session. + if r.URL.Query().Get("checkOnly") == "1" { + if err := dialVNCBackend(r.Context(), target); err != nil { + logger.Debug("vnc: preflight failed (%s): %v", target, err) + http.Error(w, fmt.Sprintf("failed to connect to VNC backend: %v", err), http.StatusBadGateway) + return + } + w.WriteHeader(http.StatusNoContent) + return + } + // Accept the WebSocket. noVNC negotiates the "binary" subprotocol; // fall back gracefully when the client sends "base64" as well. ws, err := websocket.Accept(w, r, &websocket.AcceptOptions{ @@ -63,6 +76,20 @@ func (g *Gateway) handleVNC(w http.ResponseWriter, r *http.Request) { } } +func dialVNCBackend(ctx context.Context, target string) error { + dialer := &net.Dialer{ + Timeout: vncDialTimeout, + KeepAlive: vncKeepAlive, + } + conn, err := dialer.DialContext(ctx, "tcp", target) + if err != nil { + return err + } + defer conn.Close() //nolint:errcheck + + return nil +} + func serveVNC(ctx context.Context, ws *websocket.Conn, target string) error { // Dial the VNC backend TCP server. dialer := &net.Dialer{