diff --git a/context.go b/context.go index e5a99b57..a9ea1ba3 100644 --- a/context.go +++ b/context.go @@ -5,6 +5,7 @@ package gin import ( + "bytes" "errors" "fmt" "io" @@ -914,6 +915,24 @@ func (c *Context) ShouldBindUri(obj any) error { // ShouldBindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) ShouldBindWith(obj any, b binding.Binding) error { + if b.Name() == "form-urlencoded" || b.Name() == "form" { + var body []byte + if cb, ok := c.Get(BodyBytesKey); ok { + if cbb, ok := cb.([]byte); ok { + body = cbb + } + } + + if body == nil { + var err error + body, err = io.ReadAll(c.Request.Body) + if err != nil { + return err + } + c.Set(BodyBytesKey, body) + } + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + } return b.Bind(c.Request, obj) } @@ -1077,6 +1096,13 @@ func (c *Context) GetRawData() ([]byte, error) { if c.Request.Body == nil { return nil, errors.New("cannot read nil body") } + + if cb, ok := c.Get(BodyBytesKey); ok { + if cbb, ok := cb.([]byte); ok { + return cbb, nil + } + } + return io.ReadAll(c.Request.Body) } diff --git a/context_test.go b/context_test.go index d8ff2d66..2bc4314c 100644 --- a/context_test.go +++ b/context_test.go @@ -2349,6 +2349,28 @@ func TestContextShouldBindWithQuery(t *testing.T) { assert.Equal(t, 0, w.Body.Len()) } +func TestContextGetRawDataAfterShouldBind(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest(http.MethodPost, "/", strings.NewReader("p1=1&p2=2&p3=4")) + c.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + var s struct { + P1 string `form:"p1"` + P2 string `form:"p2"` + P3 string `form:"p3"` + } + require.NoError(t, c.ShouldBind(&s)) + assert.Equal(t, "1", s.P1) + assert.Equal(t, "2", s.P2) + assert.Equal(t, "4", s.P3) + + rawData, err := c.GetRawData() + require.NoError(t, err) + assert.Equal(t, "p1=1&p2=2&p3=4", string(rawData)) +} + func TestContextShouldBindWithYAML(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w)