Repository: cloudwego/hertz
Pull request #1067 (2024-02-20 06:57:01)

chore: release v0.8.1


Patch:
diff --git a/cmd/hz/generator/package_tpl.go b/cmd/hz/generator/package_tpl.go
index b46aa0e..7f72b9b 100644
--- a/cmd/hz/generator/package_tpl.go
+++ b/cmd/hz/generator/package_tpl.go
@@ -588,6 +588,14 @@ func (r *request) addHeader(header, value string) *request {
 	return r
 }
 
+func (r *request) addHeaders(params map[string]string) *request {
+	for k, v := range params {
+		r.addHeader(k, v)
+	}
+	return r
+}
+
+
 func (r *request) setQueryParam(param string, value interface{}) *request {
 	v := reflect.ValueOf(value)
 	switch v.Kind() {
@@ -923,7 +931,7 @@ func New{{.ServiceName}}Client(hostUrl string, ops ...Option) (Client, error) {
 
 {{range $_, $MethodInfo := .ClientMethods}}
 func (s *{{$.ServiceName}}Client) {{$MethodInfo.Name}}(context context.Context, req *{{$MethodInfo.RequestTypeName}}, reqOpt ...config.RequestOption) (resp *{{$MethodInfo.ReturnTypeName}}, rawResponse *protocol.Response, err error) {
-	httpResp := &{{$MethodInfo.ReturnTypeName}}{}	
+	httpResp := &{{$MethodInfo.ReturnTypeName}}{}
 	ret, err := s.client.r().
 		setContext(context).
 		setQueryParams(map[string]interface{}{
@@ -944,7 +952,7 @@ func (s *{{$.ServiceName}}Client) {{$MethodInfo.Name}}(context context.Context,
 		{{$MethodInfo.BodyParamsCode}}
 		setRequestOption(reqOpt...).
 		setResult(httpResp).
-		execute("{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}")
+		execute("{{if EqualFold $MethodInfo.HTTPMethod "Any"}}POST{{else}}{{ $MethodInfo.HTTPMethod }}{{end}}", "{{$MethodInfo.Path}}")
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/cmd/hz/generator/template_funcs.go b/cmd/hz/generator/template_funcs.go
index 2d33d72..d6a9837 100644
--- a/cmd/hz/generator/template_funcs.go
+++ b/cmd/hz/generator/template_funcs.go
@@ -30,6 +30,7 @@ var funcMap = func() template.FuncMap {
 		"ToSnakeCase":            util.ToSnakeCase,
 		"Split":                  strings.Split,
 		"Trim":                   strings.Trim,
+		"EqualFold":              strings.EqualFold,
 	}
 	for key, f := range sprig.TxtFuncMap() {
 		m[key] = f
diff --git a/cmd/hz/meta/const.go b/cmd/hz/meta/const.go
index dfeafd2..7441eab 100644
--- a/cmd/hz/meta/const.go
+++ b/cmd/hz/meta/const.go
@@ -19,7 +19,7 @@ package meta
 import "runtime"
 
 // Version hz version
-const Version = "v0.8.0"
+const Version = "v0.8.1"
 
 const DefaultServiceName = "hertz_service"
 
diff --git a/pkg/app/context.go b/pkg/app/context.go
index 510c972..9117e3b 100644
--- a/pkg/app/context.go
+++ b/pkg/app/context.go
@@ -795,6 +795,7 @@ func (ctx *RequestContext) Copy() *RequestContext {
 	paramCopy := make([]param.Param, len(cp.Params))
 	copy(paramCopy, cp.Params)
 	cp.Params = paramCopy
+	cp.fullPath = ctx.fullPath
 	cp.clientIPFunc = ctx.clientIPFunc
 	cp.formValueFunc = ctx.formValueFunc
 	cp.binder = ctx.binder
@@ -1457,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/default.go b/pkg/app/server/binding/default.go
index 0634f26..7e09ac9 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 88697e0..95e3c4f 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 2aae0c3..e408901 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)...)
diff --git a/version.go b/version.go
index b6c0efd..b23641e 100644
--- a/version.go
+++ b/version.go
@@ -19,5 +19,5 @@ package hertz
 // Name and Version info of this framework, used for statistics and debug
 const (
 	Name    = "Hertz"
-	Version = "v0.8.0"
+	Version = "v0.8.1"
 )


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 0325bef..e16ee73 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -81,7 +81,7 @@ jobs:
 
       - name: Get changed files
         id: changed-files
-        uses: tj-actions/changed-files@v35
+        uses: tj-actions/changed-files@v41
 
       - name: Hz Test
         if: contains(steps.changed-files.outputs.all_changed_files, 'cmd/hz')
@@ -105,7 +105,7 @@ jobs:
 
       - name: Get changed files
         id: changed-files
-        uses: tj-actions/changed-files@v35
+        uses: tj-actions/changed-files@v41
 
       - name: Install Protobuf
         shell: pwsh
diff --git a/pkg/app/context_test.go b/pkg/app/context_test.go
index 85d686c..7cbe71c 100644
--- a/pkg/app/context_test.go
+++ b/pkg/app/context_test.go
@@ -220,6 +220,7 @@ func TestGet(t *testing.T) {
 func TestCopy(t *testing.T) {
 	t.Parallel()
 	ctx := NewContext(0)
+	ctx.fullPath = "full_path"
 	ctx.Request.Header.Add("header_a", "header_value_a")
 	ctx.Response.Header.Add("header_b", "header_value_b")
 	ctx.Params = param.Params{
@@ -244,6 +245,11 @@ func TestCopy(t *testing.T) {
 				return
 			}
 
+			if c.fullPath != "full_path" {
+				t.Errorf("unexpected value: %#v, expected: %#v", c.fullPath, "full_path")
+				return
+			}
+
 			reqHeaderStr := context.Request.Header.Get("header_a")
 			if reqHeaderStr != "header_value_a" {
 				t.Errorf("unexpected value: %#v, expected: %#v", reqHeaderStr, "header_value_a")
diff --git a/pkg/app/server/binding/binder_test.go b/pkg/app/server/binding/binder_test.go
index 9071dbc..7919d8d 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"`