From 6e670b49244676ef3dc0a88270b0b1234396c369 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 24 Jun 2025 00:58:46 +0900 Subject: [PATCH] updated http endpoints for more consistent xterm.html access --- client.go | 6 +--- server-ctl.go | 8 +++++ server-pxy.go | 10 +++++- server.go | 97 ++++++++++++++++++--------------------------------- xterm.html | 12 +++---- 5 files changed, 56 insertions(+), 77 deletions(-) diff --git a/client.go b/client.go index 9518eec..e62419c 100644 --- a/client.go +++ b/client.go @@ -1652,18 +1652,14 @@ func NewClient(ctx context.Context, name string, logger Logger, cfg *ClientConfi c.ctl_mux.Handle("/_pts/xterm.js", c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.js"})) - c.ctl_mux.Handle("/_pts/xterm.js.map", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_notfound"})) c.ctl_mux.Handle("/_pts/xterm-addon-fit.js", c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) - c.ctl_mux.Handle("/_pts/xterm-addon-fit.js.map", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_notfound"})) c.ctl_mux.Handle("/_pts/xterm.css", c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.css"})) c.ctl_mux.Handle("/_pts/xterm.html", c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.html"})) c.ctl_mux.Handle("/_pts/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.html"})) c.ctl_mux.Handle("/_pts/favicon.ico", c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) c.ctl_mux.Handle("/_pts/favicon.ico/", diff --git a/server-ctl.go b/server-ctl.go index c81fb81..88a17cc 100644 --- a/server-ctl.go +++ b/server-ctl.go @@ -447,6 +447,7 @@ oops: func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var s *Server var status_code int + var port_id string var conn_id string var route_id string var je *json.Encoder @@ -462,8 +463,15 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter goto done } + port_id = req.PathValue("port_id") conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") + if port_id != "" && conn_id == "" && route_id == "" { + // called from wpx. ctl.Id must be HS_ID_WPX + conn_id = port_id + route_id = PORT_ID_MARKER + } + r, err = s.FindServerRouteByIdStr(conn_id, route_id) if err != nil { /* diff --git a/server-pxy.go b/server-pxy.go index 798a293..0b79ffc 100644 --- a/server-pxy.go +++ b/server-pxy.go @@ -634,6 +634,7 @@ oops: func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { var s *Server var req *http.Request + var port_id string var conn_id string var route_id string var r *ServerRoute @@ -653,8 +654,15 @@ func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { req = ws.Request() conn_ready_chan = make(chan bool, 3) + port_id = req.PathValue("port_id") conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") + if port_id != "" && conn_id == "" && route_id == "" { + // called using the wpx endpoint. pxy.Id must be HS_ID_WPX + conn_id = port_id + route_id = PORT_ID_MARKER + } + r, err = s.FindServerRouteByIdStr(conn_id, route_id) if err != nil && route_id == PORT_ID_MARKER && s.wpx_foreign_port_proxy_maker != nil { var pi *ServerRouteProxyInfo @@ -695,7 +703,7 @@ func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) { n, err = out.Read(buf) if err != nil { if !errors.Is(err, io.EOF) { - s.log.Write(pxy.Id, LOG_ERROR, "[%s] Failed to read from SSH stdout - %s", req.RemoteAddr, err.Error()) + s.log.Write(pxy.Id, LOG_ERROR, "[%s] Failed to read from SSH stdout - %s", req.RemoteAddr, err.Error()) } break } diff --git a/server.go b/server.go index dd18b35..04be2b0 100644 --- a/server.go +++ b/server.go @@ -34,7 +34,6 @@ const PORT_ID_MARKER string = "_" const HS_ID_CTL string = "ctl" const HS_ID_WPX string = "wpx" const HS_ID_PXY string = "pxy" -const HS_ID_PXY_WS string = "pxy-ws" type ServerConnMapByAddr map[net.Addr]*ServerConn type ServerConnMapByClientToken map[string]*ServerConn @@ -1386,52 +1385,18 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.ctl_mux.Handle("/_pts/xterm.js", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.js"})) - s.ctl_mux.Handle("/_pts/xterm.js.map", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_notfound"})) s.ctl_mux.Handle("/_pts/xterm-addon-fit.js", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) - s.ctl_mux.Handle("/_pts/xterm-addon-fit.js.map", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_notfound"})) s.ctl_mux.Handle("/_pts/xterm.css", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.css"})) s.ctl_mux.Handle("/_pts/xterm.html", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.html"})) s.ctl_mux.Handle("/_pts/", - s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) + s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "xterm.html"})) s.ctl_mux.Handle("/_pts/favicon.ico", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) s.ctl_mux.Handle("/_pts/favicon.ico/", s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) - /* - // this part is duplcate of pxy_mux. - s.ctl_mux.Handle("/_ssh/ws/{conn_id}/{route_id}", - s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: HS_ID_PXY_WS}))) - s.ctl_mux.Handle("/_ssh/server-conns/{conn_id}/routes/{route_id}", - s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{ServerCtl{S: &s, Id: HS_ID_CTL, NoAuth: true}})) - s.ctl_mux.Handle("/_ssh/xterm.js", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "xterm.js"})) - s.ctl_mux.Handle("/_ssh/xterm.js.map", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_notfound"})) - s.ctl_mux.Handle("/_ssh/xterm-addon-fit.js", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "xterm-addon-fit.js"})) - s.ctl_mux.Handle("/_ssh/xterm-addon-fit.js.map", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_notfound"})) - s.ctl_mux.Handle("/_ssh/xterm.css", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "xterm.css"})) - s.ctl_mux.Handle("/_ssh/{conn_id}/", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_redirect"})) - s.ctl_mux.Handle("/_ssh/{conn_id}/{route_id}/", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "xterm.html"})) - s.ctl_mux.Handle("/_ssh/", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) - s.ctl_mux.Handle("/favicon.ico", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) - s.ctl_mux.Handle("/favicon.ico/", - s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, file: "_forbidden"})) - - s.ctl_mux.Handle("/_http/{conn_id}/{route_id}/{trailer...}", - s.WrapHttpHandler(&server_pxy_http_main{server_pxy: server_pxy{S: &s, Id: HS_ID_CTL}, prefix: "/_http"})) - */ s.ctl = make([]*http.Server, len(cfg.CtlAddrs)) for i = 0; i < len(cfg.CtlAddrs); i++ { @@ -1447,24 +1412,26 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi // --------------------------------------------------------- s.pxy_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh/ws,_http configurable... - s.pxy_mux.Handle("/_ssh/ws/{conn_id}/{route_id}", - s.SafeWrapWebsocketHandler(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{ServerCtl{S: &s, Id: HS_ID_PXY, NoAuth: true}})) - s.pxy_mux.Handle("/_ssh/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_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_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_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_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_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_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "xterm.html"})) + s.pxy_mux.Handle("/_ssh/{conn_id}/{route_id}/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/{conn_id}/{route_id}/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}/{route_id}/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/{conn_id}/{route_id}/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/{conn_id}/{route_id}/ws", + s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: HS_ID_PXY}))) + s.pxy_mux.Handle("/_ssh/{conn_id}/{route_id}/session-info", + s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{ServerCtl{S: &s, Id: HS_ID_PXY, NoAuth: true}})) + s.pxy_mux.Handle("/_ssh/", s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_forbidden"})) s.pxy_mux.Handle("/favicon.ico", @@ -1489,27 +1456,31 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi // --------------------------------------------------------- - s.wpx_mux = http.NewServeMux() - s.wpx_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh/ws,_http configurable... - s.wpx_mux.Handle("/_ssh/ws/{conn_id}/{route_id}", - s.SafeWrapWebsocketHandler(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{ServerCtl{S: &s, Id: HS_ID_WPX, NoAuth: true}})) - s.wpx_mux.Handle("/_ssh/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_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_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "xterm.css"})) - s.wpx_mux.Handle("/_ssh/{port_id}", + s.wpx_mux.Handle("/_ssh/{port_id}/", s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "xterm.html"})) + s.wpx_mux.Handle("/_ssh/{port_id}/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/{port_id}/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}/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/{port_id}/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/{port_id}/ws", + s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: HS_ID_WPX}))) + s.wpx_mux.Handle("/_ssh/{port_id}/session-info", + s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{ServerCtl{S: &s, Id: HS_ID_WPX, NoAuth: true}})) + s.wpx_mux.Handle("/_ssh/", s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "_forbidden"})) + // http proxy by port id s.wpx_mux.Handle("/{port_id}/{trailer...}", 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_pxy_http_wpx{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}})) diff --git a/xterm.html b/xterm.html index 494a798..384ff9a 100644 --- a/xterm.html +++ b/xterm.html @@ -150,12 +150,9 @@ window.onload = function(event) { let fetch_session_info = async function() { let url = window.location.protocol + '//' + window.location.host; let pathname = window.location.pathname; - pathname = pathname.replace(/\/$/, ''); + //pathname = pathname.replace(/\/$/, ''); pathname = pathname.substring(0, pathname.lastIndexOf('/')); - if (xt_mode == 'ssh') - url += pathname + `/server-conns/${conn_id}/routes/${route_id}`; - else - url += pathname + `/session-info`; + url += pathname + `/session-info`; try { const resp = await fetch(url); @@ -207,10 +204,9 @@ window.onload = function(event) { const prefix = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; let pathname = window.location.pathname; - pathname = pathname.replace(/\/$/, ''); + //pathname = pathname.replace(/\/$/, ''); pathname = pathname.substring(0, pathname.lastIndexOf('/')); - let url = prefix + window.location.host + pathname; - url += (xt_mode == 'ssh'? `/ws/${conn_id}/${route_id}`: `/ws`); + let url = prefix + window.location.host + pathname + '/ws'; const socket = new WebSocket(url); socket.binaryType = 'arraybuffer';