From 9230be3649d0e0c8612cf907b92901541467a1a4 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Thu, 5 Oct 2023 10:09:29 +0200 Subject: [PATCH] Fix jsonp ignoring custom json encoder (#2658) * add unit test to trigger the bug #2675 * implement solution --- ctx.go | 5 ++-- ctx_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/ctx.go b/ctx.go index e03b240699..3d19a45fbf 100644 --- a/ctx.go +++ b/ctx.go @@ -8,7 +8,6 @@ import ( "bytes" "context" "crypto/tls" - "encoding/json" "encoding/xml" "errors" "fmt" @@ -863,9 +862,9 @@ func (c *Ctx) JSON(data interface{}) error { // This method is identical to JSON, except that it opts-in to JSONP callback support. // By default, the callback name is simply callback. func (c *Ctx) JSONP(data interface{}, callback ...string) error { - raw, err := json.Marshal(data) + raw, err := c.app.config.JSONEncoder(data) if err != nil { - return fmt.Errorf("failed to marshal: %w", err) + return err } var result, cb string diff --git a/ctx_test.go b/ctx_test.go index 3eaaaf6091..d8edea0e9e 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -2771,6 +2771,26 @@ func Test_Ctx_JSON(t *testing.T) { testEmpty("", `""`) testEmpty(0, "0") testEmpty([]int{}, "[]") + + t.Run("custom json encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + JSONEncoder: func(v interface{}) ([]byte, error) { + return []byte(`["custom","json"]`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + err := c.JSON(Map{ // map has no order + "Name": "Grame", + "Age": 20, + }) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `["custom","json"]`, string(c.Response().Body())) + utils.AssertEqual(t, "application/json", string(c.Response().Header.Peek("content-type"))) + }) } // go test -run=^$ -bench=Benchmark_Ctx_JSON -benchmem -count=4 @@ -2820,6 +2840,26 @@ func Test_Ctx_JSONP(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, `john({"Age":20,"Name":"Grame"});`, string(c.Response().Body())) utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type"))) + + t.Run("custom json encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + JSONEncoder: func(v interface{}) ([]byte, error) { + return []byte(`["custom","json"]`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + err := c.JSONP(Map{ // map has no order + "Name": "Grame", + "Age": 20, + }) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `callback(["custom","json"]);`, string(c.Response().Body())) + utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type"))) + }) } // go test -v -run=^$ -bench=Benchmark_Ctx_JSONP -benchmem -count=4 @@ -2879,6 +2919,33 @@ func Test_Ctx_XML(t *testing.T) { testEmpty("", ``) testEmpty(0, "0") testEmpty([]int{}, "") + + t.Run("custom xml encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + XMLEncoder: func(v interface{}) ([]byte, error) { + return []byte(`xml`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + type xmlResult struct { + XMLName xml.Name `xml:"Users"` + Names []string `xml:"Names"` + Ages []int `xml:"Ages"` + } + + err := c.XML(xmlResult{ + Names: []string{"Grame", "John"}, + Ages: []int{1, 12, 20}, + }) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `xml`, string(c.Response().Body())) + utils.AssertEqual(t, "application/xml", string(c.Response().Header.Peek("content-type"))) + }) } // go test -run=^$ -bench=Benchmark_Ctx_XML -benchmem -count=4