Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / github.com / grpc-ecosystem / grpc-gateway / runtime / query.go
1 package runtime
2
3 import (
4         "encoding/base64"
5         "fmt"
6         "net/url"
7         "reflect"
8         "regexp"
9         "strconv"
10         "strings"
11         "time"
12
13         "github.com/golang/protobuf/proto"
14         "github.com/grpc-ecosystem/grpc-gateway/utilities"
15         "google.golang.org/grpc/grpclog"
16 )
17
18 // PopulateQueryParameters populates "values" into "msg".
19 // A value is ignored if its key starts with one of the elements in "filter".
20 func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
21         for key, values := range values {
22                 re, err := regexp.Compile("^(.*)\\[(.*)\\]$")
23                 if err != nil {
24                         return err
25                 }
26                 match := re.FindStringSubmatch(key)
27                 if len(match) == 3 {
28                         key = match[1]
29                         values = append([]string{match[2]}, values...)
30                 }
31                 fieldPath := strings.Split(key, ".")
32                 if filter.HasCommonPrefix(fieldPath) {
33                         continue
34                 }
35                 if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
36                         return err
37                 }
38         }
39         return nil
40 }
41
42 // PopulateFieldFromPath sets a value in a nested Protobuf structure.
43 // It instantiates missing protobuf fields as it goes.
44 func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error {
45         fieldPath := strings.Split(fieldPathString, ".")
46         return populateFieldValueFromPath(msg, fieldPath, []string{value})
47 }
48
49 func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error {
50         m := reflect.ValueOf(msg)
51         if m.Kind() != reflect.Ptr {
52                 return fmt.Errorf("unexpected type %T: %v", msg, msg)
53         }
54         var props *proto.Properties
55         m = m.Elem()
56         for i, fieldName := range fieldPath {
57                 isLast := i == len(fieldPath)-1
58                 if !isLast && m.Kind() != reflect.Struct {
59                         return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, "."))
60                 }
61                 var f reflect.Value
62                 var err error
63                 f, props, err = fieldByProtoName(m, fieldName)
64                 if err != nil {
65                         return err
66                 } else if !f.IsValid() {
67                         grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
68                         return nil
69                 }
70
71                 switch f.Kind() {
72                 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
73                         if !isLast {
74                                 return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
75                         }
76                         m = f
77                 case reflect.Slice:
78                         if !isLast {
79                                 return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
80                         }
81                         // Handle []byte
82                         if f.Type().Elem().Kind() == reflect.Uint8 {
83                                 m = f
84                                 break
85                         }
86                         return populateRepeatedField(f, values, props)
87                 case reflect.Ptr:
88                         if f.IsNil() {
89                                 m = reflect.New(f.Type().Elem())
90                                 f.Set(m.Convert(f.Type()))
91                         }
92                         m = f.Elem()
93                         continue
94                 case reflect.Struct:
95                         m = f
96                         continue
97                 case reflect.Map:
98                         if !isLast {
99                                 return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
100                         }
101                         return populateMapField(f, values, props)
102                 default:
103                         return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
104                 }
105         }
106         switch len(values) {
107         case 0:
108                 return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
109         case 1:
110         default:
111                 grpclog.Infof("too many field values: %s", strings.Join(fieldPath, "."))
112         }
113         return populateField(m, values[0], props)
114 }
115
116 // fieldByProtoName looks up a field whose corresponding protobuf field name is "name".
117 // "m" must be a struct value. It returns zero reflect.Value if no such field found.
118 func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) {
119         props := proto.GetProperties(m.Type())
120
121         // look up field name in oneof map
122         if op, ok := props.OneofTypes[name]; ok {
123                 v := reflect.New(op.Type.Elem())
124                 field := m.Field(op.Field)
125                 if !field.IsNil() {
126                         return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName)
127                 }
128                 field.Set(v)
129                 return v.Elem().Field(0), op.Prop, nil
130         }
131
132         for _, p := range props.Prop {
133                 if p.OrigName == name {
134                         return m.FieldByName(p.Name), p, nil
135                 }
136                 if p.JSONName == name {
137                         return m.FieldByName(p.Name), p, nil
138                 }
139         }
140         return reflect.Value{}, nil, nil
141 }
142
143 func populateMapField(f reflect.Value, values []string, props *proto.Properties) error {
144         if len(values) != 2 {
145                 return fmt.Errorf("more than one value provided for key %s in map %s", values[0], props.Name)
146         }
147
148         key, value := values[0], values[1]
149         keyType := f.Type().Key()
150         valueType := f.Type().Elem()
151         if f.IsNil() {
152                 f.Set(reflect.MakeMap(f.Type()))
153         }
154
155         keyConv, ok := convFromType[keyType.Kind()]
156         if !ok {
157                 return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name)
158         }
159         valueConv, ok := convFromType[valueType.Kind()]
160         if !ok {
161                 return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name)
162         }
163
164         keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)})
165         if err := keyV[1].Interface(); err != nil {
166                 return err.(error)
167         }
168         valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)})
169         if err := valueV[1].Interface(); err != nil {
170                 return err.(error)
171         }
172
173         f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType))
174
175         return nil
176 }
177
178 func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
179         elemType := f.Type().Elem()
180
181         // is the destination field a slice of an enumeration type?
182         if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
183                 return populateFieldEnumRepeated(f, values, enumValMap)
184         }
185
186         conv, ok := convFromType[elemType.Kind()]
187         if !ok {
188                 return fmt.Errorf("unsupported field type %s", elemType)
189         }
190         f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
191         for i, v := range values {
192                 result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
193                 if err := result[1].Interface(); err != nil {
194                         return err.(error)
195                 }
196                 f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
197         }
198         return nil
199 }
200
201 func populateField(f reflect.Value, value string, props *proto.Properties) error {
202         i := f.Addr().Interface()
203
204         // Handle protobuf well known types
205         type wkt interface {
206                 XXX_WellKnownType() string
207         }
208         if wkt, ok := i.(wkt); ok {
209                 switch wkt.XXX_WellKnownType() {
210                 case "Timestamp":
211                         if value == "null" {
212                                 f.Field(0).SetInt(0)
213                                 f.Field(1).SetInt(0)
214                                 return nil
215                         }
216
217                         t, err := time.Parse(time.RFC3339Nano, value)
218                         if err != nil {
219                                 return fmt.Errorf("bad Timestamp: %v", err)
220                         }
221                         f.Field(0).SetInt(int64(t.Unix()))
222                         f.Field(1).SetInt(int64(t.Nanosecond()))
223                         return nil
224                 case "Duration":
225                         if value == "null" {
226                                 f.Field(0).SetInt(0)
227                                 f.Field(1).SetInt(0)
228                                 return nil
229                         }
230                         d, err := time.ParseDuration(value)
231                         if err != nil {
232                                 return fmt.Errorf("bad Duration: %v", err)
233                         }
234
235                         ns := d.Nanoseconds()
236                         s := ns / 1e9
237                         ns %= 1e9
238                         f.Field(0).SetInt(s)
239                         f.Field(1).SetInt(ns)
240                         return nil
241                 case "DoubleValue":
242                         fallthrough
243                 case "FloatValue":
244                         float64Val, err := strconv.ParseFloat(value, 64)
245                         if err != nil {
246                                 return fmt.Errorf("bad DoubleValue: %s", value)
247                         }
248                         f.Field(0).SetFloat(float64Val)
249                         return nil
250                 case "Int64Value":
251                         fallthrough
252                 case "Int32Value":
253                         int64Val, err := strconv.ParseInt(value, 10, 64)
254                         if err != nil {
255                                 return fmt.Errorf("bad DoubleValue: %s", value)
256                         }
257                         f.Field(0).SetInt(int64Val)
258                         return nil
259                 case "UInt64Value":
260                         fallthrough
261                 case "UInt32Value":
262                         uint64Val, err := strconv.ParseUint(value, 10, 64)
263                         if err != nil {
264                                 return fmt.Errorf("bad DoubleValue: %s", value)
265                         }
266                         f.Field(0).SetUint(uint64Val)
267                         return nil
268                 case "BoolValue":
269                         if value == "true" {
270                                 f.Field(0).SetBool(true)
271                         } else if value == "false" {
272                                 f.Field(0).SetBool(false)
273                         } else {
274                                 return fmt.Errorf("bad BoolValue: %s", value)
275                         }
276                         return nil
277                 case "StringValue":
278                         f.Field(0).SetString(value)
279                         return nil
280                 case "BytesValue":
281                         bytesVal, err := base64.StdEncoding.DecodeString(value)
282                         if err != nil {
283                                 return fmt.Errorf("bad BytesValue: %s", value)
284                         }
285                         f.Field(0).SetBytes(bytesVal)
286                         return nil
287                 }
288         }
289
290         // Handle google well known types
291         if gwkt, ok := i.(proto.Message); ok {
292                 switch proto.MessageName(gwkt) {
293                 case "google.protobuf.FieldMask":
294                         p := f.Field(0)
295                         for _, v := range strings.Split(value, ",") {
296                                 if v != "" {
297                                         p.Set(reflect.Append(p, reflect.ValueOf(v)))
298                                 }
299                         }
300                         return nil
301                 }
302         }
303
304         // Handle Time and Duration stdlib types
305         switch t := i.(type) {
306         case *time.Time:
307                 pt, err := time.Parse(time.RFC3339Nano, value)
308                 if err != nil {
309                         return fmt.Errorf("bad Timestamp: %v", err)
310                 }
311                 *t = pt
312                 return nil
313         case *time.Duration:
314                 d, err := time.ParseDuration(value)
315                 if err != nil {
316                         return fmt.Errorf("bad Duration: %v", err)
317                 }
318                 *t = d
319                 return nil
320         }
321
322         // is the destination field an enumeration type?
323         if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
324                 return populateFieldEnum(f, value, enumValMap)
325         }
326
327         conv, ok := convFromType[f.Kind()]
328         if !ok {
329                 return fmt.Errorf("field type %T is not supported in query parameters", i)
330         }
331         result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
332         if err := result[1].Interface(); err != nil {
333                 return err.(error)
334         }
335         f.Set(result[0].Convert(f.Type()))
336         return nil
337 }
338
339 func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
340         // see if it's an enumeration string
341         if enumVal, ok := enumValMap[value]; ok {
342                 return reflect.ValueOf(enumVal).Convert(t), nil
343         }
344
345         // check for an integer that matches an enumeration value
346         eVal, err := strconv.Atoi(value)
347         if err != nil {
348                 return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
349         }
350         for _, v := range enumValMap {
351                 if v == int32(eVal) {
352                         return reflect.ValueOf(eVal).Convert(t), nil
353                 }
354         }
355         return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
356 }
357
358 func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
359         cval, err := convertEnum(value, f.Type(), enumValMap)
360         if err != nil {
361                 return err
362         }
363         f.Set(cval)
364         return nil
365 }
366
367 func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
368         elemType := f.Type().Elem()
369         f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
370         for i, v := range values {
371                 result, err := convertEnum(v, elemType, enumValMap)
372                 if err != nil {
373                         return err
374                 }
375                 f.Index(i).Set(result)
376         }
377         return nil
378 }
379
380 var (
381         convFromType = map[reflect.Kind]reflect.Value{
382                 reflect.String:  reflect.ValueOf(String),
383                 reflect.Bool:    reflect.ValueOf(Bool),
384                 reflect.Float64: reflect.ValueOf(Float64),
385                 reflect.Float32: reflect.ValueOf(Float32),
386                 reflect.Int64:   reflect.ValueOf(Int64),
387                 reflect.Int32:   reflect.ValueOf(Int32),
388                 reflect.Uint64:  reflect.ValueOf(Uint64),
389                 reflect.Uint32:  reflect.ValueOf(Uint32),
390                 reflect.Slice:   reflect.ValueOf(Bytes),
391         }
392 )