1
18
19
20 package keys
21
22 import (
23 "errors"
24 "fmt"
25 "sort"
26 "strings"
27
28 rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1"
29 "google.golang.org/grpc/metadata"
30 )
31
32
33 type BuilderMap map[string]builder
34
35
36
37 func MakeBuilderMap(cfg *rlspb.RouteLookupConfig) (BuilderMap, error) {
38 kbs := cfg.GetGrpcKeybuilders()
39 if len(kbs) == 0 {
40 return nil, errors.New("rls: RouteLookupConfig does not contain any GrpcKeyBuilder")
41 }
42
43 bm := make(map[string]builder)
44 for _, kb := range kbs {
45
46
47
48 var matchers []matcher
49 seenKeys := make(map[string]bool)
50 constantKeys := kb.GetConstantKeys()
51 for k := range kb.GetConstantKeys() {
52 seenKeys[k] = true
53 }
54 for _, h := range kb.GetHeaders() {
55 if h.GetRequiredMatch() {
56 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig has required_match field set {%+v}", kbs)
57 }
58 key := h.GetKey()
59 if seenKeys[key] {
60 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}", key, kbs)
61 }
62 seenKeys[key] = true
63 matchers = append(matchers, matcher{key: h.GetKey(), names: h.GetNames()})
64 }
65 if seenKeys[kb.GetExtraKeys().GetHost()] {
66 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetHost(), kbs)
67 }
68 if seenKeys[kb.GetExtraKeys().GetService()] {
69 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetService(), kbs)
70 }
71 if seenKeys[kb.GetExtraKeys().GetMethod()] {
72 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q in extra_keys from constant_keys or headers {%+v}", kb.GetExtraKeys().GetMethod(), kbs)
73 }
74 b := builder{
75 headerKeys: matchers,
76 constantKeys: constantKeys,
77 hostKey: kb.GetExtraKeys().GetHost(),
78 serviceKey: kb.GetExtraKeys().GetService(),
79 methodKey: kb.GetExtraKeys().GetMethod(),
80 }
81
82
83
84
85 names := kb.GetNames()
86 if len(names) == 0 {
87 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig does not contain any Name {%+v}", kbs)
88 }
89 for _, name := range names {
90 if name.GetService() == "" {
91 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains a Name field with no Service {%+v}", kbs)
92 }
93 if strings.Contains(name.GetMethod(), `/`) {
94 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains a method with a slash {%+v}", kbs)
95 }
96 path := "/" + name.GetService() + "/" + name.GetMethod()
97 if _, ok := bm[path]; ok {
98 return nil, fmt.Errorf("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Name field {%+v}", kbs)
99 }
100 bm[path] = b
101 }
102 }
103 return bm, nil
104 }
105
106
107 type KeyMap struct {
108
109
110
111 Map map[string]string
112
113
114
115
116
117 Str string
118 }
119
120
121
122 func (bm BuilderMap) RLSKey(md metadata.MD, host, path string) KeyMap {
123
124
125
126
127 i := strings.LastIndex(path, "/")
128 service, method := path[:i+1], path[i+1:]
129 b, ok := bm[path]
130 if !ok {
131 b, ok = bm[service]
132 if !ok {
133 return KeyMap{}
134 }
135 }
136
137 kvMap := b.buildHeaderKeys(md)
138 if b.hostKey != "" {
139 kvMap[b.hostKey] = host
140 }
141 if b.serviceKey != "" {
142 kvMap[b.serviceKey] = strings.Trim(service, "/")
143 }
144 if b.methodKey != "" {
145 kvMap[b.methodKey] = method
146 }
147 for k, v := range b.constantKeys {
148 kvMap[k] = v
149 }
150 return KeyMap{Map: kvMap, Str: mapToString(kvMap)}
151 }
152
153
154 func (bm BuilderMap) Equal(am BuilderMap) bool {
155 if (bm == nil) != (am == nil) {
156 return false
157 }
158 if len(bm) != len(am) {
159 return false
160 }
161
162 for key, bBuilder := range bm {
163 aBuilder, ok := am[key]
164 if !ok {
165 return false
166 }
167 if !bBuilder.Equal(aBuilder) {
168 return false
169 }
170 }
171 return true
172 }
173
174
175 type builder struct {
176 headerKeys []matcher
177 constantKeys map[string]string
178
179 hostKey string
180 serviceKey string
181 methodKey string
182 }
183
184
185 func (b builder) Equal(a builder) bool {
186 if len(b.headerKeys) != len(a.headerKeys) {
187 return false
188 }
189
190
191
192
193
194 for i, bMatcher := range b.headerKeys {
195 aMatcher := a.headerKeys[i]
196 if !bMatcher.Equal(aMatcher) {
197 return false
198 }
199 }
200
201 if len(b.constantKeys) != len(a.constantKeys) {
202 return false
203 }
204 for k, v := range b.constantKeys {
205 if a.constantKeys[k] != v {
206 return false
207 }
208 }
209
210 return b.hostKey == a.hostKey && b.serviceKey == a.serviceKey && b.methodKey == a.methodKey
211 }
212
213
214 type matcher struct {
215
216 key string
217
218 names []string
219 }
220
221
222 func (m matcher) Equal(a matcher) bool {
223 if m.key != a.key {
224 return false
225 }
226 if len(m.names) != len(a.names) {
227 return false
228 }
229 for i := 0; i < len(m.names); i++ {
230 if m.names[i] != a.names[i] {
231 return false
232 }
233 }
234 return true
235 }
236
237 func (b builder) buildHeaderKeys(md metadata.MD) map[string]string {
238 kvMap := make(map[string]string)
239 if len(md) == 0 {
240 return kvMap
241 }
242 for _, m := range b.headerKeys {
243 for _, name := range m.names {
244 if vals := md.Get(name); vals != nil {
245 kvMap[m.key] = strings.Join(vals, ",")
246 break
247 }
248 }
249 }
250 return kvMap
251 }
252
253 func mapToString(kv map[string]string) string {
254 keys := make([]string, 0, len(kv))
255 for k := range kv {
256 keys = append(keys, k)
257 }
258 sort.Strings(keys)
259 var sb strings.Builder
260 for i, k := range keys {
261 if i != 0 {
262 fmt.Fprint(&sb, ",")
263 }
264 fmt.Fprintf(&sb, "%s=%s", k, kv[k])
265 }
266 return sb.String()
267 }
268
View as plain text