github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocdav/delete.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package ocdav 20 21 import ( 22 "context" 23 "errors" 24 "net/http" 25 "path" 26 27 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 28 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 29 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net" 30 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup" 31 "github.com/cs3org/reva/v2/pkg/appctx" 32 "github.com/cs3org/reva/v2/pkg/errtypes" 33 rstatus "github.com/cs3org/reva/v2/pkg/rgrpc/status" 34 "github.com/cs3org/reva/v2/pkg/utils" 35 ) 36 37 func (s *svc) handlePathDelete(w http.ResponseWriter, r *http.Request, ns string) (status int, err error) { 38 ctx := r.Context() 39 ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(ctx, "path_delete") 40 defer span.End() 41 42 if r.Body != http.NoBody { 43 return http.StatusUnsupportedMediaType, errors.New("body must be empty") 44 } 45 46 fn := path.Join(ns, r.URL.Path) 47 48 space, rpcStatus, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn) 49 switch { 50 case err != nil: 51 span.RecordError(err) 52 return http.StatusInternalServerError, err 53 case rpcStatus.Code != rpc.Code_CODE_OK: 54 return rstatus.HTTPStatusFromCode(rpcStatus.Code), errtypes.NewErrtypeFromStatus(rpcStatus) 55 } 56 57 return s.handleDelete(ctx, w, r, spacelookup.MakeRelativeReference(space, fn, false)) 58 } 59 60 func (s *svc) handleDelete(ctx context.Context, w http.ResponseWriter, r *http.Request, ref *provider.Reference) (status int, err error) { 61 ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(ctx, "delete") 62 defer span.End() 63 64 req := &provider.DeleteRequest{ 65 Ref: ref, 66 LockId: requestLockToken(r), 67 } 68 69 // FIXME the lock token is part of the application level protocol, it should be part of the DeleteRequest message not the opaque 70 ih, ok := parseIfHeader(r.Header.Get(net.HeaderIf)) 71 if ok { 72 if len(ih.lists) == 1 && len(ih.lists[0].conditions) == 1 { 73 req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lockid", ih.lists[0].conditions[0].Token) 74 } 75 } else if r.Header.Get(net.HeaderIf) != "" { 76 return http.StatusBadRequest, errtypes.BadRequest("invalid if header") 77 } 78 79 client, err := s.gatewaySelector.Next() 80 if err != nil { 81 return http.StatusInternalServerError, errtypes.InternalError(err.Error()) 82 } 83 84 res, err := client.Delete(ctx, req) 85 switch { 86 case err != nil: 87 span.RecordError(err) 88 return http.StatusInternalServerError, err 89 case res.Status.Code == rpc.Code_CODE_OK: 90 return http.StatusNoContent, nil 91 case res.Status.Code == rpc.Code_CODE_NOT_FOUND: 92 //lint:ignore ST1005 mimic the exact oc10 error message 93 return http.StatusNotFound, errors.New("Resource not found") 94 case res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED: 95 status = http.StatusForbidden 96 if lockID := utils.ReadPlainFromOpaque(res.Opaque, "lockid"); lockID != "" { 97 // http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the 98 // Lock-Token value is a Coded-URL. We add angle brackets. 99 w.Header().Set("Lock-Token", "<"+lockID+">") 100 status = http.StatusLocked 101 } 102 // check if user has access to resource 103 sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: ref}) 104 if err != nil { 105 span.RecordError(err) 106 return http.StatusInternalServerError, err 107 } 108 if sRes.Status.Code != rpc.Code_CODE_OK { 109 // return not found error so we do not leak existence of a file 110 // TODO hide permission failed for users without access in every kind of request 111 // TODO should this be done in the driver? 112 //lint:ignore ST1005 mimic the exact oc10 error message 113 return http.StatusNotFound, errors.New("Resource not found") 114 } 115 return status, errors.New("") // mimic the oc10 error messages which have an empty message in this case 116 case res.Status.Code == rpc.Code_CODE_INTERNAL && res.Status.Message == "can't delete mount path": 117 // 405 must generate an Allow header 118 w.Header().Set("Allow", "PROPFIND, MOVE, COPY, POST, PROPPATCH, HEAD, GET, OPTIONS, LOCK, UNLOCK, REPORT, SEARCH, PUT") 119 return http.StatusMethodNotAllowed, errtypes.PermissionDenied(res.Status.Message) 120 } 121 return rstatus.HTTPStatusFromCode(res.Status.Code), errtypes.NewErrtypeFromStatus(res.Status) 122 } 123 124 func (s *svc) handleSpacesDelete(w http.ResponseWriter, r *http.Request, spaceID string) (status int, err error) { 125 ctx := r.Context() 126 ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(ctx, "spaces_delete") 127 defer span.End() 128 129 if r.Body != http.NoBody { 130 return http.StatusUnsupportedMediaType, errors.New("body must be empty") 131 } 132 133 ref, err := spacelookup.MakeStorageSpaceReference(spaceID, r.URL.Path) 134 if err != nil { 135 return http.StatusBadRequest, err 136 } 137 138 // do not allow deleting spaces via dav endpoint - use graph endpoint instead 139 // we get a relative reference coming from the space root 140 // so if the path is "empty" and no opaque id is present or the opaque id equals 141 // the space id, we are referencing the space 142 rid := ref.GetResourceId() 143 if ref.GetPath() == "." && 144 (rid.GetOpaqueId() == "" || rid.GetOpaqueId() == rid.GetSpaceId()) { 145 return http.StatusMethodNotAllowed, errors.New("deleting spaces via dav is not allowed") 146 } 147 148 return s.handleDelete(ctx, w, r, &ref) 149 }