mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-26 15:50:47 -05:00
171 lines
7.4 KiB
Go
171 lines
7.4 KiB
Go
package errors
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/xml"
|
|
"net/http"
|
|
|
|
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
|
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
|
"github.com/pkg/errors"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
var sabreException = map[int]string{
|
|
|
|
// the commented states have no corresponding exception in sabre/dav,
|
|
// see https://github.com/sabre-io/dav/tree/master/lib/DAV/Exception
|
|
|
|
// http.StatusMultipleChoices: "Multiple Choices",
|
|
// http.StatusMovedPermanently: "Moved Permanently",
|
|
// http.StatusFound: "Found",
|
|
// http.StatusSeeOther: "See Other",
|
|
// http.StatusNotModified: "Not Modified",
|
|
// http.StatusUseProxy: "Use Proxy",
|
|
// http.StatusTemporaryRedirect: "Temporary Redirect",
|
|
// http.StatusPermanentRedirect: "Permanent Redirect",
|
|
|
|
http.StatusBadRequest: "Sabre\\DAV\\Exception\\BadRequest",
|
|
http.StatusUnauthorized: "Sabre\\DAV\\Exception\\NotAuthenticated",
|
|
http.StatusPaymentRequired: "Sabre\\DAV\\Exception\\PaymentRequired",
|
|
http.StatusForbidden: "Sabre\\DAV\\Exception\\Forbidden", // InvalidResourceType, InvalidSyncToken, TooManyMatches
|
|
http.StatusNotFound: "Sabre\\DAV\\Exception\\NotFound",
|
|
http.StatusMethodNotAllowed: "Sabre\\DAV\\Exception\\MethodNotAllowed",
|
|
// http.StatusNotAcceptable: "Not Acceptable",
|
|
// http.StatusProxyAuthRequired: "Proxy Authentication Required",
|
|
// http.StatusRequestTimeout: "Request Timeout",
|
|
http.StatusConflict: "Sabre\\DAV\\Exception\\Conflict", // LockTokenMatchesRequestUri
|
|
// http.StatusGone: "Gone",
|
|
http.StatusLengthRequired: "Sabre\\DAV\\Exception\\LengthRequired",
|
|
http.StatusPreconditionFailed: "Sabre\\DAV\\Exception\\PreconditionFailed",
|
|
// http.StatusRequestEntityTooLarge: "Request Entity Too Large",
|
|
// http.StatusRequestURITooLong: "Request URI Too Long",
|
|
http.StatusUnsupportedMediaType: "Sabre\\DAV\\Exception\\UnsupportedMediaType", // ReportNotSupported
|
|
http.StatusRequestedRangeNotSatisfiable: "Sabre\\DAV\\Exception\\RequestedRangeNotSatisfiable",
|
|
// http.StatusExpectationFailed: "Expectation Failed",
|
|
// http.StatusTeapot: "I'm a teapot",
|
|
// http.StatusMisdirectedRequest: "Misdirected Request",
|
|
// http.StatusUnprocessableEntity: "Unprocessable Entity",
|
|
http.StatusLocked: "Sabre\\DAV\\Exception\\Locked", // ConflictingLock
|
|
// http.StatusFailedDependency: "Failed Dependency",
|
|
// http.StatusTooEarly: "Too Early",
|
|
// http.StatusUpgradeRequired: "Upgrade Required",
|
|
// http.StatusPreconditionRequired: "Precondition Required",
|
|
// http.StatusTooManyRequests: "Too Many Requests",
|
|
// http.StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large",
|
|
// http.StatusUnavailableForLegalReasons: "Unavailable For Legal Reasons",
|
|
|
|
// http.StatusInternalServerError: "Internal Server Error",
|
|
http.StatusNotImplemented: "Sabre\\DAV\\Exception\\NotImplemented",
|
|
// http.StatusBadGateway: "Bad Gateway",
|
|
http.StatusServiceUnavailable: "Sabre\\DAV\\Exception\\ServiceUnavailable",
|
|
// http.StatusGatewayTimeout: "Gateway Timeout",
|
|
// http.StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
|
|
// http.StatusVariantAlsoNegotiates: "Variant Also Negotiates",
|
|
http.StatusInsufficientStorage: "Sabre\\DAV\\Exception\\InsufficientStorage",
|
|
// http.StatusLoopDetected: "Loop Detected",
|
|
// http.StatusNotExtended: "Not Extended",
|
|
// http.StatusNetworkAuthenticationRequired: "Network Authentication Required",
|
|
}
|
|
|
|
// SabreException returns a sabre exception text for the HTTP status code. It returns the empty
|
|
// string if the code is unknown.
|
|
func SabreException(code int) string {
|
|
return sabreException[code]
|
|
}
|
|
|
|
// Exception represents a ocdav exception
|
|
type Exception struct {
|
|
Code int
|
|
Message string
|
|
Header string
|
|
}
|
|
|
|
// Marshal just calls the xml marshaller for a given exception.
|
|
func Marshal(code int, message string, header string) ([]byte, error) {
|
|
xmlstring, err := xml.Marshal(&ErrorXML{
|
|
Xmlnsd: "DAV",
|
|
Xmlnss: "http://sabredav.org/ns",
|
|
Exception: sabreException[code],
|
|
Message: message,
|
|
Header: header,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var buf bytes.Buffer
|
|
buf.WriteString(xml.Header)
|
|
buf.Write(xmlstring)
|
|
return buf.Bytes(), err
|
|
}
|
|
|
|
// ErrorXML holds the xml representation of an error
|
|
// http://www.webdav.org/specs/rfc4918.html#ELEMENT_error
|
|
type ErrorXML struct {
|
|
XMLName xml.Name `xml:"d:error"`
|
|
Xmlnsd string `xml:"xmlns:d,attr"`
|
|
Xmlnss string `xml:"xmlns:s,attr"`
|
|
Exception string `xml:"s:exception"`
|
|
Message string `xml:"s:message"`
|
|
InnerXML []byte `xml:",innerxml"`
|
|
// Header is used to indicate the conflicting request header
|
|
Header string `xml:"s:header,omitempty"`
|
|
}
|
|
|
|
var (
|
|
// ErrInvalidDepth is an invalid depth header error
|
|
ErrInvalidDepth = errors.New("webdav: invalid depth")
|
|
// ErrInvalidPropfind is an invalid propfind error
|
|
ErrInvalidPropfind = errors.New("webdav: invalid propfind")
|
|
// ErrInvalidProppatch is an invalid proppatch error
|
|
ErrInvalidProppatch = errors.New("webdav: invalid proppatch")
|
|
// ErrInvalidLockInfo is an invalid lock error
|
|
ErrInvalidLockInfo = errors.New("webdav: invalid lock info")
|
|
// ErrUnsupportedLockInfo is an unsupported lock error
|
|
ErrUnsupportedLockInfo = errors.New("webdav: unsupported lock info")
|
|
// ErrInvalidTimeout is an invalid timeout error
|
|
ErrInvalidTimeout = errors.New("webdav: invalid timeout")
|
|
// ErrInvalidIfHeader is an invalid if header error
|
|
ErrInvalidIfHeader = errors.New("webdav: invalid If header")
|
|
// ErrUnsupportedMethod is an unsupported method error
|
|
ErrUnsupportedMethod = errors.New("webdav: unsupported method")
|
|
// ErrInvalidLockToken is an invalid lock token error
|
|
ErrInvalidLockToken = errors.New("webdav: invalid lock token")
|
|
// ErrConfirmationFailed is returned by a LockSystem's Confirm method.
|
|
ErrConfirmationFailed = errors.New("webdav: confirmation failed")
|
|
// ErrForbidden is returned by a LockSystem's Unlock method.
|
|
ErrForbidden = errors.New("webdav: forbidden")
|
|
// ErrLocked is returned by a LockSystem's Create, Refresh and Unlock methods.
|
|
ErrLocked = errors.New("webdav: locked")
|
|
// ErrNoSuchLock is returned by a LockSystem's Refresh and Unlock methods.
|
|
ErrNoSuchLock = errors.New("webdav: no such lock")
|
|
// ErrNotImplemented is returned when hitting not implemented code paths
|
|
ErrNotImplemented = errors.New("webdav: not implemented")
|
|
)
|
|
|
|
// HandleErrorStatus checks the status code, logs a Debug or Error level message
|
|
// and writes an appropriate http status
|
|
func HandleErrorStatus(log *zerolog.Logger, w http.ResponseWriter, s *rpc.Status) {
|
|
hsc := status.HTTPStatusFromCode(s.Code)
|
|
if hsc == http.StatusInternalServerError {
|
|
log.Error().Interface("status", s).Int("code", hsc).Msg(http.StatusText(hsc))
|
|
} else {
|
|
log.Debug().Interface("status", s).Int("code", hsc).Msg(http.StatusText(hsc))
|
|
}
|
|
w.WriteHeader(hsc)
|
|
}
|
|
|
|
// HandleWebdavError checks the status code, logs an error and creates a webdav response body
|
|
// if needed
|
|
func HandleWebdavError(log *zerolog.Logger, w http.ResponseWriter, b []byte, err error) {
|
|
if err != nil {
|
|
log.Error().Msgf("error marshaling xml response: %s", b)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, err = w.Write(b)
|
|
if err != nil {
|
|
log.Err(err).Msg("error writing response")
|
|
}
|
|
}
|