From 9d30a0efead7edcb75f6645c2f790d165bcb18eb Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 12 Jan 2025 17:30:13 +0900 Subject: [PATCH] added more code to support foreign ports for the wpx endpoint --- client-ctl.go | 10 +++++----- server-ctl.go | 25 ++++++++++++++++++++++++- server-proxy.go | 39 +++++++++++++++++++++++++++++++-------- server.go | 20 ++++++++++---------- 4 files changed, 70 insertions(+), 24 deletions(-) diff --git a/client-ctl.go b/client-ctl.go index 111a90d..705a9cc 100644 --- a/client-ctl.go +++ b/client-ctl.go @@ -3,7 +3,7 @@ package hodu import "encoding/json" import "fmt" import "net/http" -import "net/url" +//import "net/url" import "runtime" import "strconv" import "strings" @@ -159,13 +159,13 @@ func (ctl *client_ctl_client_conns) ServeHTTP(w http.ResponseWriter, req *http.R case http.MethodGet: var cts *ClientConn var js []json_out_client_conn - var q url.Values +// var q url.Values - q = req.URL.Query() +// q = req.URL.Query() // TODO: brief listing vs full listing - if q.Get("brief") == "true" { - } +// if q.Get("brief") == "true" { +// } js = make([]json_out_client_conn, 0) c.cts_mtx.Lock() diff --git a/server-ctl.go b/server-ctl.go index 10294ba..ac46120 100644 --- a/server-ctl.go +++ b/server-ctl.go @@ -270,12 +270,35 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter s = ctl.s je = json.NewEncoder(w) + if ctl.id == "wpx" && req.Method != http.MethodGet { + // support the get method only, if invoked via the wpx endpoint + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + goto done + } + conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") r, err = s.FindServerRouteByIdStr(conn_id, route_id) + if err != nil && ctl.id == "wpx" && route_id == PORT_ID_MARKER && ctl.s.wpx_foreign_port_proxy_maker != nil { + var pi *ServerRouteProxyInfo + // currenly, this is invoked via wpx only for ssh from xterm.html + // ugly, but hard-code the type to "ssh" here for now... + pi, err = ctl.s.wpx_foreign_port_proxy_maker("ssh", conn_id) + if err == nil { + // fake route + r = &ServerRoute{ + SvcOption: pi.SvcOption, + PtcName: pi.PtcName, + PtcAddr: pi.PtcAddr, + SvcAddr: pi.SvcAddr, + } + } + } + if err != nil { status_code = http.StatusNotFound; w.WriteHeader(status_code) if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops } + goto done } switch req.Method { @@ -299,7 +322,7 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter status_code = http.StatusBadRequest; w.WriteHeader(status_code) } -//done: +done: return status_code, nil oops: diff --git a/server-proxy.go b/server-proxy.go index 5f79e1e..6459d6f 100644 --- a/server-proxy.go +++ b/server-proxy.go @@ -217,7 +217,7 @@ func (pxy *server_proxy_http_main) get_route(req *http.Request, in_wpx_mode bool if !in_wpx_mode || pxy.s.wpx_foreign_port_proxy_maker == nil { return nil, err } // call this callback only in the wpx mode - pi, err = pxy.s.wpx_foreign_port_proxy_maker(conn_id) + pi, err = pxy.s.wpx_foreign_port_proxy_maker("http", conn_id) if err != nil { return nil, err } pi.PathPrefix = path_prefix @@ -472,7 +472,6 @@ func (pxy *server_proxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.R s = pxy.s -// TODO: logging switch pxy.file { case "xterm.js": w.Header().Set("Content-Type", "text/javascript") @@ -491,13 +490,18 @@ func (pxy *server_proxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.R var conn_id string var route_id string - conn_id = req.PathValue("conn_id") - route_id = req.PathValue("route_id") - if conn_id == "" && route_id == "" { + // this endpoint is registered for /_ssh/{conn_id}/{route_id}/ under pxy. + // and for /_ssh/{port_id} under wpx. + if pxy.id == "wpx" { conn_id = req.PathValue("port_id") route_id = PORT_ID_MARKER - _, err = s.FindServerRouteByIdStr(conn_id, PORT_ID_MARKER) - } else { + _, err = s.FindServerRouteByIdStr(conn_id, route_id) + if err != nil && pxy.s.wpx_foreign_port_proxy_maker != nil { + _, err = pxy.s.wpx_foreign_port_proxy_maker("ssh", conn_id) + } + } else { + conn_id = req.PathValue("conn_id") + route_id = req.PathValue("route_id") _, err = s.FindServerRouteByIdStr(conn_id, route_id) } if err != nil { @@ -594,7 +598,6 @@ func (pxy *server_proxy_ssh_ws) connect_ssh (ctx context.Context, username strin goto oops } */ - addr = svc_addr_to_dst_addr(r.SvcAddr) dialer = &net.Dialer{} @@ -654,6 +657,26 @@ func (pxy *server_proxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) { conn_id = req.PathValue("conn_id") route_id = req.PathValue("route_id") r, err = s.FindServerRouteByIdStr(conn_id, route_id) + if err != nil && route_id == PORT_ID_MARKER && pxy.s.wpx_foreign_port_proxy_maker != nil { + var pi *ServerRouteProxyInfo + pi, err = pxy.s.wpx_foreign_port_proxy_maker("ssh", conn_id) + if err != nil { + pxy.send_ws_data(ws, "error", err.Error()) + goto done + } + + // [SUPER-IMPORTANT!!] + // create a fake server route. this is not a compleete structure. + // some pointer fields are nil. extra care needs to be taken + // below to ensure it doesn't access undesired fields when exitending + // code further + r = &ServerRoute{ + SvcOption: pi.SvcOption, + PtcName: pi.PtcName, + PtcAddr: pi.PtcAddr, + SvcAddr: pi.SvcAddr, + } + } if err != nil { pxy.send_ws_data(ws, "error", err.Error()) goto done diff --git a/server.go b/server.go index 8c4ac4a..c5f1800 100644 --- a/server.go +++ b/server.go @@ -35,7 +35,7 @@ type ServerPeerConnMap = map[PeerId]*ServerPeerConn type ServerSvcPortMap = map[PortId]ConnRouteId type ServerWpxResponseTransformer func(r *ServerRouteProxyInfo, resp *http.Response) io.Reader -type ServerWpxForeignPortProxyMaker func(port_id string) (*ServerRouteProxyInfo, error) +type ServerWpxForeignPortProxyMaker func(wpx_type string, port_id string) (*ServerRouteProxyInfo, error) type Server struct { ctx context.Context @@ -1062,27 +1062,27 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs // --------------------------------------------------------- - s.pxy_ws = &server_proxy_ssh_ws{s: &s, id: "pxy-ssh"} + s.pxy_ws = &server_proxy_ssh_ws{s: &s, 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.pxy_mux.Handle("/_ssh/server-conns/{conn_id}/routes/{route_id}", - s.wrap_http_handler(&server_ctl_server_conns_id_routes_id{server_ctl{s: &s, id: "pxy-ctl"}})) + s.wrap_http_handler(&server_ctl_server_conns_id_routes_id{server_ctl{s: &s, id: "pxy"}})) s.pxy_mux.Handle("/_ssh/{conn_id}/", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "_redirect"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "_redirect"})) s.pxy_mux.Handle("/_ssh/{conn_id}/{route_id}/", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "xterm.html"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "xterm.html"})) s.pxy_mux.Handle("/_ssh/xterm.js", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "xterm.js"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "xterm.js"})) s.pxy_mux.Handle("/_ssh/xterm-addon-fit.js", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "xterm-addon-fit.js"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "xterm-addon-fit.js"})) s.pxy_mux.Handle("/_ssh/xterm.css", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "xterm.css"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "xterm.css"})) s.pxy_mux.Handle("/_ssh/", - s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy-file"}, file: "_forbidden"})) + s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "pxy"}, file: "_forbidden"})) s.pxy_mux.Handle("/_http/{conn_id}/{route_id}/{trailer...}", - s.wrap_http_handler(&server_proxy_http_main{server_proxy: server_proxy{s: &s, id: "pxy-http"}, prefix: "/_http"})) + s.wrap_http_handler(&server_proxy_http_main{server_proxy: server_proxy{s: &s, id: "pxy"}, prefix: "/_http"})) s.pxy_addr = make([]string, len(pxy_addrs)) s.pxy = make([]*http.Server, len(pxy_addrs))