Compare commits

..

5 Commits

Author SHA1 Message Date
9dd12e301a
Add error returning for missing error output paths
Co-Authored-By: Captain ALM <captainalm@captainalm.com>
2024-09-27 00:41:21 +01:00
9094f8327e
Change this too 2024-09-26 20:53:10 +01:00
c4454bfa01
Respond with 200 OK instead of 204 No Content 2024-09-26 20:53:10 +01:00
757f4a8c2a
AddCurrentUserPrivilegeSet to find caldav 2024-09-26 20:53:10 +01:00
266c39c655
Add CurrentUserPrivilegeSet to find carddav 2024-09-26 20:53:10 +01:00
6 changed files with 132 additions and 154 deletions

View File

@ -465,10 +465,12 @@ func (b *backend) propFindRoot(ctx context.Context, propfind *internal.PropFind)
} }
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: internal.PropFindValue(&internal.CurrentUserPrincipal{ internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: principalPath}, return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}), },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(principalPath, propfind, props) return internal.NewPropFindResponse(principalPath, propfind, props)
} }
@ -484,13 +486,15 @@ func (b *backend) propFindUserPrincipal(ctx context.Context, propfind *internal.
} }
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: internal.PropFindValue(&internal.CurrentUserPrincipal{ internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: principalPath}, return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}), },
calendarHomeSetName: internal.PropFindValue(&calendarHomeSet{ calendarHomeSetName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: homeSetPath}, return &calendarHomeSet{Href: internal.Href{Path: homeSetPath}}, nil
}), },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(principalPath, propfind, props) return internal.NewPropFindResponse(principalPath, propfind, props)
} }
@ -507,10 +511,12 @@ func (b *backend) propFindHomeSet(ctx context.Context, propfind *internal.PropFi
// TODO anything else to return here? // TODO anything else to return here?
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: internal.PropFindValue(&internal.CurrentUserPrincipal{ internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: principalPath}, return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}), },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(homeSetPath, propfind, props) return internal.NewPropFindResponse(homeSetPath, propfind, props)
} }
@ -524,15 +530,19 @@ func (b *backend) propFindCalendar(ctx context.Context, propfind *internal.PropF
} }
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil
}, },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName, calendarName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
calendarDescriptionName: internal.PropFindValue(&calendarDescription{ return internal.NewResourceType(internal.CollectionName, calendarName), nil
Description: cal.Description, },
}), calendarDescriptionName: func(*internal.RawXMLValue) (interface{}, error) {
supportedCalendarDataName: internal.PropFindValue(&supportedCalendarData{ return &calendarDescription{Description: cal.Description}, nil
Types: []calendarDataType{ },
{ContentType: ical.MIMEType, Version: "2.0"}, supportedCalendarDataName: func(*internal.RawXMLValue) (interface{}, error) {
}, return &supportedCalendarData{
}), Types: []calendarDataType{
{ContentType: ical.MIMEType, Version: "2.0"},
},
}, nil
},
supportedCalendarComponentSetName: func(*internal.RawXMLValue) (interface{}, error) { supportedCalendarComponentSetName: func(*internal.RawXMLValue) (interface{}, error) {
components := []comp{} components := []comp{}
if cal.SupportedComponentSet != nil { if cal.SupportedComponentSet != nil {
@ -549,19 +559,19 @@ func (b *backend) propFindCalendar(ctx context.Context, propfind *internal.PropF
} }
if cal.Name != "" { if cal.Name != "" {
props[internal.DisplayNameName] = internal.PropFindValue(&internal.DisplayName{ props[internal.DisplayNameName] = func(*internal.RawXMLValue) (interface{}, error) {
Name: cal.Name, return &internal.DisplayName{Name: cal.Name}, nil
}) }
} }
if cal.Description != "" { if cal.Description != "" {
props[calendarDescriptionName] = internal.PropFindValue(&calendarDescription{ props[calendarDescriptionName] = func(*internal.RawXMLValue) (interface{}, error) {
Description: cal.Description, return &calendarDescription{Description: cal.Description}, nil
}) }
} }
if cal.MaxResourceSize > 0 { if cal.MaxResourceSize > 0 {
props[maxResourceSizeName] = internal.PropFindValue(&maxResourceSize{ props[maxResourceSizeName] = func(*internal.RawXMLValue) (interface{}, error) {
Size: cal.MaxResourceSize, return &maxResourceSize{Size: cal.MaxResourceSize}, nil
}) }
} }
props[internal.CurrentUserPrivilegeSetName] = func(*internal.RawXMLValue) (interface{}, error) { props[internal.CurrentUserPrivilegeSetName] = func(*internal.RawXMLValue) (interface{}, error) {
return &internal.CurrentUserPrivilegeSet{Privilege: internal.NewAllPrivileges()}, nil return &internal.CurrentUserPrivilegeSet{Privilege: internal.NewAllPrivileges()}, nil
@ -605,9 +615,9 @@ func (b *backend) propFindCalendarObject(ctx context.Context, propfind *internal
} }
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil
}, },
internal.GetContentTypeName: internal.PropFindValue(&internal.GetContentType{ internal.GetContentTypeName: func(*internal.RawXMLValue) (interface{}, error) {
Type: ical.MIMEType, return &internal.GetContentType{Type: ical.MIMEType}, nil
}), },
// TODO: calendar-data can only be used in REPORT requests // TODO: calendar-data can only be used in REPORT requests
calendarDataName: func(*internal.RawXMLValue) (interface{}, error) { calendarDataName: func(*internal.RawXMLValue) (interface{}, error) {
var buf bytes.Buffer var buf bytes.Buffer
@ -620,20 +630,20 @@ func (b *backend) propFindCalendarObject(ctx context.Context, propfind *internal
} }
if co.ContentLength > 0 { if co.ContentLength > 0 {
props[internal.GetContentLengthName] = internal.PropFindValue(&internal.GetContentLength{ props[internal.GetContentLengthName] = func(*internal.RawXMLValue) (interface{}, error) {
Length: co.ContentLength, return &internal.GetContentLength{Length: co.ContentLength}, nil
}) }
} }
if !co.ModTime.IsZero() { if !co.ModTime.IsZero() {
props[internal.GetLastModifiedName] = internal.PropFindValue(&internal.GetLastModified{ props[internal.GetLastModifiedName] = func(*internal.RawXMLValue) (interface{}, error) {
LastModified: internal.Time(co.ModTime), return &internal.GetLastModified{LastModified: internal.Time(co.ModTime)}, nil
}) }
} }
if co.ETag != "" { if co.ETag != "" {
props[internal.GetETagName] = internal.PropFindValue(&internal.GetETag{ props[internal.GetETagName] = func(*internal.RawXMLValue) (interface{}, error) {
ETag: internal.ETag(co.ETag), return &internal.GetETag{ETag: internal.ETag(co.ETag)}, nil
}) }
} }
return internal.NewPropFindResponse(co.Path, propfind, props) return internal.NewPropFindResponse(co.Path, propfind, props)

View File

@ -431,10 +431,12 @@ func (b *backend) propFindRoot(ctx context.Context, propfind *internal.PropFind)
} }
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: internal.PropFindValue(&internal.CurrentUserPrincipal{ internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: principalPath}, return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}), },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(principalPath, propfind, props) return internal.NewPropFindResponse(principalPath, propfind, props)
} }
@ -444,24 +446,30 @@ func (b *backend) propFindUserPrincipal(ctx context.Context, propfind *internal.
if err != nil { if err != nil {
return nil, err return nil, err
} }
homeSetPath, err := b.Backend.AddressBookHomeSetPath(ctx)
if err != nil {
return nil, err
}
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: internal.PropFindValue(&internal.CurrentUserPrincipal{ internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
Href: internal.Href{Path: principalPath}, return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}), },
addressBookHomeSetName: func(*internal.RawXMLValue) (interface{}, error) { addressBookHomeSetName: func(*internal.RawXMLValue) (interface{}, error) {
homeSetPath, err := b.Backend.AddressBookHomeSetPath(ctx)
if err != nil {
return nil, err
}
return &addressbookHomeSet{Href: internal.Href{Path: homeSetPath}}, nil return &addressbookHomeSet{Href: internal.Href{Path: homeSetPath}}, nil
}, },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(principalPath, propfind, props) return internal.NewPropFindResponse(principalPath, propfind, props)
} }
func (b *backend) propFindHomeSet(ctx context.Context, propfind *internal.PropFind) (*internal.Response, error) { func (b *backend) propFindHomeSet(ctx context.Context, propfind *internal.PropFind) (*internal.Response, error) {
principalPath, err := b.Backend.CurrentUserPrincipal(ctx)
if err != nil {
return nil, err
}
homeSetPath, err := b.Backend.AddressBookHomeSetPath(ctx) homeSetPath, err := b.Backend.AddressBookHomeSetPath(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -470,13 +478,11 @@ func (b *backend) propFindHomeSet(ctx context.Context, propfind *internal.PropFi
// TODO anything else to return here? // TODO anything else to return here?
props := map[xml.Name]internal.PropFindFunc{ props := map[xml.Name]internal.PropFindFunc{
internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) { internal.CurrentUserPrincipalName: func(*internal.RawXMLValue) (interface{}, error) {
principalPath, err := b.Backend.CurrentUserPrincipal(ctx)
if err != nil {
return nil, err
}
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil return &internal.CurrentUserPrincipal{Href: internal.Href{Path: principalPath}}, nil
}, },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
return internal.NewResourceType(internal.CollectionName), nil
},
} }
return internal.NewPropFindResponse(homeSetPath, propfind, props) return internal.NewPropFindResponse(homeSetPath, propfind, props)
} }
@ -490,29 +496,33 @@ func (b *backend) propFindAddressBook(ctx context.Context, propfind *internal.Pr
} }
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil
}, },
internal.ResourceTypeName: internal.PropFindValue(internal.NewResourceType(internal.CollectionName, addressBookName)), internal.ResourceTypeName: func(*internal.RawXMLValue) (interface{}, error) {
supportedAddressDataName: internal.PropFindValue(&supportedAddressData{ return internal.NewResourceType(internal.CollectionName, addressBookName), nil
Types: []addressDataType{ },
{ContentType: vcard.MIMEType, Version: "3.0"}, supportedAddressDataName: func(*internal.RawXMLValue) (interface{}, error) {
{ContentType: vcard.MIMEType, Version: "4.0"}, return &supportedAddressData{
}, Types: []addressDataType{
}), {ContentType: vcard.MIMEType, Version: "3.0"},
{ContentType: vcard.MIMEType, Version: "4.0"},
},
}, nil
},
} }
if ab.Name != "" { if ab.Name != "" {
props[internal.DisplayNameName] = internal.PropFindValue(&internal.DisplayName{ props[internal.DisplayNameName] = func(*internal.RawXMLValue) (interface{}, error) {
Name: ab.Name, return &internal.DisplayName{Name: ab.Name}, nil
}) }
} }
if ab.Description != "" { if ab.Description != "" {
props[addressBookDescriptionName] = internal.PropFindValue(&addressbookDescription{ props[addressBookDescriptionName] = func(*internal.RawXMLValue) (interface{}, error) {
Description: ab.Description, return &addressbookDescription{Description: ab.Description}, nil
}) }
} }
if ab.MaxResourceSize > 0 { if ab.MaxResourceSize > 0 {
props[maxResourceSizeName] = internal.PropFindValue(&maxResourceSize{ props[maxResourceSizeName] = func(*internal.RawXMLValue) (interface{}, error) {
Size: ab.MaxResourceSize, return &maxResourceSize{Size: ab.MaxResourceSize}, nil
}) }
} }
props[internal.CurrentUserPrivilegeSetName] = func(*internal.RawXMLValue) (interface{}, error) { props[internal.CurrentUserPrivilegeSetName] = func(*internal.RawXMLValue) (interface{}, error) {
return &internal.CurrentUserPrivilegeSet{Privilege: internal.NewAllPrivileges()}, nil return &internal.CurrentUserPrivilegeSet{Privilege: internal.NewAllPrivileges()}, nil
@ -554,9 +564,9 @@ func (b *backend) propFindAddressObject(ctx context.Context, propfind *internal.
} }
return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil return &internal.CurrentUserPrincipal{Href: internal.Href{Path: path}}, nil
}, },
internal.GetContentTypeName: internal.PropFindValue(&internal.GetContentType{ internal.GetContentTypeName: func(*internal.RawXMLValue) (interface{}, error) {
Type: vcard.MIMEType, return &internal.GetContentType{Type: vcard.MIMEType}, nil
}), },
// TODO: address-data can only be used in REPORT requests // TODO: address-data can only be used in REPORT requests
addressDataName: func(*internal.RawXMLValue) (interface{}, error) { addressDataName: func(*internal.RawXMLValue) (interface{}, error) {
var buf bytes.Buffer var buf bytes.Buffer
@ -569,20 +579,20 @@ func (b *backend) propFindAddressObject(ctx context.Context, propfind *internal.
} }
if ao.ContentLength > 0 { if ao.ContentLength > 0 {
props[internal.GetContentLengthName] = internal.PropFindValue(&internal.GetContentLength{ props[internal.GetContentLengthName] = func(*internal.RawXMLValue) (interface{}, error) {
Length: ao.ContentLength, return &internal.GetContentLength{Length: ao.ContentLength}, nil
}) }
} }
if !ao.ModTime.IsZero() { if !ao.ModTime.IsZero() {
props[internal.GetLastModifiedName] = internal.PropFindValue(&internal.GetLastModified{ props[internal.GetLastModifiedName] = func(*internal.RawXMLValue) (interface{}, error) {
LastModified: internal.Time(ao.ModTime), return &internal.GetLastModified{LastModified: internal.Time(ao.ModTime)}, nil
}) }
} }
if ao.ETag != "" { if ao.ETag != "" {
props[internal.GetETagName] = internal.PropFindValue(&internal.GetETag{ props[internal.GetETagName] = func(*internal.RawXMLValue) (interface{}, error) {
ETag: internal.ETag(ao.ETag), return &internal.GetETag{ETag: internal.ETag(ao.ETag)}, nil
}) }
} }
return internal.NewPropFindResponse(ao.Path, propfind, props) return internal.NewPropFindResponse(ao.Path, propfind, props)

View File

@ -114,31 +114,15 @@ func (fs LocalFileSystem) ReadDir(ctx context.Context, name string, recursive bo
return l, errFromOS(err) return l, errFromOS(err)
} }
func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadCloser, opts *CreateOptions) (fi *FileInfo, created bool, err error) { func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadCloser) (*FileInfo, bool, error) {
p, err := fs.localPath(name) p, err := fs.localPath(name)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
fi, _ = fs.Stat(ctx, name) created := false
created = fi == nil fi, _ := fs.Stat(ctx, name)
etag := "" if fi == nil {
if fi != nil { created = true
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"))
}
} }
wc, err := os.Create(p) wc, err := os.Create(p)
@ -148,11 +132,9 @@ func (fs LocalFileSystem) Create(ctx context.Context, name string, body io.ReadC
defer wc.Close() defer wc.Close()
if _, err := io.Copy(wc, body); err != nil { if _, err := io.Copy(wc, body); err != nil {
os.Remove(p)
return nil, false, err return nil, false, err
} }
if err := wc.Close(); err != nil { if err := wc.Close(); err != nil {
os.Remove(p)
return nil, false, err return nil, false, err
} }

View File

@ -162,17 +162,13 @@ func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) error {
type PropFindFunc func(raw *RawXMLValue) (interface{}, error) type PropFindFunc func(raw *RawXMLValue) (interface{}, error)
func PropFindValue(value interface{}) PropFindFunc {
return func(raw *RawXMLValue) (interface{}, error) {
return value, nil
}
}
func NewPropFindResponse(path string, propfind *PropFind, props map[xml.Name]PropFindFunc) (*Response, error) { func NewPropFindResponse(path string, propfind *PropFind, props map[xml.Name]PropFindFunc) (*Response, error) {
resp := &Response{Hrefs: []Href{Href{Path: path}}} resp := &Response{Hrefs: []Href{Href{Path: path}}}
if _, ok := props[ResourceTypeName]; !ok { if _, ok := props[ResourceTypeName]; !ok {
props[ResourceTypeName] = PropFindValue(NewResourceType()) props[ResourceTypeName] = func(*RawXMLValue) (interface{}, error) {
return NewResourceType(), nil
}
} }
if propfind.PropName != nil { if propfind.PropName != nil {

View File

@ -17,7 +17,7 @@ type FileSystem interface {
Open(ctx context.Context, name string) (io.ReadCloser, error) Open(ctx context.Context, name string) (io.ReadCloser, error)
Stat(ctx context.Context, name string) (*FileInfo, error) Stat(ctx context.Context, name string) (*FileInfo, error)
ReadDir(ctx context.Context, name string, recursive bool) ([]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) Create(ctx context.Context, name string, body io.ReadCloser) (fileInfo *FileInfo, created bool, err error)
RemoveAll(ctx context.Context, name string) error RemoveAll(ctx context.Context, name string) error
Mkdir(ctx context.Context, name string) error Mkdir(ctx context.Context, name string) error
Copy(ctx context.Context, name, dest string, options *CopyOptions) (created bool, err error) Copy(ctx context.Context, name, dest string, options *CopyOptions) (created bool, err error)
@ -162,26 +162,26 @@ func (b *backend) propFindFile(propfind *internal.PropFind, fi *FileInfo) (*inte
} }
if !fi.IsDir { if !fi.IsDir {
props[internal.GetContentLengthName] = internal.PropFindValue(&internal.GetContentLength{ props[internal.GetContentLengthName] = func(*internal.RawXMLValue) (interface{}, error) {
Length: fi.Size, return &internal.GetContentLength{Length: fi.Size}, nil
}) }
if !fi.ModTime.IsZero() { if !fi.ModTime.IsZero() {
props[internal.GetLastModifiedName] = internal.PropFindValue(&internal.GetLastModified{ props[internal.GetLastModifiedName] = func(*internal.RawXMLValue) (interface{}, error) {
LastModified: internal.Time(fi.ModTime), return &internal.GetLastModified{LastModified: internal.Time(fi.ModTime)}, nil
}) }
} }
if fi.MIMEType != "" { if fi.MIMEType != "" {
props[internal.GetContentTypeName] = internal.PropFindValue(&internal.GetContentType{ props[internal.GetContentTypeName] = func(*internal.RawXMLValue) (interface{}, error) {
Type: fi.MIMEType, return &internal.GetContentType{Type: fi.MIMEType}, nil
}) }
} }
if fi.ETag != "" { if fi.ETag != "" {
props[internal.GetETagName] = internal.PropFindValue(&internal.GetETag{ props[internal.GetETagName] = func(*internal.RawXMLValue) (interface{}, error) {
ETag: internal.ETag(fi.ETag), return &internal.GetETag{ETag: internal.ETag(fi.ETag)}, nil
}) }
} }
} }
@ -194,14 +194,7 @@ func (b *backend) PropPatch(r *http.Request, update *internal.PropertyUpdate) (*
} }
func (b *backend) Put(w http.ResponseWriter, r *http.Request) error { func (b *backend) Put(w http.ResponseWriter, r *http.Request) error {
ifNoneMatch := ConditionalMatch(r.Header.Get("If-None-Match")) fi, created, err := b.FileSystem.Create(r.Context(), r.URL.Path, r.Body)
ifMatch := ConditionalMatch(r.Header.Get("If-Match"))
opts := CreateOptions{
IfNoneMatch: ifNoneMatch,
IfMatch: ifMatch,
}
fi, created, err := b.FileSystem.Create(r.Context(), r.URL.Path, r.Body, &opts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -19,11 +19,6 @@ type FileInfo struct {
ETag string ETag string
} }
type CreateOptions struct {
IfMatch ConditionalMatch
IfNoneMatch ConditionalMatch
}
type CopyOptions struct { type CopyOptions struct {
NoRecursive bool NoRecursive bool
NoOverwrite bool NoOverwrite bool
@ -53,11 +48,3 @@ func (val ConditionalMatch) ETag() (string, error) {
} }
return string(e), nil return string(e), nil
} }
func (val ConditionalMatch) MatchETag(etag string) (bool, error) {
if val.IsWildcard() {
return true, nil
}
t, err := val.ETag()
return t == etag, err
}