package api import ( "net/http" "os" "path/filepath" "strings" ) // MountStatic serves files from dir under baseURL. If baseURL == "/", it serves root. // Directory listings are disabled. Unknown paths fall back to index.html (SPA). func (s *Server) MountStatic(dir string, baseURL string) { if dir == "" { return } if baseURL == "" { baseURL = "/" } fs := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.secureHeaders(w) // normalize path inside dir up := strings.TrimPrefix(r.URL.Path, baseURL) if up == "" || strings.HasSuffix(r.URL.Path, "/") { up = "index.html" } full := filepath.Join(dir, filepath.FromSlash(up)) // prevent path escape if !strings.HasPrefix(filepath.Clean(full), filepath.Clean(dir)) { http.NotFound(w, r) return } // serve if exists, else SPA fallback if st, err := os.Stat(full); err == nil && !st.IsDir() { http.ServeFile(w, r, full) return } fallback := filepath.Join(dir, "index.html") if _, err := os.Stat(fallback); err == nil { http.ServeFile(w, r, fallback) return } http.NotFound(w, r) }) // Root or subpath if baseURL == "/" { s.mux.Handle("/", fs) } else { if !strings.HasSuffix(baseURL, "/") { baseURL += "/" } s.mux.Handle(baseURL, fs) s.mux.Handle(baseURL+"", fs) // ensure exact mount works } }