package form import ( "fmt" "log" "net/url" "reflect" "strconv" "time" ) const ( errArraySize = "Array size of '%d' is larger than the maximum currently set on the decoder of '%d'. To increase this limit please see, SetMaxArraySize(size uint)" errMissingStartBracket = "Invalid formatting for key '%s' missing '[' bracket" errMissingEndBracket = "Invalid formatting for key '%s' missing ']' bracket" ) type decoder struct { d *Decoder errs DecodeErrors dm dataMap values url.Values maxKeyLen int namespace []byte } func (d *decoder) setError(namespace []byte, err error) { if d.errs == nil { d.errs = make(DecodeErrors) } d.errs[string(namespace)] = err } func (d *decoder) findAlias(ns string) *recursiveData { for i := 0; i < len(d.dm); i++ { if d.dm[i].alias == ns { return d.dm[i] } } return nil } func (d *decoder) parseMapData() { // already parsed if len(d.dm) > 0 { return } d.maxKeyLen = 0 d.dm = d.dm[0:0] var i int var idx int var l int var insideBracket bool var rd *recursiveData var isNum bool for k := range d.values { if len(k) > d.maxKeyLen { d.maxKeyLen = len(k) } for i = 0; i < len(k); i++ { switch k[i] { case '[': idx = i insideBracket = true isNum = true case ']': if !insideBracket { log.Panicf(errMissingStartBracket, k) } if rd = d.findAlias(k[:idx]); rd == nil { l = len(d.dm) + 1 if l > cap(d.dm) { dm := make(dataMap, l) copy(dm, d.dm) rd = new(recursiveData) dm[len(d.dm)] = rd d.dm = dm } else { l = len(d.dm) d.dm = d.dm[:l+1] rd = d.dm[l] rd.sliceLen = 0 rd.keys = rd.keys[0:0] } rd.alias = k[:idx] } // is map + key ke := key{ ivalue: -1, value: k[idx+1 : i], searchValue: k[idx : i+1], } // is key is number, most likely array key, keep track of just in case an array/slice. if isNum { // no need to check for error, it will always pass // as we have done the checking to ensure // the value is a number ahead of time. var err error ke.ivalue, err = strconv.Atoi(ke.value) if err != nil { ke.ivalue = -1 } if ke.ivalue > rd.sliceLen { rd.sliceLen = ke.ivalue } } rd.keys = append(rd.keys, ke) insideBracket = false default: // checking if not a number, 0-9 is 48-57 in byte, see for yourself fmt.Println('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') if insideBracket && (k[i] > 57 || k[i] < 48) { isNum = false } } } // if still inside bracket, that means no ending bracket was ever specified if insideBracket { log.Panicf(errMissingEndBracket, k) } } } func (d *decoder) traverseStruct(v reflect.Value, typ reflect.Type, namespace []byte) (set bool) { l := len(namespace) first := l == 0 // anonymous structs will still work for caching as the whole definition is stored // including tags s, ok := d.d.structCache.Get(typ) if !ok { s = d.d.structCache.parseStruct(d.d.mode, v, typ, d.d.tagName) } for _, f := range s.fields { namespace = namespace[:l] if f.isAnonymous { if d.setFieldByType(v.Field(f.idx), namespace, 0) { set = true } } if first { namespace = append(namespace, f.name...) } else { namespace = append(namespace, d.d.namespacePrefix...) namespace = append(namespace, f.name...) namespace = append(namespace, d.d.namespaceSuffix...) } if d.setFieldByType(v.Field(f.idx), namespace, 0) { set = true } } return } func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx int) (set bool) { var err error v, kind := ExtractType(current) arr, ok := d.values[string(namespace)] if d.d.customTypeFuncs != nil { if ok { if cf, ok := d.d.customTypeFuncs[v.Type()]; ok { val, err := cf(arr[idx:]) if err != nil { d.setError(namespace, err) return } v.Set(reflect.ValueOf(val)) set = true return } } } switch kind { case reflect.Interface: if !ok || idx == len(arr) { return } v.Set(reflect.ValueOf(arr[idx])) set = true case reflect.Ptr: newVal := reflect.New(v.Type().Elem()) if set = d.setFieldByType(newVal.Elem(), namespace, idx); set { v.Set(newVal) } case reflect.String: if !ok || idx == len(arr) { return } v.SetString(arr[idx]) set = true case reflect.Uint, reflect.Uint64: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var u64 uint64 if u64, err = strconv.ParseUint(arr[idx], 10, 64); err != nil { d.setError(namespace, fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetUint(u64) set = true case reflect.Uint8: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var u64 uint64 if u64, err = strconv.ParseUint(arr[idx], 10, 8); err != nil { d.setError(namespace, fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetUint(u64) set = true case reflect.Uint16: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var u64 uint64 if u64, err = strconv.ParseUint(arr[idx], 10, 16); err != nil { d.setError(namespace, fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetUint(u64) set = true case reflect.Uint32: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var u64 uint64 if u64, err = strconv.ParseUint(arr[idx], 10, 32); err != nil { d.setError(namespace, fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetUint(u64) set = true case reflect.Int, reflect.Int64: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var i64 int64 if i64, err = strconv.ParseInt(arr[idx], 10, 64); err != nil { d.setError(namespace, fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetInt(i64) set = true case reflect.Int8: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var i64 int64 if i64, err = strconv.ParseInt(arr[idx], 10, 8); err != nil { d.setError(namespace, fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetInt(i64) set = true case reflect.Int16: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var i64 int64 if i64, err = strconv.ParseInt(arr[idx], 10, 16); err != nil { d.setError(namespace, fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetInt(i64) set = true case reflect.Int32: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var i64 int64 if i64, err = strconv.ParseInt(arr[idx], 10, 32); err != nil { d.setError(namespace, fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetInt(i64) set = true case reflect.Float32: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var f float64 if f, err = strconv.ParseFloat(arr[idx], 32); err != nil { d.setError(namespace, fmt.Errorf("Invalid Float Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetFloat(f) set = true case reflect.Float64: if !ok || idx == len(arr) || len(arr[idx]) == 0 { return } var f float64 if f, err = strconv.ParseFloat(arr[idx], 64); err != nil { d.setError(namespace, fmt.Errorf("Invalid Float Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetFloat(f) set = true case reflect.Bool: if !ok || idx == len(arr) { return } var b bool if b, err = parseBool(arr[idx]); err != nil { d.setError(namespace, fmt.Errorf("Invalid Boolean Value '%s' Type '%v' Namespace '%s'", arr[idx], v.Type(), string(namespace))) return } v.SetBool(b) set = true case reflect.Slice: d.parseMapData() // slice elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"} if ok && len(arr) > 0 { var varr reflect.Value var ol int l := len(arr) if v.IsNil() { varr = reflect.MakeSlice(v.Type(), len(arr), len(arr)) } else { ol = v.Len() l += ol if v.Cap() <= l { varr = reflect.MakeSlice(v.Type(), l, l) } else { // preserve predefined capacity, possibly for reuse after decoding varr = reflect.MakeSlice(v.Type(), l, v.Cap()) } reflect.Copy(varr, v) } for i := ol; i < l; i++ { newVal := reflect.New(v.Type().Elem()).Elem() if d.setFieldByType(newVal, namespace, i-ol) { set = true varr.Index(i).Set(newVal) } } v.Set(varr) } // maybe it's an numbered array i.e. Phone[0].Number if rd := d.findAlias(string(namespace)); rd != nil { var varr reflect.Value var kv key sl := rd.sliceLen + 1 // checking below for maxArraySize, but if array exists and already // has sufficient capacity allocated then we do not check as the code // obviously allows a capacity greater than the maxArraySize. if v.IsNil() { if sl > d.d.maxArraySize { d.setError(namespace, fmt.Errorf(errArraySize, sl, d.d.maxArraySize)) return } varr = reflect.MakeSlice(v.Type(), sl, sl) } else if v.Len() < sl { if v.Cap() <= sl { if sl > d.d.maxArraySize { d.setError(namespace, fmt.Errorf(errArraySize, sl, d.d.maxArraySize)) return } varr = reflect.MakeSlice(v.Type(), sl, sl) } else { varr = reflect.MakeSlice(v.Type(), sl, v.Cap()) } reflect.Copy(varr, v) } else { varr = v } for i := 0; i < len(rd.keys); i++ { kv = rd.keys[i] newVal := reflect.New(varr.Type().Elem()).Elem() if kv.ivalue == -1 { d.setError(namespace, fmt.Errorf("invalid slice index '%s'", kv.value)) continue } if d.setFieldByType(newVal, append(namespace, kv.searchValue...), 0) { set = true varr.Index(kv.ivalue).Set(newVal) } } if !set { return } v.Set(varr) } case reflect.Array: d.parseMapData() // array elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"} if ok && len(arr) > 0 { var varr reflect.Value l := len(arr) overCapacity := v.Len() < l if overCapacity { // more values than array capacity, ignore values over capacity as it's possible some would just want // to grab the first x number of elements; in the future strict mode logic should return an error fmt.Println("warning number of post form array values is larger than array capacity, ignoring overflow values") } varr = reflect.Indirect(reflect.New(reflect.ArrayOf(v.Len(), v.Type().Elem()))) reflect.Copy(varr, v) if v.Len() < len(arr) { l = v.Len() } for i := 0; i < l; i++ { newVal := reflect.New(v.Type().Elem()).Elem() if d.setFieldByType(newVal, namespace, i) { set = true varr.Index(i).Set(newVal) } } v.Set(varr) } // maybe it's an numbered array i.e. Phone[0].Number if rd := d.findAlias(string(namespace)); rd != nil { var varr reflect.Value var kv key overCapacity := rd.sliceLen >= v.Len() if overCapacity { // more values than array capacity, ignore values over capacity as it's possible some would just want // to grab the first x number of elements; in the future strict mode logic should return an error fmt.Println("warning number of post form array values is larger than array capacity, ignoring overflow values") } varr = reflect.Indirect(reflect.New(reflect.ArrayOf(v.Len(), v.Type().Elem()))) reflect.Copy(varr, v) for i := 0; i < len(rd.keys); i++ { kv = rd.keys[i] if kv.ivalue >= v.Len() { continue } newVal := reflect.New(varr.Type().Elem()).Elem() if kv.ivalue == -1 { d.setError(namespace, fmt.Errorf("invalid array index '%s'", kv.value)) continue } if d.setFieldByType(newVal, append(namespace, kv.searchValue...), 0) { set = true varr.Index(kv.ivalue).Set(newVal) } } if !set { return } v.Set(varr) } case reflect.Map: var rd *recursiveData d.parseMapData() // no natural map support so skip directly to dm lookup if rd = d.findAlias(string(namespace)); rd == nil { return } var existing bool var kv key var mp reflect.Value var mk reflect.Value typ := v.Type() if v.IsNil() { mp = reflect.MakeMap(typ) } else { existing = true mp = v } for i := 0; i < len(rd.keys); i++ { newVal := reflect.New(typ.Elem()).Elem() mk = reflect.New(typ.Key()).Elem() kv = rd.keys[i] if err := d.getMapKey(kv.value, mk, namespace); err != nil { d.setError(namespace, err) continue } if d.setFieldByType(newVal, append(namespace, kv.searchValue...), 0) { set = true mp.SetMapIndex(mk, newVal) } } if !set || existing { return } v.Set(mp) case reflect.Struct: typ := v.Type() // if we get here then no custom time function declared so use RFC3339 by default if typ == timeType { if !ok || len(arr[idx]) == 0 { return } t, err := time.Parse(time.RFC3339, arr[idx]) if err != nil { d.setError(namespace, err) } v.Set(reflect.ValueOf(t)) set = true return } d.parseMapData() // we must be recursing infinitly...but that's ok we caught it on the very first overun. if len(namespace) > d.maxKeyLen { return } set = d.traverseStruct(v, typ, namespace) } return } func (d *decoder) getMapKey(key string, current reflect.Value, namespace []byte) (err error) { v, kind := ExtractType(current) if d.d.customTypeFuncs != nil { if cf, ok := d.d.customTypeFuncs[v.Type()]; ok { val, er := cf([]string{key}) if er != nil { err = er return } v.Set(reflect.ValueOf(val)) return } } switch kind { case reflect.Interface: // If interface would have been set on the struct before decoding, // say to a struct value we would not get here but kind would be struct. v.Set(reflect.ValueOf(key)) return case reflect.Ptr: newVal := reflect.New(v.Type().Elem()) if err = d.getMapKey(key, newVal.Elem(), namespace); err == nil { v.Set(newVal) } case reflect.String: v.SetString(key) case reflect.Uint, reflect.Uint64: u64, e := strconv.ParseUint(key, 10, 64) if e != nil { err = fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetUint(u64) case reflect.Uint8: u64, e := strconv.ParseUint(key, 10, 8) if e != nil { err = fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetUint(u64) case reflect.Uint16: u64, e := strconv.ParseUint(key, 10, 16) if e != nil { err = fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetUint(u64) case reflect.Uint32: u64, e := strconv.ParseUint(key, 10, 32) if e != nil { err = fmt.Errorf("Invalid Unsigned Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetUint(u64) case reflect.Int, reflect.Int64: i64, e := strconv.ParseInt(key, 10, 64) if e != nil { err = fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetInt(i64) case reflect.Int8: i64, e := strconv.ParseInt(key, 10, 8) if e != nil { err = fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetInt(i64) case reflect.Int16: i64, e := strconv.ParseInt(key, 10, 16) if e != nil { err = fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetInt(i64) case reflect.Int32: i64, e := strconv.ParseInt(key, 10, 32) if e != nil { err = fmt.Errorf("Invalid Integer Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetInt(i64) case reflect.Float32: f, e := strconv.ParseFloat(key, 32) if e != nil { err = fmt.Errorf("Invalid Float Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetFloat(f) case reflect.Float64: f, e := strconv.ParseFloat(key, 64) if e != nil { err = fmt.Errorf("Invalid Float Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetFloat(f) case reflect.Bool: b, e := parseBool(key) if e != nil { err = fmt.Errorf("Invalid Boolean Value '%s' Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) return } v.SetBool(b) default: err = fmt.Errorf("Unsupported Map Key '%s', Type '%v' Namespace '%s'", key, v.Type(), string(namespace)) } return }