...

Source file src/github.com/gin-gonic/gin/binding/form_mapping.go

Documentation: github.com/gin-gonic/gin/binding

     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  }
   404  

View as plain text