77 "encoding/json"
88 "errors"
99 "fmt"
10+ "mime/multipart"
1011 "net/http/httptest"
1112 "reflect"
1213 "testing"
@@ -886,7 +887,8 @@ func Test_Bind_Body(t *testing.T) {
886887 reqBody := []byte (`{"name":"john"}` )
887888
888889 type Demo struct {
889- Name string `json:"name" xml:"name" form:"name" query:"name"`
890+ Name string `json:"name" xml:"name" form:"name" query:"name"`
891+ Names []string `json:"names" xml:"names" form:"names" query:"names"`
890892 }
891893
892894 // Helper function to test compressed bodies
@@ -996,6 +998,48 @@ func Test_Bind_Body(t *testing.T) {
996998 Data []Demo `query:"data"`
997999 }
9981000
1001+ t .Run ("MultipartCollectionQueryDotNotation" , func (t * testing.T ) {
1002+ c := app .AcquireCtx (& fasthttp.RequestCtx {})
1003+ c .Request ().Reset ()
1004+
1005+ buf := & bytes.Buffer {}
1006+ writer := multipart .NewWriter (buf )
1007+ require .NoError (t , writer .WriteField ("data.0.name" , "john" ))
1008+ require .NoError (t , writer .WriteField ("data.1.name" , "doe" ))
1009+ require .NoError (t , writer .Close ())
1010+
1011+ c .Request ().Header .SetContentType (writer .FormDataContentType ())
1012+ c .Request ().SetBody (buf .Bytes ())
1013+ c .Request ().Header .SetContentLength (len (c .Body ()))
1014+
1015+ cq := new (CollectionQuery )
1016+ require .NoError (t , c .Bind ().Body (cq ))
1017+ require .Len (t , cq .Data , 2 )
1018+ require .Equal (t , "john" , cq .Data [0 ].Name )
1019+ require .Equal (t , "doe" , cq .Data [1 ].Name )
1020+ })
1021+
1022+ t .Run ("MultipartCollectionQuerySquareBrackets" , func (t * testing.T ) {
1023+ c := app .AcquireCtx (& fasthttp.RequestCtx {})
1024+ c .Request ().Reset ()
1025+
1026+ buf := & bytes.Buffer {}
1027+ writer := multipart .NewWriter (buf )
1028+ require .NoError (t , writer .WriteField ("data[0][name]" , "john" ))
1029+ require .NoError (t , writer .WriteField ("data[1][name]" , "doe" ))
1030+ require .NoError (t , writer .Close ())
1031+
1032+ c .Request ().Header .SetContentType (writer .FormDataContentType ())
1033+ c .Request ().SetBody (buf .Bytes ())
1034+ c .Request ().Header .SetContentLength (len (c .Body ()))
1035+
1036+ cq := new (CollectionQuery )
1037+ require .NoError (t , c .Bind ().Body (cq ))
1038+ require .Len (t , cq .Data , 2 )
1039+ require .Equal (t , "john" , cq .Data [0 ].Name )
1040+ require .Equal (t , "doe" , cq .Data [1 ].Name )
1041+ })
1042+
9991043 t .Run ("CollectionQuerySquareBrackets" , func (t * testing.T ) {
10001044 c := app .AcquireCtx (& fasthttp.RequestCtx {})
10011045 c .Request ().Reset ()
@@ -1192,9 +1236,57 @@ func Benchmark_Bind_Body_MultipartForm(b *testing.B) {
11921236 Name string `form:"name"`
11931237 }
11941238
1195- body := []byte ("--b\r \n Content-Disposition: form-data; name=\" name\" \r \n \r \n john\r \n --b--" )
1239+ buf := & bytes.Buffer {}
1240+ writer := multipart .NewWriter (buf )
1241+ require .NoError (b , writer .WriteField ("name" , "john" ))
1242+ require .NoError (b , writer .Close ())
1243+ body := buf .Bytes ()
1244+
1245+ c .Request ().SetBody (body )
1246+ c .Request ().Header .SetContentType (MIMEMultipartForm + `;boundary=` + writer .Boundary ())
1247+ c .Request ().Header .SetContentLength (len (body ))
1248+ d := new (Demo )
1249+
1250+ b .ReportAllocs ()
1251+ b .ResetTimer ()
1252+
1253+ for n := 0 ; n < b .N ; n ++ {
1254+ err = c .Bind ().Body (d )
1255+ }
1256+
1257+ require .NoError (b , err )
1258+ require .Equal (b , "john" , d .Name )
1259+ }
1260+
1261+ // go test -v -run=^$ -bench=Benchmark_Bind_Body_MultipartForm_Nested -benchmem -count=4
1262+ func Benchmark_Bind_Body_MultipartForm_Nested (b * testing.B ) {
1263+ var err error
1264+
1265+ app := New ()
1266+ c := app .AcquireCtx (& fasthttp.RequestCtx {})
1267+
1268+ type Person struct {
1269+ Name string `form:"name"`
1270+ Age int `form:"age"`
1271+ }
1272+
1273+ type Demo struct {
1274+ Name string `form:"name"`
1275+ Persons []Person `form:"persons"`
1276+ }
1277+
1278+ buf := & bytes.Buffer {}
1279+ writer := multipart .NewWriter (buf )
1280+ require .NoError (b , writer .WriteField ("name" , "john" ))
1281+ require .NoError (b , writer .WriteField ("persons.0.name" , "john" ))
1282+ require .NoError (b , writer .WriteField ("persons[0][age]" , "10" ))
1283+ require .NoError (b , writer .WriteField ("persons[1][name]" , "doe" ))
1284+ require .NoError (b , writer .WriteField ("persons.1.age" , "20" ))
1285+ require .NoError (b , writer .Close ())
1286+ body := buf .Bytes ()
1287+
11961288 c .Request ().SetBody (body )
1197- c .Request ().Header .SetContentType (MIMEMultipartForm + `;boundary="b"` )
1289+ c .Request ().Header .SetContentType (MIMEMultipartForm + `;boundary=` + writer . Boundary () )
11981290 c .Request ().Header .SetContentLength (len (body ))
11991291 d := new (Demo )
12001292
@@ -1204,8 +1296,13 @@ func Benchmark_Bind_Body_MultipartForm(b *testing.B) {
12041296 for n := 0 ; n < b .N ; n ++ {
12051297 err = c .Bind ().Body (d )
12061298 }
1299+
12071300 require .NoError (b , err )
12081301 require .Equal (b , "john" , d .Name )
1302+ require .Equal (b , "john" , d .Persons [0 ].Name )
1303+ require .Equal (b , 10 , d .Persons [0 ].Age )
1304+ require .Equal (b , "doe" , d .Persons [1 ].Name )
1305+ require .Equal (b , 20 , d .Persons [1 ].Age )
12091306}
12101307
12111308// go test -v -run=^$ -bench=Benchmark_Bind_Body_Form_Map -benchmem -count=4
0 commit comments