Skip to content

Commit

Permalink
refactor webdav proppatch
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Jul 13, 2021
1 parent 3defc91 commit ac70592
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 41 deletions.
102 changes: 62 additions & 40 deletions internal/http/services/owncloud/ocdav/proppatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,14 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)

func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) {
func (s *svc) handlePathProppatch(w http.ResponseWriter, r *http.Request, ns string) {
ctx := r.Context()
ctx, span := trace.StartSpan(ctx, "proppatch")
defer span.End()

acceptedProps := []xml.Name{}
removedProps := []xml.Name{}

fn := path.Join(ns, r.URL.Path)

sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
Expand All @@ -67,10 +65,9 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string)
return
}

ref := &provider.Reference{Path: fn}
// check if resource exists
statReq := &provider.StatRequest{
Ref: &provider.Reference{Path: fn},
}
statReq := &provider.StatRequest{Ref: ref}
statRes, err := c.Stat(ctx, statReq)
if err != nil {
sublog.Error().Err(err).Msg("error sending a grpc stat request")
Expand All @@ -92,26 +89,53 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string)
return
}

acceptedProps, removedProps, ok := s.handleProppatch(ctx, w, r, ref, pp, sublog)
if !ok {
// handleProppatch handles responses in error cases so we can just return
return
}

nRef := strings.TrimPrefix(fn, ns)
nRef = path.Join(ctx.Value(ctxKeyBaseURI).(string), nRef)
if statRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
nRef += "/"
}

s.handleProppatchResponse(ctx, w, r, acceptedProps, removedProps, nRef, sublog)
}

func (s *svc) handleProppatch(ctx context.Context, w http.ResponseWriter, r *http.Request, ref *provider.Reference, patches []Proppatch, log zerolog.Logger) ([]xml.Name, []xml.Name, bool) {
c, err := s.getClient()
if err != nil {
log.Error().Err(err).Msg("error getting grpc client")
w.WriteHeader(http.StatusInternalServerError)
return nil, nil, false
}

rreq := &provider.UnsetArbitraryMetadataRequest{
Ref: &provider.Reference{Path: fn},
Ref: ref,
ArbitraryMetadataKeys: []string{""},
}
sreq := &provider.SetArbitraryMetadataRequest{
Ref: &provider.Reference{Path: fn},
Ref: ref,
ArbitraryMetadata: &provider.ArbitraryMetadata{
Metadata: map[string]string{},
},
}
for i := range pp {
if len(pp[i].Props) < 1 {

acceptedProps := []xml.Name{}
removedProps := []xml.Name{}

for i := range patches {
if len(patches[i].Props) < 1 {
continue
}
for j := range pp[i].Props {
propNameXML := pp[i].Props[j].XMLName
for j := range patches[i].Props {
propNameXML := patches[i].Props[j].XMLName
// don't use path.Join. It removes the double slash! concatenate with a /
key := fmt.Sprintf("%s/%s", pp[i].Props[j].XMLName.Space, pp[i].Props[j].XMLName.Local)
value := string(pp[i].Props[j].InnerXML)
remove := pp[i].Remove
key := fmt.Sprintf("%s/%s", patches[i].Props[j].XMLName.Space, patches[i].Props[j].XMLName.Local)
value := string(patches[i].Props[j].InnerXML)
remove := patches[i].Remove
// boolean flags may be "set" to false as well
if s.isBooleanProperty(key) {
// Make boolean properties either "0" or "1"
Expand All @@ -128,48 +152,48 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string)
rreq.ArbitraryMetadataKeys[0] = key
res, err := c.UnsetArbitraryMetadata(ctx, rreq)
if err != nil {
sublog.Error().Err(err).Msg("error sending a grpc UnsetArbitraryMetadata request")
log.Error().Err(err).Msg("error sending a grpc UnsetArbitraryMetadata request")
w.WriteHeader(http.StatusInternalServerError)
return
return nil, nil, false
}

if res.Status.Code != rpc.Code_CODE_OK {
if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED {
w.WriteHeader(http.StatusForbidden)
m := fmt.Sprintf("Permission denied to remove properties on resource %v", fn)
m := fmt.Sprintf("Permission denied to remove properties on resource %v", ref.Path)
b, err := Marshal(exception{
code: SabredavPermissionDenied,
message: m,
})
HandleWebdavError(&sublog, w, b, err)
return
HandleWebdavError(&log, w, b, err)
return nil, nil, false
}
HandleErrorStatus(&sublog, w, res.Status)
return
HandleErrorStatus(&log, w, res.Status)
return nil, nil, false
}
removedProps = append(removedProps, propNameXML)
} else {
sreq.ArbitraryMetadata.Metadata[key] = value
res, err := c.SetArbitraryMetadata(ctx, sreq)
if err != nil {
sublog.Error().Err(err).Str("key", key).Str("value", value).Msg("error sending a grpc SetArbitraryMetadata request")
log.Error().Err(err).Str("key", key).Str("value", value).Msg("error sending a grpc SetArbitraryMetadata request")
w.WriteHeader(http.StatusInternalServerError)
return
return nil, nil, false
}

if res.Status.Code != rpc.Code_CODE_OK {
if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED {
w.WriteHeader(http.StatusForbidden)
m := fmt.Sprintf("Permission denied to set properties on resource %v", fn)
m := fmt.Sprintf("Permission denied to set properties on resource %v", ref.Path)
b, err := Marshal(exception{
code: SabredavPermissionDenied,
message: m,
})
HandleWebdavError(&sublog, w, b, err)
return
HandleWebdavError(&log, w, b, err)
return nil, nil, false
}
HandleErrorStatus(&sublog, w, res.Status)
return
HandleErrorStatus(&log, w, res.Status)
return nil, nil, false
}

acceptedProps = append(acceptedProps, propNameXML)
Expand All @@ -181,23 +205,21 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string)
// http://www.webdav.org/specs/rfc2518.html#rfc.section.8.2
}

ref := strings.TrimPrefix(fn, ns)
ref = path.Join(ctx.Value(ctxKeyBaseURI).(string), ref)
if statRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
ref += "/"
}
return acceptedProps, removedProps, true
}

propRes, err := s.formatProppatchResponse(ctx, acceptedProps, removedProps, ref)
func (s *svc) handleProppatchResponse(ctx context.Context, w http.ResponseWriter, r *http.Request, acceptedProps, removedProps []xml.Name, path string, log zerolog.Logger) {
propRes, err := s.formatProppatchResponse(ctx, acceptedProps, removedProps, path)
if err != nil {
sublog.Error().Err(err).Msg("error formatting proppatch response")
log.Error().Err(err).Msg("error formatting proppatch response")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("DAV", "1, 3, extended-mkcol")
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
w.Header().Set(HeaderDav, "1, 3, extended-mkcol")
w.Header().Set(HeaderContentType, "application/xml; charset=utf-8")
w.WriteHeader(http.StatusMultiStatus)
if _, err := w.Write([]byte(propRes)); err != nil {
sublog.Err(err).Msg("error writing response")
log.Err(err).Msg("error writing response")
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/http/services/owncloud/ocdav/webdav.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (h *WebDavHandler) Handler(s *svc) http.Handler {
case MethodUnlock:
s.handleUnlock(w, r, ns)
case MethodProppatch:
s.handleProppatch(w, r, ns)
s.handlePathProppatch(w, r, ns)
case MethodMkcol:
s.handlePathMkcol(w, r, ns)
case MethodMove:
Expand Down

0 comments on commit ac70592

Please sign in to comment.