Skip to content

Commit

Permalink
🐛 fix bug parse custom header (#2638)
Browse files Browse the repository at this point in the history
* 🐛 fix bug parse custom header

* 🚨 fix lint when request merge #2638

---------

Co-authored-by: Khúc Ngọc Huy <[email protected]>
  • Loading branch information
huykn and Khúc Ngọc Huy authored Sep 19, 2023
1 parent 5d6552e commit 59d3eb0
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 17 deletions.
10 changes: 5 additions & 5 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func (c *Ctx) BodyParser(out interface{}) error {
k, err = parseParamSquareBrackets(k)
}

if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) {
if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, bodyTag) {
values := strings.Split(v, ",")
for i := 0; i < len(values); i++ {
data[k] = append(data[k], values[i])
Expand Down Expand Up @@ -1220,7 +1220,7 @@ func (c *Ctx) QueryParser(out interface{}) error {
k, err = parseParamSquareBrackets(k)
}

if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) {
if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, queryTag) {
values := strings.Split(v, ",")
for i := 0; i < len(values); i++ {
data[k] = append(data[k], values[i])
Expand Down Expand Up @@ -1269,7 +1269,7 @@ func (c *Ctx) ReqHeaderParser(out interface{}) error {
k := c.app.getString(key)
v := c.app.getString(val)

if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) {
if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, reqHeaderTag) {
values := strings.Split(v, ",")
for i := 0; i < len(values); i++ {
data[k] = append(data[k], values[i])
Expand Down Expand Up @@ -1300,7 +1300,7 @@ func (*Ctx) parseToStruct(aliasTag string, out interface{}, data map[string][]st
return nil
}

func equalFieldType(out interface{}, kind reflect.Kind, key string) bool {
func equalFieldType(out interface{}, kind reflect.Kind, key, tag string) bool {
// Get type of interface
outTyp := reflect.TypeOf(out).Elem()
key = utils.ToLower(key)
Expand All @@ -1327,7 +1327,7 @@ func equalFieldType(out interface{}, kind reflect.Kind, key string) bool {
continue
}
// Get tag from field if exist
inputFieldName := typeField.Tag.Get(queryTag)
inputFieldName := typeField.Tag.Get(tag)
if inputFieldName == "" {
inputFieldName = typeField.Name
} else {
Expand Down
249 changes: 237 additions & 12 deletions ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4127,7 +4127,81 @@ func Test_Ctx_QueryParser(t *testing.T) {
c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1")
q2 := new(Query2)
q2.Bool = true
q2.Name = "hello world"
q2.Name = "hello world 1"
utils.AssertEqual(t, nil, c.QueryParser(q2))
utils.AssertEqual(t, "basketball,football", q2.Hobby)
utils.AssertEqual(t, true, q2.Bool)
utils.AssertEqual(t, "tom", q2.Name) // check value get overwritten
utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, q2.FavouriteDrinks)
var nilSlice []string
utils.AssertEqual(t, nilSlice, q2.Empty)
utils.AssertEqual(t, []string{""}, q2.Alloc)
utils.AssertEqual(t, []int64{1}, q2.No)

type RequiredQuery struct {
Name string `query:"name,required"`
}
rq := new(RequiredQuery)
c.Request().URI().SetQueryString("")
utils.AssertEqual(t, "failed to decode: name is empty", c.QueryParser(rq).Error())

type ArrayQuery struct {
Data []string
}
aq := new(ArrayQuery)
c.Request().URI().SetQueryString("data[]=john&data[]=doe")
utils.AssertEqual(t, nil, c.QueryParser(aq))
utils.AssertEqual(t, 2, len(aq.Data))
}

// go test -run Test_Ctx_QueryParserUsingTag -v
func Test_Ctx_QueryParserUsingTag(t *testing.T) {
t.Parallel()
app := New(Config{EnableSplittingOnParsers: true})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
type Query struct {
ID int `query:"id"`
Name string `query:"name"`
Hobby []string `query:"hobby"`
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football")
q := new(Query)
utils.AssertEqual(t, nil, c.QueryParser(q))
utils.AssertEqual(t, 2, len(q.Hobby))

c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football")
q = new(Query)
utils.AssertEqual(t, nil, c.QueryParser(q))
utils.AssertEqual(t, 2, len(q.Hobby))

c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football")
q = new(Query)
utils.AssertEqual(t, nil, c.QueryParser(q))
utils.AssertEqual(t, 3, len(q.Hobby))

empty := new(Query)
c.Request().URI().SetQueryString("")
utils.AssertEqual(t, nil, c.QueryParser(empty))
utils.AssertEqual(t, 0, len(empty.Hobby))

type Query2 struct {
Bool bool `query:"bool"`
ID int `query:"id"`
Name string `query:"name"`
Hobby string `query:"hobby"`
FavouriteDrinks []string `query:"favouriteDrinks"`
Empty []string `query:"empty"`
Alloc []string `query:"alloc"`
No []int64 `query:"no"`
}

c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1")
q2 := new(Query2)
q2.Bool = true
q2.Name = "hello world 2"
utils.AssertEqual(t, nil, c.QueryParser(q2))
utils.AssertEqual(t, "basketball,football", q2.Hobby)
utils.AssertEqual(t, true, q2.Bool)
Expand Down Expand Up @@ -4385,7 +4459,82 @@ func Test_Ctx_ReqHeaderParser(t *testing.T) {

h2 := new(Header2)
h2.Bool = true
h2.Name = "hello world"
h2.Name = "hello world 3"
utils.AssertEqual(t, nil, c.ReqHeaderParser(h2))
utils.AssertEqual(t, "go,fiber", h2.Hobby)
utils.AssertEqual(t, true, h2.Bool)
utils.AssertEqual(t, "Jane Doe", h2.Name) // check value get overwritten
utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, h2.FavouriteDrinks)
var nilSlice []string
utils.AssertEqual(t, nilSlice, h2.Empty)
utils.AssertEqual(t, []string{""}, h2.Alloc)
utils.AssertEqual(t, []int64{1}, h2.No)

type RequiredHeader struct {
Name string `reqHeader:"name,required"`
}
rh := new(RequiredHeader)
c.Request().Header.Del("name")
utils.AssertEqual(t, "failed to decode: name is empty", c.ReqHeaderParser(rh).Error())
}

// go test -run Test_Ctx_ReqHeaderParserUsingTag -v
func Test_Ctx_ReqHeaderParserUsingTag(t *testing.T) {
t.Parallel()
app := New(Config{EnableSplittingOnParsers: true})
c := app.AcquireCtx(&fasthttp.RequestCtx{})
defer app.ReleaseCtx(c)
type Header struct {
ID int `reqHeader:"id"`
Name string `reqHeader:"name"`
Hobby []string `reqHeader:"hobby"`
Address []string `reqHeader:"x-secure-address"`
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")

c.Request().Header.Add("id", "1")
c.Request().Header.Add("Name", "John Doe")
c.Request().Header.Add("Hobby", "golang,fiber")
c.Request().Header.Add("x-secure-address", "1st,2st")
q := new(Header)
utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
utils.AssertEqual(t, 2, len(q.Hobby))
utils.AssertEqual(t, 2, len(q.Address))

c.Request().Header.Del("hobby")
c.Request().Header.Add("Hobby", "golang,fiber,go")
q = new(Header)
utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
utils.AssertEqual(t, 3, len(q.Hobby))

empty := new(Header)
c.Request().Header.Del("hobby")
utils.AssertEqual(t, nil, c.QueryParser(empty))
utils.AssertEqual(t, 0, len(empty.Hobby))

type Header2 struct {
Bool bool `reqHeader:"bool"`
ID int `reqHeader:"id"`
Name string `reqHeader:"name"`
Hobby string `reqHeader:"hobby"`
FavouriteDrinks []string `reqHeader:"favouriteDrinks"`
Empty []string `reqHeader:"empty"`
Alloc []string `reqHeader:"alloc"`
No []int64 `reqHeader:"no"`
}

c.Request().Header.Add("id", "2")
c.Request().Header.Add("Name", "Jane Doe")
c.Request().Header.Del("hobby")
c.Request().Header.Add("Hobby", "go,fiber")
c.Request().Header.Add("favouriteDrinks", "milo,coke,pepsi")
c.Request().Header.Add("alloc", "")
c.Request().Header.Add("no", "1")

h2 := new(Header2)
h2.Bool = true
h2.Name = "hello world 4"
utils.AssertEqual(t, nil, c.ReqHeaderParser(h2))
utils.AssertEqual(t, "go,fiber", h2.Hobby)
utils.AssertEqual(t, true, h2.Bool)
Expand Down Expand Up @@ -4574,28 +4723,104 @@ func Test_Ctx_ReqHeaderParser_Schema(t *testing.T) {
utils.AssertEqual(t, 0, n.Next.Value)
}

func Test_Ctx_EqualFieldType(t *testing.T) {
// go test -run Test_Ctx_EqualFieldTypeOfRequestQuery
func Test_Ctx_EqualFieldTypeOfRequestQuery(t *testing.T) {
t.Parallel()
var out int
utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key"))
utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", queryTag))

var dummy struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key"))
utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", queryTag))

var dummy2 struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f"))
utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", queryTag))

var user struct {
Name string
Address string `query:"address"`
Age int `query:"AGE"`
}
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age"))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", queryTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", queryTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", queryTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", queryTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", queryTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", queryTag))
}

// go test -run Test_Ctx_EqualFieldTypeOfRequestHeader
func Test_Ctx_EqualFieldTypeOfRequestHeader(t *testing.T) {
t.Parallel()
var out int
utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", reqHeaderTag))

var dummy struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", reqHeaderTag))

var dummy2 struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", reqHeaderTag))

var user struct {
Name string
Address string `reqHeader:"address"`
Age int `reqHeader:"AGE"`
}
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", reqHeaderTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", reqHeaderTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", reqHeaderTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", reqHeaderTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", reqHeaderTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", reqHeaderTag))
}

// go test -run Test_Ctx_EqualFieldTypeOfRequestBody
func Test_Ctx_EqualFieldTypeOfRequestBody(t *testing.T) {
t.Parallel()
var out int
utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", bodyTag))

var dummy struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", bodyTag))

var dummy2 struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", bodyTag))

var user struct {
Name string
Address string `form:"address"`
Age int `form:"AGE"`
}
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", bodyTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", bodyTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", bodyTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", bodyTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", bodyTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", bodyTag))
}

// go test -run Test_Ctx_EqualFieldTypeOfRequestParams
func Test_Ctx_EqualFieldTypeOfRequestParams(t *testing.T) {
t.Parallel()
var out int
utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", paramsTag))

var dummy struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", paramsTag))

var dummy2 struct{ f string }
utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", paramsTag))

var user struct {
Name string
Address string `params:"address"`
Age int `params:"AGE"`
}
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", paramsTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", paramsTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", paramsTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", paramsTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", paramsTag))
utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", paramsTag))
}

// go test -v -run=^$ -bench=Benchmark_Ctx_QueryParser -benchmem -count=4
Expand Down

0 comments on commit 59d3eb0

Please sign in to comment.