Skip to content

Commit e47d0ab

Browse files
author
Maciej Mucha
committed
Handle empty indexes for slices and arrays (eg. field[]=1&field[]=2)
1 parent 8785d3c commit e47d0ab

File tree

2 files changed

+70
-30
lines changed

2 files changed

+70
-30
lines changed

decoder.go

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ func (d *decoder) parseMapData() {
7575
log.Panicf(errMissingStartBracket, k)
7676
}
7777

78+
insideBracket = false
79+
80+
// ignore empty key
81+
if i == idx+1 {
82+
continue
83+
}
84+
7885
if rd = d.findAlias(k[:idx]); rd == nil {
7986

8087
l = len(d.dm) + 1
@@ -122,8 +129,6 @@ func (d *decoder) parseMapData() {
122129
}
123130

124131
rd.keys = append(rd.keys, ke)
125-
126-
insideBracket = false
127132
default:
128133
// 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')
129134
if insideBracket && (k[i] > 57 || k[i] < 48) {
@@ -356,16 +361,24 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
356361
d.parseMapData()
357362
// slice elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"}
358363

359-
if ok && len(arr) > 0 {
360-
var varr reflect.Value
364+
// handle also param[]=1&param[]=2 syntax
365+
arraySuffix := []byte("[]")
366+
suffixNamespace := append(namespace, arraySuffix...)
361367

362-
var ol int
368+
for _, namespace := range [][]byte{namespace, suffixNamespace} {
369+
arr, ok := d.values[string(namespace)]
363370
l := len(arr)
364371

372+
if !ok || l == 0 {
373+
continue
374+
}
375+
376+
var varr reflect.Value
377+
var ol int
378+
365379
if v.IsNil() {
366-
varr = reflect.MakeSlice(v.Type(), len(arr), len(arr))
380+
varr = reflect.MakeSlice(v.Type(), l, l)
367381
} else {
368-
369382
ol = v.Len()
370383
l += ol
371384

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

457470
case reflect.Array:
458471
d.parseMapData()
459-
460472
// array elements could be mixed eg. number and non-numbers Value[0]=[]string{"10"} and Value=[]string{"10","20"}
461473

462-
if ok && len(arr) > 0 {
463-
var varr reflect.Value
474+
// handle also param[]=1&param[]=2 syntax
475+
arraySuffix := []byte("[]")
476+
suffixNamespace := append(namespace, arraySuffix...)
477+
478+
var ol int
479+
480+
for _, namespace := range [][]byte{namespace, suffixNamespace} {
481+
arr, ok := d.values[string(namespace)]
464482
l := len(arr)
465-
overCapacity := v.Len() < l
466-
if overCapacity {
483+
484+
if !ok || l == 0 {
485+
continue
486+
}
487+
488+
var varr reflect.Value
489+
490+
if v.Len() < l {
467491
// more values than array capacity, ignore values over capacity as it's possible some would just want
468492
// to grab the first x number of elements; in the future strict mode logic should return an error
469493
fmt.Println("warning number of post form array values is larger than array capacity, ignoring overflow values")
@@ -474,15 +498,19 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
474498
if v.Len() < len(arr) {
475499
l = v.Len()
476500
}
477-
for i := 0; i < l; i++ {
501+
l += ol
502+
503+
for i := ol; i < l; i++ {
478504
newVal := reflect.New(v.Type().Elem()).Elem()
479505

480-
if d.setFieldByType(newVal, namespace, i) {
506+
if d.setFieldByType(newVal, namespace, i-ol) {
481507
set = true
482508
varr.Index(i).Set(newVal)
483509
}
484510
}
511+
485512
v.Set(varr)
513+
ol = l
486514
}
487515

488516
// maybe it's an numbered array i.e. Phone[0].Number

decoder_test.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,29 +1910,41 @@ func TestDecoder_EmptyArrayBool(t *testing.T) {
19101910
Equal(t, err, nil)
19111911
}
19121912

1913-
func TestDecoder_InvalidSliceIndex(t *testing.T) {
1913+
func TestDecoder_ArrayIndexes(t *testing.T) {
19141914
type PostsRequest struct {
1915-
PostIds []string
1915+
StrSlice []string
1916+
MapOfStrSlice map[string][]string
1917+
StrSliceExplicitField []string `form:"StrArrExplicitField[]"`
1918+
StrArr [4]string
19161919
}
19171920
in := url.Values{
1918-
"PostIds[]": []string{"1", "2"},
1921+
"StrArr": []string{"0"},
1922+
"StrArr[]": []string{"1", "2"},
1923+
"StrArr[3]": []string{"3"},
1924+
"StrSlice": []string{"0"},
1925+
"StrSlice[]": []string{"1", "2"},
1926+
"StrSlice[3]": []string{"3"},
1927+
"MapOfStrSlice[test1][]": []string{"0", "1"},
1928+
"StrArrExplicitField[]": []string{"0", "1"},
19191929
}
19201930

19211931
v := new(PostsRequest)
19221932
d := NewDecoder()
19231933
err := d.Decode(v, in)
1924-
NotEqual(t, err, nil)
1925-
Equal(t, err.Error(), "Field Namespace:PostIds ERROR:invalid slice index ''")
1926-
1927-
// No error with proper name
1928-
type PostsRequest2 struct {
1929-
PostIds []string `form:"PostIds[]"`
1930-
}
1931-
1932-
v2 := new(PostsRequest2)
1933-
err = d.Decode(v2, in)
19341934
Equal(t, err, nil)
1935-
Equal(t, len(v2.PostIds), 2)
1936-
Equal(t, v2.PostIds[0], "1")
1937-
Equal(t, v2.PostIds[1], "2")
1935+
Equal(t, len(v.StrSlice), 4)
1936+
Equal(t, v.StrSlice[0], "0")
1937+
Equal(t, v.StrSlice[1], "1")
1938+
Equal(t, v.StrSlice[2], "2")
1939+
Equal(t, v.StrSlice[3], "3")
1940+
Equal(t, len(v.StrArr), 4)
1941+
Equal(t, v.StrArr[0], "0")
1942+
Equal(t, v.StrArr[1], "1")
1943+
Equal(t, v.StrArr[2], "2")
1944+
Equal(t, v.StrArr[3], "3")
1945+
Equal(t, len(v.MapOfStrSlice["test1"]), 2)
1946+
Equal(t, v.MapOfStrSlice["test1"][0], "0")
1947+
Equal(t, v.MapOfStrSlice["test1"][1], "1")
1948+
Equal(t, v.StrSliceExplicitField[0], "0")
1949+
Equal(t, v.StrSliceExplicitField[1], "1")
19381950
}

0 commit comments

Comments
 (0)