mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
fix issue when only one file was uploaded in batch receiver attribute (#2365)
* fix fixed An error occurred when only one file was uploaded in batches and add unit testing(#2092) * fix issue uploading files for ghttp.Server Co-authored-by: yxh <yxh1103@qq.com>
This commit is contained in:
@ -9,11 +9,12 @@ package ghttp_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
@ -173,7 +174,7 @@ func Test_Params_File_Batch(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_Strict_Route_File_Single(t *testing.T) {
|
||||
func Test_Params_Strict_Route_File_Single_Ptr_Attrr(t *testing.T) {
|
||||
type Req struct {
|
||||
gmeta.Meta `method:"post" mime:"multipart/form-data"`
|
||||
File *ghttp.UploadFile `type:"file"`
|
||||
@ -219,6 +220,48 @@ func Test_Params_Strict_Route_File_Single(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_Strict_Route_File_Single_Struct_Attr(t *testing.T) {
|
||||
type Req struct {
|
||||
gmeta.Meta `method:"post" mime:"multipart/form-data"`
|
||||
File ghttp.UploadFile `type:"file"`
|
||||
}
|
||||
type Res struct{}
|
||||
|
||||
dstDirPath := gfile.Temp(gtime.TimestampNanoStr())
|
||||
s := g.Server(guid.S())
|
||||
s.BindHandler("/upload/single", func(ctx context.Context, req *Req) (res *Res, err error) {
|
||||
var (
|
||||
r = g.RequestFromCtx(ctx)
|
||||
file = req.File
|
||||
)
|
||||
name, err := file.Save(dstDirPath)
|
||||
if err != nil {
|
||||
r.Response.WriteExit(err)
|
||||
}
|
||||
r.Response.WriteExit(name)
|
||||
return
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// normal name
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
|
||||
srcPath := gtest.DataPath("upload", "file1.txt")
|
||||
dstPath := gfile.Join(dstDirPath, "file1.txt")
|
||||
content := client.PostContent(ctx, "/upload/single", g.Map{
|
||||
"file": "@file:" + srcPath,
|
||||
})
|
||||
t.AssertNE(content, "")
|
||||
t.AssertNE(content, "upload failed")
|
||||
t.Assert(content, "file1.txt")
|
||||
t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_File_Upload_Required(t *testing.T) {
|
||||
type Req struct {
|
||||
gmeta.Meta `method:"post" mime:"multipart/form-data"`
|
||||
@ -274,3 +317,101 @@ func Test_Params_File_MarshalJSON(t *testing.T) {
|
||||
t.Assert(strings.Contains(content, "file1.txt"), true)
|
||||
})
|
||||
}
|
||||
|
||||
// Select only one file when batch uploading
|
||||
func Test_Params_Strict_Route_File_Batch_Up_One(t *testing.T) {
|
||||
type Req struct {
|
||||
gmeta.Meta `method:"post" mime:"multipart/form-data"`
|
||||
Files ghttp.UploadFiles `type:"file"`
|
||||
}
|
||||
type Res struct{}
|
||||
|
||||
dstDirPath := gfile.Temp(gtime.TimestampNanoStr())
|
||||
s := g.Server(guid.S())
|
||||
s.BindHandler("/upload/batch", func(ctx context.Context, req *Req) (res *Res, err error) {
|
||||
var (
|
||||
r = g.RequestFromCtx(ctx)
|
||||
files = req.Files
|
||||
)
|
||||
if len(files) == 0 {
|
||||
r.Response.WriteExit("upload file cannot be empty")
|
||||
}
|
||||
names, err := files.Save(dstDirPath)
|
||||
if err != nil {
|
||||
r.Response.WriteExit(err)
|
||||
}
|
||||
r.Response.WriteExit(gstr.Join(names, ","))
|
||||
return
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// normal name
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
|
||||
srcPath := gtest.DataPath("upload", "file1.txt")
|
||||
dstPath := gfile.Join(dstDirPath, "file1.txt")
|
||||
content := client.PostContent(ctx, "/upload/batch", g.Map{
|
||||
"files": "@file:" + srcPath,
|
||||
})
|
||||
t.AssertNE(content, "")
|
||||
t.AssertNE(content, "upload file cannot be empty")
|
||||
t.AssertNE(content, "upload failed")
|
||||
t.Assert(content, "file1.txt")
|
||||
t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))
|
||||
})
|
||||
}
|
||||
|
||||
// Select multiple files during batch upload
|
||||
func Test_Params_Strict_Route_File_Batch_Up_Multiple(t *testing.T) {
|
||||
type Req struct {
|
||||
gmeta.Meta `method:"post" mime:"multipart/form-data"`
|
||||
Files ghttp.UploadFiles `type:"file"`
|
||||
}
|
||||
type Res struct{}
|
||||
|
||||
dstDirPath := gfile.Temp(gtime.TimestampNanoStr())
|
||||
s := g.Server(guid.S())
|
||||
s.BindHandler("/upload/batch", func(ctx context.Context, req *Req) (res *Res, err error) {
|
||||
var (
|
||||
r = g.RequestFromCtx(ctx)
|
||||
files = req.Files
|
||||
)
|
||||
if len(files) == 0 {
|
||||
r.Response.WriteExit("upload file cannot be empty")
|
||||
}
|
||||
names, err := files.Save(dstDirPath)
|
||||
if err != nil {
|
||||
r.Response.WriteExit(err)
|
||||
}
|
||||
r.Response.WriteExit(gstr.Join(names, ","))
|
||||
return
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// normal name
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
|
||||
srcPath1 := gtest.DataPath("upload", "file1.txt")
|
||||
srcPath2 := gtest.DataPath("upload", "file2.txt")
|
||||
dstPath1 := gfile.Join(dstDirPath, "file1.txt")
|
||||
dstPath2 := gfile.Join(dstDirPath, "file2.txt")
|
||||
content := client.PostContent(ctx, "/upload/batch",
|
||||
"files=@file:"+srcPath1+
|
||||
"&files=@file:"+srcPath2,
|
||||
)
|
||||
t.AssertNE(content, "")
|
||||
t.AssertNE(content, "upload file cannot be empty")
|
||||
t.AssertNE(content, "upload failed")
|
||||
t.Assert(content, "file1.txt,file2.txt")
|
||||
t.Assert(gfile.GetContents(dstPath1), gfile.GetContents(srcPath1))
|
||||
t.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))
|
||||
})
|
||||
}
|
||||
|
||||
@ -145,9 +145,29 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
|
||||
|
||||
// If `params` and `pointer` are the same type, the do directly assignment.
|
||||
// For performance enhancement purpose.
|
||||
if pointerElemReflectValue.IsValid() && pointerElemReflectValue.Type() == paramsReflectValue.Type() {
|
||||
pointerElemReflectValue.Set(paramsReflectValue)
|
||||
return nil
|
||||
if pointerElemReflectValue.IsValid() {
|
||||
switch {
|
||||
// Eg:
|
||||
// UploadFile => UploadFile
|
||||
// *UploadFile => *UploadFile
|
||||
case pointerElemReflectValue.Type() == paramsReflectValue.Type():
|
||||
pointerElemReflectValue.Set(paramsReflectValue)
|
||||
return nil
|
||||
|
||||
// Eg:
|
||||
// UploadFile => *UploadFile
|
||||
case pointerElemReflectValue.Kind() == reflect.Ptr && pointerElemReflectValue.Elem().IsValid() &&
|
||||
pointerElemReflectValue.Elem().Type() == paramsReflectValue.Type():
|
||||
pointerElemReflectValue.Elem().Set(paramsReflectValue)
|
||||
return nil
|
||||
|
||||
// Eg:
|
||||
// *UploadFile => UploadFile
|
||||
case paramsReflectValue.Kind() == reflect.Ptr && paramsReflectValue.Elem().IsValid() &&
|
||||
pointerElemReflectValue.Type() == paramsReflectValue.Elem().Type():
|
||||
pointerElemReflectValue.Set(paramsReflectValue.Elem())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Normal unmarshalling interfaces checks.
|
||||
|
||||
Reference in New Issue
Block a user