@ -58,7 +58,7 @@ type Server struct {
devProxy * httputil . ReverseProxy // only filled when devMode is on
devProxy * httputil . ReverseProxy // only filled when devMode is on
cgiMode bool
cgiMode bool
cgiPath string
pathPrefix string
apiHandler http . Handler // csrf-protected api handler
apiHandler http . Handler // csrf-protected api handler
}
}
@ -69,8 +69,8 @@ type ServerOpts struct {
// CGIMode indicates if the server is running as a CGI script.
// CGIMode indicates if the server is running as a CGI script.
CGIMode bool
CGIMode bool
// If running in CGIMode, CGIPath is the URL path prefix to the CGI script .
// PathPrefix is the URL prefix added to requests by CGI or reverse proxy .
CGI Path string
PathPrefix string
// LocalClient is the tailscale.LocalClient to use for this web server.
// LocalClient is the tailscale.LocalClient to use for this web server.
// If nil, a new one will be created.
// If nil, a new one will be created.
@ -87,7 +87,7 @@ func NewServer(ctx context.Context, opts ServerOpts) (s *Server, cleanup func())
devMode : opts . DevMode ,
devMode : opts . DevMode ,
lc : opts . LocalClient ,
lc : opts . LocalClient ,
cgiMode : opts . CGIMode ,
cgiMode : opts . CGIMode ,
cgiPath: opts . CGIPath ,
pathPrefix: opts . PathPrefix ,
}
}
cleanup = func ( ) { }
cleanup = func ( ) { }
if s . devMode {
if s . devMode {
@ -116,20 +116,9 @@ func init() {
func ( s * Server ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
func ( s * Server ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
handler := s . serve
handler := s . serve
// if running in cgi mode, strip the cgi path prefix
// if path prefix is defined, strip it from requests.
if s . cgiMode {
if s . pathPrefix != "" {
prefix := s . cgiPath
handler = enforcePrefix ( s . pathPrefix , handler )
if prefix == "" {
switch distro . Get ( ) {
case distro . Synology :
prefix = synologyPrefix
case distro . QNAP :
prefix = qnapPrefix
}
}
if prefix != "" {
handler = enforcePrefix ( prefix , handler )
}
}
}
handler ( w , r )
handler ( w , r )
@ -334,7 +323,6 @@ func (s *Server) servePostNodeUpdate(w http.ResponseWriter, r *http.Request) {
} else {
} else {
io . WriteString ( w , "{}" )
io . WriteString ( w , "{}" )
}
}
return
}
}
func ( s * Server ) tailscaleUp ( ctx context . Context , st * ipnstate . Status , postData nodeUpdate ) ( authURL string , retErr error ) {
func ( s * Server ) tailscaleUp ( ctx context . Context , st * ipnstate . Status , postData nodeUpdate ) ( authURL string , retErr error ) {
@ -487,6 +475,19 @@ func (s *Server) csrfKey() []byte {
// Unlike http.StripPrefix, it does not return a 404 if the prefix is not present.
// Unlike http.StripPrefix, it does not return a 404 if the prefix is not present.
// Instead, it returns a redirect to the prefix path.
// Instead, it returns a redirect to the prefix path.
func enforcePrefix ( prefix string , h http . HandlerFunc ) http . HandlerFunc {
func enforcePrefix ( prefix string , h http . HandlerFunc ) http . HandlerFunc {
if prefix == "" {
return h
}
// ensure that prefix always has both a leading and trailing slash so
// that relative links for JS and CSS assets work correctly.
if ! strings . HasPrefix ( prefix , "/" ) {
prefix = "/" + prefix
}
if ! strings . HasSuffix ( prefix , "/" ) {
prefix += "/"
}
return func ( w http . ResponseWriter , r * http . Request ) {
return func ( w http . ResponseWriter , r * http . Request ) {
if ! strings . HasPrefix ( r . URL . Path , prefix ) {
if ! strings . HasPrefix ( r . URL . Path , prefix ) {
http . Redirect ( w , r , prefix , http . StatusFound )
http . Redirect ( w , r , prefix , http . StatusFound )