From 8105545e98cd57b13a749bd479c762895a76321e Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 12 Mar 2025 12:57:46 +0900 Subject: [PATCH] use s.WrapWebsocketHandler for ssh websockets --- server-pxy.go | 58 +++++++++++++++++++++++++-------------------------- server.go | 52 +++++++++++++++++++-------------------------- 2 files changed, 51 insertions(+), 59 deletions(-) diff --git a/server-pxy.go b/server-pxy.go index 2e126ff..bd3841a 100644 --- a/server-pxy.go +++ b/server-pxy.go @@ -30,23 +30,23 @@ var xterm_css []byte //go:embed xterm.html var xterm_html string -type server_proxy struct { +type server_pxy struct { s *Server id string } -type server_proxy_http_main struct { - server_proxy +type server_pxy_http_main struct { + server_pxy prefix string } -type server_proxy_xterm_file struct { - server_proxy +type server_pxy_xterm_file struct { + server_pxy file string } -type server_proxy_http_wpx struct { - server_proxy +type server_pxy_http_wpx struct { + server_pxy } // this is minimal information for wpx to work @@ -186,15 +186,15 @@ func mutate_proxy_req_headers(req *http.Request, newreq *http.Request, path_pref // ------------------------------------ -func (pxy *server_proxy) Id() string { +func (pxy *server_pxy) Id() string { return pxy.id } -func (pxy *server_proxy) Cors(req *http.Request) bool { +func (pxy *server_pxy) Cors(req *http.Request) bool { return false } -func (pxy *server_proxy) Authenticate(req *http.Request) (int, string) { +func (pxy *server_pxy) Authenticate(req *http.Request) (int, string) { return http.StatusOK, "" } @@ -204,7 +204,7 @@ func prevent_follow_redirect (req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } -func (pxy *server_proxy_http_main) get_route_proxy_info(req *http.Request, in_wpx_mode bool) (*ServerRouteProxyInfo, error) { +func (pxy *server_pxy_http_main) get_route_proxy_info(req *http.Request, in_wpx_mode bool) (*ServerRouteProxyInfo, error) { var conn_id string var route_id string var r *ServerRoute @@ -244,7 +244,7 @@ func (pxy *server_proxy_http_main) get_route_proxy_info(req *http.Request, in_wp return pi, nil } -func (pxy *server_proxy_http_main) serve_upgraded(w http.ResponseWriter, req *http.Request, proxy_res *http.Response) error { +func (pxy *server_pxy_http_main) serve_upgraded(w http.ResponseWriter, req *http.Request, proxy_res *http.Response) error { var err_chan chan error var proxy_res_body io.ReadWriteCloser var rc *http.ResponseController @@ -295,7 +295,7 @@ func (pxy *server_proxy_http_main) serve_upgraded(w http.ResponseWriter, req *ht return err } -func (pxy *server_proxy_http_main) addr_to_transport (ctx context.Context, addr *net.TCPAddr) (*http.Transport, error) { +func (pxy *server_pxy_http_main) addr_to_transport (ctx context.Context, addr *net.TCPAddr) (*http.Transport, error) { var dialer *net.Dialer var waitctx context.Context var cancel_wait context.CancelFunc @@ -318,7 +318,7 @@ func (pxy *server_proxy_http_main) addr_to_transport (ctx context.Context, addr }, nil } -func (pxy *server_proxy_http_main) req_to_proxy_url (req *http.Request, r *ServerRouteProxyInfo) *url.URL { +func (pxy *server_pxy_http_main) req_to_proxy_url (req *http.Request, r *ServerRouteProxyInfo) *url.URL { var proxy_proto string var proxy_url_path string @@ -343,7 +343,7 @@ func (pxy *server_proxy_http_main) req_to_proxy_url (req *http.Request, r *Serve } } -func (pxy *server_proxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { +func (pxy *server_pxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var s *Server var pi *ServerRouteProxyInfo var status_code int @@ -448,7 +448,7 @@ oops: // ------------------------------------ -func (pxy *server_proxy_http_wpx) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { +func (pxy *server_pxy_http_wpx) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var status_code int // var err error @@ -464,12 +464,12 @@ func (pxy *server_proxy_http_wpx) ServeHTTP(w http.ResponseWriter, req *http.Req } // ------------------------------------ -type server_proxy_xterm_session_info struct { +type server_pxy_xterm_session_info struct { ConnId string RouteId string } -func (pxy *server_proxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { +func (pxy *server_pxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var s *Server var status_code int var err error @@ -522,7 +522,7 @@ func (pxy *server_proxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.R } else { status_code = WriteHtmlRespHeader(w, http.StatusOK) tmpl.Execute(w, - &server_proxy_xterm_session_info{ + &server_pxy_xterm_session_info{ ConnId: conn_id, RouteId: route_id, }) @@ -554,8 +554,7 @@ oops: } // ------------------------------------ - -type server_proxy_ssh_ws struct { +type server_pxy_ssh_ws struct { s *Server ws *websocket.Conn id string @@ -566,10 +565,14 @@ type json_ssh_ws_event struct { Data []string `json:"data"` } +func (pxy *server_pxy_ssh_ws) Id() string { + return pxy.id +} + // TODO: put this task to sync group. // TODO: put the above proxy task to sync group too. -func (pxy *server_proxy_ssh_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { +func (pxy *server_pxy_ssh_ws) send_ws_data(ws *websocket.Conn, type_val string, data string) error { var msg []byte var err error @@ -578,7 +581,7 @@ func (pxy *server_proxy_ssh_ws) send_ws_data(ws *websocket.Conn, type_val string return err } -func (pxy *server_proxy_ssh_ws) connect_ssh (ctx context.Context, username string, password string, r *ServerRoute) ( *ssh.Client, *ssh.Session, io.Writer, io.Reader, error) { +func (pxy *server_pxy_ssh_ws) connect_ssh (ctx context.Context, username string, password string, r *ServerRoute) ( *ssh.Client, *ssh.Session, io.Writer, io.Reader, error) { var cc *ssh.ClientConfig var addr *net.TCPAddr var dialer *net.Dialer @@ -639,7 +642,7 @@ oops: return nil, nil, nil, nil, err } -func (pxy *server_proxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) { +func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var s *Server var req *http.Request var conn_id string @@ -801,9 +804,6 @@ done: if sess != nil { sess.Close() } if c != nil { c.Close() } wg.Wait() - if err != nil { - s.log.Write(pxy.id, LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error()) - } else { - s.log.Write(pxy.id, LOG_DEBUG, "[%s] %s %s - ended", req.RemoteAddr, req.Method, req.URL.String()) - } + + return http.StatusOK, err } diff --git a/server.go b/server.go index c2663dd..23b29eb 100644 --- a/server.go +++ b/server.go @@ -111,15 +111,12 @@ type Server struct { ext_svcs []Service ext_closed bool - pxy_ws *server_proxy_ssh_ws pxy_mux *http.ServeMux pxy []*http.Server // proxy server - wpx_ws *server_proxy_ssh_ws wpx_mux *http.ServeMux wpx []*http.Server // proxy server than handles http/https only - ctl_ws *server_ctl_ws ctl_mux *http.ServeMux ctl []*http.Server // control server @@ -1189,12 +1186,10 @@ func (s *Server) WrapWebsocketHandler(handler ServerWebsocketHandler) websocket. var req *http.Request req = ws.Request() - start_time = time.Now() s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws]", req.RemoteAddr, req.Method, req.URL.String()) + start_time = time.Now() status_code, err = handler.ServeWebsocket(ws) - // it looks like the websocket handler never comes down here... - time_taken = time.Now().Sub(start_time) if status_code > 0 { @@ -1296,7 +1291,6 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/metrics", promhttp.HandlerFor(s.promreg, promhttp.HandlerOpts{ EnableOpenMetrics: true })) - //s.ctl_ws = &server_ctl_ws{server_ctl{s: &s, id: HS_ID_CTL}} s.ctl_mux.Handle("/_ctl/events", s.WrapWebsocketHandler(&server_ctl_ws{server_ctl{s: &s, id: HS_ID_CTL}})) @@ -1313,35 +1307,34 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi // --------------------------------------------------------- - s.pxy_ws = &server_proxy_ssh_ws{s: &s, id: HS_ID_PXY_WS} s.pxy_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh_ws,_http configurable... s.pxy_mux.Handle("/_ssh-ws/{conn_id}/{route_id}", - websocket.Handler(func(ws *websocket.Conn) { s.pxy_ws.ServeWebsocket(ws) })) + s.WrapWebsocketHandler(&server_pxy_ssh_ws{s: &s, id: HS_ID_PXY_WS})) s.pxy_mux.Handle("/_ssh/server-conns/{conn_id}/routes/{route_id}", s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{server_ctl{s: &s, id: HS_ID_PXY, noauth: true}})) s.pxy_mux.Handle("/_ssh/xterm.js", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "xterm.js"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "xterm.js"})) s.pxy_mux.Handle("/_ssh/xterm.js.map", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_notfound"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_notfound"})) s.pxy_mux.Handle("/_ssh/xterm-addon-fit.js", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "xterm-addon-fit.js"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "xterm-addon-fit.js"})) s.pxy_mux.Handle("/_ssh/xterm-addon-fit.js.map", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_notfound"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_notfound"})) s.pxy_mux.Handle("/_ssh/xterm.css", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "xterm.css"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "xterm.css"})) s.pxy_mux.Handle("/_ssh/{conn_id}/", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_redirect"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_redirect"})) s.pxy_mux.Handle("/_ssh/{conn_id}/{route_id}/", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "xterm.html"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "xterm.html"})) s.pxy_mux.Handle("/_ssh/", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) s.pxy_mux.Handle("/favicon.ico", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) s.pxy_mux.Handle("/favicon.ico/", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, file: "_forbidden"})) s.pxy_mux.Handle("/_http/{conn_id}/{route_id}/{trailer...}", - s.WrapHttpHandler(&server_proxy_http_main{server_proxy: server_proxy{s: &s, id: HS_ID_PXY}, prefix: "/_http"})) + s.WrapHttpHandler(&server_pxy_http_main{server_pxy: server_pxy{s: &s, id: HS_ID_PXY}, prefix: "/_http"})) s.pxy = make([]*http.Server, len(cfg.PxyAddrs)) @@ -1359,28 +1352,27 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.wpx_mux = http.NewServeMux() - s.wpx_ws = &server_proxy_ssh_ws{s: &s, id: "wpx-ssh"} s.wpx_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh_ws,_http configurable... s.wpx_mux.Handle("/_ssh-ws/{conn_id}/{route_id}", - websocket.Handler(func(ws *websocket.Conn) { s.wpx_ws.ServeWebsocket(ws) })) + s.WrapWebsocketHandler(&server_pxy_ssh_ws{s: &s, id: "wpx-ssh"})) s.wpx_mux.Handle("/_ssh/server-conns/{conn_id}/routes/{route_id}", s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{server_ctl{s: &s, id: HS_ID_WPX, noauth: true}})) s.wpx_mux.Handle("/_ssh/xterm.js", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, file: "xterm.js"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, file: "xterm.js"})) s.wpx_mux.Handle("/_ssh/xterm-addon-fit.js", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, file: "xterm-addon-fit.js"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, file: "xterm-addon-fit.js"})) s.wpx_mux.Handle("/_ssh/xterm.css", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, file: "xterm.css"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, file: "xterm.css"})) s.wpx_mux.Handle("/_ssh/{port_id}", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, file: "xterm.html"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, file: "xterm.html"})) s.wpx_mux.Handle("/_ssh/", - s.WrapHttpHandler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, file: "_forbidden"})) + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, file: "_forbidden"})) s.wpx_mux.Handle("/{port_id}/{trailer...}", - s.WrapHttpHandler(&server_proxy_http_main{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}, prefix: PORT_ID_MARKER})) + s.WrapHttpHandler(&server_pxy_http_main{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}, prefix: PORT_ID_MARKER})) s.wpx_mux.Handle("/", - s.WrapHttpHandler(&server_proxy_http_wpx{server_proxy: server_proxy{s: &s, id: HS_ID_WPX}})) + s.WrapHttpHandler(&server_pxy_http_wpx{server_pxy: server_pxy{s: &s, id: HS_ID_WPX}})) s.wpx = make([]*http.Server, len(cfg.WpxAddrs)) @@ -1630,7 +1622,7 @@ func (s *Server) ReqStop() { // call cancellation function before anything else // to break sub-tasks relying on this server context. - // for example, http.Client in server_proxy_http_main + // for example, http.Client in server_pxy_http_main s.CtxCancel() for _, hs = range s.ctl {