mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve file uploading using strict route feature
This commit is contained in:
@ -23,8 +23,8 @@ import (
|
||||
|
||||
// UploadFile wraps the multipart uploading file with more and convenient features.
|
||||
type UploadFile struct {
|
||||
*multipart.FileHeader
|
||||
ctx context.Context
|
||||
*multipart.FileHeader `json:"-"`
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// UploadFiles is array type for *UploadFile.
|
||||
@ -32,7 +32,7 @@ type UploadFiles []*UploadFile
|
||||
|
||||
// Save saves the single uploading file to directory path and returns the saved file name.
|
||||
//
|
||||
// The parameter `dirPath` should be a directory path or it returns error.
|
||||
// The parameter `dirPath` should be a directory path, or it returns error.
|
||||
//
|
||||
// Note that it will OVERWRITE the target file if there's already a same name file exist.
|
||||
func (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename string, err error) {
|
||||
|
||||
@ -66,14 +66,10 @@ func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]inte
|
||||
var (
|
||||
ok, filter bool
|
||||
)
|
||||
var length int
|
||||
if len(kvMap) > 0 && kvMap[0] != nil {
|
||||
length = len(kvMap[0])
|
||||
filter = true
|
||||
} else {
|
||||
length = len(r.routerMap) + len(r.queryMap) + len(r.formMap) + len(r.bodyMap) + len(r.paramsMap)
|
||||
}
|
||||
m := make(map[string]interface{}, length)
|
||||
m := make(map[string]interface{})
|
||||
for k, v := range r.routerMap {
|
||||
if filter {
|
||||
if _, ok = kvMap[0][k]; !ok {
|
||||
@ -114,6 +110,16 @@ func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]inte
|
||||
}
|
||||
m[k] = v
|
||||
}
|
||||
// File uploading.
|
||||
if r.MultipartForm != nil {
|
||||
for name := range r.MultipartForm.File {
|
||||
if uploadFiles := r.GetUploadFiles(name); len(uploadFiles) == 1 {
|
||||
m[name] = uploadFiles[0]
|
||||
} else {
|
||||
m[name] = uploadFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check none exist parameters and assign it with default value.
|
||||
if filter {
|
||||
for k, v := range kvMap[0] {
|
||||
@ -171,9 +177,11 @@ func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]
|
||||
if data == nil {
|
||||
data = map[string]interface{}{}
|
||||
}
|
||||
// Default struct values.
|
||||
if err = r.mergeDefaultStructValue(data, pointer); err != nil {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
return data, gconv.Struct(data, pointer, mapping...)
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package ghttp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
@ -169,3 +171,49 @@ func Test_Params_File_Batch(t *testing.T) {
|
||||
t.Assert(gfile.GetContents(dstPath2), gfile.GetContents(srcPath2))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Params_Strict_Route_File_Single(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
|
||||
)
|
||||
if file == nil {
|
||||
r.Response.WriteExit("upload file cannot be empty")
|
||||
}
|
||||
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 := gdebug.TestDataPath("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 file cannot be empty")
|
||||
t.AssertNE(content, "upload failed")
|
||||
t.Assert(content, "file1.txt")
|
||||
t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath))
|
||||
})
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ const (
|
||||
TagNamePath = `path`
|
||||
TagNameMethod = `method`
|
||||
TagNameMime = `mime`
|
||||
TagNameConsumes = `consumes`
|
||||
TagNameType = `type`
|
||||
TagNameDomain = `domain`
|
||||
TagNameValidate = `v`
|
||||
|
||||
@ -54,7 +54,8 @@ func (oai *OpenApiV3) newParameterRefWithStructMethod(field gstructs.Field, path
|
||||
parameter.Name = field.Name()
|
||||
}
|
||||
if len(tagMap) > 0 {
|
||||
if err := gconv.Struct(oai.fileMapWithShortTags(tagMap), parameter); err != nil {
|
||||
err := gconv.Struct(oai.fileMapWithShortTags(tagMap), parameter)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, `mapping struct tags to Parameter failed`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
|
||||
}
|
||||
|
||||
var (
|
||||
mime string
|
||||
path = Path{}
|
||||
inputMetaMap = gmeta.Data(inputObject.Interface())
|
||||
outputMetaMap = gmeta.Data(outputObject.Interface())
|
||||
@ -126,12 +127,17 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
|
||||
}
|
||||
|
||||
if len(inputMetaMap) > 0 {
|
||||
if err := gconv.Struct(oai.fileMapWithShortTags(inputMetaMap), &path); err != nil {
|
||||
inputMetaMap = oai.fileMapWithShortTags(inputMetaMap)
|
||||
if err := gconv.Struct(inputMetaMap, &path); err != nil {
|
||||
return gerror.Wrap(err, `mapping struct tags to Path failed`)
|
||||
}
|
||||
if err := gconv.Struct(oai.fileMapWithShortTags(inputMetaMap), &operation); err != nil {
|
||||
if err := gconv.Struct(inputMetaMap, &operation); err != nil {
|
||||
return gerror.Wrap(err, `mapping struct tags to Operation failed`)
|
||||
}
|
||||
// Allowed request mime.
|
||||
if mime = inputMetaMap[TagNameMime]; mime == "" {
|
||||
mime = inputMetaMap[TagNameConsumes]
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================================================================
|
||||
|
||||
Reference in New Issue
Block a user