diff --git a/fs_local.go b/fs_local.go index 983cf13..a6d9b2d 100644 --- a/fs_local.go +++ b/fs_local.go @@ -24,7 +24,7 @@ func (fs LocalFileSystem) path(name string) (string, error) { return filepath.Join(string(fs), filepath.FromSlash(name)), nil } -func (fs LocalFileSystem) Open(name string) (File, error) { +func (fs LocalFileSystem) Open(name string) (io.ReadCloser, error) { p, err := fs.path(name) if err != nil { return nil, err diff --git a/server.go b/server.go index 5506552..2f9bdc7 100644 --- a/server.go +++ b/server.go @@ -8,19 +8,14 @@ import ( "net/url" "os" "path" + "strconv" "github.com/emersion/go-webdav/internal" ) -type File interface { - io.Closer - io.Reader - io.Seeker -} - // FileSystem is a WebDAV server backend. type FileSystem interface { - Open(name string) (File, error) + Open(name string) (io.ReadCloser, error) Stat(name string) (os.FileInfo, error) Readdir(name string) ([]os.FileInfo, error) Create(name string) (io.WriteCloser, error) @@ -94,7 +89,26 @@ func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error { } defer f.Close() - http.ServeContent(w, r, r.URL.Path, fi.ModTime(), f) + if rs, ok := f.(io.ReadSeeker); ok { + // If it's an io.Seeker, use http.ServeContent which supports ranges + http.ServeContent(w, r, r.URL.Path, fi.ModTime(), rs) + } else { + // TODO: fallback to http.DetectContentType + t := mime.TypeByExtension(path.Ext(r.URL.Path)) + if t != "" { + w.Header().Set("Content-Type", t) + } + + if modTime := fi.ModTime(); !modTime.IsZero() { + w.Header().Set("Last-Modified", modTime.UTC().Format(http.TimeFormat)) + } + + w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) + + if r.Method != http.MethodHead { + io.Copy(w, f) + } + } return nil }