github.com/cs3org/reva/v2@v2.27.7/internal/http/services/owncloud/ocdav/if.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 // Copyright 2014 The Go Authors. All rights reserved. 20 // Use of this source code is governed by a BSD-style 21 // license that can be found in the LICENSE file. 22 23 package ocdav 24 25 // copy of https://github.com/golang/net/blob/master/webdav/if.go 26 27 // The If header is covered by Section 10.4. 28 // http://www.webdav.org/specs/rfc4918.html#HEADER_If 29 30 import ( 31 "strings" 32 ) 33 34 // ifHeader is a disjunction (OR) of ifLists. 35 type ifHeader struct { 36 lists []ifList 37 } 38 39 // ifList is a conjunction (AND) of Conditions, and an optional resource tag. 40 type ifList struct { 41 resourceTag string 42 conditions []Condition 43 } 44 45 // parseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string 46 // should omit the "If:" prefix and have any "\r\n"s collapsed to a " ", as is 47 // returned by req.Header.Get("If") for a http.Request req. 48 func parseIfHeader(httpHeader string) (h ifHeader, ok bool) { 49 s := strings.TrimSpace(httpHeader) 50 switch tokenType, _, _ := lex(s); tokenType { 51 case '(': 52 return parseNoTagLists(s) 53 case angleTokenType: 54 return parseTaggedLists(s) 55 default: 56 return ifHeader{}, false 57 } 58 } 59 60 func parseNoTagLists(s string) (h ifHeader, ok bool) { 61 for { 62 l, remaining, ok := parseList(s) 63 if !ok { 64 return ifHeader{}, false 65 } 66 h.lists = append(h.lists, l) 67 if remaining == "" { 68 return h, true 69 } 70 s = remaining 71 } 72 } 73 74 func parseTaggedLists(s string) (h ifHeader, ok bool) { 75 resourceTag, n := "", 0 76 for first := true; ; first = false { 77 tokenType, tokenStr, remaining := lex(s) 78 switch tokenType { 79 case angleTokenType: 80 if !first && n == 0 { 81 return ifHeader{}, false 82 } 83 resourceTag, n = tokenStr, 0 84 s = remaining 85 case '(': 86 n++ 87 l, remaining, ok := parseList(s) 88 if !ok { 89 return ifHeader{}, false 90 } 91 l.resourceTag = resourceTag 92 h.lists = append(h.lists, l) 93 if remaining == "" { 94 return h, true 95 } 96 s = remaining 97 default: 98 return ifHeader{}, false 99 } 100 } 101 } 102 103 func parseList(s string) (l ifList, remaining string, ok bool) { 104 tokenType, _, s := lex(s) 105 if tokenType != '(' { 106 return ifList{}, "", false 107 } 108 for { 109 tokenType, _, remaining = lex(s) 110 if tokenType == ')' { 111 if len(l.conditions) == 0 { 112 return ifList{}, "", false 113 } 114 return l, remaining, true 115 } 116 c, remaining, ok := parseCondition(s) 117 if !ok { 118 return ifList{}, "", false 119 } 120 l.conditions = append(l.conditions, c) 121 s = remaining 122 } 123 } 124 125 func parseCondition(s string) (c Condition, remaining string, ok bool) { 126 tokenType, tokenStr, s := lex(s) 127 if tokenType == notTokenType { 128 c.Not = true 129 tokenType, tokenStr, s = lex(s) 130 } 131 switch tokenType { 132 case strTokenType, angleTokenType: 133 c.Token = tokenStr 134 case squareTokenType: 135 c.ETag = tokenStr 136 default: 137 return Condition{}, "", false 138 } 139 return c, s, true 140 } 141 142 // Single-rune tokens like '(' or ')' have a token type equal to their rune. 143 // All other tokens have a negative token type. 144 const ( 145 errTokenType = rune(-1) 146 eofTokenType = rune(-2) 147 strTokenType = rune(-3) 148 notTokenType = rune(-4) 149 angleTokenType = rune(-5) 150 squareTokenType = rune(-6) 151 ) 152 153 func lex(s string) (tokenType rune, tokenStr string, remaining string) { 154 // The net/textproto Reader that parses the HTTP header will collapse 155 // Linear White Space that spans multiple "\r\n" lines to a single " ", 156 // so we don't need to look for '\r' or '\n'. 157 for len(s) > 0 && (s[0] == '\t' || s[0] == ' ') { 158 s = s[1:] 159 } 160 if len(s) == 0 { 161 return eofTokenType, "", "" 162 } 163 i := 0 164 loop: 165 for ; i < len(s); i++ { 166 switch s[i] { 167 case '\t', ' ', '(', ')', '<', '>', '[', ']': 168 break loop 169 } 170 } 171 172 if i != 0 { 173 tokenStr, remaining = s[:i], s[i:] 174 if tokenStr == "Not" { 175 return notTokenType, "", remaining 176 } 177 return strTokenType, tokenStr, remaining 178 } 179 180 j := 0 181 switch s[0] { 182 case '<': 183 j, tokenType = strings.IndexByte(s, '>'), angleTokenType 184 case '[': 185 j, tokenType = strings.IndexByte(s, ']'), squareTokenType 186 default: 187 return rune(s[0]), "", s[1:] 188 } 189 if j < 0 { 190 return errTokenType, "", "" 191 } 192 return tokenType, s[1:j], s[j+1:] 193 }