func vncWsHandler(w http.ResponseWriter, r *http.Request) { // we assume that if we got here, then the url must be sane and of // the format /ws/<host>/<port> path := r.URL.Path if !strings.HasSuffix(path, "/") { path += "/" } fields := strings.Split(path, "/") if len(fields) != 5 { http.NotFound(w, r) return } fields = fields[2:] rhost := fmt.Sprintf("%v:%v", fields[0], fields[1]) // connect to the remote host remote, err := net.Dial("tcp", rhost) if err != nil { log.Errorln(err) http.StatusText(500) return } websocket.Handler(func(ws *websocket.Conn) { go func() { decoder := base64.NewDecoder(base64.StdEncoding, ws) tee := io.TeeReader(decoder, remote) for { // Read msg, err := vnc.ReadClientMessage(tee) if err != nil { if err == io.EOF || strings.Contains(err.Error(), "closed network") { break } log.Debugln(err) continue } if r, ok := vncKBRecording[rhost]; ok { r.RecordMessage(msg) } } remote.Close() }() func() { sbuf := make([]byte, VNC_WS_BUF) dbuf := make([]byte, 2*VNC_WS_BUF) for { n, err := remote.Read(sbuf) if err != nil { if !strings.Contains(err.Error(), "closed network connection") && err != io.EOF { log.Errorln(err) } break } base64.StdEncoding.Encode(dbuf, sbuf[0:n]) n = base64.StdEncoding.EncodedLen(n) _, err = ws.Write(dbuf[0:n]) if err != nil { log.Errorln(err) break } } ws.Close() }() }).ServeHTTP(w, r) }