mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-02-03 00:38:40 +08:00
80 lines
1.7 KiB
Go
80 lines
1.7 KiB
Go
package fileserver
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// Middleware returns a middleware that serves files from the given file system.
|
|
func Middleware(path string, fs http.FileSystem) func(http.HandlerFunc) http.HandlerFunc {
|
|
fileServer := http.FileServer(fs)
|
|
pathWithoutTrailSlash := ensureNoTrailingSlash(path)
|
|
canServe := createServeChecker(path, fs)
|
|
|
|
return func(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if canServe(r) {
|
|
r.URL.Path = r.URL.Path[len(pathWithoutTrailSlash):]
|
|
fileServer.ServeHTTP(w, r)
|
|
} else {
|
|
next(w, r)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func createFileChecker(fs http.FileSystem) func(string) bool {
|
|
var lock sync.RWMutex
|
|
fileChecker := make(map[string]bool)
|
|
|
|
return func(path string) bool {
|
|
lock.RLock()
|
|
exist, ok := fileChecker[path]
|
|
lock.RUnlock()
|
|
if ok {
|
|
return exist
|
|
}
|
|
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
|
|
file, err := fs.Open(path)
|
|
exist = err == nil
|
|
fileChecker[path] = exist
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
_ = file.Close()
|
|
return true
|
|
}
|
|
}
|
|
|
|
func createServeChecker(path string, fs http.FileSystem) func(r *http.Request) bool {
|
|
pathWithTrailSlash := ensureTrailingSlash(path)
|
|
fileChecker := createFileChecker(fs)
|
|
|
|
return func(r *http.Request) bool {
|
|
return r.Method == http.MethodGet &&
|
|
strings.HasPrefix(r.URL.Path, pathWithTrailSlash) &&
|
|
fileChecker(r.URL.Path[len(pathWithTrailSlash):])
|
|
}
|
|
}
|
|
|
|
func ensureTrailingSlash(path string) string {
|
|
if strings.HasSuffix(path, "/") {
|
|
return path
|
|
}
|
|
|
|
return path + "/"
|
|
}
|
|
|
|
func ensureNoTrailingSlash(path string) string {
|
|
if strings.HasSuffix(path, "/") {
|
|
return path[:len(path)-1]
|
|
}
|
|
|
|
return path
|
|
}
|