form_mapping.go (9202B)
1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package binding 6 7 import ( 8 "errors" 9 "fmt" 10 "reflect" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/gin-gonic/gin/internal/bytesconv" 16 "github.com/gin-gonic/gin/internal/json" 17 ) 18 19 var ( 20 errUnknownType = errors.New("unknown type") 21 22 // ErrConvertMapStringSlice can not convert to map[string][]string 23 ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings") 24 25 // ErrConvertToMapString can not convert to map[string]string 26 ErrConvertToMapString = errors.New("can not convert to map of strings") 27 ) 28 29 func mapURI(ptr any, m map[string][]string) error { 30 return mapFormByTag(ptr, m, "uri") 31 } 32 33 func mapForm(ptr any, form map[string][]string) error { 34 return mapFormByTag(ptr, form, "form") 35 } 36 37 func MapFormWithTag(ptr any, form map[string][]string, tag string) error { 38 return mapFormByTag(ptr, form, tag) 39 } 40 41 var emptyField = reflect.StructField{} 42 43 func mapFormByTag(ptr any, form map[string][]string, tag string) error { 44 // Check if ptr is a map 45 ptrVal := reflect.ValueOf(ptr) 46 var pointed any 47 if ptrVal.Kind() == reflect.Ptr { 48 ptrVal = ptrVal.Elem() 49 pointed = ptrVal.Interface() 50 } 51 if ptrVal.Kind() == reflect.Map && 52 ptrVal.Type().Key().Kind() == reflect.String { 53 if pointed != nil { 54 ptr = pointed 55 } 56 return setFormMap(ptr, form) 57 } 58 59 return mappingByPtr(ptr, formSource(form), tag) 60 } 61 62 // setter tries to set value on a walking by fields of a struct 63 type setter interface { 64 TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSet bool, err error) 65 } 66 67 type formSource map[string][]string 68 69 var _ setter = formSource(nil) 70 71 // TrySet tries to set a value by request's form source (like map[string][]string) 72 func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSet bool, err error) { 73 return setByForm(value, field, form, tagValue, opt) 74 } 75 76 func mappingByPtr(ptr any, setter setter, tag string) error { 77 _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag) 78 return err 79 } 80 81 func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { 82 if field.Tag.Get(tag) == "-" { // just ignoring this field 83 return false, nil 84 } 85 86 vKind := value.Kind() 87 88 if vKind == reflect.Ptr { 89 var isNew bool 90 vPtr := value 91 if value.IsNil() { 92 isNew = true 93 vPtr = reflect.New(value.Type().Elem()) 94 } 95 isSet, err := mapping(vPtr.Elem(), field, setter, tag) 96 if err != nil { 97 return false, err 98 } 99 if isNew && isSet { 100 value.Set(vPtr) 101 } 102 return isSet, nil 103 } 104 105 if vKind != reflect.Struct || !field.Anonymous { 106 ok, err := tryToSetValue(value, field, setter, tag) 107 if err != nil { 108 return false, err 109 } 110 if ok { 111 return true, nil 112 } 113 } 114 115 if vKind == reflect.Struct { 116 tValue := value.Type() 117 118 var isSet bool 119 for i := 0; i < value.NumField(); i++ { 120 sf := tValue.Field(i) 121 if sf.PkgPath != "" && !sf.Anonymous { // unexported 122 continue 123 } 124 ok, err := mapping(value.Field(i), sf, setter, tag) 125 if err != nil { 126 return false, err 127 } 128 isSet = isSet || ok 129 } 130 return isSet, nil 131 } 132 return false, nil 133 } 134 135 type setOptions struct { 136 isDefaultExists bool 137 defaultValue string 138 } 139 140 func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { 141 var tagValue string 142 var setOpt setOptions 143 144 tagValue = field.Tag.Get(tag) 145 tagValue, opts := head(tagValue, ",") 146 147 if tagValue == "" { // default value is FieldName 148 tagValue = field.Name 149 } 150 if tagValue == "" { // when field is "emptyField" variable 151 return false, nil 152 } 153 154 var opt string 155 for len(opts) > 0 { 156 opt, opts = head(opts, ",") 157 158 if k, v := head(opt, "="); k == "default" { 159 setOpt.isDefaultExists = true 160 setOpt.defaultValue = v 161 } 162 } 163 164 return setter.TrySet(value, field, tagValue, setOpt) 165 } 166 167 func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) { 168 vs, ok := form[tagValue] 169 if !ok && !opt.isDefaultExists { 170 return false, nil 171 } 172 173 switch value.Kind() { 174 case reflect.Slice: 175 if !ok { 176 vs = []string{opt.defaultValue} 177 } 178 return true, setSlice(vs, value, field) 179 case reflect.Array: 180 if !ok { 181 vs = []string{opt.defaultValue} 182 } 183 if len(vs) != value.Len() { 184 return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) 185 } 186 return true, setArray(vs, value, field) 187 default: 188 var val string 189 if !ok { 190 val = opt.defaultValue 191 } 192 193 if len(vs) > 0 { 194 val = vs[0] 195 } 196 return true, setWithProperType(val, value, field) 197 } 198 } 199 200 func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { 201 switch value.Kind() { 202 case reflect.Int: 203 return setIntField(val, 0, value) 204 case reflect.Int8: 205 return setIntField(val, 8, value) 206 case reflect.Int16: 207 return setIntField(val, 16, value) 208 case reflect.Int32: 209 return setIntField(val, 32, value) 210 case reflect.Int64: 211 switch value.Interface().(type) { 212 case time.Duration: 213 return setTimeDuration(val, value) 214 } 215 return setIntField(val, 64, value) 216 case reflect.Uint: 217 return setUintField(val, 0, value) 218 case reflect.Uint8: 219 return setUintField(val, 8, value) 220 case reflect.Uint16: 221 return setUintField(val, 16, value) 222 case reflect.Uint32: 223 return setUintField(val, 32, value) 224 case reflect.Uint64: 225 return setUintField(val, 64, value) 226 case reflect.Bool: 227 return setBoolField(val, value) 228 case reflect.Float32: 229 return setFloatField(val, 32, value) 230 case reflect.Float64: 231 return setFloatField(val, 64, value) 232 case reflect.String: 233 value.SetString(val) 234 case reflect.Struct: 235 switch value.Interface().(type) { 236 case time.Time: 237 return setTimeField(val, field, value) 238 } 239 return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) 240 case reflect.Map: 241 return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) 242 default: 243 return errUnknownType 244 } 245 return nil 246 } 247 248 func setIntField(val string, bitSize int, field reflect.Value) error { 249 if val == "" { 250 val = "0" 251 } 252 intVal, err := strconv.ParseInt(val, 10, bitSize) 253 if err == nil { 254 field.SetInt(intVal) 255 } 256 return err 257 } 258 259 func setUintField(val string, bitSize int, field reflect.Value) error { 260 if val == "" { 261 val = "0" 262 } 263 uintVal, err := strconv.ParseUint(val, 10, bitSize) 264 if err == nil { 265 field.SetUint(uintVal) 266 } 267 return err 268 } 269 270 func setBoolField(val string, field reflect.Value) error { 271 if val == "" { 272 val = "false" 273 } 274 boolVal, err := strconv.ParseBool(val) 275 if err == nil { 276 field.SetBool(boolVal) 277 } 278 return err 279 } 280 281 func setFloatField(val string, bitSize int, field reflect.Value) error { 282 if val == "" { 283 val = "0.0" 284 } 285 floatVal, err := strconv.ParseFloat(val, bitSize) 286 if err == nil { 287 field.SetFloat(floatVal) 288 } 289 return err 290 } 291 292 func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { 293 timeFormat := structField.Tag.Get("time_format") 294 if timeFormat == "" { 295 timeFormat = time.RFC3339 296 } 297 298 switch tf := strings.ToLower(timeFormat); tf { 299 case "unix", "unixnano": 300 tv, err := strconv.ParseInt(val, 10, 64) 301 if err != nil { 302 return err 303 } 304 305 d := time.Duration(1) 306 if tf == "unixnano" { 307 d = time.Second 308 } 309 310 t := time.Unix(tv/int64(d), tv%int64(d)) 311 value.Set(reflect.ValueOf(t)) 312 return nil 313 } 314 315 if val == "" { 316 value.Set(reflect.ValueOf(time.Time{})) 317 return nil 318 } 319 320 l := time.Local 321 if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { 322 l = time.UTC 323 } 324 325 if locTag := structField.Tag.Get("time_location"); locTag != "" { 326 loc, err := time.LoadLocation(locTag) 327 if err != nil { 328 return err 329 } 330 l = loc 331 } 332 333 t, err := time.ParseInLocation(timeFormat, val, l) 334 if err != nil { 335 return err 336 } 337 338 value.Set(reflect.ValueOf(t)) 339 return nil 340 } 341 342 func setArray(vals []string, value reflect.Value, field reflect.StructField) error { 343 for i, s := range vals { 344 err := setWithProperType(s, value.Index(i), field) 345 if err != nil { 346 return err 347 } 348 } 349 return nil 350 } 351 352 func setSlice(vals []string, value reflect.Value, field reflect.StructField) error { 353 slice := reflect.MakeSlice(value.Type(), len(vals), len(vals)) 354 err := setArray(vals, slice, field) 355 if err != nil { 356 return err 357 } 358 value.Set(slice) 359 return nil 360 } 361 362 func setTimeDuration(val string, value reflect.Value) error { 363 d, err := time.ParseDuration(val) 364 if err != nil { 365 return err 366 } 367 value.Set(reflect.ValueOf(d)) 368 return nil 369 } 370 371 func head(str, sep string) (head string, tail string) { 372 idx := strings.Index(str, sep) 373 if idx < 0 { 374 return str, "" 375 } 376 return str[:idx], str[idx+len(sep):] 377 } 378 379 func setFormMap(ptr any, form map[string][]string) error { 380 el := reflect.TypeOf(ptr).Elem() 381 382 if el.Kind() == reflect.Slice { 383 ptrMap, ok := ptr.(map[string][]string) 384 if !ok { 385 return ErrConvertMapStringSlice 386 } 387 for k, v := range form { 388 ptrMap[k] = v 389 } 390 391 return nil 392 } 393 394 ptrMap, ok := ptr.(map[string]string) 395 if !ok { 396 return ErrConvertToMapString 397 } 398 for k, v := range form { 399 ptrMap[k] = v[len(v)-1] // pick last 400 } 401 402 return nil 403 }