diff --git a/upload/base.go b/upload/base.go index 208656a..3e59b47 100644 --- a/upload/base.go +++ b/upload/base.go @@ -32,7 +32,8 @@ type BaseClient struct { RespData interface{} Results Results err error - uploadMaxSize int64 // 单位字节 (0 代表未设置,小于 0 代表不限制) + uploadMaxSize int64 // 单个文件最大尺寸 单位字节 (0 代表未设置,小于 0 代表不限制) + bodyMaxSize int64 // 限制整个提交body的尺寸 readBefore []ReadBeforeHook chunkUpload *ChunkUpload fieldMapping map[string]string @@ -55,6 +56,7 @@ func (a *BaseClient) Reset() { a.Results = nil a.err = nil a.uploadMaxSize = 0 + a.bodyMaxSize = 0 a.chunkUpload = nil a.fieldMapping = nil } @@ -64,6 +66,11 @@ func (a *BaseClient) SetUploadMaxSize(maxSize int64) Client { return a } +func (a *BaseClient) SetBodyMaxSize(maxSize int64) Client { + a.bodyMaxSize = maxSize + return a +} + func (a *BaseClient) SetReadBeforeHook(hooks ...ReadBeforeHook) Client { a.readBefore = hooks return a @@ -109,8 +116,25 @@ func (a *BaseClient) ErrorString() string { return `` } +func (a *BaseClient) checkRequestBodySize() error { + if a.bodyMaxSize > 0 { + if a.bodyMaxSize > 0 && a.Context.Request().MaxSize() > int(a.bodyMaxSize) { + return fmt.Errorf( + `%w: %d>%d `, + ErrRequestBodyExceedsLimit, + a.Context.Request().MaxSize(), + a.bodyMaxSize, + ) + } + } + return nil +} + func (a *BaseClient) Body() (file ReadCloserWithSize, err error) { - file, a.Data.FileName, err = Receive(a.Name(), a.Context) + if err := a.checkRequestBodySize(); err != nil { + return nil, err + } + file, a.Data.FileName, err = Receive(a.Context, a.Name()) if err != nil { return } diff --git a/upload/base_upload.go b/upload/base_upload.go index 5a6b69e..0305701 100644 --- a/upload/base_upload.go +++ b/upload/base_upload.go @@ -36,7 +36,10 @@ func (a *BaseClient) Upload(opts ...OptionsSetter) Client { uploadMaxSize = a.UploadMaxSize() } if uploadMaxSize > 0 && body.Size() > uploadMaxSize { - a.err = fmt.Errorf(`%w: %v`, ErrFileTooLarge, com.FormatBytes(uploadMaxSize)) + a.err = fmt.Errorf(`%w: %v>%v`, ErrFileTooLarge, + com.FormatBytes(body.Size(), 2, true), + com.FormatBytes(uploadMaxSize, 2, true), + ) return a } @@ -118,6 +121,10 @@ func (a *BaseClient) BatchUpload(opts ...OptionsSetter) Client { a.err = ErrInvalidContent return a } + if err := a.checkRequestBodySize(); err != nil { + a.err = err + return a + } m := req.MultipartForm() if m == nil || m.File == nil { a.err = ErrInvalidContent @@ -139,7 +146,11 @@ func (a *BaseClient) BatchUpload(opts ...OptionsSetter) Client { for _, fileHdr := range files { //for each fileheader, get a handle to the actual file if uploadMaxSize > 0 && fileHdr.Size > uploadMaxSize { - a.err = fmt.Errorf(`%w: %v`, ErrFileTooLarge, com.FormatBytes(uploadMaxSize)) + a.err = fmt.Errorf( + `%w: %v>%v`, ErrFileTooLarge, + com.FormatBytes(fileHdr.Size, 2, true), + com.FormatBytes(uploadMaxSize, 2, true), + ) return a } diff --git a/upload/chunk_errors.go b/upload/chunk_errors.go index 00c73cc..6a5fc34 100644 --- a/upload/chunk_errors.go +++ b/upload/chunk_errors.go @@ -8,9 +8,10 @@ var ( ErrChunkUploadCompleted = errors.New("文件分片已经上传完成") // Support - ErrChunkUnsupported = errors.New("不支持分片上传") - ErrFileSizeExceedsLimit = errors.New("文件尺寸超出限制") - ErrIncorrectSize = errors.New("文件尺寸不正确") + ErrChunkUnsupported = errors.New("不支持分片上传") + ErrFileSizeExceedsLimit = errors.New("文件尺寸超出限制") + ErrRequestBodyExceedsLimit = errors.New("提交内容尺寸超出限制") + ErrIncorrectSize = errors.New("文件尺寸不正确") // Failure ErrChunkHistoryOpenFailed = errors.New("打开历史分片文件失败") diff --git a/upload/chunk_test.go b/upload/chunk_test.go index b1debe0..44013b9 100644 --- a/upload/chunk_test.go +++ b/upload/chunk_test.go @@ -117,6 +117,7 @@ func uploadTestFile(t *testing.T, subdir string, readSeeker io.ReadSeeker, total TempDir: tempDir, SaveDir: saveDir, DelayMerge: delayMerge, + //FileMaxBytes: 1048576 * 1, // 1M, } cu.OnBeforeMerge(func(ctx context.Context, info upload.ChunkInfor, filename string) error { counters.Add(filename, 1) diff --git a/upload/chunk_upload.go b/upload/chunk_upload.go index 8c9e0eb..c7e184a 100644 --- a/upload/chunk_upload.go +++ b/upload/chunk_upload.go @@ -28,6 +28,17 @@ func (c *ChunkUpload) Upload(r *http.Request, opts ...ChunkInfoOpter) (int64, er if !c.IsSupported(info) { return 0, ErrChunkUnsupported } + if c.FileMaxBytes > 0 { + if r.ContentLength > int64(c.FileMaxBytes) { + return 0, fmt.Errorf(`%w: %d>%d `, ErrRequestBodyExceedsLimit, r.ContentLength, c.FileMaxBytes) + } + if r.MultipartForm == nil { + err := r.ParseMultipartForm(int64(c.FileMaxBytes)) + if err != nil { + return 0, fmt.Errorf("上传文件错误: %w", err) + } + } + } // 获取上传文件 upFile, fileHeader, err := r.FormFile(info.FormField) if err != nil { diff --git a/upload/client.go b/upload/client.go index 803c954..44b2733 100644 --- a/upload/client.go +++ b/upload/client.go @@ -27,6 +27,7 @@ type Client interface { //初始化 Init(echo.Context, *Result) SetUploadMaxSize(maxSize int64) Client + SetBodyMaxSize(maxSize int64) Client SetReadBeforeHook(hooks ...ReadBeforeHook) Client AddReadBeforeHook(hooks ...ReadBeforeHook) Client diff --git a/upload/receive.go b/upload/receive.go index 0b583d2..ceeeb13 100644 --- a/upload/receive.go +++ b/upload/receive.go @@ -93,7 +93,7 @@ func (w *wrapFileWithSize) Size() int64 { return w.size } -func Receive(name string, ctx echo.Context) (f ReadCloserWithSize, fileName string, err error) { +func Receive(ctx echo.Context, name string) (f ReadCloserWithSize, fileName string, err error) { switch ctx.ResolveContentType() { case "application/octet-stream": val := ctx.Request().Header().Get("Content-Disposition") diff --git a/upload/utesting/chunk_testutils.go b/upload/utesting/chunk_testutils.go index 5408ced..18c81cf 100644 --- a/upload/utesting/chunk_testutils.go +++ b/upload/utesting/chunk_testutils.go @@ -101,5 +101,7 @@ func VerifyUploadedTestFile(t *testing.T, parentCU *upload.ChunkUpload, fileName assert.NoError(t, err) fi, err := os.Stat(savePath) test.Eq(t, nil, err) - test.Eq(t, totalSize, fi.Size()) + if err == nil { + test.Eq(t, totalSize, fi.Size()) + } }