binding: add BindPlain function

```go
package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	router.POST("/", func(c *gin.Context) {
		var s string
		c.BindPlain(&s)
		c.String(200, s)
	})

	router.Run()
}

// client
// curl -d "test string" 127.0.0.1:8080
// output
// test string
```
This commit is contained in:
guonaihong 2019-09-03 22:50:13 +08:00
parent 01ca625b98
commit 53df00ffe4
6 changed files with 151 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
*~
vendor/*
!vendor/vendor.json
coverage.out

View File

@ -79,6 +79,7 @@ var (
YAML = yamlBinding{}
Uri = uriBinding{}
Header = headerBinding{}
Plain = plainBinding{}
)
// Default returns the appropriate Binding instance based on the HTTP method
@ -101,6 +102,8 @@ func Default(method, contentType string) Binding {
return YAML
case MIMEMultipartPOSTForm:
return FormMultipart
case MIMEPlain:
return Plain
default: // case MIMEPOSTForm:
return Form
}

View File

@ -156,6 +156,9 @@ func TestBindingDefault(t *testing.T) {
assert.Equal(t, FormMultipart, Default("POST", MIMEMultipartPOSTForm))
assert.Equal(t, FormMultipart, Default("PUT", MIMEMultipartPOSTForm))
assert.Equal(t, Plain, Default("POST", MIMEPlain))
assert.Equal(t, Plain, Default("PUT", MIMEPlain))
assert.Equal(t, ProtoBuf, Default("POST", MIMEPROTOBUF))
assert.Equal(t, ProtoBuf, Default("PUT", MIMEPROTOBUF))
@ -680,6 +683,46 @@ func TestExistsFails(t *testing.T) {
assert.Error(t, err)
}
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 TestHeaderBinding(t *testing.T) {
h := Header
assert.Equal(t, "header", h.Name())

47
binding/plain.go Normal file
View File

@ -0,0 +1,47 @@
package binding
import (
"fmt"
"io/ioutil"
"net/http"
"reflect"
"unsafe"
)
type plainBinding struct{}
func (plainBinding) Name() string {
return "plain"
}
func (plainBinding) Bind(req *http.Request, obj interface{}) error {
if obj == nil {
return nil
}
v := reflect.ValueOf(obj)
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return nil
}
v = v.Elem()
}
all, err := ioutil.ReadAll(req.Body)
if err != nil {
return err
}
if v.Kind() == reflect.String {
v.SetString(*(*string)(unsafe.Pointer(&all)))
return nil
}
if _, ok := v.Interface().([]byte); ok {
v.SetBytes(all)
return nil
}
return fmt.Errorf("type (%T) unkown type", v)
}

View File

@ -583,6 +583,11 @@ func (c *Context) BindYAML(obj interface{}) error {
return c.MustBindWith(obj, binding.YAML)
}
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Plain).
func (c *Context) BindPlain(obj interface{}) error {
return c.MustBindWith(obj, binding.Plain)
}
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
func (c *Context) BindHeader(obj interface{}) error {
return c.MustBindWith(obj, binding.Header)
@ -642,6 +647,11 @@ func (c *Context) ShouldBindYAML(obj interface{}) error {
return c.ShouldBindWith(obj, binding.YAML)
}
// ShouldBindPlain is a shortcut for c.ShouldBindWith(obj, binding.Header).
func (c *Context) ShouldBindPlain(obj interface{}) error {
return c.ShouldBindWith(obj, binding.Plain)
}
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
func (c *Context) ShouldBindHeader(obj interface{}) error {
return c.ShouldBindWith(obj, binding.Header)

View File

@ -1436,6 +1436,30 @@ func TestContextBindWithXML(t *testing.T) {
assert.Equal(t, 0, w.Body.Len())
}
func TestContextBindPlain(t *testing.T) {
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())
// ========================
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) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
@ -1565,6 +1589,29 @@ func TestContextShouldBindWithXML(t *testing.T) {
assert.Equal(t, 0, w.Body.Len())
}
func TestContextShouldBindPlain(t *testing.T) {
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())
// ========================
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 TestContextShouldBindHeader(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)