Files
epusdt/src/util/http/spa.go
T
line-6000 3a3a830d93 fix(server): prevent SPA fallback from swallowing API routes
- add ShouldSkipSPAFallback() deny prefixes: /api, /admin/api, /payments, /pay
- apply StaticWithConfig Skipper in both main http server and install server
- add unit tests for fallback skip matching behavior
2026-04-22 20:27:34 +08:00

50 lines
1.3 KiB
Go

package http
import (
"os"
"path/filepath"
"strings"
)
var spaFallbackDenyPrefixes = []string{
"/api",
"/admin/api",
"/payments",
"/pay",
}
// ShouldSkipSPAFallback reports whether a request path should bypass
// server-side SPA fallback to index.html and continue normal backend routing.
func ShouldSkipSPAFallback(requestPath string) bool {
for _, prefix := range spaFallbackDenyPrefixes {
if requestPath == prefix || strings.HasPrefix(requestPath, prefix+"/") {
return true
}
}
return false
}
// ResolveSPAFilePath normalizes a wildcard SPA path and maps it under wwwRoot.
// It strips any leading slash and blocks path traversal outside wwwRoot.
// The second return value indicates whether the caller should try os.Stat
// against the returned path (true) or directly fall back to index.html (false).
func ResolveSPAFilePath(wwwRoot, wildcard string) (string, bool) {
indexPath := filepath.Join(wwwRoot, "index.html")
cleaned := strings.TrimPrefix(filepath.Clean(wildcard), "/")
if cleaned == "" || cleaned == "." {
return indexPath, false
}
requestedPath := filepath.Join(wwwRoot, cleaned)
base := filepath.Clean(wwwRoot)
resolved := filepath.Clean(requestedPath)
if resolved != base && !strings.HasPrefix(resolved, base+string(os.PathSeparator)) {
return indexPath, false
}
return requestedPath, true
}