Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle empty indexes for slices and arrays (eg. field[]=1&field[]=2) #64

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 43 additions & 19 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ func (d *decoder) parseMapData() {
log.Panicf(errMissingStartBracket, k)
}

insideBracket = false

// ignore empty key
if i == idx+1 {
continue
}

if rd = d.findAlias(k[:idx]); rd == nil {

l = len(d.dm) + 1
Expand Down Expand Up @@ -109,11 +116,7 @@ func (d *decoder) parseMapData() {
// 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
}
ke.ivalue, _ = strconv.Atoi(ke.value)

if ke.ivalue > rd.sliceLen {
rd.sliceLen = ke.ivalue
Expand All @@ -122,8 +125,6 @@ func (d *decoder) parseMapData() {
}

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) {
Expand Down Expand Up @@ -356,16 +357,24 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
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
// handle also param[]=1&param[]=2 syntax
arraySuffix := []byte("[]")
suffixNamespace := append(namespace, arraySuffix...)

var ol int
for _, namespace := range [][]byte{namespace, suffixNamespace} {
arr, ok := d.values[string(namespace)]
l := len(arr)

if !ok || l == 0 {
continue
}

var varr reflect.Value
var ol int

if v.IsNil() {
varr = reflect.MakeSlice(v.Type(), len(arr), len(arr))
varr = reflect.MakeSlice(v.Type(), l, l)
} else {

ol = v.Len()
l += ol

Expand Down Expand Up @@ -456,14 +465,25 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in

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
// handle also param[]=1&param[]=2 syntax
arraySuffix := []byte("[]")
suffixNamespace := append(namespace, arraySuffix...)

var ol int

for _, namespace := range [][]byte{namespace, suffixNamespace} {
arr, ok := d.values[string(namespace)]
l := len(arr)
overCapacity := v.Len() < l
if overCapacity {

if !ok || l == 0 {
continue
}

var varr reflect.Value

if v.Len() < l {
// 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")
Expand All @@ -474,15 +494,19 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
if v.Len() < len(arr) {
l = v.Len()
}
for i := 0; i < l; i++ {
l += ol

for i := ol; i < l; i++ {
newVal := reflect.New(v.Type().Elem()).Elem()

if d.setFieldByType(newVal, namespace, i) {
if d.setFieldByType(newVal, namespace, i-ol) {
set = true
varr.Index(i).Set(newVal)
}
}

v.Set(varr)
ol = l
}

// maybe it's an numbered array i.e. Phone[0].Number
Expand Down
44 changes: 28 additions & 16 deletions decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1910,29 +1910,41 @@ func TestDecoder_EmptyArrayBool(t *testing.T) {
Equal(t, err, nil)
}

func TestDecoder_InvalidSliceIndex(t *testing.T) {
func TestDecoder_ArrayIndexes(t *testing.T) {
type PostsRequest struct {
PostIds []string
StrSlice []string
MapOfStrSlice map[string][]string
StrSliceExplicitField []string `form:"StrArrExplicitField[]"`
StrArr [4]string
}
in := url.Values{
"PostIds[]": []string{"1", "2"},
"StrArr": []string{"0"},
"StrArr[]": []string{"1", "2"},
"StrArr[3]": []string{"3"},
"StrSlice": []string{"0"},
"StrSlice[]": []string{"1", "2"},
"StrSlice[3]": []string{"3"},
"MapOfStrSlice[test1][]": []string{"0", "1"},
"StrArrExplicitField[]": []string{"0", "1"},
}

v := new(PostsRequest)
d := NewDecoder()
err := d.Decode(v, in)
NotEqual(t, err, nil)
Equal(t, err.Error(), "Field Namespace:PostIds ERROR:invalid slice index ''")

// No error with proper name
type PostsRequest2 struct {
PostIds []string `form:"PostIds[]"`
}

v2 := new(PostsRequest2)
err = d.Decode(v2, in)
Equal(t, err, nil)
Equal(t, len(v2.PostIds), 2)
Equal(t, v2.PostIds[0], "1")
Equal(t, v2.PostIds[1], "2")
Equal(t, len(v.StrSlice), 4)
Equal(t, v.StrSlice[0], "0")
Equal(t, v.StrSlice[1], "1")
Equal(t, v.StrSlice[2], "2")
Equal(t, v.StrSlice[3], "3")
Equal(t, len(v.StrArr), 4)
Equal(t, v.StrArr[0], "0")
Equal(t, v.StrArr[1], "1")
Equal(t, v.StrArr[2], "2")
Equal(t, v.StrArr[3], "3")
Equal(t, len(v.MapOfStrSlice["test1"]), 2)
Equal(t, v.MapOfStrSlice["test1"][0], "0")
Equal(t, v.MapOfStrSlice["test1"][1], "1")
Equal(t, v.StrSliceExplicitField[0], "0")
Equal(t, v.StrSliceExplicitField[1], "1")
}
Loading