diff --git a/client-pts.go b/client-pts.go index e39851e..12b25c5 100644 --- a/client-pts.go +++ b/client-pts.go @@ -9,6 +9,7 @@ import "os" import "os/exec" import "os/user" import "strconv" +import "strings" import "sync" import "syscall" import "text/template" @@ -306,6 +307,7 @@ func (pts *client_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req }) } + case "_forbidden": status_code = WriteEmptyRespHeader(w, http.StatusForbidden) @@ -313,7 +315,13 @@ func (pts *client_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteEmptyRespHeader(w, http.StatusNotFound) default: - status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + if strings.HasPrefix(pts.file, "_redir:") { + status_code = http.StatusMovedPermanently + w.Header().Set("Location", pts.file[7:]) + w.WriteHeader(status_code) + } else { + status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + } } //done: diff --git a/client.go b/client.go index 0c8a798..329139d 100644 --- a/client.go +++ b/client.go @@ -1652,14 +1652,22 @@ 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/", + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) 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/", + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) 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.css/", + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) 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/xterm.html/", // without this forbidden, /_pts/xterm.js/ access resulted in xterm.html. + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_forbidden"})) c.ctl_mux.Handle("/_pts/", - c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "xterm.html"})) + c.WrapHttpHandler(&client_pts_xterm_file{client_ctl: client_ctl{c: &c, id: HS_ID_CTL}, file: "_redir:xterm.html"})) c.ctl_addr = make([]string, len(cfg.CtlAddrs)) c.ctl = make([]*http.Server, len(cfg.CtlAddrs)) diff --git a/server-pts.go b/server-pts.go index 6187138..c84dd50 100644 --- a/server-pts.go +++ b/server-pts.go @@ -9,6 +9,7 @@ import "os" import "os/exec" import "os/user" import "strconv" +import "strings" import "sync" import "syscall" import "text/template" @@ -313,7 +314,13 @@ func (pts *server_pts_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteEmptyRespHeader(w, http.StatusNotFound) default: - status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + if strings.HasPrefix(pts.file, "_redir:") { + status_code = http.StatusMovedPermanently + w.Header().Set("Location", pts.file[7:]) + w.WriteHeader(status_code) + } else { + status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + } } //done: diff --git a/server-pxy.go b/server-pxy.go index 0b79ffc..34fca19 100644 --- a/server-pxy.go +++ b/server-pxy.go @@ -525,7 +525,6 @@ func (pxy *server_pxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req w.Header().Set("Location", req.URL.Path + "_/") w.WriteHeader(status_code) - case "_forbidden": status_code = WriteEmptyRespHeader(w, http.StatusForbidden) @@ -533,7 +532,13 @@ func (pxy *server_pxy_xterm_file) ServeHTTP(w http.ResponseWriter, req *http.Req status_code = WriteEmptyRespHeader(w, http.StatusNotFound) default: - status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + if strings.HasPrefix(pxy.file, "_redir:") { + status_code = http.StatusMovedPermanently + w.Header().Set("Location", pxy.file[7:]) + w.WriteHeader(status_code) + } else { + status_code = WriteEmptyRespHeader(w, http.StatusNotFound) + } } //done: diff --git a/server.go b/server.go index 59b4148..a9c3cd1 100644 --- a/server.go +++ b/server.go @@ -1382,7 +1382,6 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi s.ctl_mux.Handle("/_pts/ws", s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pts_ws{S: &s, Id: HS_ID_CTL}))) - 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-addon-fit.js", @@ -1392,7 +1391,7 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi 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: "xterm.html"})) + s.WrapHttpHandler(&server_pts_xterm_file{ServerCtl: ServerCtl{S: &s, Id: HS_ID_CTL}, file: "_redir:xterm.html"})) s.ctl = make([]*http.Server, len(cfg.CtlAddrs)) for i = 0; i < len(cfg.CtlAddrs); i++ { @@ -1413,15 +1412,23 @@ func NewServer(ctx context.Context, name string, logger Logger, cfg *ServerConfi 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.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_redir: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.html/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_forbidden"})) 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.css/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_forbidden"})) 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.js/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_forbidden"})) 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}/xterm-addon-fit.js/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_PXY}, file: "_forbidden"})) s.pxy_mux.Handle("/_ssh/{conn_id}/{route_id}/ws", s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: HS_ID_PXY}))) @@ -1455,15 +1462,23 @@ 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.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: "_redir: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.html/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "_forbidden"})) 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.css/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "_forbidden"})) 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.js/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "_forbidden"})) 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}/xterm-addon-fit.js/", + s.WrapHttpHandler(&server_pxy_xterm_file{server_pxy: server_pxy{S: &s, Id: HS_ID_WPX}, file: "_forbidden"})) s.wpx_mux.Handle("/_ssh/{port_id}/ws", s.SafeWrapWebsocketHandler(s.WrapWebsocketHandler(&server_pxy_ssh_ws{S: &s, Id: HS_ID_WPX})))