diff --git a/context.go b/context.go
index 046f284e..3d7927c7 100644
--- a/context.go
+++ b/context.go
@@ -5,6 +5,7 @@
package gin
import (
+ "bytes"
"errors"
"fmt"
"io"
@@ -33,7 +34,6 @@ const (
MIMEPOSTForm = binding.MIMEPOSTForm
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
MIMEYAML = binding.MIMEYAML
- BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
)
const abortIndex int8 = math.MaxInt8 / 2
@@ -666,19 +666,15 @@ func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
// NOTE: This method reads the body before binding. So you should use
// ShouldBindWith for better performance if you need to call only once.
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) {
- var body []byte
- if cb, ok := c.Get(BodyBytesKey); ok {
- if cbb, ok := cb.([]byte); ok {
- body = cbb
- }
- }
- if body == nil {
- body, err = ioutil.ReadAll(c.Request.Body)
- if err != nil {
- return err
- }
- c.Set(BodyBytesKey, body)
+ var buf bytes.Buffer
+ tee := io.TeeReader(c.Request.Body, &buf)
+ body, err := ioutil.ReadAll(tee)
+ if err != nil {
+ return err
}
+ defer c.Request.Body.Close()
+
+ c.Request.Body = ioutil.NopCloser(&buf)
return bb.BindBody(body, obj)
}
diff --git a/context_test.go b/context_test.go
index f7bb0f51..de7d39c4 100644
--- a/context_test.go
+++ b/context_test.go
@@ -1651,31 +1651,38 @@ func TestContextShouldBindBodyWith(t *testing.T) {
Bar string `json:"bar" xml:"bar" binding:"required"`
}
for _, tt := range []struct {
- name string
- bindingA, bindingB binding.BindingBody
- bodyA, bodyB string
+ name string
+ bindingA, bindingB binding.BindingBody
+ bodyA, bodyB string
+ contentTypeA, contentTypeB string
}{
{
- name: "JSON & JSON",
- bindingA: binding.JSON,
- bindingB: binding.JSON,
- bodyA: `{"foo":"FOO"}`,
- bodyB: `{"bar":"BAR"}`,
+ name: "JSON & JSON",
+ bindingA: binding.JSON,
+ bindingB: binding.JSON,
+ bodyA: `{"foo":"FOO"}`,
+ bodyB: `{"bar":"BAR"}`,
+ contentTypeA: binding.MIMEJSON,
+ contentTypeB: binding.MIMEJSON,
},
{
- name: "JSON & XML",
- bindingA: binding.JSON,
- bindingB: binding.XML,
- bodyA: `{"foo":"FOO"}`,
+ name: "JSON & XML",
+ bindingA: binding.JSON,
+ bindingB: binding.XML,
+ contentTypeA: binding.MIMEJSON,
+ contentTypeB: binding.MIMEXML,
+ bodyA: `{"foo":"FOO"}`,
bodyB: `
BAR
`,
},
{
- name: "XML & XML",
- bindingA: binding.XML,
- bindingB: binding.XML,
+ name: "XML & XML",
+ bindingA: binding.XML,
+ bindingB: binding.XML,
+ contentTypeA: binding.MIMEXML,
+ contentTypeB: binding.MIMEXML,
bodyA: `
FOO
@@ -1694,6 +1701,7 @@ func TestContextShouldBindBodyWith(t *testing.T) {
c.Request, _ = http.NewRequest(
"POST", "http://example.com", bytes.NewBufferString(tt.bodyA),
)
+ c.Request.Header.Add("Content-Type", tt.contentTypeA)
// When it binds to typeA and typeB, it finds the body is
// not typeB but typeA.
objA := typeA{}
@@ -1702,6 +1710,9 @@ func TestContextShouldBindBodyWith(t *testing.T) {
objB := typeB{}
assert.Error(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
assert.NotEqual(t, typeB{"BAR"}, objB)
+ objB2 := typeB{}
+ assert.Error(t, c.ShouldBind(&objB2))
+ assert.NotEqual(t, typeB{"BAR"}, objB2)
}
// bodyB to typeA and typeB
{
@@ -1712,12 +1723,16 @@ func TestContextShouldBindBodyWith(t *testing.T) {
c.Request, _ = http.NewRequest(
"POST", "http://example.com", bytes.NewBufferString(tt.bodyB),
)
+ c.Request.Header.Add("Content-Type", tt.contentTypeB)
objA := typeA{}
assert.Error(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
assert.NotEqual(t, typeA{"FOO"}, objA)
objB := typeB{}
assert.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
assert.Equal(t, typeB{"BAR"}, objB)
+ objB2 := typeB{}
+ assert.NoError(t, c.ShouldBind(&objB2))
+ assert.Equal(t, typeB{"BAR"}, objB2)
}
}
}