barometer: update DMA's vendoring packages
[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 == http.MethodGet || req.Method == http.MethodDelete {
35                         if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
36                                 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
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, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
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())).SetInternal(err)
50                         } else {
51                                 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
52                         }
53                         return NewHTTPError(http.StatusBadRequest, err.Error())
54                 }
55         case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
56                 if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
57                         if ute, ok := err.(*xml.UnsupportedTypeError); ok {
58                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
59                         } else if se, ok := err.(*xml.SyntaxError); ok {
60                                 return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
61                         } else {
62                                 return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
63                         }
64                         return NewHTTPError(http.StatusBadRequest, err.Error())
65                 }
66         case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
67                 params, err := c.FormParams()
68                 if err != nil {
69                         return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
70                 }
71                 if err = b.bindData(i, params, "form"); err != nil {
72                         return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
73                 }
74         default:
75                 return ErrUnsupportedMediaType
76         }
77         return
78 }
79
80 func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
81         typ := reflect.TypeOf(ptr).Elem()
82         val := reflect.ValueOf(ptr).Elem()
83
84         if typ.Kind() != reflect.Struct {
85                 return errors.New("binding element must be a struct")
86         }
87
88         for i := 0; i < typ.NumField(); i++ {
89                 typeField := typ.Field(i)
90                 structField := val.Field(i)
91                 if !structField.CanSet() {
92                         continue
93                 }
94                 structFieldKind := structField.Kind()
95                 inputFieldName := typeField.Tag.Get(tag)
96
97                 if inputFieldName == "" {
98                         inputFieldName = typeField.Name
99                         // If tag is nil, we inspect if the field is a struct.
100                         if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
101                                 if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
102                                         return err
103                                 }
104                                 continue
105                         }
106                 }
107
108                 inputValue, exists := data[inputFieldName]
109                 if !exists {
110                         // Go json.Unmarshal supports case insensitive binding.  However the
111                         // url params are bound case sensitive which is inconsistent.  To
112                         // fix this we must check all of the map values in a
113                         // case-insensitive search.
114                         inputFieldName = strings.ToLower(inputFieldName)
115                         for k, v := range data {
116                                 if strings.ToLower(k) == inputFieldName {
117                                         inputValue = v
118                                         exists = true
119                                         break
120                                 }
121                         }
122                 }
123
124                 if !exists {
125                         continue
126                 }
127
128                 // Call this first, in case we're dealing with an alias to an array type
129                 if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
130                         if err != nil {
131                                 return err
132                         }
133                         continue
134                 }
135
136                 numElems := len(inputValue)
137                 if structFieldKind == reflect.Slice && numElems > 0 {
138                         sliceOf := structField.Type().Elem().Kind()
139                         slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
140                         for j := 0; j < numElems; j++ {
141                                 if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
142                                         return err
143                                 }
144                         }
145                         val.Field(i).Set(slice)
146                 } else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
147                         return err
148
149                 }
150         }
151         return nil
152 }
153
154 func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
155         // But also call it here, in case we're dealing with an array of BindUnmarshalers
156         if ok, err := unmarshalField(valueKind, val, structField); ok {
157                 return err
158         }
159
160         switch valueKind {
161         case reflect.Ptr:
162                 return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
163         case reflect.Int:
164                 return setIntField(val, 0, structField)
165         case reflect.Int8:
166                 return setIntField(val, 8, structField)
167         case reflect.Int16:
168                 return setIntField(val, 16, structField)
169         case reflect.Int32:
170                 return setIntField(val, 32, structField)
171         case reflect.Int64:
172                 return setIntField(val, 64, structField)
173         case reflect.Uint:
174                 return setUintField(val, 0, structField)
175         case reflect.Uint8:
176                 return setUintField(val, 8, structField)
177         case reflect.Uint16:
178                 return setUintField(val, 16, structField)
179         case reflect.Uint32:
180                 return setUintField(val, 32, structField)
181         case reflect.Uint64:
182                 return setUintField(val, 64, structField)
183         case reflect.Bool:
184                 return setBoolField(val, structField)
185         case reflect.Float32:
186                 return setFloatField(val, 32, structField)
187         case reflect.Float64:
188                 return setFloatField(val, 64, structField)
189         case reflect.String:
190                 structField.SetString(val)
191         default:
192                 return errors.New("unknown type")
193         }
194         return nil
195 }
196
197 func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
198         switch valueKind {
199         case reflect.Ptr:
200                 return unmarshalFieldPtr(val, field)
201         default:
202                 return unmarshalFieldNonPtr(val, field)
203         }
204 }
205
206 // bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
207 func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
208         ptr := reflect.New(field.Type())
209         if ptr.CanInterface() {
210                 iface := ptr.Interface()
211                 if unmarshaler, ok := iface.(BindUnmarshaler); ok {
212                         return unmarshaler, ok
213                 }
214         }
215         return nil, false
216 }
217
218 func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
219         if unmarshaler, ok := bindUnmarshaler(field); ok {
220                 err := unmarshaler.UnmarshalParam(value)
221                 field.Set(reflect.ValueOf(unmarshaler).Elem())
222                 return true, err
223         }
224         return false, nil
225 }
226
227 func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
228         if field.IsNil() {
229                 // Initialize the pointer to a nil value
230                 field.Set(reflect.New(field.Type().Elem()))
231         }
232         return unmarshalFieldNonPtr(value, field.Elem())
233 }
234
235 func setIntField(value string, bitSize int, field reflect.Value) error {
236         if value == "" {
237                 value = "0"
238         }
239         intVal, err := strconv.ParseInt(value, 10, bitSize)
240         if err == nil {
241                 field.SetInt(intVal)
242         }
243         return err
244 }
245
246 func setUintField(value string, bitSize int, field reflect.Value) error {
247         if value == "" {
248                 value = "0"
249         }
250         uintVal, err := strconv.ParseUint(value, 10, bitSize)
251         if err == nil {
252                 field.SetUint(uintVal)
253         }
254         return err
255 }
256
257 func setBoolField(value string, field reflect.Value) error {
258         if value == "" {
259                 value = "false"
260         }
261         boolVal, err := strconv.ParseBool(value)
262         if err == nil {
263                 field.SetBool(boolVal)
264         }
265         return err
266 }
267
268 func setFloatField(value string, bitSize int, field reflect.Value) error {
269         if value == "" {
270                 value = "0.0"
271         }
272         floatVal, err := strconv.ParseFloat(value, bitSize)
273         if err == nil {
274                 field.SetFloat(floatVal)
275         }
276         return err
277 }