@ -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\"}"))
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user