github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocdav/head.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  	"fmt"
    24  	"net/http"
    25  	"path"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/cs3org/reva/v2/pkg/storagespace"
    31  
    32  	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    33  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	"github.com/cs3org/reva/v2/internal/grpc/services/storageprovider"
    35  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
    36  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
    37  	"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup"
    38  	"github.com/cs3org/reva/v2/pkg/appctx"
    39  	"github.com/cs3org/reva/v2/pkg/utils"
    40  	"github.com/rs/zerolog"
    41  )
    42  
    43  func (s *svc) handlePathHead(w http.ResponseWriter, r *http.Request, ns string) {
    44  	ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(r.Context(), "head")
    45  	defer span.End()
    46  
    47  	fn := path.Join(ns, r.URL.Path)
    48  
    49  	sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger()
    50  
    51  	space, status, err := spacelookup.LookUpStorageSpaceForPath(ctx, s.gatewaySelector, fn)
    52  	if err != nil {
    53  		sublog.Error().Err(err).Str("path", fn).Msg("failed to look up storage space")
    54  		w.WriteHeader(http.StatusInternalServerError)
    55  		return
    56  	}
    57  	if status.Code != rpc.Code_CODE_OK {
    58  		errors.HandleErrorStatus(&sublog, w, status)
    59  		return
    60  	}
    61  
    62  	s.handleHead(ctx, w, r, spacelookup.MakeRelativeReference(space, fn, false), sublog)
    63  }
    64  
    65  func (s *svc) handleHead(ctx context.Context, w http.ResponseWriter, r *http.Request, ref *provider.Reference, log zerolog.Logger) {
    66  	client, err := s.gatewaySelector.Next()
    67  	if err != nil {
    68  		log.Error().Err(err).Msg("error selecting next client")
    69  		w.WriteHeader(http.StatusInternalServerError)
    70  		return
    71  	}
    72  	req := &provider.StatRequest{Ref: ref}
    73  	res, err := client.Stat(ctx, req)
    74  	if err != nil {
    75  		log.Error().Err(err).Msg("error sending grpc stat request")
    76  		w.WriteHeader(http.StatusInternalServerError)
    77  		return
    78  	}
    79  
    80  	if res.Status.Code != rpc.Code_CODE_OK {
    81  		errors.HandleErrorStatus(&log, w, res.Status)
    82  		return
    83  	}
    84  
    85  	info := res.Info
    86  	w.Header().Set(net.HeaderContentType, info.MimeType)
    87  	w.Header().Set(net.HeaderETag, info.Etag)
    88  	w.Header().Set(net.HeaderOCFileID, storagespace.FormatResourceID(info.Id))
    89  	w.Header().Set(net.HeaderOCETag, info.Etag)
    90  	if info.Checksum != nil {
    91  		w.Header().Set(net.HeaderOCChecksum, fmt.Sprintf("%s:%s", strings.ToUpper(string(storageprovider.GRPC2PKGXS(info.Checksum.Type))), info.Checksum.Sum))
    92  	}
    93  	t := utils.TSToTime(info.Mtime).UTC()
    94  	lastModifiedString := t.Format(time.RFC1123Z)
    95  	w.Header().Set(net.HeaderLastModified, lastModifiedString)
    96  	w.Header().Set(net.HeaderContentLength, strconv.FormatUint(info.Size, 10))
    97  	if info.Type != provider.ResourceType_RESOURCE_TYPE_CONTAINER {
    98  		w.Header().Set(net.HeaderAcceptRanges, "bytes")
    99  	}
   100  	if utils.ReadPlainFromOpaque(res.GetInfo().GetOpaque(), "status") == "processing" {
   101  		w.WriteHeader(http.StatusTooEarly)
   102  		return
   103  	}
   104  	w.WriteHeader(http.StatusOK)
   105  }
   106  
   107  func (s *svc) handleSpacesHead(w http.ResponseWriter, r *http.Request, spaceID string) {
   108  	ctx, span := appctx.GetTracerProvider(r.Context()).Tracer(tracerName).Start(r.Context(), "spaces_head")
   109  	defer span.End()
   110  
   111  	sublog := appctx.GetLogger(ctx).With().Str("spaceid", spaceID).Str("path", r.URL.Path).Logger()
   112  
   113  	ref, err := spacelookup.MakeStorageSpaceReference(spaceID, r.URL.Path)
   114  	if err != nil {
   115  		w.WriteHeader(http.StatusBadRequest)
   116  		return
   117  	}
   118  
   119  	s.handleHead(ctx, w, r, &ref, sublog)
   120  }