mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
//
|
|
// dir_render.go
|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
// 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, "<!doctype html>\n")
|
|
fmt.Fprintf(w, "<meta name=\"viewport\" content=\"width=device-width\">\n")
|
|
fmt.Fprintf(w, "<pre>\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, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
|
|
}
|
|
fmt.Fprintf(w, "</pre>\n")
|
|
}
|
|
|
|
var htmlReplacer = strings.NewReplacer(
|
|
"&", "&",
|
|
"<", "<",
|
|
">", ">",
|
|
// """ is shorter than """.
|
|
`"`, """,
|
|
// "'" is shorter than "'" and apos was not in HTML until HTML5.
|
|
"'", "'",
|
|
)
|