parent
40131af124
commit
6ca8ddb1ae
@ -84,6 +84,7 @@ var (
|
|||||||
YAML BindingBody = yamlBinding{}
|
YAML BindingBody = yamlBinding{}
|
||||||
Uri BindingUri = uriBinding{}
|
Uri BindingUri = uriBinding{}
|
||||||
Header Binding = headerBinding{}
|
Header Binding = headerBinding{}
|
||||||
|
Plain BindingBody = plainBinding{}
|
||||||
TOML BindingBody = tomlBinding{}
|
TOML BindingBody = tomlBinding{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ var (
|
|||||||
Uri = uriBinding{}
|
Uri = uriBinding{}
|
||||||
Header = headerBinding{}
|
Header = headerBinding{}
|
||||||
TOML = tomlBinding{}
|
TOML = tomlBinding{}
|
||||||
|
Plain = plainBinding{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default returns the appropriate Binding instance based on the HTTP method
|
// Default returns the appropriate Binding instance based on the HTTP method
|
||||||
|
@ -1342,6 +1342,46 @@ func (h hook) Read([]byte) (int, error) {
|
|||||||
return 0, errors.New("error")
|
return 0, errors.New("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type failRead struct{}
|
||||||
|
|
||||||
|
func (f *failRead) Read(b []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("my fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *failRead) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlainBinding(t *testing.T) {
|
||||||
|
p := Plain
|
||||||
|
assert.Equal(t, "plain", p.Name())
|
||||||
|
|
||||||
|
var s string
|
||||||
|
req := requestWithBody("POST", "/", "test string")
|
||||||
|
assert.NoError(t, p.Bind(req, &s))
|
||||||
|
assert.Equal(t, s, "test string")
|
||||||
|
|
||||||
|
var bs []byte
|
||||||
|
req = requestWithBody("POST", "/", "test []byte")
|
||||||
|
assert.NoError(t, p.Bind(req, &bs))
|
||||||
|
assert.Equal(t, bs, []byte("test []byte"))
|
||||||
|
|
||||||
|
var i int
|
||||||
|
req = requestWithBody("POST", "/", "test fail")
|
||||||
|
assert.Error(t, p.Bind(req, &i))
|
||||||
|
|
||||||
|
req = requestWithBody("POST", "/", "")
|
||||||
|
req.Body = &failRead{}
|
||||||
|
assert.Error(t, p.Bind(req, &s))
|
||||||
|
|
||||||
|
req = requestWithBody("POST", "/", "")
|
||||||
|
assert.Nil(t, p.Bind(req, nil))
|
||||||
|
|
||||||
|
var ptr *string
|
||||||
|
req = requestWithBody("POST", "/", "")
|
||||||
|
assert.Nil(t, p.Bind(req, ptr))
|
||||||
|
}
|
||||||
|
|
||||||
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
|
56
binding/plain.go
Normal file
56
binding/plain.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/internal/bytesconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type plainBinding struct{}
|
||||||
|
|
||||||
|
func (plainBinding) Name() string {
|
||||||
|
return "plain"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (plainBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
|
all, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodePlain(all, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (plainBinding) BindBody(body []byte, obj any) error {
|
||||||
|
return decodePlain(body, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePlain(data []byte, obj any) error {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
|
||||||
|
for v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() == reflect.String {
|
||||||
|
v.SetString(bytesconv.BytesToString(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := v.Interface().([]byte); ok {
|
||||||
|
v.SetBytes(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("type (%T) unknown type", v)
|
||||||
|
}
|
17
context.go
17
context.go
@ -614,7 +614,7 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
|
|||||||
}
|
}
|
||||||
defer src.Close()
|
defer src.Close()
|
||||||
|
|
||||||
if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
|
if err = os.MkdirAll(filepath.Dir(dst), 0o750); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,6 +667,11 @@ func (c *Context) BindTOML(obj any) error {
|
|||||||
return c.MustBindWith(obj, binding.TOML)
|
return c.MustBindWith(obj, binding.TOML)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BindPlain is a shortcut for c.MustBindWith(obj, binding.Plain).
|
||||||
|
func (c *Context) BindPlain(obj any) error {
|
||||||
|
return c.MustBindWith(obj, binding.Plain)
|
||||||
|
}
|
||||||
|
|
||||||
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
|
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
|
||||||
func (c *Context) BindHeader(obj any) error {
|
func (c *Context) BindHeader(obj any) error {
|
||||||
return c.MustBindWith(obj, binding.Header)
|
return c.MustBindWith(obj, binding.Header)
|
||||||
@ -732,6 +737,11 @@ func (c *Context) ShouldBindTOML(obj any) error {
|
|||||||
return c.ShouldBindWith(obj, binding.TOML)
|
return c.ShouldBindWith(obj, binding.TOML)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldBindPlain is a shortcut for c.ShouldBindWith(obj, binding.Plain).
|
||||||
|
func (c *Context) ShouldBindPlain(obj any) error {
|
||||||
|
return c.ShouldBindWith(obj, binding.Plain)
|
||||||
|
}
|
||||||
|
|
||||||
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
|
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
|
||||||
func (c *Context) ShouldBindHeader(obj any) error {
|
func (c *Context) ShouldBindHeader(obj any) error {
|
||||||
return c.ShouldBindWith(obj, binding.Header)
|
return c.ShouldBindWith(obj, binding.Header)
|
||||||
@ -794,6 +804,11 @@ func (c *Context) ShouldBindBodyWithTOML(obj any) error {
|
|||||||
return c.ShouldBindBodyWith(obj, binding.TOML)
|
return c.ShouldBindBodyWith(obj, binding.TOML)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShouldBindBodyWithJSON is a shortcut for c.ShouldBindBodyWith(obj, binding.JSON).
|
||||||
|
func (c *Context) ShouldBindBodyWithPlain(obj any) error {
|
||||||
|
return c.ShouldBindBodyWith(obj, binding.Plain)
|
||||||
|
}
|
||||||
|
|
||||||
// ClientIP implements one best effort algorithm to return the real client IP.
|
// ClientIP implements one best effort algorithm to return the real client IP.
|
||||||
// It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
|
// It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
|
||||||
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
|
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
|
||||||
|
124
context_test.go
124
context_test.go
@ -1670,6 +1670,31 @@ func TestContextBindWithXML(t *testing.T) {
|
|||||||
assert.Equal(t, 0, w.Body.Len())
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContextBindPlain(t *testing.T) {
|
||||||
|
|
||||||
|
// string
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`test string`))
|
||||||
|
c.Request.Header.Add("Content-Type", MIMEPlain)
|
||||||
|
|
||||||
|
var s string
|
||||||
|
|
||||||
|
assert.NoError(t, c.BindPlain(&s))
|
||||||
|
assert.Equal(t, "test string", s)
|
||||||
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
|
|
||||||
|
// []byte
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`test []byte`))
|
||||||
|
c.Request.Header.Add("Content-Type", MIMEPlain)
|
||||||
|
|
||||||
|
var bs []byte
|
||||||
|
|
||||||
|
assert.NoError(t, c.BindPlain(&bs))
|
||||||
|
assert.Equal(t, []byte("test []byte"), bs)
|
||||||
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
|
}
|
||||||
|
|
||||||
func TestContextBindHeader(t *testing.T) {
|
func TestContextBindHeader(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
@ -1816,6 +1841,31 @@ func TestContextShouldBindWithXML(t *testing.T) {
|
|||||||
assert.Equal(t, 0, w.Body.Len())
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContextShouldBindPlain(t *testing.T) {
|
||||||
|
// string
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`test string`))
|
||||||
|
c.Request.Header.Add("Content-Type", MIMEPlain)
|
||||||
|
|
||||||
|
var s string
|
||||||
|
|
||||||
|
assert.NoError(t, c.ShouldBindPlain(&s))
|
||||||
|
assert.Equal(t, "test string", s)
|
||||||
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
|
// []byte
|
||||||
|
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`test []byte`))
|
||||||
|
c.Request.Header.Add("Content-Type", MIMEPlain)
|
||||||
|
|
||||||
|
var bs []byte
|
||||||
|
|
||||||
|
assert.NoError(t, c.ShouldBindPlain(&bs))
|
||||||
|
assert.Equal(t, []byte("test []byte"), bs)
|
||||||
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestContextShouldBindHeader(t *testing.T) {
|
func TestContextShouldBindHeader(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
@ -2247,6 +2297,80 @@ func TestContextShouldBindBodyWithTOML(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContextShouldBindBodyWithPlain(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
name string
|
||||||
|
bindingBody binding.BindingBody
|
||||||
|
body string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: " JSON & JSON-BODY ",
|
||||||
|
bindingBody: binding.JSON,
|
||||||
|
body: `{"foo":"FOO"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: " JSON & XML-BODY ",
|
||||||
|
bindingBody: binding.XML,
|
||||||
|
body: `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<root>
|
||||||
|
<foo>FOO</foo>
|
||||||
|
</root>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: " JSON & YAML-BODY ",
|
||||||
|
bindingBody: binding.YAML,
|
||||||
|
body: `foo: FOO`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: " JSON & TOM-BODY ",
|
||||||
|
bindingBody: binding.TOML,
|
||||||
|
body: `foo=FOO`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: " JSON & Plain-BODY ",
|
||||||
|
bindingBody: binding.Plain,
|
||||||
|
body: `foo=FOO`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("testing: %s", tt.name)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(tt.body))
|
||||||
|
|
||||||
|
type typeJSON struct {
|
||||||
|
Foo string `json:"foo" binding:"required"`
|
||||||
|
}
|
||||||
|
objJSON := typeJSON{}
|
||||||
|
|
||||||
|
if tt.bindingBody == binding.Plain {
|
||||||
|
body := ""
|
||||||
|
assert.NoError(t, c.ShouldBindBodyWithPlain(&body))
|
||||||
|
assert.Equal(t, body, "foo=FOO")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.bindingBody == binding.JSON {
|
||||||
|
assert.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
|
||||||
|
assert.Equal(t, typeJSON{"FOO"}, objJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.bindingBody == binding.XML {
|
||||||
|
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
|
||||||
|
assert.Equal(t, typeJSON{}, objJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.bindingBody == binding.YAML {
|
||||||
|
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
|
||||||
|
assert.Equal(t, typeJSON{}, objJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.bindingBody == binding.TOML {
|
||||||
|
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
|
||||||
|
assert.Equal(t, typeJSON{}, objJSON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestContextGolangContext(t *testing.T) {
|
func TestContextGolangContext(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
|
Loading…
Reference in New Issue
Block a user