renamed server_ctl to ServerCtl and capitalized the first letter of inner fields for exposure

This commit is contained in:
hyung-hwan 2025-03-29 13:29:02 +09:00
parent 76cba687ed
commit 918b887517
6 changed files with 199 additions and 151 deletions

View File

@ -180,7 +180,7 @@ type client_ctl_ws struct {
// ------------------------------------ // ------------------------------------
func (ctl *client_ctl) Id() string { func (ctl *client_ctl) Identity() string {
return ctl.id return ctl.id
} }
@ -532,9 +532,9 @@ func (ctl *client_ctl_client_conns_id_routes) ServeHTTP(w http.ResponseWriter, r
Id: jcr.RId, Id: jcr.RId,
PeerAddr: jcr.ClientPeerAddr, PeerAddr: jcr.ClientPeerAddr,
PeerName: jcr.ClientPeerName, PeerName: jcr.ClientPeerName,
Option: server_peer_option,
ServiceAddr: jcr.ServerPeerSvcAddr, ServiceAddr: jcr.ServerPeerSvcAddr,
ServiceNet: jcr.ServerPeerSvcNet, ServiceNet: jcr.ServerPeerSvcNet,
ServiceOption: server_peer_option,
Lifetime: lifetime, Lifetime: lifetime,
Static: false, Static: false,
} }

View File

