Skip to content

fix(net/ghttp): panic when post empty string parameter to *ghttp.UploadFile #4226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions net/ghttp/ghttp_z_unit_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,3 +726,33 @@ func Test_Issue4093(t *testing.T) {
t.Assert(client.PostContent(ctx, "/test"), `{"page":1,"pageSize":10,"pagination":true,"name":"john","number":1}`)
})
}

// https://github.com/gogf/gf/issues/4193
func Test_Issue4193(t *testing.T) {
type Req struct {
g.Meta `method:"post" mime:"multipart/form-data"`
File *ghttp.UploadFile `v:"required" type:"file"` // File is required
}
type Res struct{}

s := g.Server(guid.S())
s.BindMiddlewareDefault(ghttp.MiddlewareHandlerResponse)
s.BindHandler("/upload", func(ctx context.Context, req *Req) (res *Res, err error) {
return
})
s.SetDumpRouterMap(false)
s.SetAccessLogEnabled(false)
s.SetErrorLogEnabled(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)

gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
content := client.PostContent(ctx, "/upload", g.Map{
"file": "",
})
t.Assert(content, `{"code":51,"message":"The File field is required","data":null}`)
})
}
2 changes: 1 addition & 1 deletion util/gconv/gconv_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package gconv
// TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`.
func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {
option := ScanOption{
ContinueOnError: true,
ContinueOnError: false,
}
if len(paramKeyToAttrMap) > 0 {
option.ParamKeyToAttrMap = paramKeyToAttrMap[0]
Expand Down
8 changes: 6 additions & 2 deletions util/gconv/internal/converter/converter_convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,11 @@ func (c *Converter) doConvertForDefault(in doConvertInput, option ConvertOption)
}

// custom converter.
dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)
var (
ok bool
dstReflectValue reflect.Value
)
dstReflectValue, ok, err = c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)
if err != nil {
return nil, err
}
Expand All @@ -415,7 +419,7 @@ func (c *Converter) doConvertForDefault(in doConvertInput, option ConvertOption)
switch referReflectValue.Kind() {
case reflect.Ptr:
// Type converting for custom type pointers.
// Eg:
// Example:
// type PayMode int
// type Req struct{
// Mode *PayMode
Expand Down
18 changes: 16 additions & 2 deletions util/gconv/internal/converter/converter_float.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ func (c *Converter) Float32(any any) (float32, error) {
}
return 0, nil
case reflect.String:
f, err := strconv.ParseFloat(rv.String(), 32)
s := rv.String()
if s == "" {
return 0, nil
}
f, err := strconv.ParseFloat(s, 32)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any,
Expand All @@ -68,6 +72,9 @@ func (c *Converter) Float32(any any) (float32, error) {
if err != nil {
return 0, err
}
if s == "" {
return 0, nil
}
v, err := strconv.ParseFloat(s, 32)
if err != nil {
return 0, gerror.WrapCodef(
Expand Down Expand Up @@ -112,7 +119,11 @@ func (c *Converter) Float64(any any) (float64, error) {
}
return 0, nil
case reflect.String:
f, err := strconv.ParseFloat(rv.String(), 64)
s := rv.String()
if s == "" {
return 0, nil
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, gerror.WrapCodef(
gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any,
Expand All @@ -135,6 +146,9 @@ func (c *Converter) Float64(any any) (float64, error) {
if err != nil {
return 0, err
}
if s == "" {
return 0, nil
}
v, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, gerror.WrapCodef(
Expand Down
12 changes: 12 additions & 0 deletions util/gconv/internal/converter/converter_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func (c *Converter) doMapConvert(
value any, recursive RecursiveType, mustMapReturn bool, option MapOption,
) (map[string]any, error) {
if value == nil {
if mustMapReturn {
return map[string]any{}, nil
}
return nil, nil
}
// It redirects to its underlying value if it has implemented interface iVal.
Expand Down Expand Up @@ -119,6 +122,10 @@ func (c *Converter) doMapConvert(
return nil, err
}
} else {
if len(r) == 0 && mustMapReturn {
return map[string]any{}, nil
}
// if r is not empty, which means it fails converting to map.
return nil, nil
}
case []byte:
Expand All @@ -128,6 +135,10 @@ func (c *Converter) doMapConvert(
return nil, err
}
} else {
if len(r) == 0 && mustMapReturn {
return map[string]any{}, nil
}
// if r is not empty, which means it fails converting to map.
return nil, nil
}
case map[interface{}]interface{}:
Expand Down Expand Up @@ -328,6 +339,7 @@ func (c *Converter) doMapConvert(
return m, nil
}
return nil, nil

default:
return nil, nil
}
Expand Down
10 changes: 6 additions & 4 deletions util/gconv/internal/converter/converter_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,11 @@ func (c *Converter) Struct(params, pointer any, option ...StructOption) (err err
return err
}
if paramsMap == nil {
// fails converting params to map, it so cannot be converted to struct pointer.
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`convert params from "%#v" to "map[string]any" failed`,
params,
`convert params "%v" to "%s" failed`,
params, pointerReflectValue.Type(),
)
}
}
Expand Down Expand Up @@ -505,8 +506,7 @@ func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value
case reflect.Struct:
// Recursively converting for struct attribute.
if err = c.Struct(value, structFieldValue, option); err != nil {
// Note there's reflect conversion mechanism here.
structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
return err
}

// Note that the slice element might be type of struct,
Expand Down Expand Up @@ -637,6 +637,8 @@ func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value
elem := item.Elem()
if err = c.bindVarToReflectValue(elem, value, option); err == nil {
structFieldValue.Set(elem.Addr())
} else {
return err
}
} else {
// Not empty pointer, it assigns values to it.
Expand Down
Loading