package handler import ( "errors" "io/fs" "net/http" "os" "path/filepath" "strings" ) type FileHandler struct { Root string Default string http.FileSystem } func (f FileHandler) Open(name string) (http.File, error) { if strings.HasPrefix(name, "../") { return nil, errors.New("not permitted") } rPath := filepath.Join(f.Root, strings.TrimPrefix(name, "/")) if rPath == f.Root { if f.Default == "" { return nil, errors.New("not permit list dir") } rPath = filepath.Join(rPath, f.Default) } fInfo, _, err := FileExists(rPath) if err != nil { return nil, err } if fInfo.IsDir() { return nil, errors.New("not permit list dir") } if fInfo.Mode() == fs.ModeSymlink { return nil, errors.New("not permit follow symbol link") } return os.Open(rPath) } func FileExists(name string) (os.FileInfo, bool, error) { info, err := os.Stat(name) if err != nil { return nil, os.IsExist(err), err } return info, true, nil } func NewFileHandler(f FileHandler) http.Handler { return http.FileServer(f) }