1/* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19package resolver 20 21import ( 22 "fmt" 23 "regexp" 24 "strconv" 25 "strings" 26 27 "google.golang.org/grpc/metadata" 28) 29 30type headerMatcherInterface interface { 31 match(metadata.MD) bool 32 String() string 33} 34 35// mdValuesFromOutgoingCtx retrieves metadata from context. If there are 36// multiple values, the values are concatenated with "," (comma and no space). 37// 38// All header matchers only match against the comma-concatenated string. 39func mdValuesFromOutgoingCtx(md metadata.MD, key string) (string, bool) { 40 vs, ok := md[key] 41 if !ok { 42 return "", false 43 } 44 return strings.Join(vs, ","), true 45} 46 47type headerExactMatcher struct { 48 key string 49 exact string 50} 51 52func newHeaderExactMatcher(key, exact string) *headerExactMatcher { 53 return &headerExactMatcher{key: key, exact: exact} 54} 55 56func (hem *headerExactMatcher) match(md metadata.MD) bool { 57 v, ok := mdValuesFromOutgoingCtx(md, hem.key) 58 if !ok { 59 return false 60 } 61 return v == hem.exact 62} 63 64func (hem *headerExactMatcher) String() string { 65 return fmt.Sprintf("headerExact:%v:%v", hem.key, hem.exact) 66} 67 68type headerRegexMatcher struct { 69 key string 70 re *regexp.Regexp 71} 72 73func newHeaderRegexMatcher(key string, re *regexp.Regexp) *headerRegexMatcher { 74 return &headerRegexMatcher{key: key, re: re} 75} 76 77func (hrm *headerRegexMatcher) match(md metadata.MD) bool { 78 v, ok := mdValuesFromOutgoingCtx(md, hrm.key) 79 if !ok { 80 return false 81 } 82 return hrm.re.MatchString(v) 83} 84 85func (hrm *headerRegexMatcher) String() string { 86 return fmt.Sprintf("headerRegex:%v:%v", hrm.key, hrm.re.String()) 87} 88 89type headerRangeMatcher struct { 90 key string 91 start, end int64 // represents [start, end). 92} 93 94func newHeaderRangeMatcher(key string, start, end int64) *headerRangeMatcher { 95 return &headerRangeMatcher{key: key, start: start, end: end} 96} 97 98func (hrm *headerRangeMatcher) match(md metadata.MD) bool { 99 v, ok := mdValuesFromOutgoingCtx(md, hrm.key) 100 if !ok { 101 return false 102 } 103 if i, err := strconv.ParseInt(v, 10, 64); err == nil && i >= hrm.start && i < hrm.end { 104 return true 105 } 106 return false 107} 108 109func (hrm *headerRangeMatcher) String() string { 110 return fmt.Sprintf("headerRange:%v:[%d,%d)", hrm.key, hrm.start, hrm.end) 111} 112 113type headerPresentMatcher struct { 114 key string 115 present bool 116} 117 118func newHeaderPresentMatcher(key string, present bool) *headerPresentMatcher { 119 return &headerPresentMatcher{key: key, present: present} 120} 121 122func (hpm *headerPresentMatcher) match(md metadata.MD) bool { 123 vs, ok := mdValuesFromOutgoingCtx(md, hpm.key) 124 present := ok && len(vs) > 0 125 return present == hpm.present 126} 127 128func (hpm *headerPresentMatcher) String() string { 129 return fmt.Sprintf("headerPresent:%v:%v", hpm.key, hpm.present) 130} 131 132type headerPrefixMatcher struct { 133 key string 134 prefix string 135} 136 137func newHeaderPrefixMatcher(key string, prefix string) *headerPrefixMatcher { 138 return &headerPrefixMatcher{key: key, prefix: prefix} 139} 140 141func (hpm *headerPrefixMatcher) match(md metadata.MD) bool { 142 v, ok := mdValuesFromOutgoingCtx(md, hpm.key) 143 if !ok { 144 return false 145 } 146 return strings.HasPrefix(v, hpm.prefix) 147} 148 149func (hpm *headerPrefixMatcher) String() string { 150 return fmt.Sprintf("headerPrefix:%v:%v", hpm.key, hpm.prefix) 151} 152 153type headerSuffixMatcher struct { 154 key string 155 suffix string 156} 157 158func newHeaderSuffixMatcher(key string, suffix string) *headerSuffixMatcher { 159 return &headerSuffixMatcher{key: key, suffix: suffix} 160} 161 162func (hsm *headerSuffixMatcher) match(md metadata.MD) bool { 163 v, ok := mdValuesFromOutgoingCtx(md, hsm.key) 164 if !ok { 165 return false 166 } 167 return strings.HasSuffix(v, hsm.suffix) 168} 169 170func (hsm *headerSuffixMatcher) String() string { 171 return fmt.Sprintf("headerSuffix:%v:%v", hsm.key, hsm.suffix) 172} 173 174type invertMatcher struct { 175 m headerMatcherInterface 176} 177 178func newInvertMatcher(m headerMatcherInterface) *invertMatcher { 179 return &invertMatcher{m: m} 180} 181 182func (i *invertMatcher) match(md metadata.MD) bool { 183 return !i.m.match(md) 184} 185 186func (i *invertMatcher) String() string { 187 return fmt.Sprintf("invert{%s}", i.m) 188} 189