Skip to content

Commit

Permalink
Add support for meta-path-for-user propfind (#2741)
Browse files Browse the repository at this point in the history
* Add support for meta-path-for-user propfind

* handle invalid resourceID

Co-authored-by: Michael Barz <[email protected]>
  • Loading branch information
kulmann and micbar authored Apr 27, 2022
1 parent 8ff0830 commit 0164880
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
6 changes: 6 additions & 0 deletions changelog/unreleased/meta-path-for-user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Meta path for user

We've added support for requesting the `meta-path-for-user` via a propfind to the `dav/meta/<id>` endpoint.

https://github.com/cs3org/reva/pull/2741
https://doc.owncloud.com/server/next/developer_manual/webdav_api/meta.html
122 changes: 121 additions & 1 deletion internal/http/services/owncloud/ocdav/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,20 @@
package ocdav

import (
"encoding/xml"
"fmt"
"net/http"
"path"

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/prop"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
rtrace "github.com/cs3org/reva/v2/pkg/trace"
"github.com/cs3org/reva/v2/pkg/utils/resourceid"
)

Expand All @@ -42,15 +53,30 @@ func (h *MetaHandler) Handler(s *svc) http.Handler {
var id string
id, r.URL.Path = router.ShiftPath(r.URL.Path)
if id == "" {
http.Error(w, "400 Bad Request", http.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
return
}

did := resourceid.OwnCloudResourceIDUnwrap(id)
if did == nil {
logger := appctx.GetLogger(r.Context())
logger.Debug().Str("prop", net.PropOcMetaPathForUser).Msg("invalid resource id")
w.WriteHeader(http.StatusBadRequest)
m := fmt.Sprintf("Invalid resource id %v", id)
b, err := errors.Marshal(http.StatusBadRequest, m, "")
errors.HandleWebdavError(logger, w, b, err)
return
}

var head string
head, r.URL.Path = router.ShiftPath(r.URL.Path)
switch head {
case "":
if r.Method != MethodPropfind {
w.WriteHeader(http.StatusBadRequest)
return
}
h.handlePathForUser(w, r, s, did)
case "v":
h.VersionsHandler.Handler(s, did).ServeHTTP(w, r)
default:
Expand All @@ -59,3 +85,97 @@ func (h *MetaHandler) Handler(s *svc) http.Handler {

})
}

func (h *MetaHandler) handlePathForUser(w http.ResponseWriter, r *http.Request, s *svc, rid *provider.ResourceId) {
ctx, span := rtrace.Provider.Tracer("ocdav").Start(r.Context(), "meta_propfind")
defer span.End()

id := resourceid.OwnCloudResourceIDWrap(rid)
sublog := appctx.GetLogger(ctx).With().Str("path", r.URL.Path).Str("resourceid", id).Logger()
client, err := s.getClient()
if err != nil {
sublog.Error().Err(err).Msg("error getting grpc client")
w.WriteHeader(http.StatusInternalServerError)
return
}

pf, status, err := propfind.ReadPropfind(r.Body)
if err != nil {
sublog.Debug().Err(err).Msg("error reading propfind request")
w.WriteHeader(status)
return
}

if ok := hasProp(&pf, net.PropOcMetaPathForUser); !ok {
sublog.Debug().Str("prop", net.PropOcMetaPathForUser).Msg("error finding prop in request")
w.WriteHeader(http.StatusBadRequest)
return
}

pathReq := &provider.GetPathRequest{ResourceId: rid}
pathRes, err := client.GetPath(ctx, pathReq)
if err != nil {
sublog.Error().Err(err).Msg("error sending GetPath grpc request")
w.WriteHeader(http.StatusInternalServerError)
return
}

switch pathRes.Status.Code {
case rpc.Code_CODE_NOT_FOUND:
sublog.Debug().Str("code", string(pathRes.Status.Code)).Msg("resource not found")
w.WriteHeader(http.StatusNotFound)
m := fmt.Sprintf("Resource %s not found", id)
b, err := errors.Marshal(http.StatusNotFound, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
case rpc.Code_CODE_PERMISSION_DENIED:
// raise StatusNotFound so that resources can't be enumerated
sublog.Debug().Str("code", string(pathRes.Status.Code)).Msg("resource access denied")
w.WriteHeader(http.StatusNotFound)
m := fmt.Sprintf("Resource %s not found", id)
b, err := errors.Marshal(http.StatusNotFound, m, "")
errors.HandleWebdavError(&sublog, w, b, err)
return
}

propstatOK := propfind.PropstatXML{
Status: "HTTP/1.1 200 OK",
Prop: []prop.PropertyXML{
prop.Escaped("oc:meta-path-for-user", pathRes.Path),
},
}
baseURI := ctx.Value(net.CtxKeyBaseURI).(string)
msr := propfind.NewMultiStatusResponseXML()
msr.Responses = []*propfind.ResponseXML{
{
Href: net.EncodePath(path.Join(baseURI, id) + "/"),
Propstat: []propfind.PropstatXML{
propstatOK,
},
},
}
propRes, err := xml.Marshal(msr)
if err != nil {
sublog.Error().Err(err).Msg("error marshalling propfind response xml")
w.WriteHeader(http.StatusInternalServerError)
return
}

w.Header().Set(net.HeaderDav, "1, 3, extended-mkcol")
w.Header().Set(net.HeaderContentType, "application/xml; charset=utf-8")
w.WriteHeader(http.StatusMultiStatus)
if _, err := w.Write(propRes); err != nil {
sublog.Error().Err(err).Msg("error writing propfind response")
return
}
}

func hasProp(pf *propfind.XML, key string) bool {
for i := range pf.Prop {
k := fmt.Sprintf("%s/%s", pf.Prop[i].Space, pf.Prop[i].Local)
if k == key {
return true
}
}
return false
}
2 changes: 2 additions & 0 deletions internal/http/services/owncloud/ocdav/net/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const (
PropQuotaUnknown = "-2"
// PropOcFavorite is the favorite ns property
PropOcFavorite = "http://owncloud.org/ns/favorite"
// PropOcMetaPathForUser is the meta-path-for-user ns property
PropOcMetaPathForUser = "http://owncloud.org/ns/meta-path-for-user"

// DepthZero represents the webdav zero depth value
DepthZero Depth = "0"
Expand Down

0 comments on commit 0164880

Please sign in to comment.