src: Add DMA localagent
[barometer.git] / src / dma / vendor / github.com / labstack / echo / bind.go
1 package echo
2
3 import (
4         "encoding/json"
5         "encoding/xml"
6         "errors"
7         "fmt"
8         "net/http"
9         "reflect"
10         "strconv"
11         "strings"
12 )
13
14 type (
15         // Binder is the interface that wraps the Bind method.
16         Binder interface {
17                 Bind(i interface{}, c Context) error
18         }
19
20         // DefaultBinder is the default implementation of the Binder interface.
21         DefaultBinder struct{}
22
23         // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
24         BindUnmarshaler interface {
25                 // UnmarshalParam decodes and assigns a value from an form or query param.
26                 UnmarshalParam(param string) error
27         }
28 )
29
30 // Bind implements the `Binder#Bind` function.
31 func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
32         req := c.Request()
33         if req.ContentLength == 0 {
34                 if req.Method == GET || req.Method == DELETE {
35                         if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
36                                 return NewHTTPError(http.StatusBadRequest, err.Error())
37                         }
38                         return
39                 }
40                 return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
41         }
42         ctype := req.Header.Get(HeaderContentType)
43         switch {
44         case strings.HasPrefix(ctype, MIMEApplicationJSON):
45                 if err = json.NewDecoder(req.Body).Decode(i); err != nil {
46                         if ute, ok := err.(*json.UnmarshalTypeError); ok {
47                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, offset=%v", ute.Type, ute.Value, ute.Offset))
48                         } else if se, ok := err.(*json.SyntaxError); ok {
49                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error()))
50                         } else {
51                                 return NewHTTPError(http.StatusBadRequest, err.Error())
52                         }
53                 }
54         case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
55                 if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
56                         if ute, ok := err.(*xml.UnsupportedTypeError); ok {
57                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
58                         } else if se, ok := err.(*xml.SyntaxError); ok {
59                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error()))
60                         } else {
61                                 return NewHTTPError(http.StatusBadRequest, err.Error())
62                         }
63                 }
64         case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
65                 params, err := c.FormParams()
66                 if err != nil {
67                         return NewHTTPError(http.StatusBadRequest, err.Error())
68                 }
69                 if err = b.bindData(i, params, "form"); err != nil {
70                         return NewHTTPError(http.StatusBadRequest, err.Error())
71                 }
72         default:
73                 return ErrUnsupportedMediaType
74         }
75         return
76 }
77
78 func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
79         typ := reflect.TypeOf(ptr).Elem()
80         val := reflect.ValueOf(ptr).Elem()
81
82         if typ.Kind() != reflect.Struct {
83                 return errors.New("binding element must be a struct")
84         }
85
86         for i := 0; i < typ.NumField(); i++ {
87                 typeField := typ.Field(i)
88                 structField := val.Field(i)
89                 if !structField.CanSet() {
90                         continue
91                 }
92                 structFieldKind := structField.Kind()
93                 inputFieldName := typeField.Tag.Get(tag)
94
95                 if inputFieldName == "" {
96                         inputFieldName = typeField.Name
97                         // If tag is nil, we inspect if the field is a struct.
98                         if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
99                                 err := b.bindData(structField.Addr().Interface(), data, tag)
100                                 if err != nil {
101                                         return err
102                                 }
103                                 continue
104                         }
105                 }
106                 inputValue, exists := data[inputFieldName]
107                 if !exists {
108                         continue
109                 }
110
111                 // Call this first, in case we're dealing with an alias to an array type
112                 if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
113                         if err != nil {
114                                 return err
115                         }
116                         continue
117                 }
118
119                 numElems := len(inputValue)
120                 if structFieldKind == reflect.Slice && numElems > 0 {
121                         sliceOf := structField.Type().Elem().Kind()
122                         slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
123                         for j := 0; j < numElems; j++ {
124                                 if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
125                                         return err
126                                 }
127                         }
128                         val.Field(i).Set(slice)
129                 } else {
130                         if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
131                                 return err
132                         }
133                 }
134         }
135         return nil
136 }
137
138 func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
139         // But also call it here, in case we're dealing with an array of BindUnmarshalers
140         if ok, err := unmarshalField(valueKind, val, structField); ok {
141                 return err
142         }
143
144         switch valueKind {
145         case reflect.Ptr:
146                 return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
147         case reflect.Int:
148                 return setIntField(val, 0, structField)
149         case reflect.Int8:
150                 return setIntField(val, 8, structField)
151         case reflect.Int16:
152                 return setIntField(val, 16, structField)
153         case reflect.Int32:
154                 return setIntField(val, 32, structField)
155         case reflect.Int64:
156                 return setIntField(val, 64, structField)
157         case reflect.Uint:
158                 return setUintField(val, 0, structField)
159         case reflect.Uint8:
160                 return setUintField(val, 8, structField)
161         case reflect.Uint16:
162                 return setUintField(val, 16, structField)
163         case reflect.Uint32:
164                 return setUintField(val, 32, structField)
165         case reflect.Uint64:
166                 return setUintField(val, 64, structField)
167         case reflect.Bool:
168                 return setBoolField(val, structField)
169         case reflect.Float32:
170                 return setFloatField(val, 32, structField)
171         case reflect.Float64:
172                 return setFloatField(val, 64, structField)
173         case reflect.String:
174                 structField.SetString(val)
175         default:
176                 return errors.New("unknown type")
177         }
178         return nil
179 }
180
181 func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
182         switch valueKind {
183         case reflect.Ptr:
184                 return unmarshalFieldPtr(val, field)
185         default:
186                 return unmarshalFieldNonPtr(val, field)
187         }
188 }
189
190 // bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
191 func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
192         ptr := reflect.New(field.Type())
193         if ptr.CanInterface() {
194                 iface := ptr.Interface()
195                 if unmarshaler, ok := iface.(BindUnmarshaler); ok {
196                         return unmarshaler, ok
197                 }
198         }
199         return nil, false
200 }
201
202 func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
203         if unmarshaler, ok := bindUnmarshaler(field); ok {
204                 err := unmarshaler.UnmarshalParam(value)
205                 field.Set(reflect.ValueOf(unmarshaler).Elem())
206                 return true, err
207         }
208         return false, nil
209 }
210
211 func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
212         if field.IsNil() {
213                 // Initialize the pointer to a nil value
214                 field.Set(reflect.New(field.Type().Elem()))
215         }
216         return unmarshalFieldNonPtr(value, field.Elem())
217 }
218
219 func setIntField(value string, bitSize int, field reflect.Value) error {
220         if value == "" {
221                 value = "0"
222         }
223         intVal, err := strconv.ParseInt(value, 10, bitSize)
224         if err == nil {
225                 field.SetInt(intVal)
226         }
227         return err
228 }
229
230 func setUintField(value string, bitSize int, field reflect.Value) error {
231         if value == "" {
232                 value = "0"
233         }
234         uintVal, err := strconv.ParseUint(value, 10, bitSize)
235         if err == nil {
236                 field.SetUint(uintVal)
237         }
238         return err
239 }
240
241 func setBoolField(value string, field reflect.Value) error {
242         if value == "" {
243                 value = "false"
244         }
245         boolVal, err := strconv.ParseBool(value)
246         if err == nil {
247                 field.SetBool(boolVal)
248         }
249         return err
250 }
251
252 func setFloatField(value string, bitSize int, field reflect.Value) error {
253         if value == "" {
254                 value = "0.0"
255         }
256         floatVal, err := strconv.ParseFloat(value, bitSize)
257         if err == nil {
258                 field.SetFloat(floatVal)
259         }
260         return err
261 }