diff --git a/caldav/server.go b/caldav/server.go index 1e50827..e29fe2e 100644 --- a/caldav/server.go +++ b/caldav/server.go @@ -23,10 +23,10 @@ import ( type PutCalendarObjectOptions struct { // IfNoneMatch indicates that the client does not want to overwrite // an existing resource. - IfNoneMatch bool + IfNoneMatch webdav.ConditionalMatch // IfMatch provides the ETag of the resource that the client intends // to overwrite, can be "" - IfMatch string + IfMatch webdav.ConditionalMatch } // Backend is a CalDAV server backend. @@ -642,13 +642,12 @@ func (b *backend) PropPatch(r *http.Request, update *internal.PropertyUpdate) (* } func (b *backend) Put(r *http.Request) (*internal.Href, error) { - if inm := r.Header.Get("If-None-Match"); inm != "" && inm != "*" { - return nil, internal.HTTPErrorf(http.StatusBadRequest, "invalid value for If-None-Match header") - } + ifNoneMatch := webdav.ConditionalMatch(r.Header.Get("If-None-Match")) + ifMatch := webdav.ConditionalMatch(r.Header.Get("If-Match")) opts := PutCalendarObjectOptions{ - IfNoneMatch: r.Header.Get("If-None-Match") == "*", - IfMatch: r.Header.Get("If-Match"), + IfNoneMatch: ifNoneMatch, + IfMatch: ifMatch, } t, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) diff --git a/carddav/server.go b/carddav/server.go index 7e069ea..d2762e0 100644 --- a/carddav/server.go +++ b/carddav/server.go @@ -21,10 +21,10 @@ import ( type PutAddressObjectOptions struct { // IfNoneMatch indicates that the client does not want to overwrite // an existing resource. - IfNoneMatch bool + IfNoneMatch webdav.ConditionalMatch // IfMatch provides the ETag of the resource that the client intends // to overwrite, can be "" - IfMatch string + IfMatch webdav.ConditionalMatch } // Backend is a CardDAV server backend. @@ -631,13 +631,12 @@ func (b *backend) PropPatch(r *http.Request, update *internal.PropertyUpdate) (* } func (b *backend) Put(r *http.Request) (*internal.Href, error) { - if inm := r.Header.Get("If-None-Match"); inm != "" && inm != "*" { - return nil, internal.HTTPErrorf(http.StatusBadRequest, "invalid value for If-None-Match header") - } + ifNoneMatch := webdav.ConditionalMatch(r.Header.Get("If-None-Match")) + ifMatch := webdav.ConditionalMatch(r.Header.Get("If-Match")) opts := PutAddressObjectOptions{ - IfNoneMatch: r.Header.Get("If-None-Match") == "*", - IfMatch: r.Header.Get("If-Match"), + IfNoneMatch: ifNoneMatch, + IfMatch: ifMatch, } t, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) diff --git a/elements.go b/elements.go index 70f9e9b..f1f2d7f 100644 --- a/elements.go +++ b/elements.go @@ -30,3 +30,24 @@ type groupMembership struct { XMLName xml.Name `xml:"DAV: group-membership"` Hrefs []internal.Href `xml:"href"` } + +// ConditionalMatch represents the value of a conditional header +// according to RFC 2068 section 14.25 and RFC 2068 section 14.26 +// The (optional) value can either be a wildcard or an ETag. +type ConditionalMatch string + +func (val ConditionalMatch) IsSet() bool { + return val != "" +} + +func (val ConditionalMatch) IsWildcard() bool { + return val == "*" +} + +func (val ConditionalMatch) ETag() (string, error) { + var e internal.ETag + if err := e.UnmarshalText([]byte(val)); err != nil { + return "", err + } + return string(e), nil +}