cachefs/pkg/srv/cache.go
2022-03-23 22:02:35 +01:00

102 lines
1.9 KiB
Go

// Copyright (C) 2022 Marius Schellenberger
package srv
import (
"io"
"net/http"
"path"
"strings"
"cachefs/pkg/fs"
"github.com/go-logr/logr"
)
type CacheFS struct {
fs *fs.FS
}
func (cfs *CacheFS) Open(name string) (http.File, error) {
return cfs.fs.OpenDst(name)
}
type CacheServer struct {
log logr.Logger
fs *fs.FS
h http.Handler
}
func NewCacheServer(fs *fs.FS, log logr.Logger) http.Handler {
return &CacheServer{log, fs, http.FileServer(&CacheFS{fs})}
}
func (cs *CacheServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s := &statusInterceptor{w: w}
w = s
if !skipLog(r.RequestURI) {
defer func() {
if s.Status() == http.StatusPartialContent {
return
}
cs.log.Info("access",
"client", r.RemoteAddr,
"method", r.Method,
"status", s.Status(),
"uri", r.RequestURI,
)
}()
}
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
p := path.Clean(upath)
option := r.FormValue("o")
d, err := cs.fs.StatDst(p)
if err != nil {
msg, code := toHTTPError(err)
http.Error(w, msg, code)
return
}
h := w.Header()
if option == "v" {
h.Set(csp, videoCSP)
err = video.Execute(w, data{Paths: dirContents{Base: r.URL.Path}})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
if !d.IsDir() {
cs.h.ServeHTTP(w, r)
return
}
i := &responseInterceptor{w: w}
r.Header.Del("If-Modified-Since")
r.Header.Del("Cache-Control")
cs.h.ServeHTTP(i, r)
h.Del("Last-Modified")
paths, err := i.GetPaths(p, cs.fs, true)
if err == io.EOF {
w.WriteHeader(i.Status())
return
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
h.Set(csp, indexCSP)
w.WriteHeader(i.Status())
err = cache.Execute(w, data{Paths: paths})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}