13 "github.com/golang/protobuf/proto"
14 "github.com/grpc-ecosystem/grpc-gateway/utilities"
15 "google.golang.org/grpc/grpclog"
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("^(.*)\\[(.*)\\]$")
26 match := re.FindStringSubmatch(key)
29 values = append([]string{match[2]}, values...)
31 fieldPath := strings.Split(key, ".")
32 if filter.HasCommonPrefix(fieldPath) {
35 if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
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})
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)
54 var props *proto.Properties
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, "."))
63 f, props, err = fieldByProtoName(m, fieldName)
66 } else if !f.IsValid() {
67 grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
72 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
74 return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
79 return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
82 if f.Type().Elem().Kind() == reflect.Uint8 {
86 return populateRepeatedField(f, values, props)
89 m = reflect.New(f.Type().Elem())
90 f.Set(m.Convert(f.Type()))
99 return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
101 return populateMapField(f, values, props)
103 return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
108 return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
111 grpclog.Infof("too many field values: %s", strings.Join(fieldPath, "."))
113 return populateField(m, values[0], props)
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())
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)
126 return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName)
129 return v.Elem().Field(0), op.Prop, nil
132 for _, p := range props.Prop {
133 if p.OrigName == name {
134 return m.FieldByName(p.Name), p, nil
136 if p.JSONName == name {
137 return m.FieldByName(p.Name), p, nil
140 return reflect.Value{}, nil, nil
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)
148 key, value := values[0], values[1]
149 keyType := f.Type().Key()
150 valueType := f.Type().Elem()
152 f.Set(reflect.MakeMap(f.Type()))
155 keyConv, ok := convFromType[keyType.Kind()]
157 return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name)
159 valueConv, ok := convFromType[valueType.Kind()]
161 return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name)
164 keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)})
165 if err := keyV[1].Interface(); err != nil {
168 valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)})
169 if err := valueV[1].Interface(); err != nil {
173 f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType))
178 func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
179 elemType := f.Type().Elem()
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)
186 conv, ok := convFromType[elemType.Kind()]
188 return fmt.Errorf("unsupported field type %s", elemType)
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 {
196 f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
201 func populateField(f reflect.Value, value string, props *proto.Properties) error {
202 i := f.Addr().Interface()
204 // Handle protobuf well known types
206 XXX_WellKnownType() string
208 if wkt, ok := i.(wkt); ok {
209 switch wkt.XXX_WellKnownType() {
217 t, err := time.Parse(time.RFC3339Nano, value)
219 return fmt.Errorf("bad Timestamp: %v", err)
221 f.Field(0).SetInt(int64(t.Unix()))
222 f.Field(1).SetInt(int64(t.Nanosecond()))
230 d, err := time.ParseDuration(value)
232 return fmt.Errorf("bad Duration: %v", err)
235 ns := d.Nanoseconds()
239 f.Field(1).SetInt(ns)
244 float64Val, err := strconv.ParseFloat(value, 64)
246 return fmt.Errorf("bad DoubleValue: %s", value)
248 f.Field(0).SetFloat(float64Val)
253 int64Val, err := strconv.ParseInt(value, 10, 64)
255 return fmt.Errorf("bad DoubleValue: %s", value)
257 f.Field(0).SetInt(int64Val)
262 uint64Val, err := strconv.ParseUint(value, 10, 64)
264 return fmt.Errorf("bad DoubleValue: %s", value)
266 f.Field(0).SetUint(uint64Val)
270 f.Field(0).SetBool(true)
271 } else if value == "false" {
272 f.Field(0).SetBool(false)
274 return fmt.Errorf("bad BoolValue: %s", value)
278 f.Field(0).SetString(value)
281 bytesVal, err := base64.StdEncoding.DecodeString(value)
283 return fmt.Errorf("bad BytesValue: %s", value)
285 f.Field(0).SetBytes(bytesVal)
290 // Handle google well known types
291 if gwkt, ok := i.(proto.Message); ok {
292 switch proto.MessageName(gwkt) {
293 case "google.protobuf.FieldMask":
295 for _, v := range strings.Split(value, ",") {
297 p.Set(reflect.Append(p, reflect.ValueOf(v)))
304 // Handle Time and Duration stdlib types
305 switch t := i.(type) {
307 pt, err := time.Parse(time.RFC3339Nano, value)
309 return fmt.Errorf("bad Timestamp: %v", err)
314 d, err := time.ParseDuration(value)
316 return fmt.Errorf("bad Duration: %v", err)
322 // is the destination field an enumeration type?
323 if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
324 return populateFieldEnum(f, value, enumValMap)
327 conv, ok := convFromType[f.Kind()]
329 return fmt.Errorf("field type %T is not supported in query parameters", i)
331 result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
332 if err := result[1].Interface(); err != nil {
335 f.Set(result[0].Convert(f.Type()))
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
345 // check for an integer that matches an enumeration value
346 eVal, err := strconv.Atoi(value)
348 return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
350 for _, v := range enumValMap {
351 if v == int32(eVal) {
352 return reflect.ValueOf(eVal).Convert(t), nil
355 return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
358 func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
359 cval, err := convertEnum(value, f.Type(), enumValMap)
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)
375 f.Index(i).Set(result)
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),