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  }