fix: can upload file larger than 10MB (#17801)

This commit is contained in:
Haruko386
2026-08-04 18:01:04 +08:00
committed by GitHub
parent 49c24d8bce
commit 0cb078ecc0
4 changed files with 76 additions and 3 deletions

View File

@@ -37,6 +37,7 @@ const (
EnvComponentExecTimeout = "COMPONENT_EXEC_TIMEOUT"
EnvDocEngine = "DOC_ENGINE"
EnvMaxFileNumPerUser = "MAX_FILE_NUM_PER_USER"
EnvMaxContentLength = "MAX_CONTENT_LENGTH"
EnvRAGFlowDictPath = "RAGFLOW_DICT_PATH"
EnvDefaultSuperuserEmail = "DEFAULT_SUPERUSER_EMAIL"
EnvDefaultSuperuserNickname = "DEFAULT_SUPERUSER_NICKNAME"

View File

@@ -279,6 +279,12 @@ func (h *FileHandler) UploadFile(c *gin.Context) {
ctx := c.Request.Context()
if strings.Contains(contentType, "multipart/form-data") {
uploadLimit := file.DeploymentUploadMaxBytes()
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, uploadLimit)
if cl := c.Request.ContentLength; cl > uploadLimit {
common.ResponseWithCodeData(c, common.CodeBadRequest, nil, "request body exceeds deployment upload limit")
return
}
if err := c.Request.ParseMultipartForm(32 << 20); err != nil {
common.ResponseWithCodeData(c, common.CodeBadRequest, nil, "Failed to parse multipart form: "+err.Error())
return
@@ -313,7 +319,7 @@ func (h *FileHandler) UploadFile(c *gin.Context) {
}
ctx := c.Request.Context()
result, err := h.fileService.UploadFile(ctx, userID, parentID, files)
result, err := h.fileService.UploadFile(ctx, userID, parentID, files, uploadLimit)
if err != nil {
common.ErrorWithCode(c, common.CodeBadRequest, err.Error())
return

View File

@@ -45,6 +45,38 @@ func testFileService() *FileService {
}
}
func TestDeploymentUploadMaxBytes(t *testing.T) {
t.Setenv("MAX_CONTENT_LENGTH", "")
if got := DeploymentUploadMaxBytes(); got != defaultDeploymentUploadMaxBytes {
t.Fatalf("default limit = %d, want %d", got, defaultDeploymentUploadMaxBytes)
}
t.Setenv("MAX_CONTENT_LENGTH", "12345")
if got := DeploymentUploadMaxBytes(); got != 12345 {
t.Fatalf("configured limit = %d, want 12345", got)
}
t.Setenv("MAX_CONTENT_LENGTH", "invalid")
if got := DeploymentUploadMaxBytes(); got != defaultDeploymentUploadMaxBytes {
t.Fatalf("invalid limit = %d, want default %d", got, defaultDeploymentUploadMaxBytes)
}
}
func TestReadDeploymentUploadDataLimit(t *testing.T) {
data, err := readDeploymentUploadData(strings.NewReader("hello"), 5)
if err != nil {
t.Fatalf("readDeploymentUploadData exact limit: %v", err)
}
if string(data) != "hello" {
t.Fatalf("data = %q, want hello", string(data))
}
_, err = readDeploymentUploadData(strings.NewReader("hello!"), 5)
if err == nil || !strings.Contains(err.Error(), "deployment upload limit of 5 bytes") {
t.Fatalf("error = %v, want deployment upload limit", err)
}
}
func (f *fakeStorage) Type() string { return "fake_storage" }
func (f *fakeStorage) Health(ctx context.Context) bool {

View File

@@ -11,12 +11,27 @@ import (
"ragflow/internal/entity"
"ragflow/internal/storage"
"ragflow/internal/utility"
"strconv"
"strings"
"time"
)
const defaultDeploymentUploadMaxBytes int64 = 1 << 30
func DeploymentUploadMaxBytes() int64 {
raw := common.GetEnv(common.EnvMaxContentLength)
if raw == "" {
return defaultDeploymentUploadMaxBytes
}
n, err := strconv.ParseInt(raw, 10, 64)
if err != nil || n <= 0 {
return defaultDeploymentUploadMaxBytes
}
return n
}
// UploadFile uploads files to a folder
func (s *FileService) UploadFile(ctx context.Context, tenantID, parentID string, files []*multipart.FileHeader) ([]map[string]interface{}, error) {
func (s *FileService) UploadFile(ctx context.Context, tenantID, parentID string, files []*multipart.FileHeader, maxBytes int64) ([]map[string]interface{}, error) {
if parentID == "" {
rootFolder, err := s.fileDAO.GetRootFolder(ctx, dao.DB, tenantID)
if err != nil {
@@ -58,6 +73,10 @@ func (s *FileService) UploadFile(ctx context.Context, tenantID, parentID string,
return nil, fmt.Errorf("no file selected")
}
if maxBytes > 0 && fileHeader.Size > maxBytes {
return nil, fmt.Errorf("file %s exceeds deployment upload limit of %d bytes", filename, maxBytes)
}
fileType := utility.FilenameType(filename)
fileObjNames := s.parseFilePath(filename)
@@ -101,7 +120,7 @@ func (s *FileService) UploadFile(ctx context.Context, tenantID, parentID string,
}
var data []byte
data, err = io.ReadAll(src)
data, err = readDeploymentUploadData(src, maxBytes)
src.Close()
if err != nil {
return nil, fmt.Errorf("failed to read file data: %w", err)
@@ -139,6 +158,21 @@ func (s *FileService) UploadFile(ctx context.Context, tenantID, parentID string,
return result, nil
}
func readDeploymentUploadData(r io.Reader, maxBytes int64) ([]byte, error) {
if maxBytes <= 0 {
return io.ReadAll(r)
}
limited := &io.LimitedReader{R: r, N: maxBytes + 1}
data, err := io.ReadAll(limited)
if err != nil {
return nil, err
}
if int64(len(data)) > maxBytes {
return nil, fmt.Errorf("file size exceeds deployment upload limit of %d bytes", maxBytes)
}
return data, nil
}
// UploadInfos mirrors Python's upload_info file branch: store raw bytes in the
// per-user downloads bucket and return lightweight upload descriptors instead
// of creating full File rows in the file-management tree.