github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocdav/net/net.go (about) 1 // Copyright 2018-2022 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 net 20 21 import ( 22 "net/url" 23 "strings" 24 25 "github.com/pkg/errors" 26 ) 27 28 var ( 29 // ErrInvalidHeaderValue defines an error which can occure when trying to parse a header value. 30 ErrInvalidHeaderValue = errors.New("invalid value") 31 ) 32 33 type ctxKey int 34 35 const ( 36 // CtxKeyBaseURI is the key of the base URI context field 37 CtxKeyBaseURI ctxKey = iota 38 39 // NsDav is the Dav ns 40 NsDav = "DAV:" 41 // NsOwncloud is the owncloud ns 42 NsOwncloud = "http://owncloud.org/ns" 43 // NsOCS is the OCS ns 44 NsOCS = "http://open-collaboration-services.org/ns" 45 46 // RFC1123 time that mimics oc10. time.RFC1123 would end in "UTC", see https://github.com/golang/go/issues/13781 47 RFC1123 = "Mon, 02 Jan 2006 15:04:05 GMT" 48 49 // PropQuotaUnknown is the quota unknown property 50 PropQuotaUnknown = "-2" 51 // PropOcFavorite is the favorite ns property 52 PropOcFavorite = "http://owncloud.org/ns/favorite" 53 // PropOcMetaPathForUser is the meta-path-for-user ns property 54 PropOcMetaPathForUser = "http://owncloud.org/ns/meta-path-for-user" 55 56 // DepthZero represents the webdav zero depth value 57 DepthZero Depth = "0" 58 // DepthOne represents the webdav one depth value 59 DepthOne Depth = "1" 60 // DepthInfinity represents the webdav infinity depth value 61 DepthInfinity Depth = "infinity" 62 ) 63 64 // Depth is a type representing the webdav depth header value 65 type Depth string 66 67 // String returns the string representation of the webdav depth value 68 func (d Depth) String() string { 69 return string(d) 70 } 71 72 // EncodePath encodes the path of a url. 73 // 74 // slashes (/) are treated as path-separators. 75 func EncodePath(path string) string { 76 return (&url.URL{Path: path}).EscapedPath() 77 } 78 79 // ParseDepth parses the depth header value defined in https://tools.ietf.org/html/rfc4918#section-9.1 80 // Valid values are "0", "1" and "infinity". An empty string will be parsed to "1". 81 // For all other values this method returns an error. 82 func ParseDepth(s string) (Depth, error) { 83 if s == "" { 84 return DepthOne, nil 85 } 86 87 switch strings.ToLower(s) { 88 case DepthZero.String(): 89 return DepthZero, nil 90 case DepthOne.String(): 91 return DepthOne, nil 92 case DepthInfinity.String(): 93 return DepthInfinity, nil 94 default: 95 return "", errors.Wrapf(ErrInvalidHeaderValue, "invalid depth: %s", s) 96 } 97 } 98 99 // ParseOverwrite parses the overwrite header value defined in https://datatracker.ietf.org/doc/html/rfc4918#section-10.6 100 // Valid values are "T" and "F". An empty string will be parse to true. 101 func ParseOverwrite(s string) (bool, error) { 102 if s == "" { 103 s = "T" 104 } 105 if s != "T" && s != "F" { 106 return false, errors.Wrapf(ErrInvalidHeaderValue, "invalid overwrite: %s", s) 107 } 108 return s == "T", nil 109 } 110 111 // ParseDestination parses the destination header value defined in https://datatracker.ietf.org/doc/html/rfc4918#section-10.3 112 // The returned path will be relative to the given baseURI. 113 func ParseDestination(baseURI, s string) (string, error) { 114 if s == "" { 115 return "", errors.Wrap(ErrInvalidHeaderValue, "destination header is empty") 116 } 117 dstURL, err := url.ParseRequestURI(s) 118 if err != nil { 119 return "", errors.Wrap(ErrInvalidHeaderValue, err.Error()) 120 } 121 122 // TODO check if path is on same storage, return 502 on problems, see https://tools.ietf.org/html/rfc4918#section-9.9.4 123 // TODO make request.php optional in destination header 124 // Strip the base URI from the destination. The destination might contain redirection prefixes which need to be handled 125 urlSplit := strings.Split(dstURL.Path, baseURI) 126 if len(urlSplit) != 2 { 127 return "", errors.Wrap(ErrInvalidHeaderValue, "destination path does not contain base URI") 128 } 129 130 return urlSplit[1], nil 131 } 132 133 // ParsePrefer parses the prefer header value defined in https://datatracker.ietf.org/doc/html/rfc8144 134 func ParsePrefer(s string) map[string]string { 135 parts := strings.Split(s, ",") 136 m := make(map[string]string, len(parts)) 137 for _, part := range parts { 138 kv := strings.SplitN(strings.ToLower(strings.Trim(part, " ")), "=", 2) 139 if len(kv) == 2 { 140 m[kv[0]] = kv[1] 141 } else { 142 m[kv[0]] = "1" // mark it as set 143 } 144 } 145 return m 146 }