@@ -29,25 +29,11 @@ import (
2929 "google.golang.org/grpc/metadata"
3030)
3131
32- // BuilderMap provides a mapping from a request path to the key builder to be
33- // used for that path.
34- // The BuilderMap is constructed by parsing the RouteLookupConfig received by
35- // the RLS balancer as part of its ServiceConfig, and is used by the picker in
36- // the data path to build the RLS keys to be used for a given request.
32+ // BuilderMap maps from request path to the key builder for that path.
3733type BuilderMap map [string ]builder
3834
3935// MakeBuilderMap parses the provided RouteLookupConfig proto and returns a map
4036// from paths to key builders.
41- //
42- // The following conditions are validated, and an error is returned if any of
43- // them is not met:
44- // grpc_keybuilders field
45- // * must have at least one entry
46- // * must not have two entries with the same Name
47- // * must not have any entry with a Name with the service field unset or empty
48- // * must not have any entries without a Name
49- // * must not have a headers entry that has required_match set
50- // * must not have two headers entries with the same key within one entry
5137func MakeBuilderMap (cfg * rlspb.RouteLookupConfig ) (BuilderMap , error ) {
5238 kbs := cfg .GetGrpcKeybuilders ()
5339 if len (kbs ) == 0 {
@@ -56,21 +42,46 @@ func MakeBuilderMap(cfg *rlspb.RouteLookupConfig) (BuilderMap, error) {
5642
5743 bm := make (map [string ]builder )
5844 for _ , kb := range kbs {
45+ // Extract keys from `headers`, `constant_keys` and `extra_keys` fields
46+ // and populate appropriate values in the builder struct. Also ensure
47+ // that keys are not repeated.
5948 var matchers []matcher
6049 seenKeys := make (map [string ]bool )
50+ constantKeys := kb .GetConstantKeys ()
51+ for k := range kb .GetConstantKeys () {
52+ seenKeys [k ] = true
53+ }
6154 for _ , h := range kb .GetHeaders () {
6255 if h .GetRequiredMatch () {
6356 return nil , fmt .Errorf ("rls: GrpcKeyBuilder in RouteLookupConfig has required_match field set {%+v}" , kbs )
6457 }
6558 key := h .GetKey ()
6659 if seenKeys [key ] {
67- return nil , fmt .Errorf ("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated Key field in headers {%+v}" , kbs )
60+ return nil , fmt .Errorf ("rls: GrpcKeyBuilder in RouteLookupConfig contains repeated key %q across headers, constant_keys and extra_keys {%+v}" , key , kbs )
6861 }
6962 seenKeys [key ] = true
7063 matchers = append (matchers , matcher {key : h .GetKey (), names : h .GetNames ()})
7164 }
72- b := builder {matchers : matchers }
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+ }
7381
82+ // Store the builder created above in the BuilderMap based on the value
83+ // of the `Names` field, which wraps incoming request's service and
84+ // method. Also, ensure that there are no repeated `Names` field.
7485 names := kb .GetNames ()
7586 if len (names ) == 0 {
7687 return nil , fmt .Errorf ("rls: GrpcKeyBuilder in RouteLookupConfig does not contain any Name {%+v}" , kbs )
@@ -108,16 +119,31 @@ type KeyMap struct {
108119
109120// RLSKey builds the RLS keys to be used for the given request, identified by
110121// the request path and the request headers stored in metadata.
111- func (bm BuilderMap ) RLSKey (md metadata.MD , path string ) KeyMap {
122+ func (bm BuilderMap ) RLSKey (md metadata.MD , host , path string ) KeyMap {
123+ i := strings .LastIndex (path , "/" )
124+ service , method := path [:i + 1 ], path [i + 1 :]
112125 b , ok := bm [path ]
113126 if ! ok {
114- i := strings .LastIndex (path , "/" )
115- b , ok = bm [path [:i + 1 ]]
127+ b , ok = bm [service ]
116128 if ! ok {
117129 return KeyMap {}
118130 }
119131 }
120- return b .keys (md )
132+
133+ kvMap := b .buildHeaderKeys (md )
134+ if b .hostKey != "" {
135+ kvMap [b .hostKey ] = host
136+ }
137+ if b .serviceKey != "" {
138+ kvMap [b .serviceKey ] = service
139+ }
140+ if b .methodKey != "" {
141+ kvMap [b .methodKey ] = method
142+ }
143+ for k , v := range b .constantKeys {
144+ kvMap [k ] = v
145+ }
146+ return KeyMap {Map : kvMap , Str : mapToString (kvMap )}
121147}
122148
123149// Equal reports whether bm and am represent equivalent BuilderMaps.
@@ -141,40 +167,43 @@ func (bm BuilderMap) Equal(am BuilderMap) bool {
141167 return true
142168}
143169
144- // builder provides the actual functionality of building RLS keys. These are
145- // stored in the BuilderMap.
146- // While processing a pick, the picker looks in the BuilderMap for the
147- // appropriate builder to be used for the given RPC. For each of the matchers
148- // in the found builder, we iterate over the list of request headers (available
149- // as metadata in the context). Once a header matches one of the names in the
150- // matcher, we set the value of the header in the keyMap (with the key being
151- // the one found in the matcher) and move on to the next matcher. If no
152- // KeyBuilder was found in the map, or no header match was found, an empty
153- // keyMap is returned.
170+ // builder provides the actual functionality of building RLS keys.
154171type builder struct {
155- matchers []matcher
172+ headerKeys []matcher
173+ constantKeys map [string ]string
174+ // The following keys mirror corresponding fields in `extra_keys`.
175+ hostKey string
176+ serviceKey string
177+ methodKey string
156178}
157179
158180// Equal reports whether b and a represent equivalent key builders.
159181func (b builder ) Equal (a builder ) bool {
160- if (b .matchers == nil ) != (a .matchers == nil ) {
161- return false
162- }
163- if len (b .matchers ) != len (a .matchers ) {
182+ if len (b .headerKeys ) != len (a .headerKeys ) {
164183 return false
165184 }
166185 // Protobuf serialization maintains the order of repeated fields. Matchers
167186 // are specified as a repeated field inside the KeyBuilder proto. If the
168187 // order changes, it means that the order in the protobuf changed. We report
169188 // this case as not being equal even though the builders could possible be
170189 // functionally equal.
171- for i , bMatcher := range b .matchers {
172- aMatcher := a .matchers [i ]
190+ for i , bMatcher := range b .headerKeys {
191+ aMatcher := a .headerKeys [i ]
173192 if ! bMatcher .Equal (aMatcher ) {
174193 return false
175194 }
176195 }
177- return true
196+
197+ if len (b .constantKeys ) != len (a .constantKeys ) {
198+ return false
199+ }
200+ for k , v := range b .constantKeys {
201+ if a .constantKeys [k ] != v {
202+ return false
203+ }
204+ }
205+
206+ return b .hostKey == a .hostKey && b .serviceKey == a .serviceKey && b .methodKey == a .methodKey
178207}
179208
180209// matcher helps extract a key from request headers based on a given name.
@@ -185,14 +214,11 @@ type matcher struct {
185214 names []string
186215}
187216
188- // Equal reports if m and are are equivalent matchers .
217+ // Equal reports if m and are are equivalent headerKeys .
189218func (m matcher ) Equal (a matcher ) bool {
190219 if m .key != a .key {
191220 return false
192221 }
193- if (m .names == nil ) != (a .names == nil ) {
194- return false
195- }
196222 if len (m .names ) != len (a .names ) {
197223 return false
198224 }
@@ -204,17 +230,20 @@ func (m matcher) Equal(a matcher) bool {
204230 return true
205231}
206232
207- func (b builder ) keys (md metadata.MD ) KeyMap {
233+ func (b builder ) buildHeaderKeys (md metadata.MD ) map [ string ] string {
208234 kvMap := make (map [string ]string )
209- for _ , m := range b .matchers {
235+ if len (md ) == 0 {
236+ return kvMap
237+ }
238+ for _ , m := range b .headerKeys {
210239 for _ , name := range m .names {
211240 if vals := md .Get (name ); vals != nil {
212241 kvMap [m .key ] = strings .Join (vals , "," )
213242 break
214243 }
215244 }
216245 }
217- return KeyMap { Map : kvMap , Str : mapToString ( kvMap )}
246+ return kvMap
218247}
219248
220249func mapToString (kv map [string ]string ) string {
0 commit comments