Implemented symlinks and mimetype for serve
This commit is contained in:
parent
523e519a3b
commit
605dc5352c
5 changed files with 81 additions and 16 deletions
71
server.go
71
server.go
|
|
@ -5,6 +5,7 @@ import (
|
|||
_ "embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -30,6 +31,7 @@ type server struct {
|
|||
rootReal string // symlink-resolved root, used for containment checks
|
||||
hidden bool
|
||||
footer string
|
||||
follow bool // serve symlinks even when they point outside root
|
||||
tpl *template.Template
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +45,7 @@ func newServer(cfg *Config) *server {
|
|||
rootReal: rootReal,
|
||||
hidden: cfg.Hidden,
|
||||
footer: cfg.Footer,
|
||||
follow: cfg.FollowSymlinks,
|
||||
tpl: template.Must(template.New("index").Parse(indexHTML)),
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +114,7 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if realPath != s.rootReal && !strings.HasPrefix(realPath, s.rootReal+string(os.PathSeparator)) {
|
||||
if !s.follow && realPath != s.rootReal && !strings.HasPrefix(realPath, s.rootReal+string(os.PathSeparator)) {
|
||||
http.NotFound(w, r) // symlink escaping the served root
|
||||
return
|
||||
}
|
||||
|
|
@ -147,11 +150,48 @@ func (s *server) serveFile(w http.ResponseWriter, r *http.Request, path, name st
|
|||
return
|
||||
}
|
||||
defer f.Close()
|
||||
disp := "attachment"
|
||||
if inlineFile(f, name) {
|
||||
disp = "inline"
|
||||
}
|
||||
w.Header().Set("Content-Disposition",
|
||||
mime.FormatMediaType("attachment", map[string]string{"filename": name}))
|
||||
mime.FormatMediaType(disp, map[string]string{"filename": name}))
|
||||
http.ServeContent(w, r, name, info.ModTime(), f)
|
||||
}
|
||||
|
||||
func inlineFile(f *os.File, name string) bool {
|
||||
if ct := mime.TypeByExtension(strings.ToLower(filepath.Ext(name))); ct != "" {
|
||||
return inlineMIME(ct)
|
||||
}
|
||||
buf := make([]byte, 512)
|
||||
n, err := f.Read(buf)
|
||||
if _, serr := f.Seek(0, io.SeekStart); serr != nil {
|
||||
return false
|
||||
}
|
||||
if err != nil && err != io.EOF {
|
||||
return false
|
||||
}
|
||||
return inlineMIME(http.DetectContentType(buf[:n]))
|
||||
}
|
||||
|
||||
func inlineMIME(ct string) bool {
|
||||
if i := strings.IndexByte(ct, ';'); i >= 0 {
|
||||
ct = strings.TrimSpace(ct[:i])
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(ct, "image/"),
|
||||
strings.HasPrefix(ct, "audio/"),
|
||||
strings.HasPrefix(ct, "video/"),
|
||||
strings.HasPrefix(ct, "text/"):
|
||||
return ct != "text/html"
|
||||
case ct == "application/pdf",
|
||||
ct == "application/xml",
|
||||
ct == "application/json":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *server) serveListing(w http.ResponseWriter, r *http.Request, dirPath, urlPath string) {
|
||||
entries, err := os.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
|
|
@ -176,20 +216,31 @@ func (s *server) serveListing(w http.ResponseWriter, r *http.Request, dirPath, u
|
|||
continue
|
||||
}
|
||||
isDir := e.IsDir()
|
||||
var size int64
|
||||
var mod time.Time
|
||||
if info, err := e.Info(); err == nil { // lstat: does not follow symlinks
|
||||
mod = info.ModTime()
|
||||
if !isDir {
|
||||
size = info.Size()
|
||||
}
|
||||
}
|
||||
if e.Type()&os.ModeSymlink != 0 {
|
||||
if ti, err := os.Stat(filepath.Join(dirPath, name)); err == nil {
|
||||
isDir = ti.IsDir()
|
||||
mod = ti.ModTime()
|
||||
if isDir {
|
||||
size = 0
|
||||
} else {
|
||||
size = ti.Size()
|
||||
}
|
||||
}
|
||||
}
|
||||
typ := "-"
|
||||
if isDir {
|
||||
typ = "dir"
|
||||
} else if ext := strings.TrimPrefix(filepath.Ext(name), "."); ext != "" {
|
||||
typ = strings.ToLower(ext)
|
||||
}
|
||||
var size int64
|
||||
var mod time.Time
|
||||
if info, err := e.Info(); err == nil {
|
||||
mod = info.ModTime()
|
||||
if !isDir {
|
||||
size = info.Size()
|
||||
}
|
||||
}
|
||||
rows = append(rows, row{
|
||||
Name: name,
|
||||
URL: dirURL + url.PathEscape(name),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue