From c528e170911215b678b7c9b531230ace5c6ed2bc Mon Sep 17 00:00:00 2001 From: GuangyuFan <97507466+FGYFFFF@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:57:14 +0800 Subject: [PATCH] fix: do not pre-bind for BindXXX interface & normalize content-type (#1060) --- pkg/app/context.go | 2 +- pkg/app/server/binding/binder_test.go | 42 +++++++++++++++++++ pkg/app/server/binding/default.go | 13 +++--- .../internal/decoder/gjson_required.go | 2 +- .../internal/decoder/sonic_required.go | 2 +- 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/pkg/app/context.go b/pkg/app/context.go index 91b5e0da5..9117e3b34 100644 --- a/pkg/app/context.go +++ b/pkg/app/context.go @@ -1458,7 +1458,7 @@ func (ctx *RequestContext) BindByContentType(obj interface{}) error { return ctx.BindQuery(obj) } ct := utils.FilterContentType(bytesconv.B2s(ctx.Request.Header.ContentType())) - switch ct { + switch strings.ToLower(ct) { case consts.MIMEApplicationJSON: return ctx.BindJSON(obj) case consts.MIMEPROTOBUF: diff --git a/pkg/app/server/binding/binder_test.go b/pkg/app/server/binding/binder_test.go index 9071dbc85..7919d8d60 100644 --- a/pkg/app/server/binding/binder_test.go +++ b/pkg/app/server/binding/binder_test.go @@ -1549,6 +1549,48 @@ func TestBind_Issue1015(t *testing.T) { assert.DeepEqual(t, "asd", result.A) } +func TestBind_WithoutPreBindForTag(t *testing.T) { + type BaseQuery struct { + Action string `query:"Action" binding:"required"` + Version string `query:"Version" binding:"required"` + } + + req := newMockRequest(). + SetJSONContentType(). + SetRequestURI("http://foobar.com/?Action=action&Version=version"). + SetBody([]byte(``)) + + var result BaseQuery + + err := DefaultBinder().BindQuery(req.Req, &result) + if err != nil { + t.Error(err) + } + assert.DeepEqual(t, "action", result.Action) + assert.DeepEqual(t, "version", result.Version) +} + +func TestBind_NormalizeContentType(t *testing.T) { + type BaseQuery struct { + Action string `json:"action" binding:"required"` + Version string `json:"version" binding:"required"` + } + + req := newMockRequest(). + SetHeader("Content-Type", "ApplicAtion/json"). + SetRequestURI("http://foobar.com/?Action=action&Version=version"). + SetBody([]byte(`{"action":"action", "version":"version"}`)) + + var result BaseQuery + + err := DefaultBinder().BindQuery(req.Req, &result) + if err != nil { + t.Error(err) + } + assert.DeepEqual(t, "action", result.Action) + assert.DeepEqual(t, "version", result.Version) +} + func Benchmark_Binding(b *testing.B) { type Req struct { Version string `path:"v"` diff --git a/pkg/app/server/binding/default.go b/pkg/app/server/binding/default.go index 0634f26cf..7e09ac9bb 100644 --- a/pkg/app/server/binding/default.go +++ b/pkg/app/server/binding/default.go @@ -67,6 +67,7 @@ import ( "io" "net/url" "reflect" + "strings" "sync" exprValidator "github.com/bytedance/go-tagexpr/v2/validator" @@ -175,9 +176,11 @@ func (b *defaultBinder) bindTag(req *protocol.Request, v interface{}, params par return b.bindNonStruct(req, v) } - err := b.preBindBody(req, v) - if err != nil { - return fmt.Errorf("bind body failed, err=%v", err) + if len(tag) == 0 { + err := b.preBindBody(req, v) + if err != nil { + return fmt.Errorf("bind body failed, err=%v", err) + } } cache := b.tagCache(tag) cached, ok := cache.Load(typeID) @@ -323,7 +326,7 @@ func (b *defaultBinder) preBindBody(req *protocol.Request, v interface{}) error return nil } ct := bytesconv.B2s(req.Header.ContentType()) - switch utils.FilterContentType(ct) { + switch strings.ToLower(utils.FilterContentType(ct)) { case consts.MIMEApplicationJSON: return hJson.Unmarshal(req.Body(), v) case consts.MIMEPROTOBUF: @@ -339,7 +342,7 @@ func (b *defaultBinder) preBindBody(req *protocol.Request, v interface{}) error func (b *defaultBinder) bindNonStruct(req *protocol.Request, v interface{}) (err error) { ct := bytesconv.B2s(req.Header.ContentType()) - switch utils.FilterContentType(ct) { + switch strings.ToLower(utils.FilterContentType(ct)) { case consts.MIMEApplicationJSON: err = hJson.Unmarshal(req.Body(), v) case consts.MIMEPROTOBUF: diff --git a/pkg/app/server/binding/internal/decoder/gjson_required.go b/pkg/app/server/binding/internal/decoder/gjson_required.go index 88697e0f3..95e3c4fc5 100644 --- a/pkg/app/server/binding/internal/decoder/gjson_required.go +++ b/pkg/app/server/binding/internal/decoder/gjson_required.go @@ -33,7 +33,7 @@ func checkRequireJSON(req *protocol.Request, tagInfo TagInfo) bool { return true } ct := bytesconv.B2s(req.Header.ContentType()) - if utils.FilterContentType(ct) != consts.MIMEApplicationJSON { + if !strings.EqualFold(utils.FilterContentType(ct), consts.MIMEApplicationJSON) { return false } result := gjson.GetBytes(req.Body(), tagInfo.JSONName) diff --git a/pkg/app/server/binding/internal/decoder/sonic_required.go b/pkg/app/server/binding/internal/decoder/sonic_required.go index 2aae0c3a4..e408901a9 100644 --- a/pkg/app/server/binding/internal/decoder/sonic_required.go +++ b/pkg/app/server/binding/internal/decoder/sonic_required.go @@ -35,7 +35,7 @@ func checkRequireJSON(req *protocol.Request, tagInfo TagInfo) bool { return true } ct := bytesconv.B2s(req.Header.ContentType()) - if utils.FilterContentType(ct) != consts.MIMEApplicationJSON { + if !strings.EqualFold(utils.FilterContentType(ct), consts.MIMEApplicationJSON) { return false } node, _ := sonic.Get(req.Body(), stringSliceForInterface(tagInfo.JSONName)...)