1
18
19 package matcher
20
21 import (
22 "fmt"
23 "regexp"
24 "strconv"
25 "strings"
26
27 "google.golang.org/grpc/internal/grpcutil"
28 "google.golang.org/grpc/metadata"
29 )
30
31
32
33
34 type HeaderMatcher interface {
35 Match(metadata.MD) bool
36 String() string
37 }
38
39
40
41
42
43 func mdValuesFromOutgoingCtx(md metadata.MD, key string) (string, bool) {
44 vs, ok := md[key]
45 if !ok {
46 return "", false
47 }
48 return strings.Join(vs, ","), true
49 }
50
51
52 type HeaderExactMatcher struct {
53 key string
54 exact string
55 invert bool
56 }
57
58
59 func NewHeaderExactMatcher(key, exact string, invert bool) *HeaderExactMatcher {
60 return &HeaderExactMatcher{key: key, exact: exact, invert: invert}
61 }
62
63
64
65 func (hem *HeaderExactMatcher) Match(md metadata.MD) bool {
66 v, ok := mdValuesFromOutgoingCtx(md, hem.key)
67 if !ok {
68 return false
69 }
70 return (v == hem.exact) != hem.invert
71 }
72
73 func (hem *HeaderExactMatcher) String() string {
74 return fmt.Sprintf("headerExact:%v:%v", hem.key, hem.exact)
75 }
76
77
78
79 type HeaderRegexMatcher struct {
80 key string
81 re *regexp.Regexp
82 invert bool
83 }
84
85
86 func NewHeaderRegexMatcher(key string, re *regexp.Regexp, invert bool) *HeaderRegexMatcher {
87 return &HeaderRegexMatcher{key: key, re: re, invert: invert}
88 }
89
90
91
92 func (hrm *HeaderRegexMatcher) Match(md metadata.MD) bool {
93 v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
94 if !ok {
95 return false
96 }
97 return grpcutil.FullMatchWithRegex(hrm.re, v) != hrm.invert
98 }
99
100 func (hrm *HeaderRegexMatcher) String() string {
101 return fmt.Sprintf("headerRegex:%v:%v", hrm.key, hrm.re.String())
102 }
103
104
105
106 type HeaderRangeMatcher struct {
107 key string
108 start, end int64
109 invert bool
110 }
111
112
113 func NewHeaderRangeMatcher(key string, start, end int64, invert bool) *HeaderRangeMatcher {
114 return &HeaderRangeMatcher{key: key, start: start, end: end, invert: invert}
115 }
116
117
118
119 func (hrm *HeaderRangeMatcher) Match(md metadata.MD) bool {
120 v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
121 if !ok {
122 return false
123 }
124 if i, err := strconv.ParseInt(v, 10, 64); err == nil && i >= hrm.start && i < hrm.end {
125 return !hrm.invert
126 }
127 return hrm.invert
128 }
129
130 func (hrm *HeaderRangeMatcher) String() string {
131 return fmt.Sprintf("headerRange:%v:[%d,%d)", hrm.key, hrm.start, hrm.end)
132 }
133
134
135
136 type HeaderPresentMatcher struct {
137 key string
138 present bool
139 }
140
141
142 func NewHeaderPresentMatcher(key string, present bool, invert bool) *HeaderPresentMatcher {
143 if invert {
144 present = !present
145 }
146 return &HeaderPresentMatcher{key: key, present: present}
147 }
148
149
150
151 func (hpm *HeaderPresentMatcher) Match(md metadata.MD) bool {
152 vs, ok := mdValuesFromOutgoingCtx(md, hpm.key)
153 present := ok && len(vs) > 0
154 return present == hpm.present
155 }
156
157 func (hpm *HeaderPresentMatcher) String() string {
158 return fmt.Sprintf("headerPresent:%v:%v", hpm.key, hpm.present)
159 }
160
161
162
163 type HeaderPrefixMatcher struct {
164 key string
165 prefix string
166 invert bool
167 }
168
169
170 func NewHeaderPrefixMatcher(key string, prefix string, invert bool) *HeaderPrefixMatcher {
171 return &HeaderPrefixMatcher{key: key, prefix: prefix, invert: invert}
172 }
173
174
175
176 func (hpm *HeaderPrefixMatcher) Match(md metadata.MD) bool {
177 v, ok := mdValuesFromOutgoingCtx(md, hpm.key)
178 if !ok {
179 return false
180 }
181 return strings.HasPrefix(v, hpm.prefix) != hpm.invert
182 }
183
184 func (hpm *HeaderPrefixMatcher) String() string {
185 return fmt.Sprintf("headerPrefix:%v:%v", hpm.key, hpm.prefix)
186 }
187
188
189
190 type HeaderSuffixMatcher struct {
191 key string
192 suffix string
193 invert bool
194 }
195
196
197 func NewHeaderSuffixMatcher(key string, suffix string, invert bool) *HeaderSuffixMatcher {
198 return &HeaderSuffixMatcher{key: key, suffix: suffix, invert: invert}
199 }
200
201
202
203 func (hsm *HeaderSuffixMatcher) Match(md metadata.MD) bool {
204 v, ok := mdValuesFromOutgoingCtx(md, hsm.key)
205 if !ok {
206 return false
207 }
208 return strings.HasSuffix(v, hsm.suffix) != hsm.invert
209 }
210
211 func (hsm *HeaderSuffixMatcher) String() string {
212 return fmt.Sprintf("headerSuffix:%v:%v", hsm.key, hsm.suffix)
213 }
214
215
216
217 type HeaderContainsMatcher struct {
218 key string
219 contains string
220 invert bool
221 }
222
223
224
225
226
227 func NewHeaderContainsMatcher(key string, contains string, invert bool) *HeaderContainsMatcher {
228 return &HeaderContainsMatcher{key: key, contains: contains, invert: invert}
229 }
230
231
232
233 func (hcm *HeaderContainsMatcher) Match(md metadata.MD) bool {
234 v, ok := mdValuesFromOutgoingCtx(md, hcm.key)
235 if !ok {
236 return false
237 }
238 return strings.Contains(v, hcm.contains) != hcm.invert
239 }
240
241 func (hcm *HeaderContainsMatcher) String() string {
242 return fmt.Sprintf("headerContains:%v%v", hcm.key, hcm.contains)
243 }
244
245
246
247 type HeaderStringMatcher struct {
248 key string
249 stringMatcher StringMatcher
250 invert bool
251 }
252
253
254 func NewHeaderStringMatcher(key string, sm StringMatcher, invert bool) *HeaderStringMatcher {
255 return &HeaderStringMatcher{
256 key: key,
257 stringMatcher: sm,
258 invert: invert,
259 }
260 }
261
262
263
264 func (hsm *HeaderStringMatcher) Match(md metadata.MD) bool {
265 v, ok := mdValuesFromOutgoingCtx(md, hsm.key)
266 if !ok {
267 return false
268 }
269 return hsm.stringMatcher.Match(v) != hsm.invert
270 }
271
272 func (hsm *HeaderStringMatcher) String() string {
273 return fmt.Sprintf("headerString:%v:%v", hsm.key, hsm.stringMatcher)
274 }
275
View as plain text