gotosocial/vendor/github.com/go-playground/form/v4/decoder.go

753 lines
17 KiB
Go

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
}