// // dir_render.go // Copyright (C) 2024 veypi // 2024-10-18 19:35 // Distributed under terms of the GPL license. // package webdav import ( "fmt" "io/fs" "net/http" "net/url" "sort" "strings" "github.com/veypi/utils/logv" ) type anyDirs interface { len() int name(i int) string isDir(i int) bool } type fileInfoDirs []fs.FileInfo func (d fileInfoDirs) len() int { return len(d) } func (d fileInfoDirs) isDir(i int) bool { return d[i].IsDir() } func (d fileInfoDirs) name(i int) string { return d[i].Name() } type dirEntryDirs []fs.DirEntry func (d dirEntryDirs) len() int { return len(d) } func (d dirEntryDirs) isDir(i int) bool { return d[i].IsDir() } func (d dirEntryDirs) name(i int) string { return d[i].Name() } func dirList(w http.ResponseWriter, r *http.Request, f File) { // Prefer to use ReadDir instead of Readdir, // because the former doesn't require calling // Stat on every entry of a directory on Unix. var dirs anyDirs var err error if d, ok := f.(fs.ReadDirFile); ok { var list dirEntryDirs list, err = d.ReadDir(-1) dirs = list } else { var list fileInfoDirs list, err = f.Readdir(-1) dirs = list } if err != nil { logv.Warn().Msgf("http: error reading directory: %v", err) http.Error(w, "Error reading directory", http.StatusInternalServerError) return } sort.Slice(dirs, func(i, j int) bool { return dirs.name(i) < dirs.name(j) }) w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprintf(w, "\n") fmt.Fprintf(w, "\n") fmt.Fprintf(w, "
\n")
	for i, n := 0, dirs.len(); i < n; i++ {
		name := dirs.name(i)
		if dirs.isDir(i) {
			name += "/"
		}
		// name may contain '?' or '#', which must be escaped to remain
		// part of the URL path, and not indicate the start of a query
		// string or fragment.
		url := url.URL{Path: name}
		fmt.Fprintf(w, "%s\n", url.String(), htmlReplacer.Replace(name))
	}
	fmt.Fprintf(w, "
\n") } var htmlReplacer = strings.NewReplacer( "&", "&", "<", "<", ">", ">", // """ is shorter than """. `"`, """, // "'" is shorter than "'" and apos was not in HTML until HTML5. "'", "'", )