fix: don't rely on content length header for optional json binding

This commit is contained in:
Elias Schneider
2026-08-04 21:10:17 +02:00
parent aec376bb54
commit 2c7d1b63e1
2 changed files with 29 additions and 7 deletions
+3 -7
View File
@@ -33,17 +33,13 @@ func BindJSON(c *gin.Context, value any) error {
// BindOptionalJSON accepts an empty body while normalizing valid input and classifying malformed JSON as invalid input
func BindOptionalJSON(c *gin.Context, value any) error {
if c.Request.ContentLength == 0 {
return nil
}
if err := requireJSONContentType(c); err != nil {
return err
}
err := c.ShouldBindJSON(value)
if errors.Is(err, io.EOF) {
return nil
}
if contentTypeErr := requireJSONContentType(c); contentTypeErr != nil {
return contentTypeErr
}
if err = classifyBindingError(err); err != nil {
return err
}
@@ -97,6 +97,32 @@ func TestBindJSONAcceptsStructuredJSONContentType(t *testing.T) {
require.Equal(t, "admin", input.Name)
}
func TestBindOptionalJSONDoesNotRelyOnContentLength(t *testing.T) {
for _, test := range []struct {
name string
contentLength int64
}{
{name: "zero", contentLength: 0},
{name: "unknown", contentLength: -1},
} {
t.Run(test.name, func(t *testing.T) {
gin.SetMode(gin.TestMode)
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/", strings.NewReader(`{"secret":"custom-secret"}`))
c.Request.ContentLength = test.contentLength
c.Request.Header.Set("Content-Type", "application/json")
var input struct {
Secret string `json:"secret"`
}
err := BindOptionalJSON(c, &input)
require.NoError(t, err)
require.Equal(t, "custom-secret", input.Secret)
})
}
}
func TestFormFileClassifiesMissingField(t *testing.T) {
gin.SetMode(gin.TestMode)
c, _ := gin.CreateTestContext(httptest.NewRecorder())