package fileserver import ( "fmt" "html/template" "io" "net/http" "path/filepath" "strings" ) type DirEntry struct { Name string FullName string Size int IsDir bool } func (d DirEntry) Si() string { if d.IsDir { return "" } f := float64(d.Size) i := 0 for f > 1024 { f /= 1024 i++ } s := fmt.Sprintf("%.2f", f) s = strings.TrimRight(s, ".0") return fmt.Sprintf("%s %cB", s, " KMGTPEZY"[i]) } type TemplateData struct { Path string Dirs []DirEntry Items []DirEntry } var Temp *template.Template func FillTemp(w io.Writer, path string, items []DirEntry) error { var data = TemplateData{Path: path, Dirs: []DirEntry{}, Items: []DirEntry{}} for _, item := range items { if item.IsDir { data.Dirs = append(data.Dirs, item) } else { data.Items = append(data.Items, item) } } return Temp.ExecuteTemplate(w, "index", data) } func init() { Temp = template.New("index") Temp.Parse(`{{ define "index" }} {{ .Path }}

Index of: {{.Path}}

{{ range .Dirs }}
{{ .Name }}{{ .Si }}
{{ end }} {{ range .Items }}
{{ .Name }}{{ .Si }}
{{ end }}
{{ end }}`) } func Handler(prefix string, dir func(string) ([]byte, []DirEntry, error)) (string, http.Handler) { return prefix, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, items, err := dir(strings.TrimPrefix(r.URL.Path, prefix)) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } w.WriteHeader(http.StatusOK) if data != nil { w.Write(data) return } items = append([]DirEntry{{ Name: "../", FullName: filepath.Dir(strings.TrimSuffix(r.URL.Path, "/")), Size: 0, IsDir: true, }}, items...) err = FillTemp(w, r.URL.Path, items) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) } func Handle(prefix string, dir func(string) ([]byte, []DirEntry, error)) { http.Handle(Handler(prefix, dir)) }