webdav: add context to FileSystem

This commit is contained in:
Simon Ser 2023-12-19 21:29:28 +01:00
parent 379a418130
commit d033e09835
2 changed files with 29 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package webdav package webdav
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"mime" "mime"
@ -15,6 +16,8 @@ import (
type LocalFileSystem string type LocalFileSystem string
var _ FileSystem = LocalFileSystem("")
func (fs LocalFileSystem) localPath(name string) (string, error) { func (fs LocalFileSystem) localPath(name string) (string, error) {
if (filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0) || strings.Contains(name, "\x00") { if (filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0) || strings.Contains(name, "\x00") {
return "", internal.HTTPErrorf(http.StatusBadRequest, "webdav: invalid character in path") return "", internal.HTTPErrorf(http.StatusBadRequest, "webdav: invalid character in path")
@ -34,7 +37,7 @@ func (fs LocalFileSystem) externalPath(name string) (string, error) {
return "/" + filepath.ToSlash(rel), nil return "/" + filepath.ToSlash(rel), nil
} }
func (fs LocalFileSystem) Open(name string) (io.ReadCloser, error) { func (fs LocalFileSystem) Open(ctx context.Context, name string) (io.ReadCloser, error) {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -59,7 +62,7 @@ func fileInfoFromOS(p string, fi os.FileInfo) *FileInfo {
} }
} }
func (fs LocalFileSystem) Stat(name string) (*FileInfo, error) { func (fs LocalFileSystem) Stat(ctx context.Context, name string) (*FileInfo, error) {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -71,7 +74,7 @@ func (fs LocalFileSystem) Stat(name string) (*FileInfo, error) {
return fileInfoFromOS(name, fi), nil return fileInfoFromOS(name, fi), nil
} }
func (fs LocalFileSystem) Readdir(name string, recursive bool) ([]FileInfo, error) { func (fs LocalFileSystem) ReadDir(ctx context.Context, name string, recursive bool) ([]FileInfo, error) {
path, err := fs.localPath(name) path, err := fs.localPath(name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -98,7 +101,7 @@ func (fs LocalFileSystem) Readdir(name string, recursive bool) ([]FileInfo, erro
return l, err return l, err
} }
func (fs LocalFileSystem) Create(name string) (io.WriteCloser, error) { func (fs LocalFileSystem) Create(ctx context.Context, name string) (io.WriteCloser, error) {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -106,7 +109,7 @@ func (fs LocalFileSystem) Create(name string) (io.WriteCloser, error) {
return os.Create(p) return os.Create(p)
} }
func (fs LocalFileSystem) RemoveAll(name string) error { func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string) error {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return err return err
@ -121,7 +124,7 @@ func (fs LocalFileSystem) RemoveAll(name string) error {
return os.RemoveAll(p) return os.RemoveAll(p)
} }
func (fs LocalFileSystem) Mkdir(name string) error { func (fs LocalFileSystem) Mkdir(ctx context.Context, name string) error {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return err return err
@ -150,7 +153,7 @@ func copyRegularFile(src, dst string, perm os.FileMode) error {
return dstFile.Close() return dstFile.Close()
} }
func (fs LocalFileSystem) Copy(src, dst string, recursive, overwrite bool) (created bool, err error) { func (fs LocalFileSystem) Copy(ctx context.Context, src, dst string, recursive, overwrite bool) (created bool, err error) {
srcPath, err := fs.localPath(src) srcPath, err := fs.localPath(src)
if err != nil { if err != nil {
return false, err return false, err
@ -210,7 +213,7 @@ func (fs LocalFileSystem) Copy(src, dst string, recursive, overwrite bool) (crea
return created, nil return created, nil
} }
func (fs LocalFileSystem) MoveAll(src, dst string, overwrite bool) (created bool, err error) { func (fs LocalFileSystem) MoveAll(ctx context.Context, src, dst string, overwrite bool) (created bool, err error) {
srcPath, err := fs.localPath(src) srcPath, err := fs.localPath(src)
if err != nil { if err != nil {
return false, err return false, err
@ -240,5 +243,3 @@ func (fs LocalFileSystem) MoveAll(src, dst string, overwrite bool) (created bool
return created, nil return created, nil
} }
var _ FileSystem = LocalFileSystem("")

View File

@ -14,14 +14,14 @@ import (
// FileSystem is a WebDAV server backend. // FileSystem is a WebDAV server backend.
type FileSystem interface { type FileSystem interface {
Open(name string) (io.ReadCloser, error) Open(ctx context.Context, name string) (io.ReadCloser, error)
Stat(name string) (*FileInfo, error) Stat(ctx context.Context, name string) (*FileInfo, error)
Readdir(name string, recursive bool) ([]FileInfo, error) ReadDir(ctx context.Context, name string, recursive bool) ([]FileInfo, error)
Create(name string) (io.WriteCloser, error) Create(ctx context.Context, name string) (io.WriteCloser, error)
RemoveAll(name string) error RemoveAll(ctx context.Context, name string) error
Mkdir(name string) error Mkdir(ctx context.Context, name string) error
Copy(name, dest string, recursive, overwrite bool) (created bool, err error) Copy(ctx context.Context, name, dest string, recursive, overwrite bool) (created bool, err error)
MoveAll(name, dest string, overwrite bool) (created bool, err error) MoveAll(ctx context.Context, name, dest string, overwrite bool) (created bool, err error)
} }
// Handler handles WebDAV HTTP requests. It can be used to create a WebDAV // Handler handles WebDAV HTTP requests. It can be used to create a WebDAV
@ -56,7 +56,7 @@ type backend struct {
} }
func (b *backend) Options(r *http.Request) (caps []string, allow []string, err error) { func (b *backend) Options(r *http.Request) (caps []string, allow []string, err error) {
fi, err := b.FileSystem.Stat(r.URL.Path) fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, []string{http.MethodOptions, http.MethodPut, "MKCOL"}, nil return nil, []string{http.MethodOptions, http.MethodPut, "MKCOL"}, nil
} else if err != nil { } else if err != nil {
@ -79,7 +79,7 @@ func (b *backend) Options(r *http.Request) (caps []string, allow []string, err e
} }
func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error { func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error {
fi, err := b.FileSystem.Stat(r.URL.Path) fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return &internal.HTTPError{Code: http.StatusNotFound, Err: err} return &internal.HTTPError{Code: http.StatusNotFound, Err: err}
} else if err != nil { } else if err != nil {
@ -89,7 +89,7 @@ func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error {
return &internal.HTTPError{Code: http.StatusMethodNotAllowed} return &internal.HTTPError{Code: http.StatusMethodNotAllowed}
} }
f, err := b.FileSystem.Open(r.URL.Path) f, err := b.FileSystem.Open(r.Context(), r.URL.Path)
if err != nil { if err != nil {
return err return err
} }
@ -120,7 +120,7 @@ func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error {
func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth internal.Depth) (*internal.MultiStatus, error) { func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth internal.Depth) (*internal.MultiStatus, error) {
// TODO: use partial error Response on error // TODO: use partial error Response on error
fi, err := b.FileSystem.Stat(r.URL.Path) fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, &internal.HTTPError{Code: http.StatusNotFound, Err: err} return nil, &internal.HTTPError{Code: http.StatusNotFound, Err: err}
} else if err != nil { } else if err != nil {
@ -129,7 +129,7 @@ func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth i
var resps []internal.Response var resps []internal.Response
if depth != internal.DepthZero && fi.IsDir { if depth != internal.DepthZero && fi.IsDir {
children, err := b.FileSystem.Readdir(r.URL.Path, depth == internal.DepthInfinity) children, err := b.FileSystem.ReadDir(r.Context(), r.URL.Path, depth == internal.DepthInfinity)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -198,7 +198,7 @@ func (b *backend) PropPatch(r *http.Request, update *internal.PropertyUpdate) (*
} }
func (b *backend) Put(r *http.Request) (*internal.Href, error) { func (b *backend) Put(r *http.Request) (*internal.Href, error) {
wc, err := b.FileSystem.Create(r.URL.Path) wc, err := b.FileSystem.Create(r.Context(), r.URL.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -212,7 +212,7 @@ func (b *backend) Put(r *http.Request) (*internal.Href, error) {
} }
func (b *backend) Delete(r *http.Request) error { func (b *backend) Delete(r *http.Request) error {
err := b.FileSystem.RemoveAll(r.URL.Path) err := b.FileSystem.RemoveAll(r.Context(), r.URL.Path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return &internal.HTTPError{Code: http.StatusNotFound, Err: err} return &internal.HTTPError{Code: http.StatusNotFound, Err: err}
} }
@ -223,7 +223,7 @@ func (b *backend) Mkcol(r *http.Request) error {
if r.Header.Get("Content-Type") != "" { if r.Header.Get("Content-Type") != "" {
return internal.HTTPErrorf(http.StatusUnsupportedMediaType, "webdav: request body not supported in MKCOL request") return internal.HTTPErrorf(http.StatusUnsupportedMediaType, "webdav: request body not supported in MKCOL request")
} }
err := b.FileSystem.Mkdir(r.URL.Path) err := b.FileSystem.Mkdir(r.Context(), r.URL.Path)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return &internal.HTTPError{Code: http.StatusConflict, Err: err} return &internal.HTTPError{Code: http.StatusConflict, Err: err}
} }
@ -231,7 +231,7 @@ func (b *backend) Mkcol(r *http.Request) error {
} }
func (b *backend) Copy(r *http.Request, dest *internal.Href, recursive, overwrite bool) (created bool, err error) { func (b *backend) Copy(r *http.Request, dest *internal.Href, recursive, overwrite bool) (created bool, err error) {
created, err = b.FileSystem.Copy(r.URL.Path, dest.Path, recursive, overwrite) created, err = b.FileSystem.Copy(r.Context(), r.URL.Path, dest.Path, recursive, overwrite)
if os.IsExist(err) { if os.IsExist(err) {
return false, &internal.HTTPError{http.StatusPreconditionFailed, err} return false, &internal.HTTPError{http.StatusPreconditionFailed, err}
} }
@ -239,7 +239,7 @@ func (b *backend) Copy(r *http.Request, dest *internal.Href, recursive, overwrit
} }
func (b *backend) Move(r *http.Request, dest *internal.Href, overwrite bool) (created bool, err error) { func (b *backend) Move(r *http.Request, dest *internal.Href, overwrite bool) (created bool, err error) {
created, err = b.FileSystem.MoveAll(r.URL.Path, dest.Path, overwrite) created, err = b.FileSystem.MoveAll(r.Context(), r.URL.Path, dest.Path, overwrite)
if os.IsExist(err) { if os.IsExist(err) {
return false, &internal.HTTPError{http.StatusPreconditionFailed, err} return false, &internal.HTTPError{http.StatusPreconditionFailed, err}
} }