Fix: Enforce 10MB upload limit for knowledge base with clear error handling (#1755)

* Initial plan

* Set MAX_CONTENT_LENGTH to 10MB and add file size validation

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Add custom error handler for 413 RequestEntityTooLarge

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Refactor: Extract MAX_FILE_SIZE constant to avoid duplication

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Fix file name extraction and add missing file validation

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Apply file size validation to all upload endpoints consistently

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Add frontend file size validation for knowledge base and plugin uploads

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Remove file size validation from plugin uploads, keep only for knowledge base

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* perf: ui

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
Co-authored-by: Junyan Qin <rockchinq@gmail.com>
This commit is contained in:
Copilot
2025-11-06 18:50:29 +08:00
committed by GitHub
parent 61bc6a1dc2
commit 68eb0290e0
8 changed files with 57 additions and 5 deletions

View File

@@ -31,19 +31,41 @@ class FilesRouterGroup(group.RouterGroup):
@self.route('/documents', methods=['POST'], auth_type=group.AuthType.USER_TOKEN)
async def _() -> quart.Response:
request = quart.request
# Check file size limit before reading the file
content_length = request.content_length
if content_length and content_length > group.MAX_FILE_SIZE:
return self.fail(400, 'File size exceeds 10MB limit. Please split large files into smaller parts.')
# get file bytes from 'file'
file = (await request.files)['file']
files = await request.files
if 'file' not in files:
return self.fail(400, 'No file provided in request')
file = files['file']
assert isinstance(file, quart.datastructures.FileStorage)
file_bytes = await asyncio.to_thread(file.stream.read)
extension = file.filename.split('.')[-1]
file_name = file.filename.split('.')[0]
# Double-check actual file size after reading
if len(file_bytes) > group.MAX_FILE_SIZE:
return self.fail(400, 'File size exceeds 10MB limit. Please split large files into smaller parts.')
# Split filename and extension properly
if '.' in file.filename:
file_name, extension = file.filename.rsplit('.', 1)
else:
file_name = file.filename
extension = ''
# check if file name contains '/' or '\'
if '/' in file_name or '\\' in file_name:
return self.fail(400, 'File name contains invalid characters')
file_key = file_name + '_' + str(uuid.uuid4())[:8] + '.' + extension
file_key = file_name + '_' + str(uuid.uuid4())[:8]
if extension:
file_key += '.' + extension
# save file to storage
await self.ap.storage_mgr.storage_provider.save(file_key, file_bytes)
return self.success(