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 }