mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
fix: to prevent query
, cookie
, header
,uri
tag bind value into request body struct. (#1)
* fix: bug uri, query, header, cookie can bind value into param body struct
This commit is contained in:
parent
14f40ade40
commit
5960b6f5f9
12
README.md
12
README.md
@ -1003,10 +1003,14 @@ see `Authorization` in `Params` of [Bind Request](#bind-request)
|
||||
|
||||
`c.BindRequest` and `c.ShouldBindRquest` can bind all wanted values into struct instance at once.
|
||||
Now,
|
||||
+ supports values from `form`, `uri`, `header`, `cookie`
|
||||
and request `req.Body`.
|
||||
+ supports values from `query`, `uri`, `header`, `cookie`, `form`
|
||||
and `body` for request `req.Body`.
|
||||
+ `req.Body` decocder is decided by header `Content-Type` value, see more [request_test.go](./binding/binding_request_test.go#L40)
|
||||
|
||||
> ❗️ Attention:
|
||||
>> 1. tag `query`, `uri`, `header`, `cookie` must never be used in body struct, or it will be panic.
|
||||
>> 2. tag `query` only work for `c.BindRequest` and `c.ShouldBindRequest` api.
|
||||
|
||||
**example**
|
||||
|
||||
```go
|
||||
@ -1019,8 +1023,8 @@ import (
|
||||
|
||||
type Params struct {
|
||||
Name string `uri:"name"`
|
||||
Age int `form:"age,default=18"`
|
||||
Money int32 `form:"money" binding:"required"`
|
||||
Age int `query:"age,default=18"`
|
||||
Money int32 `query:"money" binding:"required"`
|
||||
Authorization string `cookie:"Authorization"`
|
||||
UserAgent string `header:"User-Agent"`
|
||||
Data struct {
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
|
||||
type Params struct {
|
||||
Name string `uri:"name"`
|
||||
Age int `form:"age,default=18"`
|
||||
Money int32 `form:"money" binding:"required"`
|
||||
Age int `query:"age,default=18"`
|
||||
Money int32 `query:"money" binding:"required"`
|
||||
Authorization string `cookie:"Authorization"`
|
||||
UserAgent string `header:"User-Agent"`
|
||||
Data struct {
|
||||
|
@ -1,10 +1,13 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var ErrInvalidTagInRequestBody = errors.New("body struct should not contain tag `query`, `header`, `cookie`, `uri` in binding request api")
|
||||
|
||||
type requestBinding struct{}
|
||||
|
||||
func (requestBinding) Name() string {
|
||||
@ -25,12 +28,14 @@ func (b requestBinding) BindOnly(obj interface{}, req *http.Request, uriMap map[
|
||||
return err
|
||||
}
|
||||
|
||||
binders := []interface{}{Header, Query, Cookie}
|
||||
for _, binder := range binders {
|
||||
if b, ok := binder.(Binding); ok {
|
||||
if err := b.BindOnly(req, obj); err != nil {
|
||||
if err := b.bindingQuery(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binders := []Binding{Header, Cookie}
|
||||
for _, binder := range binders {
|
||||
if err := binder.BindOnly(req, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +55,11 @@ func (b requestBinding) BindOnly(obj interface{}, req *http.Request, uriMap map[
|
||||
|
||||
}
|
||||
|
||||
func (b requestBinding) bindingQuery(req *http.Request, obj interface{}) error {
|
||||
values := req.URL.Query()
|
||||
return mapFormByTag(obj, values, "query")
|
||||
}
|
||||
|
||||
// extractBody return body object
|
||||
func extractBody(obj interface{}) interface{} {
|
||||
|
||||
@ -60,10 +70,16 @@ func extractBody(obj interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
return extract(rv)
|
||||
}
|
||||
|
||||
func extract(rv reflect.Value) interface{} {
|
||||
|
||||
typ := rv.Type()
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
tf := typ.Field(i)
|
||||
vf := rv.Field(i)
|
||||
|
||||
_, ok := tf.Tag.Lookup("body")
|
||||
if !ok {
|
||||
continue
|
||||
@ -71,9 +87,32 @@ func extractBody(obj interface{}) interface{} {
|
||||
|
||||
// find body struct
|
||||
if reflect.Indirect(vf).Kind() == reflect.Struct {
|
||||
// body must not has tag "query"
|
||||
if hasTag(vf, "query") || hasTag(vf, "header") ||
|
||||
hasTag(vf, "cookie") || hasTag(vf, "uri") {
|
||||
panic(ErrInvalidTagInRequestBody)
|
||||
}
|
||||
|
||||
return vf.Addr().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasTag(rv reflect.Value, tag string) bool {
|
||||
rv = reflect.Indirect(rv)
|
||||
if rv.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
|
||||
typ := rv.Type()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
_, ok := typ.Field(i).Tag.Lookup(tag)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
11
context.go
11
context.go
@ -724,13 +724,18 @@ func (c *Context) ShouldBindUri(obj interface{}) error {
|
||||
// `uri`,
|
||||
// `query`
|
||||
// `header` and
|
||||
// `body data` with tag `body:"body"`
|
||||
// `body data` with tag `body:""`
|
||||
// and it's decoder is decided by header `Content-Type` value
|
||||
// following tags must not be used in body struct, or it will be panic,
|
||||
// uri
|
||||
// query
|
||||
// header
|
||||
// cookie
|
||||
//
|
||||
// type Params struct {
|
||||
// Name string `uri:"name"`
|
||||
// Age int `form:"age,default=18"`
|
||||
// Money int32 `form:"money" binding:"required"`
|
||||
// Age int `query:"age,default=18"`
|
||||
// Money int32 `query:"money" binding:"required"`
|
||||
// Authorization string `cookie:"Authorization"`
|
||||
// UserAgent string `header:"User-Agent"`
|
||||
// Data struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user