@ -37,9 +37,9 @@ type ClientRouteConfig struct {
Id RouteId // requested id to be assigned. 0 for automatic assignment Id RouteId // requested id to be assigned. 0 for automatic assignment
PeerAddr string PeerAddr string
PeerName string PeerName string
Option RouteOption
ServiceAddr string // server-peer-svc-addr ServiceAddr string // server-peer-svc-addr
ServiceNet string // server-peer-svc-net ServiceNet string // server-peer-svc-net
ServiceOption RouteOption
Lifetime time.Duration Lifetime time.Duration
Static bool Static bool
} }
@ -202,7 +202,7 @@ type ClientRoute struct {
PeerAddr string PeerAddr string
PeerName string PeerName string
PeerOption RouteOption PeerOption RouteOption // internally used in connecting
ReqServerPeerSvcAddr string // requested server-side service address ReqServerPeerSvcAddr string // requested server-side service address
ReqServerPeerSvcNet string // requested server-side service address ReqServerPeerSvcNet string // requested server-side service address
@ -841,7 +841,7 @@ func (cts *ClientConn) AddNewClientRoute(rc *ClientRouteConfig) (*ClientRoute, e
assigned_id = rc.Id assigned_id = rc.Id
} }
r = NewClientRoute(cts, assigned_id, rc.Static, rc.PeerAddr, rc.PeerName, rc.ServiceAddr, rc.ServiceNet, rc.Option, rc.Lifetime) r = NewClientRoute(cts, assigned_id, rc.Static, rc.PeerAddr, rc.PeerName, rc.ServiceAddr, rc.ServiceNet, rc.ServiceOption, rc.Lifetime)
cts.route_map[r.Id] = r cts.route_map[r.Id] = r
cts.C.stats.routes.Add(1) cts.C.stats.routes.Add(1)
if cts.C.route_persister != nil { cts.C.route_persister.Save(cts, r) } if cts.C.route_persister != nil { cts.C.route_persister.Save(cts, r) }
@ -1454,19 +1454,19 @@ func (hlw *client_ctl_log_writer) Write(p []byte) (n int, err error) {
} }
type ClientHttpHandler interface { type ClientHttpHandler interface {
Id() string Identity() string
Cors(req *http.Request) bool Cors(req *http.Request) bool
Authenticate(req *http.Request) (int, string) Authenticate(req *http.Request) (int, string)
ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error) ServeHTTP (w http.ResponseWriter, req *http.Request) (int, error)
} }
type ClientWebsocketHandler interface { type ClientWebsocketHandler interface {
Id() string Identity() string
ServeWebsocket(ws *websocket.Conn) (int, error) ServeWebsocket(ws *websocket.Conn) (int, error)
} }
func (c *Client) wrap_http_handler(handler ClientHttpHandler) http.Handler { func (c *Client) WrapHttpHandler(handler ClientHttpHandler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var status_code int var status_code int
var err error var err error
@ -1512,9 +1512,9 @@ func (c *Client) wrap_http_handler(handler ClientHttpHandler) http.Handler {
if status_code > 0 { if status_code > 0 {
if err != nil { if err != nil {
c.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error()) c.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
} else { } else {
c.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds()) c.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
} }
} }
}) })
@ -1529,7 +1529,7 @@ func (s *Client) WrapWebsocketHandler(handler ClientWebsocketHandler) websocket.
var req *http.Request var req *http.Request
req = ws.Request() req = ws.Request()
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws]", req.RemoteAddr, req.Method, req.URL.String()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws]", req.RemoteAddr, req.Method, req.URL.String())
start_time = time.Now() start_time = time.Now()
status_code, err = handler.ServeWebsocket(ws) status_code, err = handler.ServeWebsocket(ws)
@ -1537,9 +1537,9 @@ func (s *Client) WrapWebsocketHandler(handler ClientWebsocketHandler) websocket.
if status_code > 0 { if status_code > 0 {
if err != nil { if err != nil {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws] %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws] %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
} else { } else {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws] %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws] %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
} }
} }
}) })
@ -1573,36 +1573,36 @@ func NewClient(ctx context.Context, name string, logger Logger, cfg *ClientConfi
c.ctl_cors = cfg.CtlCors c.ctl_cors = cfg.CtlCors
c.ctl_mux = http.NewServeMux() c.ctl_mux = http.NewServeMux()
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns",
c.wrap_http_handler(&client_ctl_client_conns{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}",
c.wrap_http_handler(&client_ctl_client_conns_id{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes",
c.wrap_http_handler(&client_ctl_client_conns_id_routes{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_routes{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}",
c.wrap_http_handler(&client_ctl_client_conns_id_routes_id{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_routes_id{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes-spsp/{port_id}", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes-spsp/{port_id}",
c.wrap_http_handler(&client_ctl_client_conns_id_routes_spsp{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_routes_spsp{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers",
c.wrap_http_handler(&client_ctl_client_conns_id_routes_id_peers{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_routes_id_peers{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers/{peer_id}", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers/{peer_id}",
c.wrap_http_handler(&client_ctl_client_conns_id_routes_id_peers_id{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_routes_id_peers_id{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/peers", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/peers",
c.wrap_http_handler(&client_ctl_client_conns_id_peers{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_conns_id_peers{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-routes", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-routes",
c.wrap_http_handler(&client_ctl_client_routes{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_routes{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-peers", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-peers",
c.wrap_http_handler(&client_ctl_client_peers{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_client_peers{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/notices", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/notices",
c.wrap_http_handler(&client_ctl_notices{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_notices{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/notices/{conn_id}", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/notices/{conn_id}",
c.wrap_http_handler(&client_ctl_notices_id{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_notices_id{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/stats", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/stats",
c.wrap_http_handler(&client_ctl_stats{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_stats{client_ctl{c: &c, id: HS_ID_CTL}}))
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/token", c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/token",
c.wrap_http_handler(&client_ctl_token{client_ctl{c: &c, id: HS_ID_CTL}})) c.WrapHttpHandler(&client_ctl_token{client_ctl{c: &c, id: HS_ID_CTL}}))
// TODO: make this optional. add this endpoint only if it's enabled... // TODO: make this optional. add this endpoint only if it's enabled...
c.promreg = prometheus.NewRegistry() c.promreg = prometheus.NewRegistry()
@ -2068,6 +2068,16 @@ func (c *Client) SetRoutePersister(persister ClientRoutePersister) {
c.route_persister = persister c.route_persister = persister
} }
func (c *Client) AddCtlHandler(path string, handler ClientHttpHandler) {
// parked under /_ctl
c.ctl_mux.Handle(c.ctl_prefix + "/_ctl" + path, c.WrapHttpHandler(handler))
}
func (c *Client) AddCtlRootHandler(path string, handler ClientHttpHandler) {
// parked at the root level. must avoid conflicting path
c.ctl_mux.Handle(c.ctl_prefix + path, c.WrapHttpHandler(handler))
}
func (c *Client) AddCtlMetricsCollector(col prometheus.Collector) error { func (c *Client) AddCtlMetricsCollector(col prometheus.Collector) error {
return c.promreg.Register(col) return c.promreg.Register(col)
} }

View File

@ -240,7 +240,7 @@ func parse_client_route_config(v string) (*hodu.ClientRouteConfig, error) {
ptc_name = strings.TrimSpace(va[3]) ptc_name = strings.TrimSpace(va[3])
} }
return &hodu.ClientRouteConfig{PeerAddr: va[0], PeerName: ptc_name, Option: option, ServiceAddr: svc_addr}, nil // TODO: other fields return &hodu.ClientRouteConfig{PeerAddr: va[0], PeerName: ptc_name, ServiceOption: option, ServiceAddr: svc_addr}, nil // TODO: other fields
} }
func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, logfile string, cfg *ClientConfig) error { func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, logfile string, cfg *ClientConfig) error {

View File

@ -86,81 +86,81 @@ type json_in_server_notice struct {
// ------------------------------------ // ------------------------------------
type server_ctl struct { type ServerCtl struct {
s *Server S *Server
id string Id string
noauth bool // override the auth configuration if true NoAuth bool // override the auth configuration if true
} }
type server_ctl_token struct { type server_ctl_token struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns struct { type server_ctl_server_conns struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id struct { type server_ctl_server_conns_id struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id_routes struct { type server_ctl_server_conns_id_routes struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id_routes_id struct { type server_ctl_server_conns_id_routes_id struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id_routes_id_peers struct { type server_ctl_server_conns_id_routes_id_peers struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id_routes_id_peers_id struct { type server_ctl_server_conns_id_routes_id_peers_id struct {
server_ctl ServerCtl
} }
type server_ctl_server_conns_id_peers struct { type server_ctl_server_conns_id_peers struct {
server_ctl ServerCtl
} }
type server_ctl_server_routes struct { type server_ctl_server_routes struct {
server_ctl ServerCtl
} }
type server_ctl_server_peers struct { type server_ctl_server_peers struct {
server_ctl ServerCtl
} }
type server_ctl_notices struct { type server_ctl_notices struct {
server_ctl ServerCtl
} }
type server_ctl_notices_id struct { type server_ctl_notices_id struct {
server_ctl ServerCtl
} }
type server_ctl_stats struct { type server_ctl_stats struct {
server_ctl ServerCtl
} }
type server_ctl_ws struct { type server_ctl_ws struct {
server_ctl ServerCtl
} }
// ------------------------------------ // ------------------------------------
func (ctl *server_ctl) Id() string { func (ctl *ServerCtl) Identity() string {
return ctl.id return ctl.Id
} }
func (ctl *server_ctl) Cors(req *http.Request) bool { func (ctl *ServerCtl) Cors(req *http.Request) bool {
return ctl.s.Cfg.CtlCors return ctl.S.Cfg.CtlCors
} }
func (ctl *server_ctl) Authenticate(req *http.Request) (int, string) { func (ctl *ServerCtl) Authenticate(req *http.Request) (int, string) {
if ctl.noauth || ctl.s.Cfg.CtlAuth == nil { return http.StatusOK, "" } if ctl.NoAuth || ctl.S.Cfg.CtlAuth == nil { return http.StatusOK, "" }
return ctl.s.Cfg.CtlAuth.Authenticate(req) return ctl.S.Cfg.CtlAuth.Authenticate(req)
} }
// ------------------------------------ // ------------------------------------
@ -171,7 +171,7 @@ func (ctl *server_ctl_token) ServeHTTP(w http.ResponseWriter, req *http.Request)
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
switch req.Method { switch req.Method {
@ -224,7 +224,7 @@ func (ctl *server_ctl_server_conns) ServeHTTP(w http.ResponseWriter, req *http.R
var routes bool var routes bool
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
q = req.URL.Query() q = req.URL.Query()
@ -305,7 +305,7 @@ func (ctl *server_ctl_server_conns_id) ServeHTTP(w http.ResponseWriter, req *htt
var routes bool var routes bool
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
q = req.URL.Query() q = req.URL.Query()
@ -385,7 +385,7 @@ func (ctl *server_ctl_server_conns_id_routes) ServeHTTP(w http.ResponseWriter, r
var je *json.Encoder var je *json.Encoder
var cts *ServerConn var cts *ServerConn
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
@ -452,10 +452,10 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter
var r *ServerRoute var r *ServerRoute
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
if ctl.id == HS_ID_WPX && req.Method != http.MethodGet { if ctl.Id == HS_ID_WPX && req.Method != http.MethodGet {
// support the get method only, if invoked via the wpx endpoint // support the get method only, if invoked via the wpx endpoint
status_code = WriteEmptyRespHeader(w, http.StatusBadRequest) status_code = WriteEmptyRespHeader(w, http.StatusBadRequest)
goto done goto done
@ -466,23 +466,23 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter
r, err = s.FindServerRouteByIdStr(conn_id, route_id) r, err = s.FindServerRouteByIdStr(conn_id, route_id)
if err != nil { if err != nil {
/* /*
if route_id == PORT_ID_MARKER && ctl.s.wpx_foreign_port_proxy_marker != nil { if route_id == PORT_ID_MARKER && ctl.S.wpx_foreign_port_proxy_marker != nil {
// don't care if the ctl call is from wpx or not. if the request // don't care if the ctl call is from wpx or not. if the request
// is by the port number(noted by route being PORT_ID_MARKER), // is by the port number(noted by route being PORT_ID_MARKER),
// check if it's a foreign port // check if it's a foreign port
var pi *ServerRouteProxyInfo var pi *ServerRouteProxyInfo
// currenly, this is invoked via wpx only for ssh from xterm.html // currenly, this is invoked via wpx only for ssh from xterm.html
// ugly, but hard-code the type to "ssh" here for now... // ugly, but hard-code the type to "ssh" here for now...
pi, err = ctl.s.wpx_foreign_port_proxy_maker("ssh", conn_id) pi, err = ctl.S.wpx_foreign_port_proxy_maker("ssh", conn_id)
if err == nil { r = proxy_info_to_server_route(pi) } // fake route if err == nil { r = proxy_info_to_server_route(pi) } // fake route
} }
*/ */
if ctl.id == HS_ID_WPX && route_id == PORT_ID_MARKER && ctl.s.wpx_foreign_port_proxy_maker != nil { if ctl.Id == HS_ID_WPX && route_id == PORT_ID_MARKER && ctl.S.wpx_foreign_port_proxy_maker != nil {
var pi *ServerRouteProxyInfo var pi *ServerRouteProxyInfo
// currenly, this is invoked via wpx only for ssh from xterm.html // currenly, this is invoked via wpx only for ssh from xterm.html
// ugly, but hard-code the type to "ssh" here for now... // ugly, but hard-code the type to "ssh" here for now...
pi, err = ctl.s.wpx_foreign_port_proxy_maker("ssh", conn_id) pi, err = ctl.S.wpx_foreign_port_proxy_maker("ssh", conn_id)
if err == nil { r = proxy_info_to_server_route(pi) } // fake route if err == nil { r = proxy_info_to_server_route(pi) } // fake route
} }
} }
@ -511,7 +511,7 @@ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter
case http.MethodDelete: case http.MethodDelete:
/*if r is foreign { /*if r is foreign {
// foreign route // foreign route
ctl.s.wpx_foreign_port_proxy_stopper(conn_id) ctl.S.wpx_foreign_port_proxy_stopper(conn_id)
} else {*/ } else {*/
// native route // native route
r.ReqStop() r.ReqStop()
@ -540,7 +540,7 @@ func (ctl *server_ctl_server_conns_id_routes_id_peers) ServeHTTP(w http.Response
var r *ServerRoute var r *ServerRoute
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
@ -605,7 +605,7 @@ func (ctl *server_ctl_server_conns_id_routes_id_peers_id) ServeHTTP(w http.Respo
var p *ServerPeerConn var p *ServerPeerConn
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
@ -660,7 +660,7 @@ func (ctl *server_ctl_server_conns_id_peers) ServeHTTP(w http.ResponseWriter, re
var je *json.Encoder var je *json.Encoder
var cts *ServerConn var cts *ServerConn
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
@ -716,7 +716,7 @@ func (ctl *server_ctl_server_routes) ServeHTTP(w http.ResponseWriter, req *http.
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
switch req.Method { switch req.Method {
@ -763,7 +763,7 @@ func (ctl *server_ctl_server_peers) ServeHTTP(w http.ResponseWriter, req *http.R
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
switch req.Method { switch req.Method {
@ -811,7 +811,7 @@ func (ctl *server_ctl_notices) ServeHTTP(w http.ResponseWriter, req *http.Reques
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
switch req.Method { switch req.Method {
@ -853,7 +853,7 @@ func (ctl *server_ctl_notices_id) ServeHTTP(w http.ResponseWriter, req *http.Req
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id") // server connection conn_id = req.PathValue("conn_id") // server connection
@ -896,7 +896,7 @@ func (ctl *server_ctl_stats) ServeHTTP(w http.ResponseWriter, req *http.Request)
var je *json.Encoder var je *json.Encoder
var err error var err error
s = ctl.s s = ctl.S
je = json.NewEncoder(w) je = json.NewEncoder(w)
switch req.Method { switch req.Method {
@ -931,11 +931,11 @@ func (ctl *server_ctl_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
var err error var err error
var xerr error var xerr error
s = ctl.s s = ctl.S
// handle authentication using the first message. // handle authentication using the first message.
// end this task if authentication fails. // end this task if authentication fails.
if !ctl.noauth && s.Cfg.CtlAuth != nil { if !ctl.NoAuth && s.Cfg.CtlAuth != nil {
var req *http.Request var req *http.Request
req = ws.Request() req = ws.Request()

View File

@ -31,8 +31,8 @@ var xterm_css []byte
var xterm_html string var xterm_html string
type server_pxy struct { type server_pxy struct {
s *Server S *Server
id string Id string
} }
type server_pxy_http_main struct { type server_pxy_http_main struct {
@ -186,8 +186,8 @@ func mutate_proxy_req_headers(req *http.Request, newreq *http.Request, path_pref
// ------------------------------------ // ------------------------------------
func (pxy *server_pxy) Id() string { func (pxy *server_pxy) Identity() string {
return pxy.id return pxy.Id
} }
func (pxy *server_pxy) Cors(req *http.Request) bool { func (pxy *server_pxy) Cors(req *http.Request) bool {
@ -205,6 +205,7 @@ func prevent_follow_redirect (req *http.Request, via []*http.Request) error {
} }
func (pxy *server_pxy_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 s *Server
var conn_id string var conn_id string
var route_id string var route_id string
var r *ServerRoute var r *ServerRoute
@ -212,6 +213,8 @@ func (pxy *server_pxy_http_main) get_route_proxy_info(req *http.Request, in_wpx_
var path_prefix string var path_prefix string
var err error var err error
s = pxy.S
if in_wpx_mode { // for wpx if in_wpx_mode { // for wpx
conn_id = req.PathValue("port_id") conn_id = req.PathValue("port_id")
route_id = pxy.prefix // this is PORT_ID_MARKER route_id = pxy.prefix // this is PORT_ID_MARKER
@ -225,12 +228,12 @@ func (pxy *server_pxy_http_main) get_route_proxy_info(req *http.Request, in_wpx_
path_prefix = fmt.Sprintf("%s/%s/%s", pxy.prefix, conn_id, route_id) path_prefix = fmt.Sprintf("%s/%s/%s", pxy.prefix, conn_id, route_id)
} }
r, err = pxy.s.FindServerRouteByIdStr(conn_id, route_id) r, err = s.FindServerRouteByIdStr(conn_id, route_id)
if err != nil { if err != nil {
if !in_wpx_mode || pxy.s.wpx_foreign_port_proxy_maker == nil { return nil, err } if !in_wpx_mode || s.wpx_foreign_port_proxy_maker == nil { return nil, err }
// call this callback only in the wpx mode // call this callback only in the wpx mode
pi, err = pxy.s.wpx_foreign_port_proxy_maker("http", conn_id) pi, err = s.wpx_foreign_port_proxy_maker("http", conn_id)
if err != nil { return nil, err } if err != nil { return nil, err }
pi.IsForeign = true // just to ensure this pi.IsForeign = true // just to ensure this
} else { } else {
@ -304,7 +307,7 @@ func (pxy *server_pxy_http_main) addr_to_transport (ctx context.Context, addr *n
// establish the connection. // establish the connection.
dialer = &net.Dialer{} dialer = &net.Dialer{}
waitctx, cancel_wait = context.WithTimeout(ctx, 3 * time.Second) // TODO: make timeout configurable waitctx, cancel_wait = context.WithTimeout(ctx, 5 * time.Second) // TODO: make timeout configurable
conn, err = dialer.DialContext(waitctx, TcpAddrClass(addr), addr.String()) conn, err = dialer.DialContext(waitctx, TcpAddrClass(addr), addr.String())
cancel_wait() cancel_wait()
if err != nil { return nil, err } if err != nil { return nil, err }
@ -357,7 +360,7 @@ func (pxy *server_pxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Requ
var upgrade_required bool var upgrade_required bool
var err error var err error
s = pxy.s s = pxy.S
in_wpx_mode = (pxy.prefix == PORT_ID_MARKER) in_wpx_mode = (pxy.prefix == PORT_ID_MARKER)
pi, err = pxy.get_route_proxy_info(req, in_wpx_mode) pi, err = pxy.get_route_proxy_info(req, in_wpx_mode)
@ -381,7 +384,7 @@ func (pxy *server_pxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Requ
} }
proxy_url = pxy.req_to_proxy_url(req, pi) proxy_url = pxy.req_to_proxy_url(req, pi)
s.log.Write(pxy.id, LOG_INFO, "[%s] %s %s -> %+v", req.RemoteAddr, req.Method, req.URL.String(), proxy_url) s.log.Write(pxy.Id, LOG_INFO, "[%s] %s %s -> %+v", req.RemoteAddr, req.Method, req.URL.String(), proxy_url)
proxy_req, err = http.NewRequestWithContext(s.Ctx, req.Method, proxy_url.String(), req.Body) proxy_req, err = http.NewRequestWithContext(s.Ctx, req.Method, proxy_url.String(), req.Body)
if err != nil { if err != nil {
@ -407,7 +410,7 @@ func (pxy *server_pxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Requ
} else { } else {
status_code = resp.StatusCode status_code = resp.StatusCode
if upgrade_required && resp.StatusCode == http.StatusSwitchingProtocols { if upgrade_required && resp.StatusCode == http.StatusSwitchingProtocols {
s.log.Write(pxy.id, LOG_INFO, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) s.log.Write(pxy.Id, LOG_INFO, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code)
err = pxy.serve_upgraded(w, req, resp) err = pxy.serve_upgraded(w, req, resp)
if err != nil { goto oops } if err != nil { goto oops }
return 0, nil// print the log mesage before calling serve_upgraded() and exit here return 0, nil// print the log mesage before calling serve_upgraded() and exit here
@ -432,7 +435,7 @@ func (pxy *server_pxy_http_main) ServeHTTP(w http.ResponseWriter, req *http.Requ
_, err = io.Copy(w, resp_body) _, err = io.Copy(w, resp_body)
if err != nil { if err != nil {
s.log.Write(pxy.id, LOG_WARN, "[%s] %s %s %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error()) s.log.Write(pxy.Id, LOG_WARN, "[%s] %s %s %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error())
} }
// TODO: handle trailers // TODO: handle trailers
@ -474,7 +477,7 @@ func (pxy *server_pxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req
var status_code int var status_code int
var err error var err error
s = pxy.s s = pxy.S
switch pxy.file { switch pxy.file {
case "xterm.js": case "xterm.js":
@ -493,12 +496,12 @@ func (pxy *server_pxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req
// this endpoint is registered for /_ssh/{conn_id}/{route_id}/ under pxy. // this endpoint is registered for /_ssh/{conn_id}/{route_id}/ under pxy.
// and for /_ssh/{port_id} under wpx. // and for /_ssh/{port_id} under wpx.
if pxy.id == HS_ID_WPX { if pxy.Id == HS_ID_WPX {
conn_id = req.PathValue("port_id") conn_id = req.PathValue("port_id")
route_id = PORT_ID_MARKER route_id = PORT_ID_MARKER
_, err = s.FindServerRouteByIdStr(conn_id, route_id) _, err = s.FindServerRouteByIdStr(conn_id, route_id)
if err != nil && pxy.s.wpx_foreign_port_proxy_maker != nil { if err != nil && s.wpx_foreign_port_proxy_maker != nil {
_, err = pxy.s.wpx_foreign_port_proxy_maker("ssh", conn_id) _, err = s.wpx_foreign_port_proxy_maker("ssh", conn_id)
} }
} else { } else {
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
@ -555,9 +558,9 @@ oops:
// ------------------------------------ // ------------------------------------
type server_pxy_ssh_ws struct { type server_pxy_ssh_ws struct {
s *Server S *Server
ws *websocket.Conn ws *websocket.Conn
id string Id string
} }
type json_ssh_ws_event struct { type json_ssh_ws_event struct {
@ -565,8 +568,8 @@ type json_ssh_ws_event struct {
Data []string `json:"data"` Data []string `json:"data"`
} }
func (pxy *server_pxy_ssh_ws) Id() string { func (pxy *server_pxy_ssh_ws) Identity() string {
return pxy.id return pxy.Id
} }
// TODO: put this task to sync group. // TODO: put this task to sync group.
@ -664,16 +667,16 @@ func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
var connect_ssh_cancel Atom[context.CancelFunc] var connect_ssh_cancel Atom[context.CancelFunc]
var err error var err error
s = pxy.s s = pxy.S
req = ws.Request() req = ws.Request()
conn_ready_chan = make(chan bool, 3) conn_ready_chan = make(chan bool, 3)
conn_id = req.PathValue("conn_id") conn_id = req.PathValue("conn_id")
route_id = req.PathValue("route_id") route_id = req.PathValue("route_id")
r, err = s.FindServerRouteByIdStr(conn_id, 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 { if err != nil && route_id == PORT_ID_MARKER && s.wpx_foreign_port_proxy_maker != nil {
var pi *ServerRouteProxyInfo var pi *ServerRouteProxyInfo
pi, err = pxy.s.wpx_foreign_port_proxy_maker("ssh", conn_id) pi, err = s.wpx_foreign_port_proxy_maker("ssh", conn_id)
if err != nil { if err != nil {
pxy.send_ws_data(ws, "error", err.Error()) pxy.send_ws_data(ws, "error", err.Error())
goto done goto done
@ -710,14 +713,14 @@ func (pxy *server_pxy_ssh_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
n, err = out.Read(buf) n, err = out.Read(buf)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
s.log.Write(pxy.id, LOG_ERROR, "Read from SSH stdout error - %s", err.Error()) s.log.Write(pxy.Id, LOG_ERROR, "Read from SSH stdout error - %s", err.Error())
} }
break break
} }
if n > 0 { if n > 0 {
err = pxy.send_ws_data(ws, "iov", string(buf[:n])) err = pxy.send_ws_data(ws, "iov", string(buf[:n]))
if err != nil { if err != nil {
s.log.Write(pxy.id, LOG_ERROR, "Failed to send to websocket - %s", err.Error()) s.log.Write(pxy.Id, LOG_ERROR, "Failed to send to websocket - %s", err.Error())
break break
} }
} }
@ -754,13 +757,13 @@ ws_recv_loop:
defer wg.Done() defer wg.Done()
c, sess, in, out, err = pxy.connect_ssh(connect_ssh_ctx, username, password, r) c, sess, in, out, err = pxy.connect_ssh(connect_ssh_ctx, username, password, r)
if err != nil { if err != nil {
s.log.Write(pxy.id, LOG_ERROR, "failed to connect ssh - %s", err.Error()) s.log.Write(pxy.Id, LOG_ERROR, "failed to connect ssh - %s", err.Error())
pxy.send_ws_data(ws, "error", err.Error()) pxy.send_ws_data(ws, "error", err.Error())
ws.Close() // dirty way to flag out the error ws.Close() // dirty way to flag out the error
} else { } else {
err = pxy.send_ws_data(ws, "status", "opened") err = pxy.send_ws_data(ws, "status", "opened")
if err != nil { if err != nil {
s.log.Write(pxy.id, LOG_ERROR, "Failed to write opened event to websocket - %s", err.Error()) s.log.Write(pxy.Id, LOG_ERROR, "Failed to write opened event to websocket - %s", err.Error())
ws.Close() // dirty way to flag out the error ws.Close() // dirty way to flag out the error
} else { } else {
conn_ready_chan <- true conn_ready_chan <- true
@ -792,7 +795,7 @@ ws_recv_loop:
rows, _ = strconv.Atoi(ev.Data[0]) rows, _ = strconv.Atoi(ev.Data[0])
cols, _ = strconv.Atoi(ev.Data[1]) cols, _ = strconv.Atoi(ev.Data[1])
sess.WindowChange(rows, cols) sess.WindowChange(rows, cols)
s.log.Write(pxy.id, LOG_DEBUG, "Resized terminal to %d,%d", rows, cols) s.log.Write(pxy.Id, LOG_DEBUG, "Resized terminal to %d,%d", rows, cols)
// ignore error // ignore error
} }
} }

121
server.go
View File

@ -1153,14 +1153,14 @@ func (hlw *server_http_log_writer) Write(p []byte) (n int, err error) {
} }
type ServerHttpHandler interface { type ServerHttpHandler interface {
Id() string Identity() string
Cors(req *http.Request) bool Cors(req *http.Request) bool
Authenticate(req *http.Request) (int, string) Authenticate(req *http.Request) (int, string)
ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error)
} }
type ServerWebsocketHandler interface { type ServerWebsocketHandler interface {
Id() string Identity() string
ServeWebsocket(ws *websocket.Conn) (int, error) ServeWebsocket(ws *websocket.Conn) (int, error)
} }
@ -1208,9 +1208,9 @@ func (s *Server) WrapHttpHandler(handler ServerHttpHandler) http.Handler {
if status_code > 0 { if status_code > 0 {
if err != nil { if err != nil {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
} else { } else {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
} }
} }
}) })
@ -1225,7 +1225,7 @@ func (s *Server) WrapWebsocketHandler(handler ServerWebsocketHandler) websocket.
var req *http.Request var req *http.Request
req = ws.Request() req = ws.Request()
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws]", req.RemoteAddr, req.Method, req.URL.String()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws]", req.RemoteAddr, req.Method, req.URL.String())
start_time = time.Now() start_time = time.Now()
status_code, err = handler.ServeWebsocket(ws) status_code, err = handler.ServeWebsocket(ws)
@ -1233,9 +1233,9 @@ func (s *Server) WrapWebsocketHandler(handler ServerWebsocketHandler) websocket.
if status_code > 0 { if status_code > 0 {
if err != nil { if err != nil {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws] %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws] %d %.9f - %s", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds(), err.Error())
} else { } else {
s.log.Write(handler.Id(), LOG_INFO, "[%s] %s %s [ws] %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds()) s.log.Write(handler.Identity(), LOG_INFO, "[%s] %s %s [ws] %d %.9f", req.RemoteAddr, req.Method, req.URL.String(), status_code, time_taken.Seconds())
} }
} }
}) })
@ -1305,31 +1305,31 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi
s.ctl_mux = http.NewServeMux() s.ctl_mux = http.NewServeMux()
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns",
s.WrapHttpHandler(&server_ctl_server_conns{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}",
s.WrapHttpHandler(&server_ctl_server_conns_id{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes",
s.WrapHttpHandler(&server_ctl_server_conns_id_routes{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id_routes{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}",
s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}/peers", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}/peers",
s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id_peers{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id_peers{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}/peers/{peer_id}", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/routes/{route_id}/peers/{peer_id}",
s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id_peers_id{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id_routes_id_peers_id{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/peers", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-conns/{conn_id}/peers",
s.WrapHttpHandler(&server_ctl_server_conns_id_peers{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_conns_id_peers{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-routes", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-routes",
s.WrapHttpHandler(&server_ctl_server_routes{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_routes{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-peers", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/server-peers",
s.WrapHttpHandler(&server_ctl_server_peers{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_server_peers{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/notices", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/notices",
s.WrapHttpHandler(&server_ctl_notices{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_notices{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/notices/{conn_id}", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/notices/{conn_id}",
s.WrapHttpHandler(&server_ctl_notices_id{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_notices_id{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/stats", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/stats",
s.WrapHttpHandler(&server_ctl_stats{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_stats{ServerCtl{S: &s, Id: HS_ID_CTL}}))
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/token", s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl/token",
s.WrapHttpHandler(&server_ctl_token{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapHttpHandler(&server_ctl_token{ServerCtl{S: &s, Id: HS_ID_CTL}}))
// TODO: make this optional. add this endpoint only if it's enabled... // TODO: make this optional. add this endpoint only if it's enabled...
s.promreg = prometheus.NewRegistry() s.promreg = prometheus.NewRegistry()
@ -1339,7 +1339,36 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi
promhttp.HandlerFor(s.promreg, promhttp.HandlerOpts{ EnableOpenMetrics: true })) promhttp.HandlerFor(s.promreg, promhttp.HandlerOpts{ EnableOpenMetrics: true }))
s.ctl_mux.Handle("/_ctl/events", s.ctl_mux.Handle("/_ctl/events",
s.WrapWebsocketHandler(&server_ctl_ws{server_ctl{s: &s, id: HS_ID_CTL}})) s.WrapWebsocketHandler(&server_ctl_ws{ServerCtl{S: &s, Id: HS_ID_CTL}}))
// this part is duplcate of pxy_mux.
s.ctl_mux.Handle("/_ssh-ws/{conn_id}/{route_id}",
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)) s.ctl = make([]*http.Server, len(cfg.CtlAddrs))
for i = 0; i < len(cfg.CtlAddrs); i++ { for i = 0; i < len(cfg.CtlAddrs); i++ {
@ -1356,32 +1385,32 @@ 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 = http.NewServeMux() // TODO: make /_init,_ssh,_ssh_ws,_http configurable...
s.pxy_mux.Handle("/_ssh-ws/{conn_id}/{route_id}", s.pxy_mux.Handle("/_ssh-ws/{conn_id}/{route_id}",
s.WrapWebsocketHandler(&server_pxy_ssh_ws{s: &s, id: HS_ID_PXY_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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "xterm.html"}))
s.pxy_mux.Handle("/_ssh/", s.pxy_mux.Handle("/_ssh/",
s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{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.pxy_mux.Handle("/favicon.ico",
s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{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.pxy_mux.Handle("/favicon.ico/",
s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{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.pxy_mux.Handle("/_http/{conn_id}/{route_id}/{trailer...}",
s.WrapHttpHandler(&server_pxy_http_main{server_pxy: server_pxy{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)) s.pxy = make([]*http.Server, len(cfg.PxyAddrs))
@ -1401,25 +1430,25 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi
s.wpx_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh_ws,_http configurable... s.wpx_mux = http.NewServeMux() // TODO: make /_init,_ssh,_ssh_ws,_http configurable...
s.wpx_mux.Handle("/_ssh-ws/{conn_id}/{route_id}", s.wpx_mux.Handle("/_ssh-ws/{conn_id}/{route_id}",
s.WrapWebsocketHandler(&server_pxy_ssh_ws{s: &s, id: "wpx-ssh"})) s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: "wpx-ssh"}))
s.wpx_mux.Handle("/_ssh/server-conns/{conn_id}/routes/{route_id}", 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.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.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.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.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.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.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.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.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "xterm.html"}))
s.wpx_mux.Handle("/_ssh/", s.wpx_mux.Handle("/_ssh/",
s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{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.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.WrapHttpHandler(&server_pxy_http_main{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, prefix: PORT_ID_MARKER}))
s.wpx_mux.Handle("/", s.wpx_mux.Handle("/",
s.WrapHttpHandler(&server_pxy_http_wpx{server_pxy: server_pxy{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)) s.wpx = make([]*http.Server, len(cfg.WpxAddrs))
@ -2081,9 +2110,15 @@ func (s *Server) SetConnNoticeHandlers(handlers []ServerConnNoticeHandler) {
} }
func (s *Server) AddCtlHandler(path string, handler ServerHttpHandler) { func (s *Server) AddCtlHandler(path string, handler ServerHttpHandler) {
// parked under /_ctl
s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl" + path, s.WrapHttpHandler(handler)) s.ctl_mux.Handle(s.Cfg.CtlPrefix + "/_ctl" + path, s.WrapHttpHandler(handler))
} }
func (s *Server) AddCtlRootHandler(path string, handler ServerHttpHandler) {
// parked at the root level. must avoid conflicting path
s.ctl_mux.Handle(s.Cfg.CtlPrefix + path, s.WrapHttpHandler(handler))
}
func (s *Server) AddCtlMetricsCollector(col prometheus.Collector) error { func (s *Server) AddCtlMetricsCollector(col prometheus.Collector) error {
return s.promreg.Register(col) return s.promreg.Register(col)
} }