diff --git a/binding/json.go b/binding/json.go index e21c2ee3..35037fb2 100644 --- a/binding/json.go +++ b/binding/json.go @@ -13,6 +13,11 @@ import ( "github.com/gin-gonic/gin/internal/json" ) +var ( + // ErrInvalidJSON invalid json + ErrInvalidJSON = errors.New("invalid JSON") +) + // EnableDecoderUseNumber is used to call the UseNumber method on the JSON // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an // any as a Number instead of as a float64. @@ -34,10 +39,19 @@ func (jsonBinding) Bind(req *http.Request, obj any) error { if req == nil || req.Body == nil { return errors.New("invalid request") } - return decodeJSON(req.Body, obj) + body, _ := io.ReadAll(req.Body) + ok := json.Valid(body) + if !ok { + return ErrInvalidJSON + } + return decodeJSON(bytes.NewReader(body), obj) } func (jsonBinding) BindBody(body []byte, obj any) error { + ok := json.Valid(body) + if !ok { + return ErrInvalidJSON + } return decodeJSON(bytes.NewReader(body), obj) } diff --git a/binding/json_test.go b/binding/json_test.go index fbd5c527..cb175eff 100644 --- a/binding/json_test.go +++ b/binding/json_test.go @@ -5,6 +5,8 @@ package binding import ( + "bytes" + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -18,6 +20,9 @@ func TestJSONBindingBindBody(t *testing.T) { err := jsonBinding{}.BindBody([]byte(`{"foo": "FOO"}`), &s) require.NoError(t, err) assert.Equal(t, "FOO", s.Foo) + + err = jsonBinding{}.BindBody([]byte(`{"foo": "FOO}`), &s) + assert.Equal(t, ErrInvalidJSON, err) } func TestJSONBindingBindBodyMap(t *testing.T) { @@ -27,4 +32,21 @@ func TestJSONBindingBindBodyMap(t *testing.T) { assert.Len(t, s, 2) assert.Equal(t, "FOO", s["foo"]) assert.Equal(t, "world", s["hello"]) + + err = jsonBinding{}.BindBody([]byte(`{"foo": "FOO","hello":"world}`), &s) + assert.Equal(t, ErrInvalidJSON, err) +} + +func TestTestJSONBindingBind(t *testing.T) { + var s struct { + Foo string `json:"foo"` + } + req, _ := http.NewRequest(http.MethodPost, "/", bytes.NewBufferString(`{"foo":"FOO"}`)) + err := jsonBinding{}.Bind(req, &s) + require.NoError(t, err) + assert.Equal(t, "FOO", s.Foo) + + req, _ = http.NewRequest(http.MethodPost, "/", bytes.NewBufferString(`{"foo":"FOO}`)) + err = jsonBinding{}.Bind(req, &s) + assert.Equal(t, ErrInvalidJSON, err) } diff --git a/internal/json/go_json.go b/internal/json/go_json.go index dee09dec..e759ca71 100644 --- a/internal/json/go_json.go +++ b/internal/json/go_json.go @@ -6,7 +6,7 @@ package json -import json "github.com/goccy/go-json" +import "github.com/goccy/go-json" var ( // Marshal is exported by gin/json package. @@ -19,6 +19,8 @@ var ( NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder + // Valid is exported by gin/json package. + Valid = json.Valid ) // Package indicates what library is being used for JSON encoding. diff --git a/internal/json/json.go b/internal/json/json.go index 539daa78..43c1a918 100644 --- a/internal/json/json.go +++ b/internal/json/json.go @@ -19,6 +19,8 @@ var ( NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder + // Valid is exported by gin/json package. + Valid = json.Valid ) // Package indicates what library is being used for JSON encoding. diff --git a/internal/json/jsoniter.go b/internal/json/jsoniter.go index 287ebf70..c54cdc74 100644 --- a/internal/json/jsoniter.go +++ b/internal/json/jsoniter.go @@ -20,6 +20,8 @@ var ( NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder + // Valid is exported by gin/json package. + Valid = json.Valid ) // Package indicates what library is being used for JSON encoding. diff --git a/internal/json/sonic.go b/internal/json/sonic.go index b3f72424..5091671b 100644 --- a/internal/json/sonic.go +++ b/internal/json/sonic.go @@ -20,6 +20,8 @@ var ( NewDecoder = json.NewDecoder // NewEncoder is exported by gin/json package. NewEncoder = json.NewEncoder + // Valid is exported by gin/json package. + Valid = json.Valid ) // Package indicates what library is being used for JSON encoding.