From e00c8390476a35530c5f211d954ffe0cb08ee2e8 Mon Sep 17 00:00:00 2001 From: takanuva15 <6986426+takanuva15@users.noreply.github.com> Date: Mon, 2 Mar 2026 16:54:20 -0500 Subject: [PATCH] copilot fixes --- binding/all.go | 4 ++++ context.go | 15 +++++++++++++-- context_test.go | 43 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/binding/all.go b/binding/all.go index 1069863f..fbaee1e3 100644 --- a/binding/all.go +++ b/binding/all.go @@ -1,3 +1,7 @@ +// Copyright 2026 Gin Core Team. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + package binding import ( diff --git a/context.go b/context.go index 8eadec26..7c8509e7 100644 --- a/context.go +++ b/context.go @@ -813,8 +813,19 @@ func (c *Context) BindUri(obj any) error { // - Caller must provide Content-Type header to select the correct body binding (eg "application/json" for JSON binding) // - Binding validation tags are verified after all request parts have been bound func (c *Context) BindAll(obj any) error { - if err := c.ShouldBindAll(obj); err != nil { - c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck + err := c.ShouldBindAll(obj) + if err != nil { + var maxBytesErr *http.MaxBytesError + + // Note: When using sonic or go-json as JSON encoder, they do not propagate the http.MaxBytesError error + // https://github.com/goccy/go-json/issues/485 + // https://github.com/bytedance/sonic/issues/800 + switch { + case errors.As(err, &maxBytesErr): + c.AbortWithError(http.StatusRequestEntityTooLarge, err).SetType(ErrorTypeBind) //nolint: errcheck + default: + c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck + } return err } return nil diff --git a/context_test.go b/context_test.go index f0ea2e8c..442d7fed 100644 --- a/context_test.go +++ b/context_test.go @@ -2318,7 +2318,7 @@ func TestContextBindAll(t *testing.T) { c.Request, _ = http.NewRequest(http.MethodPost, "/1234?foo=true", strings.NewReader(`{"bar":"spam"}`)) c.Params = []Param{{Key: "id", Value: "1234"}} - c.Request.Header.Add("Content-Type", MIMEJSON) // set fake content-type + c.Request.Header.Add("Content-Type", MIMEJSON) c.Request.Header.Add("Limit", "100") var obj struct { @@ -2340,7 +2340,7 @@ func TestContextBindAll_400OnError(t *testing.T) { c, _ := CreateTestContext(w) c.Request, _ = http.NewRequest(http.MethodPost, "/1234?foo=true", strings.NewReader(`{"bar":"spam"}`)) - c.Request.Header.Add("Content-Type", MIMEJSON) // set fake content-type + c.Request.Header.Add("Content-Type", MIMEJSON) c.Request.Header.Add("Limit", "100") var obj struct { @@ -2353,6 +2353,45 @@ func TestContextBindAll_400OnError(t *testing.T) { require.ErrorContains(t, err, "Field validation for 'ID' failed") } +func TestContextBindAll_413MaxBytes(t *testing.T) { + // When using go-json as JSON encoder, they do not propagate the http.MaxBytesError error + // The response will fail with a generic 400 instead of 413 + // https://github.com/goccy/go-json/issues/485 + var expectedCode int + switch json.Package { + case "github.com/goccy/go-json": + expectedCode = http.StatusBadRequest + default: + expectedCode = http.StatusRequestEntityTooLarge + } + + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest(http.MethodPost, "/1234?foo=true", strings.NewReader(`{"bar":"spam"}`)) + c.Params = []Param{{Key: "id", Value: "1234"}} + c.Request.Header.Add("Content-Type", MIMEJSON) + c.Request.Header.Add("Limit", "100") + c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 10) + + var obj struct { + Limit int `header:"limit" binding:"required"` + ID string `uri:"id" binding:"required,numeric"` + Foo bool `form:"foo" binding:"required"` + Bar string `form:"bar" xml:"bar" binding:"required"` + } + err := c.BindAll(&obj) + require.Error(t, err) + if json.Package != "github.com/goccy/go-json" { + var maxBytesErr *http.MaxBytesError + require.ErrorAs(t, err, &maxBytesErr) + } + c.Writer.WriteHeaderNow() + + assert.Equal(t, expectedCode, w.Code) + assert.True(t, c.IsAborted()) +} + func TestContextBadAutoBind(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w)