diff --git a/carddav/server.go b/carddav/server.go index d4cf876..5aeb714 100644 --- a/carddav/server.go +++ b/carddav/server.go @@ -439,3 +439,28 @@ 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) { panic("TODO") } + +// https://tools.ietf.org/rfcmarkup?doc=6352#section-6.3.2.1 +type PreconditionType string + +const ( + PreconditionNoUIDConflict PreconditionType = "no-uid-conflict" + PreconditionSupportedAddressData PreconditionType = "supported-address-data" + PreconditionValidAddressData PreconditionType = "valid-address-data" + PreconditionMaxResourceSize PreconditionType = "max-resource-size" +) + +func NewPreconditionError(err PreconditionType) error { + name := xml.Name{"urn:ietf:params:xml:ns:carddav", string(err)} + elem := internal.NewRawXMLElement(name, nil, nil) + e := internal.Error{ + Raw: []internal.RawXMLValue{ + *elem, + }, + } + return &internal.DAVError{ + Code: 409, + Msg: fmt.Sprintf("precondition not met: %s", string(err)), + Err: e, + } +} diff --git a/internal/internal.go b/internal/internal.go index 08c2ef8..065e66f 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -99,3 +99,14 @@ func (err *HTTPError) Error() string { return s } } + +// DAVError is a XML error with HTTP status and a human readable message +type DAVError struct { + Code int + Msg string + Err Error +} + +func (err *DAVError) Error() string { + return err.Msg +} diff --git a/internal/server.go b/internal/server.go index 5a51aed..66f4964 100644 --- a/internal/server.go +++ b/internal/server.go @@ -10,6 +10,12 @@ import ( ) func ServeError(w http.ResponseWriter, err error) { + if davErr, ok := err.(*DAVError); ok { + w.WriteHeader(davErr.Code) + ServeXML(w).Encode(davErr.Err) + return + } + code := http.StatusInternalServerError if httpErr, ok := err.(*HTTPError); ok { code = httpErr.Code @@ -102,11 +108,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if err != nil { - code := http.StatusInternalServerError - if httpErr, ok := err.(*HTTPError); ok { - code = httpErr.Code - } - http.Error(w, err.Error(), code) + ServeError(w, err) } }