chore: refactor rest file server (#4851)

Signed-off-by: kevin <wanjunfeng@gmail.com>
This commit is contained in:
Kevin Wan
2025-05-11 12:44:43 +08:00
committed by GitHub
parent 5564c43197
commit 2e91ba5811

View File

@@ -2,16 +2,16 @@ package fileserver
import ( import (
"net/http" "net/http"
pathpkg "path" "path"
"strings" "strings"
"sync" "sync"
) )
// Middleware returns a middleware that serves files from the given file system. // Middleware returns a middleware that serves files from the given file system.
func Middleware(path string, fs http.FileSystem) func(http.HandlerFunc) http.HandlerFunc { func Middleware(upath string, fs http.FileSystem) func(http.HandlerFunc) http.HandlerFunc {
fileServer := http.FileServer(fs) fileServer := http.FileServer(fs)
pathWithoutTrailSlash := ensureNoTrailingSlash(path) pathWithoutTrailSlash := ensureNoTrailingSlash(upath)
canServe := createServeChecker(path, fs) canServe := createServeChecker(upath, fs)
return func(next http.HandlerFunc) http.HandlerFunc { return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
@@ -29,7 +29,7 @@ func createFileChecker(fs http.FileSystem) func(string) bool {
var lock sync.RWMutex var lock sync.RWMutex
fileChecker := make(map[string]bool) fileChecker := make(map[string]bool)
return func(path string) bool { return func(upath string) bool {
// Emulate http.Dir.Opens path normalization for embed.FS.Open. // Emulate http.Dir.Opens path normalization for embed.FS.Open.
// http.FileServer redirects any request ending in "/index.html" // http.FileServer redirects any request ending in "/index.html"
// to the same path without the final "index.html". // to the same path without the final "index.html".
@@ -37,13 +37,14 @@ func createFileChecker(fs http.FileSystem) func(string) bool {
// http.Dir.Open uses this logic to clean the path, // http.Dir.Open uses this logic to clean the path,
// correctly handling those two cases. // correctly handling those two cases.
// embed.FS doesnt perform this normalization, so we apply the same logic here. // embed.FS doesnt perform this normalization, so we apply the same logic here.
path = pathpkg.Clean("/" + path)[1:] upath = path.Clean("/" + upath)[1:]
if path == "" { if len(upath) == 0 {
path = "." // if the path is empty, we use "." to open the current directory
upath = "."
} }
lock.RLock() lock.RLock()
exist, ok := fileChecker[path] exist, ok := fileChecker[upath]
lock.RUnlock() lock.RUnlock()
if ok { if ok {
return exist return exist
@@ -52,9 +53,9 @@ func createFileChecker(fs http.FileSystem) func(string) bool {
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
file, err := fs.Open(path) file, err := fs.Open(upath)
exist = err == nil exist = err == nil
fileChecker[path] = exist fileChecker[upath] = exist
if err != nil { if err != nil {
return false return false
} }
@@ -64,8 +65,8 @@ func createFileChecker(fs http.FileSystem) func(string) bool {
} }
} }
func createServeChecker(path string, fs http.FileSystem) func(r *http.Request) bool { func createServeChecker(upath string, fs http.FileSystem) func(r *http.Request) bool {
pathWithTrailSlash := ensureTrailingSlash(path) pathWithTrailSlash := ensureTrailingSlash(upath)
fileChecker := createFileChecker(fs) fileChecker := createFileChecker(fs)
return func(r *http.Request) bool { return func(r *http.Request) bool {
@@ -75,18 +76,18 @@ func createServeChecker(path string, fs http.FileSystem) func(r *http.Request) b
} }
} }
func ensureTrailingSlash(path string) string { func ensureTrailingSlash(upath string) string {
if strings.HasSuffix(path, "/") { if strings.HasSuffix(upath, "/") {
return path return upath
} }
return path + "/" return upath + "/"
} }
func ensureNoTrailingSlash(path string) string { func ensureNoTrailingSlash(upath string) string {
if strings.HasSuffix(path, "/") { if strings.HasSuffix(upath, "/") {
return path[:len(path)-1] return upath[:len(upath)-1]
} }
return path return upath
} }