github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocdav/spaces.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 "net/http" 23 "path" 24 "strings" 25 26 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 27 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/config" 28 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors" 29 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net" 30 "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind" 31 "github.com/cs3org/reva/v2/pkg/appctx" 32 "github.com/cs3org/reva/v2/pkg/rhttp/router" 33 "github.com/cs3org/reva/v2/pkg/storagespace" 34 "github.com/cs3org/reva/v2/pkg/utils" 35 "google.golang.org/protobuf/proto" 36 ) 37 38 // SpacesHandler handles trashbin requests 39 type SpacesHandler struct { 40 gatewaySvc string 41 namespace string 42 useLoggedInUserNS bool 43 } 44 45 func (h *SpacesHandler) init(c *config.Config) error { 46 h.gatewaySvc = c.GatewaySvc 47 h.namespace = path.Join("/", c.WebdavNamespace) 48 h.useLoggedInUserNS = true 49 return nil 50 } 51 52 // Handler handles requests 53 func (h *SpacesHandler) Handler(s *svc, trashbinHandler *TrashbinHandler) http.Handler { 54 config := s.Config() 55 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 56 // ctx := r.Context() 57 // log := appctx.GetLogger(ctx) 58 59 if r.Method == http.MethodOptions { 60 s.handleOptions(w, r) 61 return 62 } 63 64 var segment string 65 segment, r.URL.Path = router.ShiftPath(r.URL.Path) 66 if segment == "" { 67 // listing is disabled, no auth will change that 68 w.WriteHeader(http.StatusMethodNotAllowed) 69 return 70 } 71 72 if segment == _trashbinPath { 73 h.handleSpacesTrashbin(w, r, s, trashbinHandler) 74 return 75 } 76 77 spaceID := segment 78 79 // TODO initialize status with http.StatusBadRequest 80 // TODO initialize err with errors.ErrUnsupportedMethod 81 var status int // status 0 means the handler already sent the response 82 var err error 83 switch r.Method { 84 case MethodPropfind: 85 p := propfind.NewHandler(config.PublicURL, s.gatewaySelector, config) 86 p.HandleSpacesPropfind(w, r, spaceID) 87 case MethodProppatch: 88 status, err = s.handleSpacesProppatch(w, r, spaceID) 89 case MethodLock: 90 status, err = s.handleSpacesLock(w, r, spaceID) 91 case MethodUnlock: 92 status, err = s.handleSpaceUnlock(w, r, spaceID) 93 case MethodMkcol: 94 status, err = s.handleSpacesMkCol(w, r, spaceID) 95 case MethodMove: 96 s.handleSpacesMove(w, r, spaceID) 97 case MethodCopy: 98 s.handleSpacesCopy(w, r, spaceID) 99 case MethodReport: 100 s.handleReport(w, r, spaceID) 101 case http.MethodGet: 102 s.handleSpacesGet(w, r, spaceID) 103 case http.MethodPut: 104 s.handleSpacesPut(w, r, spaceID) 105 case http.MethodPost: 106 s.handleSpacesTusPost(w, r, spaceID) 107 case http.MethodOptions: 108 s.handleOptions(w, r) 109 case http.MethodHead: 110 s.handleSpacesHead(w, r, spaceID) 111 case http.MethodDelete: 112 status, err = s.handleSpacesDelete(w, r, spaceID) 113 default: 114 http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented) 115 } 116 117 if status != 0 { // 0 means the handler already sent the response 118 w.WriteHeader(status) 119 if status != http.StatusNoContent { 120 var b []byte 121 if b, err = errors.Marshal(status, err.Error(), "", ""); err == nil { 122 _, err = w.Write(b) 123 } 124 } 125 } 126 if err != nil { 127 appctx.GetLogger(r.Context()).Error().Err(err).Msg(err.Error()) 128 } 129 }) 130 } 131 132 func (h *SpacesHandler) handleSpacesTrashbin(w http.ResponseWriter, r *http.Request, s *svc, trashbinHandler *TrashbinHandler) { 133 ctx := r.Context() 134 log := appctx.GetLogger(ctx) 135 136 spaceID, key := splitSpaceAndKey(r.URL.Path) 137 if spaceID == "" { 138 // listing is disabled, no auth will change that 139 w.WriteHeader(http.StatusMethodNotAllowed) 140 return 141 } 142 143 ref, err := storagespace.ParseReference(spaceID) 144 if err != nil { 145 w.WriteHeader(http.StatusBadRequest) 146 return 147 } 148 149 switch r.Method { 150 case MethodPropfind: 151 trashbinHandler.listTrashbin(w, r, s, &ref, path.Join(_trashbinPath, spaceID), key) 152 case MethodMove: 153 if key == "" { 154 http.Error(w, "501 Not implemented", http.StatusNotImplemented) 155 break 156 } 157 // find path in url relative to trash base 158 baseURI := ctx.Value(net.CtxKeyBaseURI).(string) 159 baseURI = path.Join(baseURI, spaceID) 160 161 dh := r.Header.Get(net.HeaderDestination) 162 dst, err := net.ParseDestination(baseURI, dh) 163 if err != nil { 164 w.WriteHeader(http.StatusBadRequest) 165 return 166 } 167 log.Debug().Str("key", key).Str("dst", dst).Msg("spaces restore") 168 169 dstRef := proto.Clone(&ref).(*provider.Reference) 170 dstRef.Path = utils.MakeRelativePath(dst) 171 172 trashbinHandler.restore(w, r, s, &ref, dstRef, key) 173 case http.MethodDelete: 174 trashbinHandler.delete(w, r, s, &ref, key) 175 default: 176 http.Error(w, "501 Not implemented", http.StatusNotImplemented) 177 } 178 } 179 180 func splitSpaceAndKey(p string) (space, key string) { 181 p = strings.TrimPrefix(p, "/") 182 parts := strings.SplitN(p, "/", 2) 183 space = parts[0] 184 if len(parts) > 1 { 185 key = parts[1] 186 } 187 return 188 }