Fix ShouldBindBodyWith method

This commit is contained in:
Shintaro Ikeda 2020-09-18 17:22:12 +09:00
parent 3100b7cb05
commit 5d5b60cf0a
3 changed files with 22 additions and 4 deletions

View File

@ -1989,9 +1989,9 @@ func SomeHandler(c *gin.Context) {
}
```
* `c.ShouldBindBodyWith` stores body into the context before binding. This has
a slight impact to performance, so you should not use this method if you are
enough to call binding at once.
* `c.ShouldBindBodyWith` stores body into the context before binding, and it
does not consume the request body. This has a slight impact to performance,
so you should not use this method if you are enough to call binding at once.
* This feature is only needed for some formats -- `JSON`, `XML`, `MsgPack`,
`ProtoBuf`. For other formats, `Query`, `Form`, `FormPost`, `FormMultipart`,
can be called by `c.ShouldBind()` multiple times without any damage to

View File

@ -5,6 +5,7 @@
package gin
import (
"bytes"
"errors"
"fmt"
"io"
@ -706,7 +707,7 @@ func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
// body into the context, and reuse when it is called again.
//
// NOTE: This method reads the body before binding. So you should use
// NOTE: This method copies 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
@ -720,6 +721,8 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e
if err != nil {
return err
}
c.Request.Body.Close()
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
c.Set(BodyBytesKey, body)
}
return bb.BindBody(body, obj)

View File

@ -1761,6 +1761,21 @@ func TestContextShouldBindBodyWith(t *testing.T) {
assert.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
assert.Equal(t, typeB{"BAR"}, objB)
}
// not affect the request body
{
// After it binds, other bind methods can bind without EOF error.
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest(
"POST", "http://example.com", bytes.NewBufferString(tt.bodyA),
)
objA := typeA{}
assert.NoError(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
assert.Equal(t, typeA{"FOO"}, objA)
anotherOjbA := typeA{}
assert.NoError(t, c.ShouldBindWith(&anotherOjbA, tt.bindingA))
assert.Equal(t, typeA{"FOO"}, anotherOjbA)
}
}
}