diff --git a/fs_local.go b/fs_local.go index c2cfd46..ed66dd0 100644 --- a/fs_local.go +++ b/fs_local.go @@ -114,6 +114,31 @@ func (fs LocalFileSystem) ReadDir(ctx context.Context, name string, recursive bo return l, errFromOS(err) } +func checkConditionalMatches(fi *FileInfo, ifMatch, ifNoneMatch ConditionalMatch) error { + etag := "" + if fi != nil { + etag = fi.ETag + } + + if ifMatch.IsSet() { + if ok, err := ifMatch.MatchETag(etag); err != nil { + return NewHTTPError(http.StatusBadRequest, err) + } else if !ok { + return NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("If-Match condition failed")) + } + } + + if ifNoneMatch.IsSet() { + if ok, err := ifNoneMatch.MatchETag(etag); err != nil { + return NewHTTPError(http.StatusBadRequest, err) + } else if ok { + return NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("If-None-Match condition failed")) + } + } + + return nil +} + func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadCloser, opts *CreateOptions) (fi *FileInfo, created bool, err error) { p, err := fs.localPath(name) if err != nil { @@ -121,24 +146,9 @@ func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadC } fi, _ = fs.Stat(ctx, name) created = fi == nil - etag := "" - if fi != nil { - etag = fi.ETag - } - if opts.IfMatch.IsSet() { - if ok, err := opts.IfMatch.MatchETag(etag); err != nil { - return nil, false, NewHTTPError(http.StatusBadRequest, err) - } else if !ok { - return nil, false, NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("If-Match condition failed")) - } - } - if opts.IfNoneMatch.IsSet() { - if ok, err := opts.IfNoneMatch.MatchETag(etag); err != nil { - return nil, false, NewHTTPError(http.StatusBadRequest, err) - } else if ok { - return nil, false, NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("If-None-Match condition failed")) - } + if err := checkConditionalMatches(fi, opts.IfMatch, opts.IfNoneMatch); err != nil { + return nil, false, err } wc, err := os.Create(p) @@ -164,7 +174,7 @@ func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadC return fi, created, err } -func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string) error { +func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string, opts *RemoveAllOptions) error { p, err := fs.localPath(name) if err != nil { return err @@ -172,10 +182,15 @@ func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string) error { // WebDAV semantics are that it should return a "404 Not Found" error in // case the resource doesn't exist. We need to Stat before RemoveAll. - if _, err = os.Stat(p); err != nil { + fi, err := fs.Stat(ctx, name) + if err != nil { return errFromOS(err) } + if err := checkConditionalMatches(fi, opts.IfMatch, opts.IfNoneMatch); err != nil { + return err + } + return errFromOS(os.RemoveAll(p)) } diff --git a/server.go b/server.go index 954bbb7..1b18be0 100644 --- a/server.go +++ b/server.go @@ -18,7 +18,7 @@ type FileSystem interface { Stat(ctx context.Context, name string) (*FileInfo, error) ReadDir(ctx context.Context, name string, recursive bool) ([]FileInfo, error) Create(ctx context.Context, name string, body io.ReadCloser, opts *CreateOptions) (fileInfo *FileInfo, created bool, err error) - RemoveAll(ctx context.Context, name string) error + RemoveAll(ctx context.Context, name string, opts *RemoveAllOptions) error Mkdir(ctx context.Context, name string) error Copy(ctx context.Context, name, dest string, options *CopyOptions) (created bool, err error) Move(ctx context.Context, name, dest string, options *MoveOptions) (created bool, err error) @@ -226,7 +226,14 @@ func (b *backend) Put(w http.ResponseWriter, r *http.Request) error { } func (b *backend) Delete(r *http.Request) error { - return b.FileSystem.RemoveAll(r.Context(), r.URL.Path) + ifNoneMatch := ConditionalMatch(r.Header.Get("If-None-Match")) + ifMatch := ConditionalMatch(r.Header.Get("If-Match")) + + opts := RemoveAllOptions{ + IfNoneMatch: ifNoneMatch, + IfMatch: ifMatch, + } + return b.FileSystem.RemoveAll(r.Context(), r.URL.Path, &opts) } func (b *backend) Mkcol(r *http.Request) error { diff --git a/webdav.go b/webdav.go index 2634636..aa16fd1 100644 --- a/webdav.go +++ b/webdav.go @@ -24,6 +24,11 @@ type CreateOptions struct { IfNoneMatch ConditionalMatch } +type RemoveAllOptions struct { + IfMatch ConditionalMatch + IfNoneMatch ConditionalMatch +} + type CopyOptions struct { NoRecursive bool NoOverwrite bool