mirror of
https://github.com/1f349/go-webdav.git
synced 2024-12-23 00:34:23 +00:00
85d2b222bb
Backends will need some way to signal that a precondition error occurred (and specifying which one) without causing the server to return a 500. This commit adds an exported function to create a specific error for this. The existing error handling routine is slightly adapted to handle this error in such a way that it returns the desired result. Usage would be something like: ``` return "", carddav.NewPreconditionError(carddav.PreconditionNoUIDConflict) ``` which triggers the following HTTP response: ``` HTTP/1.1 409 Conflict. Content-Type: text/xml; charset=utf-8. Date: Thu, 10 Mar 2022 10:28:56 GMT. Content-Length: 141. Connection: close. <?xml version="1.0" encoding="UTF-8"?> <error xmlns="DAV:"><no-uid-conflict xmlns="urn:ietf:params:xml:ns:carddav"></no-uid-conflict></error> ``` This response gets correctly recognized by e.g. Evolution (though it's handling is not great). The added error type is generic enough to be used for other stuff also. As it is not exported (internal package), new functions for creating such errors would have to be added.
113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
// Package internal provides low-level helpers for WebDAV clients and servers.
|
|
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// Depth indicates whether a request applies to the resource's members. It's
|
|
// defined in RFC 4918 section 10.2.
|
|
type Depth int
|
|
|
|
const (
|
|
// DepthZero indicates that the request applies only to the resource.
|
|
DepthZero Depth = 0
|
|
// DepthOne indicates that the request applies to the resource and its
|
|
// internal members only.
|
|
DepthOne Depth = 1
|
|
// DepthInfinity indicates that the request applies to the resource and all
|
|
// of its members.
|
|
DepthInfinity Depth = -1
|
|
)
|
|
|
|
// ParseDepth parses a Depth header.
|
|
func ParseDepth(s string) (Depth, error) {
|
|
switch s {
|
|
case "0":
|
|
return DepthZero, nil
|
|
case "1":
|
|
return DepthOne, nil
|
|
case "infinity":
|
|
return DepthInfinity, nil
|
|
}
|
|
return 0, fmt.Errorf("webdav: invalid Depth value")
|
|
}
|
|
|
|
// String formats the depth.
|
|
func (d Depth) String() string {
|
|
switch d {
|
|
case DepthZero:
|
|
return "0"
|
|
case DepthOne:
|
|
return "1"
|
|
case DepthInfinity:
|
|
return "infinity"
|
|
}
|
|
panic("webdav: invalid Depth value")
|
|
}
|
|
|
|
// ParseOverwrite parses an Overwrite header.
|
|
func ParseOverwrite(s string) (bool, error) {
|
|
switch s {
|
|
case "T":
|
|
return true, nil
|
|
case "F":
|
|
return false, nil
|
|
}
|
|
return false, fmt.Errorf("webdav: invalid Overwrite value")
|
|
}
|
|
|
|
// FormatOverwrite formats an Overwrite header.
|
|
func FormatOverwrite(overwrite bool) string {
|
|
if overwrite {
|
|
return "T"
|
|
} else {
|
|
return "F"
|
|
}
|
|
}
|
|
|
|
type HTTPError struct {
|
|
Code int
|
|
Err error
|
|
}
|
|
|
|
func HTTPErrorFromError(err error) *HTTPError {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if httpErr, ok := err.(*HTTPError); ok {
|
|
return httpErr
|
|
} else {
|
|
return &HTTPError{http.StatusInternalServerError, err}
|
|
}
|
|
}
|
|
|
|
func IsNotFound(err error) bool {
|
|
return HTTPErrorFromError(err).Code == http.StatusNotFound
|
|
}
|
|
|
|
func HTTPErrorf(code int, format string, a ...interface{}) *HTTPError {
|
|
return &HTTPError{code, fmt.Errorf(format, a...)}
|
|
}
|
|
|
|
func (err *HTTPError) Error() string {
|
|
s := fmt.Sprintf("%v %v", err.Code, http.StatusText(err.Code))
|
|
if err.Err != nil {
|
|
return fmt.Sprintf("%v: %v", s, err.Err)
|
|
} else {
|
|
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
|
|
}
|