From 1f9997cabc88b3a0db263b6d8a0188d3568261f1 Mon Sep 17 00:00:00 2001 From: kinggo Date: Tue, 5 Mar 2024 11:21:21 +0800 Subject: [PATCH 1/5] optimize: filter shortConnErr in tracer (#1037) --- pkg/protocol/http1/server.go | 16 ++++++++++------ pkg/protocol/http1/server_test.go | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/protocol/http1/server.go b/pkg/protocol/http1/server.go index a5d33f13d..535d1d5e2 100644 --- a/pkg/protocol/http1/server.go +++ b/pkg/protocol/http1/server.go @@ -114,9 +114,6 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) { defer func() { if s.EnableTrace { - if shouldRecordInTraceError(err) { - ctx.GetTraceInfo().Stats().SetError(err) - } // in case of error, we need to trigger all events if eventsToTrigger != nil { for last := eventsToTrigger.pop(); last != nil; last = eventsToTrigger.pop() { @@ -124,8 +121,11 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) { } s.eventStackPool.Put(eventsToTrigger) } - - traceCtl.DoFinish(cc, ctx, err) + if shouldRecordInTraceError(err) { + traceCtl.DoFinish(cc, ctx, err) + } else { + traceCtl.DoFinish(cc, ctx, nil) + } } // Hijack may release and close the connection already @@ -384,7 +384,11 @@ func (s Server) Serve(c context.Context, conn network.Conn) (err error) { } // general case if s.EnableTrace { - traceCtl.DoFinish(cc, ctx, err) + if shouldRecordInTraceError(err) { + traceCtl.DoFinish(cc, ctx, err) + } else { + traceCtl.DoFinish(cc, ctx, nil) + } } ctx.ResetWithoutConn() diff --git a/pkg/protocol/http1/server_test.go b/pkg/protocol/http1/server_test.go index dc8790a97..2263ece77 100644 --- a/pkg/protocol/http1/server_test.go +++ b/pkg/protocol/http1/server_test.go @@ -70,6 +70,7 @@ func TestTraceEventCompleted(t *testing.T) { assert.False(t, traceInfo.Stats().GetEvent(stats.WriteStart).IsNil()) assert.False(t, traceInfo.Stats().GetEvent(stats.WriteFinish).IsNil()) assert.False(t, traceInfo.Stats().GetEvent(stats.HTTPFinish).IsNil()) + assert.Nil(t, traceInfo.Stats().Error()) } func TestTraceEventReadHeaderError(t *testing.T) { From f91ce33ef96420be64145eaf29a0edf75e561036 Mon Sep 17 00:00:00 2001 From: Guangming Luo Date: Thu, 7 Mar 2024 11:50:43 +0800 Subject: [PATCH 2/5] chore: update readme images and documentation (#1075) --- README.md | 10 ++++++---- README_cn.md | 10 ++++++---- images/wechat_group_cn.png | Bin 45791 -> 0 bytes images/wechat_group_en.png | Bin 50570 -> 0 bytes pkg/protocol/http1/proxy/proxy.go | 2 -- 5 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 images/wechat_group_cn.png delete mode 100644 images/wechat_group_en.png diff --git a/README.md b/README.md index 23fcc2e6a..4fb87b7e4 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,10 @@ Hertz [həːts] is a high-usability, high-performance and high-extensibility Gol The Hertz-Examples repository provides code out of the box. [more](https://www.cloudwego.io/zh/docs/hertz/tutorials/example/) ### Basic Features Contains introduction and use of general middleware, context selection, data binding, data rendering, direct access, logging, error handling. [more](https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/) +### Observability + Contains instrumentation, logging, tracing, monitoring, OpenTelemetry integration. [more](https://www.cloudwego.io/docs/hertz/tutorials/observability/) ### Service Governance - Contains tracer monitor. [more](https://www.cloudwego.io/zh/docs/hertz/tutorials/service-governance/) + Contains service registration and discovery extensions, Sentinel integration. [more](https://www.cloudwego.io/zh/docs/hertz/tutorials/service-governance/) ### Framework Extension Contains network library extensions. [more](https://www.cloudwego.io/zh/docs/hertz/tutorials/framework-exten/) ### Reference @@ -51,10 +53,10 @@ Hertz [həːts] is a high-usability, high-performance and high-extensibility Gol Frequently Asked Questions. [more](https://www.cloudwego.io/zh/docs/hertz/faq/) ## Performance Performance testing can only provide a relative reference. In production, there are many factors that can affect actual performance. - We provide the hertz-benchmark project to track and compare the performance of Hertz and other frameworks in different situations for reference. + We provide the [hertz-benchmark](https://github.com/cloudwego/hertz-benchmark) project to track and compare the performance of Hertz and other frameworks in different situations for reference. ## Related Projects - [Netpoll](https://github.com/cloudwego/netpoll): A high-performance network library. Hertz integrated by default. -- [Hertz-Contrib](https://github.com/hertz-contrib): A partial extension library of Hertz, which users can integrate into Hertz through options according to their needs. +- [Hertz-contrib](https://github.com/hertz-contrib): A partial extension library of Hertz, which users can integrate into Hertz through options according to their needs. - [Example](https://github.com/cloudwego/hertz-examples): Use examples of Hertz. ## Extensions @@ -120,7 +122,7 @@ Thank you for your contribution to Hertz! ## Landscapes

-   +  

CloudWeGo enriches the CNCF CLOUD NATIVE Landscape.

diff --git a/README_cn.md b/README_cn.md index 6468418b4..812c65973 100644 --- a/README_cn.md +++ b/README_cn.md @@ -41,8 +41,10 @@ Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了 ### 用户指南 ### 基本特性 包含通用中间件的介绍和使用,上下文选择,数据绑定,数据渲染,直连访问,日志,错误处理,[详见文档](https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/) +### 可观测性 + 包含日志,链路追踪,埋点,监控,OpenTelemetry 集成,[详见文档](https://www.cloudwego.io/zh/docs/hertz/tutorials/observability/) ### 治理特性 - 包含 trace monitor,[详见文档](https://www.cloudwego.io/zh/docs/hertz/tutorials/service-governance/) + 包含服务注册与发现扩展,Sentinel 集成,[详见文档](https://www.cloudwego.io/zh/docs/hertz/tutorials/service-governance/) ### 框架扩展 包含网络库扩展,[详见文档](https://www.cloudwego.io/zh/docs/hertz/tutorials/framework-exten/) ### 参考 @@ -51,10 +53,10 @@ Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了 常见问题排查,[详见文档](https://www.cloudwego.io/zh/docs/hertz/faq/) ## 框架性能 性能测试只能提供相对参考,工业场景下,有诸多因素可以影响实际的性能表现 - 我们提供了 hertz-benchmark 项目用来长期追踪和比较 Hertz 与其他框架在不同情况下的性能数据以供参考 + 我们提供了 [hertz-benchmark](https://github.com/cloudwego/hertz-benchmark) 项目用来长期追踪和比较 Hertz 与其他框架在不同情况下的性能数据以供参考 ## 相关项目 - [Netpoll](https://github.com/cloudwego/netpoll): 自研高性能网络库,Hertz 默认集成 -- [Hertz-Contrib](https://github.com/hertz-contrib): Hertz 扩展仓库,提供中间件、tracer 等能力 +- [hertz-Contrib](https://github.com/hertz-contrib): Hertz 扩展仓库,提供可观测、安全、流量治理、协议、HTTP 通用能力等扩展 - [Example](https://github.com/cloudwego/hertz-examples): Hertz 使用例子 ## 相关拓展 @@ -121,7 +123,7 @@ Hertz 基于[Apache License 2.0](https://github.com/cloudwego/hertz/blob/main/LI ## Landscapes

-   +  

CloudWeGo 丰富了 CNCF 云原生生态

diff --git a/images/wechat_group_cn.png b/images/wechat_group_cn.png deleted file mode 100644 index a9bf48ce11e55e122f513ece24e82ef0492d7d9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45791 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

@YuDJfA19qd0@ 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%0DQp6d_8kQNNlGL6ScF+8qp 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

H_MjsyV7L<--n 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 Gp#KBcSFa`j diff --git a/pkg/protocol/http1/proxy/proxy.go b/pkg/protocol/http1/proxy/proxy.go index f8bae7608..2b243ff04 100644 --- a/pkg/protocol/http1/proxy/proxy.go +++ b/pkg/protocol/http1/proxy/proxy.go @@ -81,13 +81,11 @@ func SetupProxy(conn network.Conn, addr string, proxyURI *protocol.URI, tlsConfi defer close(didReadResponse) err = reqI.Write(connectReq, conn) - if err != nil { return } err = conn.Flush() - if err != nil { return } From 81f0c83c4cdca1c7eb4b640bc7eb6eb1f2c390ca Mon Sep 17 00:00:00 2001 From: XiaoYi-byte <72679319+XiaoYi-byte@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:21:16 +0800 Subject: [PATCH 3/5] Increased unit test coverage for pkg/protocol/header_test (#1074) --- pkg/protocol/header_test.go | 110 ++++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/pkg/protocol/header_test.go b/pkg/protocol/header_test.go index 35cc0011f..a14704053 100644 --- a/pkg/protocol/header_test.go +++ b/pkg/protocol/header_test.go @@ -69,18 +69,18 @@ func TestResponseHeaderSetHeaderLength(t *testing.T) { func TestSetNoHTTP11(t *testing.T) { rh := ResponseHeader{} - rh.SetNoHTTP11(true) + rh.SetProtocol(consts.HTTP10) assert.DeepEqual(t, consts.HTTP10, rh.protocol) - rh.SetNoHTTP11(false) + rh.SetProtocol(consts.HTTP11) assert.DeepEqual(t, consts.HTTP11, rh.protocol) assert.True(t, rh.IsHTTP11()) h := RequestHeader{} - h.SetNoHTTP11(true) + h.SetProtocol(consts.HTTP10) assert.DeepEqual(t, consts.HTTP10, h.protocol) - h.SetNoHTTP11(false) + h.SetProtocol(consts.HTTP11) assert.DeepEqual(t, consts.HTTP11, h.protocol) assert.True(t, h.IsHTTP11()) } @@ -101,6 +101,17 @@ func TestSetContentLengthBytes(t *testing.T) { assert.DeepEqual(t, rh.contentLengthBytes, []byte("foo")) } +func TestInitContentLengthWithValue(t *testing.T) { + initLength := 100 + h := RequestHeader{} + h.InitContentLengthWithValue(initLength) + assert.DeepEqual(t, h.contentLength, initLength) + + rh := ResponseHeader{} + rh.InitContentLengthWithValue(initLength) + assert.DeepEqual(t, rh.contentLength, initLength) +} + func TestSetContentEncoding(t *testing.T) { rh := ResponseHeader{} rh.SetContentEncoding("gzip") @@ -171,24 +182,71 @@ func TestResponseHeaderGet(t *testing.T) { assert.DeepEqual(t, val, rightVal) } +func TestRequestHeaderGetAll(t *testing.T) { + h := RequestHeader{} + h.Set("Foo-Bar", "foo") + h.Add("Foo-Bar", "bar") + h.Add("Foo-Bar", "foo-bar") + values := h.GetAll("Foo-Bar") + assert.DeepEqual(t, values, []string{"foo", "bar", "foo-bar"}) +} + +func TestResponseHeaderGetAll(t *testing.T) { + h := ResponseHeader{} + h.Set("Foo-Bar", "foo") + h.Add("Foo-Bar", "bar") + h.Add("Foo-Bar", "foo-bar") + values := h.GetAll("Foo-Bar") + assert.DeepEqual(t, values, []string{"foo", "bar", "foo-bar"}) +} + func TestRequestHeaderVisitAll(t *testing.T) { h := RequestHeader{} h.Set("xxx", "yyy") h.Set("xxx2", "yyy2") - h.VisitAll( - func(k, v []byte) { - key := string(k) - value := string(v) - if key != "Xxx" && key != "Xxx2" { - t.Fatalf("Unexpected %v. Expected %v", key, "xxx or yyy") - } - if key == "Xxx" && value != "yyy" { - t.Fatalf("Unexpected %v. Expected %v", value, "yyy") - } - if key == "Xxx2" && value != "yyy2" { - t.Fatalf("Unexpected %v. Expected %v", value, "yyy2") - } - }) + h.SetHost("host") + h.SetContentLengthBytes([]byte("content-length")) + h.Set(consts.HeaderContentType, "content-type") + h.Set(consts.HeaderUserAgent, "user-agent") + err := h.Trailer().SetTrailers([]byte("foo, bar")) + if err != nil { + t.Fatalf("Set trailer err %v", err) + } + h.SetCookie("foo", "bar") + h.Set(consts.HeaderConnection, "close") + h.VisitAll(func(k, v []byte) { + key := string(k) + value := string(v) + switch key { + case consts.HeaderHost: + assert.DeepEqual(t, value, "host") + case consts.HeaderContentLength: + assert.DeepEqual(t, value, "content-length") + case consts.HeaderContentType: + assert.DeepEqual(t, value, "content-type") + case consts.HeaderUserAgent: + assert.DeepEqual(t, value, "user-agent") + case consts.HeaderTrailer: + assert.DeepEqual(t, value, "Foo, Bar") + case consts.HeaderCookie: + assert.DeepEqual(t, value, "foo=bar") + case consts.HeaderConnection: + assert.DeepEqual(t, value, "close") + case "Xxx": + assert.DeepEqual(t, value, "yyy") + case "Xxx2": + assert.DeepEqual(t, value, "yyy2") + default: + t.Fatalf("Unexpected key %v", key) + } + }) +} + +func TestRequestHeaderCookie(t *testing.T) { + var h RequestHeader + h.SetCookie("foo", "bar") + cookie := h.Cookie("foo") + assert.DeepEqual(t, []byte("bar"), cookie) } func TestRequestHeaderCookies(t *testing.T) { @@ -215,6 +273,7 @@ func TestRequestHeaderDel(t *testing.T) { h.Set(consts.HeaderServer, "aaabbb") h.Set(consts.HeaderContentLength, "1123") h.Set(consts.HeaderTrailer, "foo, bar") + h.Set(consts.HeaderUserAgent, "foo-bar") h.SetHost("foobar") h.SetCookie("foo", "bar") @@ -226,6 +285,7 @@ func TestRequestHeaderDel(t *testing.T) { h.del([]byte("Set-Cookie")) h.del([]byte("Host")) h.del([]byte(consts.HeaderTrailer)) + h.del([]byte(consts.HeaderUserAgent)) h.DelCookie("foo") h.Del("ccc") @@ -269,6 +329,10 @@ func TestRequestHeaderDel(t *testing.T) { if len(hv) > 0 { t.Fatalf("non-zero value: %q", hv) } + hv = h.Peek(consts.HeaderUserAgent) + if len(hv) > 0 { + t.Fatalf("non-zero value: %q", hv) + } if h.ContentLength() != 0 { t.Fatalf("unexpected content-length: %d. Expecting 0", h.ContentLength()) } @@ -584,6 +648,16 @@ func TestRequestHeaderDelAllCookies(t *testing.T) { } } +func TestResponseHeaderDelAllCookies(t *testing.T) { + var h ResponseHeader + h.SetCanonical([]byte(consts.HeaderSetCookie), []byte("foo")) + h.DelAllCookies() + hv := h.FullCookie() + if len(hv) > 0 { + t.Fatalf("non-zero value: %q", hv) + } +} + func TestRequestHeaderSetNoDefaultContentType(t *testing.T) { var h RequestHeader h.SetMethod(http.MethodPost) From b7cbc9de1778367e157c1509818da08f5e16592c Mon Sep 17 00:00:00 2001 From: qingmu Date: Sun, 10 Mar 2024 19:34:39 +0800 Subject: [PATCH 4/5] feat: add SetHandlers when fast fail for no valid host and invalid rPath (#1057) --- pkg/app/server/hertz_test.go | 57 +++++++++++++++++++++++++++++++++++- pkg/route/engine.go | 2 ++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/pkg/app/server/hertz_test.go b/pkg/app/server/hertz_test.go index 4a9cee3d0..3352d34c8 100644 --- a/pkg/app/server/hertz_test.go +++ b/pkg/app/server/hertz_test.go @@ -196,7 +196,10 @@ func formatAsDate(t time.Time) string { } // copied from router -var default400Body = []byte("400 bad request") +var ( + default400Body = []byte("400 bad request") + requiredHostBody = []byte("missing required Host header") +) func TestServer_Use(t *testing.T) { router := New() @@ -284,6 +287,13 @@ func TestNotAbsolutePath(t *testing.T) { func TestNotAbsolutePathWithRawPath(t *testing.T) { engine := New(WithHostPorts("127.0.0.1:9991"), WithUseRawPath(true)) + const ( + MiddlewareKey = "middleware_key" + MiddlewareValue = "middleware_value" + ) + engine.Use(func(c context.Context, ctx *app.RequestContext) { + ctx.Response.Header.Set(MiddlewareKey, MiddlewareValue) + }) engine.POST("/", func(c context.Context, ctx *app.RequestContext) { }) engine.POST("/a", func(c context.Context, ctx *app.RequestContext) { @@ -301,6 +311,8 @@ func TestNotAbsolutePathWithRawPath(t *testing.T) { engine.ServeHTTP(context.Background(), ctx) assert.DeepEqual(t, consts.StatusBadRequest, ctx.Response.StatusCode()) assert.DeepEqual(t, default400Body, ctx.Response.Body()) + gh := ctx.Response.Header.Get(MiddlewareKey) + assert.DeepEqual(t, MiddlewareValue, gh) s = "POST a?a=b HTTP/1.1\r\nHost: a.b.c\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" zr = mock.NewZeroCopyReader(s) @@ -312,6 +324,49 @@ func TestNotAbsolutePathWithRawPath(t *testing.T) { engine.ServeHTTP(context.Background(), ctx) assert.DeepEqual(t, consts.StatusBadRequest, ctx.Response.StatusCode()) assert.DeepEqual(t, default400Body, ctx.Response.Body()) + gh = ctx.Response.Header.Get(MiddlewareKey) + assert.DeepEqual(t, MiddlewareValue, gh) +} + +func TestNotValidHost(t *testing.T) { + engine := New(WithHostPorts("127.0.0.1:9992")) + const ( + MiddlewareKey = "middleware_key" + MiddlewareValue = "middleware_value" + ) + engine.Use(func(c context.Context, ctx *app.RequestContext) { + ctx.Response.Header.Set(MiddlewareKey, MiddlewareValue) + }) + engine.POST("/", func(c context.Context, ctx *app.RequestContext) { + }) + engine.POST("/a", func(c context.Context, ctx *app.RequestContext) { + }) + + s := "POST ?a=b HTTP/1.1\r\nHost: \r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" + zr := mock.NewZeroCopyReader(s) + + ctx := app.NewContext(0) + if err := req.Read(&ctx.Request, zr); err != nil { + t.Fatalf("unexpected error: %s", err) + } + engine.ServeHTTP(context.Background(), ctx) + assert.DeepEqual(t, consts.StatusBadRequest, ctx.Response.StatusCode()) + assert.DeepEqual(t, requiredHostBody, ctx.Response.Body()) + gh := ctx.Response.Header.Get(MiddlewareKey) + assert.DeepEqual(t, MiddlewareValue, gh) + + s = "POST a?a=b HTTP/1.1\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343" + zr = mock.NewZeroCopyReader(s) + + ctx = app.NewContext(0) + if err := req.Read(&ctx.Request, zr); err != nil { + t.Fatalf("unexpected error: %s", err) + } + engine.ServeHTTP(context.Background(), ctx) + assert.DeepEqual(t, consts.StatusBadRequest, ctx.Response.StatusCode()) + assert.DeepEqual(t, requiredHostBody, ctx.Response.Body()) + gh = ctx.Response.Header.Get(MiddlewareKey) + assert.DeepEqual(t, MiddlewareValue, gh) } func TestWithBasePath(t *testing.T) { diff --git a/pkg/route/engine.go b/pkg/route/engine.go index 8b65e6e7a..30b899dac 100644 --- a/pkg/route/engine.go +++ b/pkg/route/engine.go @@ -726,6 +726,7 @@ func (engine *Engine) ServeHTTP(c context.Context, ctx *app.RequestContext) { // align with https://datatracker.ietf.org/doc/html/rfc2616#section-5.2 if len(ctx.Request.Host()) == 0 && ctx.Request.Header.IsHTTP11() && bytesconv.B2s(ctx.Request.Method()) != consts.MethodConnect { + ctx.SetHandlers(engine.Handlers) serveError(c, ctx, consts.StatusBadRequest, requiredHostBody) return } @@ -743,6 +744,7 @@ func (engine *Engine) ServeHTTP(c context.Context, ctx *app.RequestContext) { // Follow RFC7230#section-5.3 if rPath == "" || rPath[0] != '/' { + ctx.SetHandlers(engine.Handlers) serveError(c, ctx, consts.StatusBadRequest, default400Body) return } From 4742b2e84cea58493560407e3c0ccee47aab58e7 Mon Sep 17 00:00:00 2001 From: fgy Date: Tue, 30 Jan 2024 21:37:59 +0800 Subject: [PATCH 5/5] feat: add more default type --- _typos.toml | 6 +- pkg/app/server/binding/binder_test.go | 51 +++++++- .../internal/decoder/base_type_decoder.go | 7 +- .../decoder/customized_type_decoder.go | 9 +- .../binding/internal/decoder/decoder.go | 2 +- .../internal/decoder/gjson_required.go | 9 ++ .../internal/decoder/map_type_decoder.go | 7 +- .../internal/decoder/slice_type_decoder.go | 47 +++---- .../internal/decoder/sonic_required.go | 9 ++ .../internal/decoder/struct_type_decoder.go | 7 +- .../server/binding/internal/decoder/tag.go | 8 +- .../server/binding/internal/decoder/util.go | 76 ++++++++++++ pkg/app/server/binding/tagexpr_bind_test.go | 117 +++++++++--------- 13 files changed, 247 insertions(+), 108 deletions(-) create mode 100644 pkg/app/server/binding/internal/decoder/util.go diff --git a/_typos.toml b/_typos.toml index 3d3103e19..bb673bac6 100644 --- a/_typos.toml +++ b/_typos.toml @@ -18,4 +18,8 @@ HeaderReferer = "HeaderReferer" expectedReferer = "expectedReferer" Referer = "Referer" O_WRONLY = "O_WRONLY" -WRONLY = "WRONLY" \ No newline at end of file +WRONLY = "WRONLY" +ome = "ome" +ifModifiedSice = "ifModifiedSice" +hd = "hd" +pn = "pn" \ No newline at end of file diff --git a/pkg/app/server/binding/binder_test.go b/pkg/app/server/binding/binder_test.go index 7919d8d60..225b8bd2e 100644 --- a/pkg/app/server/binding/binder_test.go +++ b/pkg/app/server/binding/binder_test.go @@ -417,10 +417,11 @@ func TestBind_ZeroValueBind(t *testing.T) { func TestBind_DefaultValueBind(t *testing.T) { var s struct { - A int `default:"15"` - B float64 `query:"b" default:"17"` - C []int `default:"15"` - D []string `default:"qwe"` + A int `default:"15"` + B float64 `query:"b" default:"17"` + C []int `default:"[15]"` + D []string `default:"['qwe','asd']"` + F [2]string `default:"['qwe','asd','zxc']"` } req := newMockRequest(). SetRequestURI("http://foobar.com") @@ -432,7 +433,23 @@ func TestBind_DefaultValueBind(t *testing.T) { assert.DeepEqual(t, 15, s.A) assert.DeepEqual(t, float64(17), s.B) assert.DeepEqual(t, 15, s.C[0]) + assert.DeepEqual(t, 2, len(s.D)) assert.DeepEqual(t, "qwe", s.D[0]) + assert.DeepEqual(t, "asd", s.D[1]) + assert.DeepEqual(t, 2, len(s.F)) + assert.DeepEqual(t, "qwe", s.F[0]) + assert.DeepEqual(t, "asd", s.F[1]) + + var s2 struct { + F [2]string `default:"['qwe']"` + } + err = DefaultBinder().Bind(req.Req, &s2, nil) + if err != nil { + t.Fatal(err) + } + assert.DeepEqual(t, 2, len(s2.F)) + assert.DeepEqual(t, "qwe", s2.F[0]) + assert.DeepEqual(t, "", s2.F[1]) var d struct { D [2]string `default:"qwe"` @@ -1549,6 +1566,32 @@ func TestBind_Issue1015(t *testing.T) { assert.DeepEqual(t, "asd", result.A) } +func TestBind_JSONWithDefault(t *testing.T) { + type Req struct { + J1 string `json:"j1" default:"j1default"` + } + + req := newMockRequest(). + SetJSONContentType(). + SetBody([]byte(`{"j1":"j1"}`)) + var result Req + err := DefaultBinder().Bind(req.Req, &result, nil) + if err != nil { + t.Error(err) + } + assert.DeepEqual(t, "j1", result.J1) + + result = Req{} + req = newMockRequest(). + SetJSONContentType(). + SetBody([]byte(`{"j2":"j2"}`)) + err = DefaultBinder().Bind(req.Req, &result, nil) + if err != nil { + t.Error(err) + } + assert.DeepEqual(t, "j1default", result.J1) +} + func TestBind_WithoutPreBindForTag(t *testing.T) { type BaseQuery struct { Action string `query:"Action" binding:"required"` diff --git a/pkg/app/server/binding/internal/decoder/base_type_decoder.go b/pkg/app/server/binding/internal/decoder/base_type_decoder.go index ece04f737..9c5cb1200 100644 --- a/pkg/app/server/binding/internal/decoder/base_type_decoder.go +++ b/pkg/app/server/binding/internal/decoder/base_type_decoder.go @@ -69,14 +69,17 @@ func (d *baseTypeFieldTextDecoder) Decode(req *protocol.Request, params param.Pa var defaultValue string for _, tagInfo := range d.tagInfos { if tagInfo.Skip || tagInfo.Key == jsonTag || tagInfo.Key == fileNameTag { - defaultValue = tagInfo.Default if tagInfo.Key == jsonTag { + defaultValue = tagInfo.Default found := checkRequireJSON(req, tagInfo) if found { err = nil } else { err = fmt.Errorf("'%s' field is a 'required' parameter, but the request body does not have this parameter '%s'", d.fieldName, tagInfo.JSONName) } + if len(tagInfo.Default) != 0 && keyExist(req, tagInfo) { + defaultValue = "" + } } continue } @@ -94,7 +97,7 @@ func (d *baseTypeFieldTextDecoder) Decode(req *protocol.Request, params param.Pa return err } if len(text) == 0 && len(defaultValue) != 0 { - text = defaultValue + text = toDefaultValue(d.fieldType, defaultValue) } if !exist && len(text) == 0 { return nil diff --git a/pkg/app/server/binding/internal/decoder/customized_type_decoder.go b/pkg/app/server/binding/internal/decoder/customized_type_decoder.go index 19efa46ae..ab343c811 100644 --- a/pkg/app/server/binding/internal/decoder/customized_type_decoder.go +++ b/pkg/app/server/binding/internal/decoder/customized_type_decoder.go @@ -60,7 +60,12 @@ func (d *customizedFieldTextDecoder) Decode(req *protocol.Request, params param. var defaultValue string for _, tagInfo := range d.tagInfos { if tagInfo.Skip || tagInfo.Key == jsonTag || tagInfo.Key == fileNameTag { - defaultValue = tagInfo.Default + if tagInfo.Key == jsonTag { + defaultValue = tagInfo.Default + if len(tagInfo.Default) != 0 && keyExist(req, tagInfo) { + defaultValue = "" + } + } continue } text, exist = tagInfo.Getter(req, params, tagInfo.Value) @@ -73,7 +78,7 @@ func (d *customizedFieldTextDecoder) Decode(req *protocol.Request, params param. return nil } if len(text) == 0 && len(defaultValue) != 0 { - text = defaultValue + text = toDefaultValue(d.fieldType, defaultValue) } v, err := d.decodeFunc(req, params, text) diff --git a/pkg/app/server/binding/internal/decoder/decoder.go b/pkg/app/server/binding/internal/decoder/decoder.go index f18a68127..4c36bcea9 100644 --- a/pkg/app/server/binding/internal/decoder/decoder.go +++ b/pkg/app/server/binding/internal/decoder/decoder.go @@ -124,7 +124,7 @@ func getFieldDecoder(pInfo parentInfos, field reflect.StructField, index int, by // JSONName is like 'a.b.c' for 'required validate' fieldTagInfos, newParentJSONName, needValidate := lookupFieldTags(field, pInfo.JSONName, config) if len(fieldTagInfos) == 0 && !config.DisableDefaultTag { - fieldTagInfos = getDefaultFieldTags(field) + fieldTagInfos, newParentJSONName = getDefaultFieldTags(field, pInfo.JSONName) } if len(byTag) != 0 { fieldTagInfos = getFieldTagInfoByTag(field, byTag) diff --git a/pkg/app/server/binding/internal/decoder/gjson_required.go b/pkg/app/server/binding/internal/decoder/gjson_required.go index 95e3c4fc5..130d65d8f 100644 --- a/pkg/app/server/binding/internal/decoder/gjson_required.go +++ b/pkg/app/server/binding/internal/decoder/gjson_required.go @@ -47,3 +47,12 @@ func checkRequireJSON(req *protocol.Request, tagInfo TagInfo) bool { } return true } + +func keyExist(req *protocol.Request, tagInfo TagInfo) bool { + ct := bytesconv.B2s(req.Header.ContentType()) + if utils.FilterContentType(ct) != consts.MIMEApplicationJSON { + return false + } + result := gjson.GetBytes(req.Body(), tagInfo.JSONName) + return result.Exists() +} diff --git a/pkg/app/server/binding/internal/decoder/map_type_decoder.go b/pkg/app/server/binding/internal/decoder/map_type_decoder.go index 31fe85a1b..59fed7716 100644 --- a/pkg/app/server/binding/internal/decoder/map_type_decoder.go +++ b/pkg/app/server/binding/internal/decoder/map_type_decoder.go @@ -61,14 +61,17 @@ func (d *mapTypeFieldTextDecoder) Decode(req *protocol.Request, params param.Par var defaultValue string for _, tagInfo := range d.tagInfos { if tagInfo.Skip || tagInfo.Key == jsonTag || tagInfo.Key == fileNameTag { - defaultValue = tagInfo.Default if tagInfo.Key == jsonTag { + defaultValue = tagInfo.Default found := checkRequireJSON(req, tagInfo) if found { err = nil } else { err = fmt.Errorf("'%s' field is a 'required' parameter, but the request does not have this parameter", d.fieldName) } + if len(tagInfo.Default) != 0 && keyExist(req, tagInfo) { + defaultValue = "" + } } continue } @@ -86,7 +89,7 @@ func (d *mapTypeFieldTextDecoder) Decode(req *protocol.Request, params param.Par return err } if len(text) == 0 && len(defaultValue) != 0 { - text = defaultValue + text = toDefaultValue(d.fieldType, defaultValue) } if !exist && len(text) == 0 { return nil diff --git a/pkg/app/server/binding/internal/decoder/slice_type_decoder.go b/pkg/app/server/binding/internal/decoder/slice_type_decoder.go index fc5c9814f..c2887d1c4 100644 --- a/pkg/app/server/binding/internal/decoder/slice_type_decoder.go +++ b/pkg/app/server/binding/internal/decoder/slice_type_decoder.go @@ -61,16 +61,20 @@ func (d *sliceTypeFieldTextDecoder) Decode(req *protocol.Request, params param.P var texts []string var defaultValue string var bindRawBody bool + var isDefault bool for _, tagInfo := range d.tagInfos { if tagInfo.Skip || tagInfo.Key == jsonTag || tagInfo.Key == fileNameTag { - defaultValue = tagInfo.Default if tagInfo.Key == jsonTag { + defaultValue = tagInfo.Default found := checkRequireJSON(req, tagInfo) if found { err = nil } else { err = fmt.Errorf("'%s' field is a 'required' parameter, but the request does not have this parameter", d.fieldName) } + if len(tagInfo.Default) != 0 && keyExist(req, tagInfo) { // + defaultValue = "" + } } continue } @@ -91,7 +95,9 @@ func (d *sliceTypeFieldTextDecoder) Decode(req *protocol.Request, params param.P return err } if len(texts) == 0 && len(defaultValue) != 0 { + defaultValue = toDefaultValue(d.fieldType, defaultValue) texts = append(texts, defaultValue) + isDefault = true } if len(texts) == 0 { return nil @@ -113,7 +119,7 @@ func (d *sliceTypeFieldTextDecoder) Decode(req *protocol.Request, params param.P } if d.isArray { - if len(texts) != field.Len() { + if len(texts) != field.Len() && !isDefault { return fmt.Errorf("%q is not valid value for %s", texts, field.Type().String()) } } else { @@ -135,6 +141,13 @@ func (d *sliceTypeFieldTextDecoder) Decode(req *protocol.Request, params param.P elemKind = t.Kind() ptrDepth++ } + if isDefault { + err = hJson.Unmarshal(bytesconv.S2b(texts[0]), reqValue.Field(d.index).Addr().Interface()) + if err != nil { + return fmt.Errorf("using '%s' to unmarshal field '%s: %s' failed, %v", texts[0], d.fieldName, d.fieldType.String(), err) + } + return nil + } for idx, text := range texts { var vv reflect.Value @@ -218,33 +231,3 @@ func getSliceFieldDecoder(field reflect.StructField, index int, tagInfos []TagIn isArray: isArray, }}, nil } - -func stringToValue(elemType reflect.Type, text string, req *protocol.Request, params param.Params, config *DecodeConfig) (v reflect.Value, err error) { - v = reflect.New(elemType).Elem() - if customizedFunc, exist := config.TypeUnmarshalFuncs[elemType]; exist { - val, err := customizedFunc(req, params, text) - if err != nil { - return reflect.Value{}, err - } - return val, nil - } - switch elemType.Kind() { - case reflect.Struct: - err = hJson.Unmarshal(bytesconv.S2b(text), v.Addr().Interface()) - case reflect.Map: - err = hJson.Unmarshal(bytesconv.S2b(text), v.Addr().Interface()) - case reflect.Array, reflect.Slice: - // do nothing - default: - decoder, err := SelectTextDecoder(elemType) - if err != nil { - return reflect.Value{}, fmt.Errorf("unsupported type %s for slice/array", elemType.String()) - } - err = decoder.UnmarshalString(text, v, config.LooseZeroMode) - if err != nil { - return reflect.Value{}, fmt.Errorf("unable to decode '%s' as %s: %w", text, elemType.String(), err) - } - } - - return v, err -} diff --git a/pkg/app/server/binding/internal/decoder/sonic_required.go b/pkg/app/server/binding/internal/decoder/sonic_required.go index e408901a9..61f3d8d68 100644 --- a/pkg/app/server/binding/internal/decoder/sonic_required.go +++ b/pkg/app/server/binding/internal/decoder/sonic_required.go @@ -60,3 +60,12 @@ func stringSliceForInterface(s string) (ret []interface{}) { } return } + +func keyExist(req *protocol.Request, tagInfo TagInfo) bool { + ct := bytesconv.B2s(req.Header.ContentType()) + if utils.FilterContentType(ct) != consts.MIMEApplicationJSON { + return false + } + node, _ := sonic.Get(req.Body(), stringSliceForInterface(tagInfo.JSONName)...) + return node.Exists() +} diff --git a/pkg/app/server/binding/internal/decoder/struct_type_decoder.go b/pkg/app/server/binding/internal/decoder/struct_type_decoder.go index 3030f2ac6..75f3ae4aa 100644 --- a/pkg/app/server/binding/internal/decoder/struct_type_decoder.go +++ b/pkg/app/server/binding/internal/decoder/struct_type_decoder.go @@ -38,14 +38,17 @@ func (d *structTypeFieldTextDecoder) Decode(req *protocol.Request, params param. var defaultValue string for _, tagInfo := range d.tagInfos { if tagInfo.Skip || tagInfo.Key == jsonTag || tagInfo.Key == fileNameTag { - defaultValue = tagInfo.Default if tagInfo.Key == jsonTag { + defaultValue = tagInfo.Default found := checkRequireJSON(req, tagInfo) if found { err = nil } else { err = fmt.Errorf("'%s' field is a 'required' parameter, but the request does not have this parameter", d.fieldName) } + if len(tagInfo.Default) != 0 && keyExist(req, tagInfo) { + defaultValue = "" + } } continue } @@ -63,7 +66,7 @@ func (d *structTypeFieldTextDecoder) Decode(req *protocol.Request, params param. return err } if len(text) == 0 && len(defaultValue) != 0 { - text = defaultValue + text = toDefaultValue(d.fieldType, defaultValue) } if !exist && len(text) == 0 { return nil diff --git a/pkg/app/server/binding/internal/decoder/tag.go b/pkg/app/server/binding/internal/decoder/tag.go index 6df09aaa3..8ca5ae0e6 100644 --- a/pkg/app/server/binding/internal/decoder/tag.go +++ b/pkg/app/server/binding/internal/decoder/tag.go @@ -87,7 +87,7 @@ func lookupFieldTags(field reflect.StructField, parentJSONName string, config *D tagValue = field.Name } skip := false - jsonName := "" + jsonName := parentJSONName + "." + field.Name if tag == jsonTag { jsonName = parentJSONName + "." + tagValue } @@ -120,7 +120,7 @@ func lookupFieldTags(field reflect.StructField, parentJSONName string, config *D return tagInfos, newParentJSONName, needValidate } -func getDefaultFieldTags(field reflect.StructField) (tagInfos []TagInfo) { +func getDefaultFieldTags(field reflect.StructField, parentJSONName string) (tagInfos []TagInfo, newParentJSONName string) { defaultVal := "" if val, ok := field.Tag.Lookup(defaultTag); ok { defaultVal = val @@ -128,8 +128,10 @@ func getDefaultFieldTags(field reflect.StructField) (tagInfos []TagInfo) { tags := []string{pathTag, formTag, queryTag, cookieTag, headerTag, jsonTag, fileNameTag} for _, tag := range tags { - tagInfos = append(tagInfos, TagInfo{Key: tag, Value: field.Name, Default: defaultVal}) + jsonName := strings.TrimPrefix(parentJSONName+"."+field.Name, ".") + tagInfos = append(tagInfos, TagInfo{Key: tag, Value: field.Name, Default: defaultVal, JSONName: jsonName}) } + newParentJSONName = strings.TrimPrefix(parentJSONName+"."+field.Name, ".") return } diff --git a/pkg/app/server/binding/internal/decoder/util.go b/pkg/app/server/binding/internal/decoder/util.go new file mode 100644 index 000000000..be141c282 --- /dev/null +++ b/pkg/app/server/binding/internal/decoder/util.go @@ -0,0 +1,76 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package decoder + +import ( + "fmt" + "reflect" + "strings" + + "github.com/cloudwego/hertz/internal/bytesconv" + hJson "github.com/cloudwego/hertz/pkg/common/json" + "github.com/cloudwego/hertz/pkg/protocol" + "github.com/cloudwego/hertz/pkg/route/param" +) + +const ( + specialChar = "\x07" +) + +// toDefaultValue will preprocess the default value and transfer it to be standard format +func toDefaultValue(typ reflect.Type, defaultValue string) string { + switch typ.Kind() { + case reflect.Slice, reflect.Array, reflect.Map, reflect.Struct: + // escape single quote and double quote, replace single quote with double quote + defaultValue = strings.Replace(defaultValue, `"`, `\"`, -1) + defaultValue = strings.Replace(defaultValue, `\'`, specialChar, -1) + defaultValue = strings.Replace(defaultValue, `'`, `"`, -1) + defaultValue = strings.Replace(defaultValue, specialChar, `'`, -1) + } + return defaultValue +} + +// stringToValue is used to dynamically create reflect.Value for 'text' +func stringToValue(elemType reflect.Type, text string, req *protocol.Request, params param.Params, config *DecodeConfig) (v reflect.Value, err error) { + v = reflect.New(elemType).Elem() + if customizedFunc, exist := config.TypeUnmarshalFuncs[elemType]; exist { + val, err := customizedFunc(req, params, text) + if err != nil { + return reflect.Value{}, err + } + return val, nil + } + switch elemType.Kind() { + case reflect.Struct: + err = hJson.Unmarshal(bytesconv.S2b(text), v.Addr().Interface()) + case reflect.Map: + err = hJson.Unmarshal(bytesconv.S2b(text), v.Addr().Interface()) + case reflect.Array, reflect.Slice: + // do nothing + default: + decoder, err := SelectTextDecoder(elemType) + if err != nil { + return reflect.Value{}, fmt.Errorf("unsupported type %s for slice/array", elemType.String()) + } + err = decoder.UnmarshalString(text, v, config.LooseZeroMode) + if err != nil { + return reflect.Value{}, fmt.Errorf("unable to decode '%s' as %s: %w", text, elemType.String(), err) + } + } + + return v, err +} diff --git a/pkg/app/server/binding/tagexpr_bind_test.go b/pkg/app/server/binding/tagexpr_bind_test.go index 82221745c..1533b5aea 100644 --- a/pkg/app/server/binding/tagexpr_bind_test.go +++ b/pkg/app/server/binding/tagexpr_bind_test.go @@ -539,38 +539,37 @@ func TestPath(t *testing.T) { assert.DeepEqual(t, (*int64)(nil), recv.Z) } -// FIXME: 复杂类型的默认值,暂时先不做,低优 func TestDefault(t *testing.T) { - //type S struct { - // SS string `json:"ss"` - //} + type S struct { + SS string `json:"ss"` + } type Recv struct { X **struct { - A []string `path:"a" json:"a"` - B int32 `path:"b" default:"32"` - C bool `json:"c" default:"true"` - D *float32 `default:"123.4"` - // E *[]string `default:"['a','b','c','d,e,f']"` - // F map[string]string `default:"{'a':'\"\\'1','\"b':'c','c':'2'}"` - // G map[string]int64 `default:"{'a':1,'b':2,'c':3}"` - // H map[string]float64 `default:"{'a':0.1,'b':1.2,'c':2.3}"` - // I map[string]float64 `default:"{'\"a\"':0.1,'b':1.2,'c':2.3}"` - Empty string `default:""` - Null string `default:""` - CommaSpace string `default:",a:c "` - Dash string `default:"-"` + A []string `path:"a" json:"a"` + B int32 `path:"b" default:"32"` + C bool `json:"c" default:"true"` + D *float32 `default:"123.4"` + E *[]string `default:"['a','b','c','d,e,f']"` + F map[string]string `default:"{'a':'\"\\'1','\"b':'c','c':'2'}"` + G map[string]int64 `default:"{'a':1,'b':2,'c':3}"` + H map[string]float64 `default:"{'a':0.1,'b':1.2,'c':2.3}"` + I map[string]float64 `default:"{'\"a\"':0.1,'b':1.2,'c':2.3}"` + Empty string `default:""` + Null string `default:""` + CommaSpace string `default:",a:c "` + Dash string `default:"-"` // InvalidInt int `default:"abc"` // InvalidMap map[string]string `default:"abc"` } - Y string `json:"y" default:"y1"` - Z int64 - W string `json:"w"` - // V []int64 `json:"u" default:"[1,2,3]"` - // U []float32 `json:"u" default:"[1.1,2,3]"` - T *string `json:"t" default:"t1"` - // S S `default:"{'ss':'test'}"` - // O *S `default:"{'ss':'test2'}"` - // Complex map[string][]map[string][]int64 `default:"{'a':[{'aa':[1,2,3], 'bb':[4,5]}],'b':[{}]}"` + Y string `json:"y" default:"y1"` + Z int64 + W string `json:"w"` + V []int64 `json:"v" default:"[1,2,3]"` + U []float32 `json:"u" default:"[1.1,2,3]"` + T *string `json:"t" default:"t1"` + S S `default:"{'ss':'test'}"` + O *S `default:"{'ss':'test2'}"` + Complex map[string][]map[string][]int64 `default:"{'a':[{'aa':[1,2,3], 'bb':[4,5]}],'b':[{}]}"` } bodyReader := strings.NewReader(`{ @@ -601,11 +600,11 @@ func TestDefault(t *testing.T) { assert.DeepEqual(t, int32(32), (**recv.X).B) assert.DeepEqual(t, true, (**recv.X).C) assert.DeepEqual(t, float32(123.4), *(**recv.X).D) - // assert.DeepEqual(t, []string{"a", "b", "c", "d,e,f"}, *(**recv.X).E) - // assert.DeepEqual(t, map[string]string{"a": "\"'1", "\"b": "c", "c": "2"}, (**recv.X).F) - // assert.DeepEqual(t, map[string]int64{"a": 1, "b": 2, "c": 3}, (**recv.X).G) - // assert.DeepEqual(t, map[string]float64{"a": 0.1, "b": 1.2, "c": 2.3}, (**recv.X).H) - // assert.DeepEqual(t, map[string]float64{"\"a\"": 0.1, "b": 1.2, "c": 2.3}, (**recv.X).I) + assert.DeepEqual(t, []string{"a", "b", "c", "d,e,f"}, *(**recv.X).E) + assert.DeepEqual(t, map[string]string{"a": "\"'1", "\"b": "c", "c": "2"}, (**recv.X).F) + assert.DeepEqual(t, map[string]int64{"a": 1, "b": 2, "c": 3}, (**recv.X).G) + assert.DeepEqual(t, map[string]float64{"a": 0.1, "b": 1.2, "c": 2.3}, (**recv.X).H) + assert.DeepEqual(t, map[string]float64{"\"a\"": 0.1, "b": 1.2, "c": 2.3}, (**recv.X).I) assert.DeepEqual(t, "", (**recv.X).Empty) assert.DeepEqual(t, "", (**recv.X).Null) assert.DeepEqual(t, ",a:c ", (**recv.X).CommaSpace) @@ -615,11 +614,11 @@ func TestDefault(t *testing.T) { assert.DeepEqual(t, "y1", recv.Y) assert.DeepEqual(t, "t1", *recv.T) assert.DeepEqual(t, int64(6), recv.Z) - // assert.DeepEqual(t, []int64{1, 2, 3}, recv.V) - // assert.DeepEqual(t, []float32{1.1, 2, 3}, recv.U) - // assert.DeepEqual(t, S{SS: "test"}, recv.S) - // assert.DeepEqual(t, &S{SS: "test2"}, recv.O) - // assert.DeepEqual(t, map[string][]map[string][]int64{"a": {{"aa": {1, 2, 3}, "bb": []int64{4, 5}}}, "b": {map[string][]int64{}}}, recv.Complex) + assert.DeepEqual(t, []int64{1, 2, 3}, recv.V) + assert.DeepEqual(t, []float32{1.1, 2, 3}, recv.U) + assert.DeepEqual(t, S{SS: "test"}, recv.S) + assert.DeepEqual(t, &S{SS: "test2"}, recv.O) + assert.DeepEqual(t, map[string][]map[string][]int64{"a": {{"aa": {1, 2, 3}, "bb": []int64{4, 5}}}, "b": {map[string][]int64{}}}, recv.Complex) } func TestAuto(t *testing.T) { @@ -1196,29 +1195,29 @@ func TestIssue26(t *testing.T) { assert.DeepEqual(t, recv, recv2) } -// FIXME: after 'json unmarshal', the default value will change it -//func TestDefault2(t *testing.T) { -// type Recv struct { -// X **struct { -// Dash string `default:"xxxx"` -// } -// } -// bodyReader := strings.NewReader(`{ -// "X": { -// "Dash": "hello Dash" -// } -// }`) -// header := make(http.Header) -// header.Set("Content-Type", consts.MIMEApplicationJSON) -// req := newRequest("", header, nil, bodyReader) -// recv := new(Recv) -// -// err := DefaultBinder().Bind(req.Req, nil, recv) -// if err != nil { -// t.Error(err) -// } -// assert.DeepEqual(t, "hello Dash", (**recv.X).Dash) -//} +// BUGFIX: after 'json unmarshal', the default value will change it +func TestDefault2(t *testing.T) { + type Recv struct { + X **struct { + Dash string `default:"xxxx"` + } + } + bodyReader := strings.NewReader(`{ + "X": { + "Dash": "hello Dash" + } + }`) + header := make(http.Header) + header.Set("Content-Type", consts.MIMEApplicationJSON) + req := newRequest("", header, nil, bodyReader) + recv := new(Recv) + + err := DefaultBinder().Bind(req.Req, recv, nil) + if err != nil { + t.Error(err) + } + assert.DeepEqual(t, "hello Dash", (**recv.X).Dash) +} type ( files map[string][]file