fix: infinite-recursion-form-mapping

This commit is contained in:
SHRIMPTAILS_\shrim 2025-08-25 21:46:42 +09:00
parent 077a2f39c8
commit 19f326156f
2 changed files with 73 additions and 3 deletions

View File

@ -75,15 +75,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 {
@ -93,7 +103,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
} }
@ -122,7 +133,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
} }

View File

@ -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)
}