mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-14 04:08:15 +08:00
Merge 19f326156f8f9cca7e8d54e1646043b46af12354 into 4dec17afdff48e8018c83618fbbe69fceeb2b41d
This commit is contained in:
commit
44692e5c87
@ -76,15 +76,25 @@ func (form formSource) TrySet(value reflect.Value, field reflect.StructField, ta
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mappingByPtr(ptr any, setter setter, tag string) error {
|
func mappingByPtr(ptr any, setter setter, tag string) error {
|
||||||
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
_, err := mappingWithDepth(reflect.ValueOf(ptr), emptyField, setter, tag, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||||
|
return mappingWithDepth(value, field, setter, tag, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxMappingDepth = 10
|
||||||
|
|
||||||
|
func mappingWithDepth(value reflect.Value, field reflect.StructField, setter setter, tag string, depth int) (bool, error) {
|
||||||
if field.Tag.Get(tag) == "-" { // just ignoring this field
|
if field.Tag.Get(tag) == "-" { // just ignoring this field
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if depth > maxMappingDepth {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
vKind := value.Kind()
|
vKind := value.Kind()
|
||||||
|
|
||||||
if vKind == reflect.Ptr {
|
if vKind == reflect.Ptr {
|
||||||
@ -94,7 +104,8 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||||||
isNew = true
|
isNew = true
|
||||||
vPtr = reflect.New(value.Type().Elem())
|
vPtr = reflect.New(value.Type().Elem())
|
||||||
}
|
}
|
||||||
isSet, err := mapping(vPtr.Elem(), field, setter, tag)
|
|
||||||
|
isSet, err := mappingWithDepth(vPtr.Elem(), field, setter, tag, depth+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -123,7 +134,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ok, err := mapping(value.Field(i), sf, setter, tag)
|
ok, err := mappingWithDepth(value.Field(i), sf, setter, tag, depth+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -635,3 +635,62 @@ func TestMappingCustomArrayForm(t *testing.T) {
|
|||||||
expected, _ := convertTo(val)
|
expected, _ := convertTo(val)
|
||||||
assert.Equal(t, expected, s.FileData)
|
assert.Equal(t, expected, s.FileData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test case for infinite recursion bug fix
|
||||||
|
func TestInfiniteRecursionBug(t *testing.T) {
|
||||||
|
type Req struct {
|
||||||
|
Parent *Req `form:"parent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var s Req
|
||||||
|
err := MapFormWithTag(&s, map[string][]string{}, "form")
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, s.Parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case for the user's specific example from GitHub issue
|
||||||
|
func TestInfiniteRecursionUserExample(t *testing.T) {
|
||||||
|
type Req struct {
|
||||||
|
Foo string `form:"foo"`
|
||||||
|
Bar string `form:"bar"`
|
||||||
|
Foo1 string `form:"Foo"`
|
||||||
|
Bar1 string `form:"Bar"`
|
||||||
|
Foo2 *Req `form:"foo2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var s Req
|
||||||
|
|
||||||
|
formData := map[string][]string{
|
||||||
|
"foo": {"test_foo"},
|
||||||
|
"bar": {"test_bar"},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := MapFormWithTag(&s, formData, "form")
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "test_foo", s.Foo)
|
||||||
|
assert.Equal(t, "test_bar", s.Bar)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case for nested self-reference that should work when data is provided
|
||||||
|
func TestValidNestedSelfReference(t *testing.T) {
|
||||||
|
type Req struct {
|
||||||
|
Name string `form:"name"`
|
||||||
|
Parent *Req `form:"parent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var s Req
|
||||||
|
|
||||||
|
formData := map[string][]string{
|
||||||
|
"name": {"child"},
|
||||||
|
"parent": {`{"name": "parent_name"}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := MapFormWithTag(&s, formData, "form")
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "child", s.Name)
|
||||||
|
assert.NotNil(t, s.Parent)
|
||||||
|
assert.Equal(t, "parent_name", s.Parent.Name)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user