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
14
README.md
14
README.md
@ -48,7 +48,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
|||||||
- [Bind Uri](#bind-uri)
|
- [Bind Uri](#bind-uri)
|
||||||
- [Bind Header](#bind-header)
|
- [Bind Header](#bind-header)
|
||||||
- [Bind Cookie](#bind-cookie)
|
- [Bind Cookie](#bind-cookie)
|
||||||
- [Bind Request](#bind-request)
|
- [Bind Request](#bind-request)
|
||||||
- [Bind HTML checkboxes](#bind-html-checkboxes)
|
- [Bind HTML checkboxes](#bind-html-checkboxes)
|
||||||
- [Multipart/Urlencoded binding](#multiparturlencoded-binding)
|
- [Multipart/Urlencoded binding](#multiparturlencoded-binding)
|
||||||
- [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
|
- [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
|
||||||
@ -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.
|
`c.BindRequest` and `c.ShouldBindRquest` can bind all wanted values into struct instance at once.
|
||||||
Now,
|
Now,
|
||||||
+ supports values from `form`, `uri`, `header`, `cookie`
|
+ supports values from `query`, `uri`, `header`, `cookie`, `form`
|
||||||
and request `req.Body`.
|
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)
|
+ `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**
|
**example**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@ -1019,8 +1023,8 @@ import (
|
|||||||
|
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Name string `uri:"name"`
|
Name string `uri:"name"`
|
||||||
Age int `form:"age,default=18"`
|
Age int `query:"age,default=18"`
|
||||||
Money int32 `form:"money" binding:"required"`
|
Money int32 `query:"money" binding:"required"`
|
||||||
Authorization string `cookie:"Authorization"`
|
Authorization string `cookie:"Authorization"`
|
||||||
UserAgent string `header:"User-Agent"`
|
UserAgent string `header:"User-Agent"`
|
||||||
Data struct {
|
Data struct {
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Name string `uri:"name"`
|
Name string `uri:"name"`
|
||||||
Age int `form:"age,default=18"`
|
Age int `query:"age,default=18"`
|
||||||
Money int32 `form:"money" binding:"required"`
|
Money int32 `query:"money" binding:"required"`
|
||||||
Authorization string `cookie:"Authorization"`
|
Authorization string `cookie:"Authorization"`
|
||||||
UserAgent string `header:"User-Agent"`
|
UserAgent string `header:"User-Agent"`
|
||||||
Data struct {
|
Data struct {
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrInvalidTagInRequestBody = errors.New("body struct should not contain tag `query`, `header`, `cookie`, `uri` in binding request api")
|
||||||
|
|
||||||
type requestBinding struct{}
|
type requestBinding struct{}
|
||||||
|
|
||||||
func (requestBinding) Name() string {
|
func (requestBinding) Name() string {
|
||||||
@ -25,12 +28,14 @@ func (b requestBinding) BindOnly(obj interface{}, req *http.Request, uriMap map[
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
binders := []interface{}{Header, Query, Cookie}
|
if err := b.bindingQuery(req, obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
binders := []Binding{Header, Cookie}
|
||||||
for _, binder := range binders {
|
for _, binder := range binders {
|
||||||
if b, ok := binder.(Binding); ok {
|
if err := binder.BindOnly(req, obj); err != nil {
|
||||||
if err := b.BindOnly(req, obj); err != nil {
|
return err
|
||||||
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
|
// extractBody return body object
|
||||||
func extractBody(obj interface{}) interface{} {
|
func extractBody(obj interface{}) interface{} {
|
||||||
|
|
||||||
@ -60,10 +70,16 @@ func extractBody(obj interface{}) interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return extract(rv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extract(rv reflect.Value) interface{} {
|
||||||
|
|
||||||
typ := rv.Type()
|
typ := rv.Type()
|
||||||
for i := 0; i < rv.NumField(); i++ {
|
for i := 0; i < rv.NumField(); i++ {
|
||||||
tf := typ.Field(i)
|
tf := typ.Field(i)
|
||||||
vf := rv.Field(i)
|
vf := rv.Field(i)
|
||||||
|
|
||||||
_, ok := tf.Tag.Lookup("body")
|
_, ok := tf.Tag.Lookup("body")
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
@ -71,9 +87,32 @@ func extractBody(obj interface{}) interface{} {
|
|||||||
|
|
||||||
// find body struct
|
// find body struct
|
||||||
if reflect.Indirect(vf).Kind() == reflect.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 vf.Addr().Interface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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`,
|
// `uri`,
|
||||||
// `query`
|
// `query`
|
||||||
// `header` and
|
// `header` and
|
||||||
// `body data` with tag `body:"body"`
|
// `body data` with tag `body:""`
|
||||||
// and it's decoder is decided by header `Content-Type` value
|
// 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 {
|
// type Params struct {
|
||||||
// Name string `uri:"name"`
|
// Name string `uri:"name"`
|
||||||
// Age int `form:"age,default=18"`
|
// Age int `query:"age,default=18"`
|
||||||
// Money int32 `form:"money" binding:"required"`
|
// Money int32 `query:"money" binding:"required"`
|
||||||
// Authorization string `cookie:"Authorization"`
|
// Authorization string `cookie:"Authorization"`
|
||||||
// UserAgent string `header:"User-Agent"`
|
// UserAgent string `header:"User-Agent"`
|
||||||
// Data struct {
|
// Data struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user