mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-07 04:00:17 -06:00
Serve dir listing
This commit is contained in:
@@ -6,11 +6,53 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var htmlReplacer = strings.NewReplacer(
|
||||
"&", "&",
|
||||
"<", "<",
|
||||
">", ">",
|
||||
// """ is shorter than """.
|
||||
`"`, """,
|
||||
// "'" is shorter than "'" and apos was not in HTML until HTML5.
|
||||
"'", "'",
|
||||
)
|
||||
|
||||
func serveCollection(w http.ResponseWriter, r *http.Request, ri ResourceInfo) {
|
||||
if checkIfModifiedSince(r, ri) == condFalse {
|
||||
writeNotModified(w)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Last-Modified", ri.ModTime().Format(http.TimeFormat))
|
||||
|
||||
files, err := ri.Readdir(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "Error reading directory", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sort.Slice(files, func(i, j int) bool { return files[i].Name() < files[j].Name() })
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
fmt.Fprintf(w, "<pre>\n")
|
||||
for _, f := range files {
|
||||
name := f.Name()
|
||||
if f.IsDir() {
|
||||
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")
|
||||
}
|
||||
|
||||
func serveResource(w http.ResponseWriter, r *http.Request, ri ResourceInfo) {
|
||||
w.Header().Set("Etag", ri.ETag())
|
||||
w.Header().Set("Last-Modified", ri.ModTime().Format(http.TimeFormat))
|
||||
@@ -52,6 +94,11 @@ func serveResource(w http.ResponseWriter, r *http.Request, ri ResourceInfo) {
|
||||
reader, err = ri.OpenRead(r.Context(), 0, -1)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
|
||||
w.WriteHeader(code)
|
||||
@@ -70,13 +117,6 @@ func (r httpRange) contentRange(size int64) string {
|
||||
return fmt.Sprintf("bytes %d-%d/%d", r.start, r.start+r.length-1, size)
|
||||
}
|
||||
|
||||
func (r httpRange) mimeHeader(contentType string, size int64) textproto.MIMEHeader {
|
||||
return textproto.MIMEHeader{
|
||||
"Content-Range": {r.contentRange(size)},
|
||||
"Content-Type": {contentType},
|
||||
}
|
||||
}
|
||||
|
||||
// parseRange parses a Range header string as per RFC 7233.
|
||||
// errNoOverlap is returned if none of the ranges overlap.
|
||||
func parseRange(s string, size int64) ([]httpRange, error) {
|
||||
|
||||
@@ -204,10 +204,11 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return http.StatusMethodNotAllowed, nil
|
||||
serveCollection(w, r, fi)
|
||||
} else {
|
||||
serveResource(w, r, fi)
|
||||
}
|
||||
|
||||
serveResource(w, r, fi)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user