增加web_api
This commit is contained in:
68
src/gasflux/blueprints/download.py
Normal file
68
src/gasflux/blueprints/download.py
Normal file
@ -0,0 +1,68 @@
|
||||
"""
|
||||
Download Blueprint
|
||||
Handles file download endpoints.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from flask import Blueprint, send_file, current_app
|
||||
|
||||
from ..shared import _format_response, log_performance, logger
|
||||
|
||||
# Create blueprint
|
||||
download_bp = Blueprint('download', __name__, url_prefix='/download')
|
||||
|
||||
|
||||
@download_bp.route('/<path:filename>')
|
||||
@log_performance
|
||||
def download_file(filename):
|
||||
"""Download a processed file."""
|
||||
from flask import request
|
||||
|
||||
logger.info(f"Download request for file: {filename} from IP {request.remote_addr}")
|
||||
|
||||
try:
|
||||
# 支持两种路径格式:
|
||||
# 1. 绝对路径(以 / 开头,如 /full/path/to/file)
|
||||
# 2. 相对路径(task_id/filename)
|
||||
if filename.startswith('/'):
|
||||
# 绝对路径 - 直接使用
|
||||
file_path = Path(filename)
|
||||
else:
|
||||
# 相对路径 - 相对于 OUTPUT_FOLDER
|
||||
output_folder = Path(current_app.config.get('OUTPUT_FOLDER') or '')
|
||||
if not output_folder:
|
||||
logger.error("OUTPUT_FOLDER not configured")
|
||||
return _format_response(500, "服务器配置错误")
|
||||
|
||||
# 解析 task_id/filename 格式
|
||||
parts = filename.split('/', 1)
|
||||
if len(parts) != 2:
|
||||
logger.warning(f"Invalid relative path format: {filename}")
|
||||
return _format_response(400, "无效的文件路径")
|
||||
|
||||
task_id, filename_part = parts
|
||||
file_path = output_folder / task_id / filename_part
|
||||
|
||||
# Security check - ensure file is within output folder
|
||||
file_path = file_path.resolve()
|
||||
output_folder = Path(current_app.config.get('OUTPUT_FOLDER') or '').resolve()
|
||||
if output_folder and not str(file_path).startswith(str(output_folder)):
|
||||
logger.warning(f"Security violation: Attempted to access file outside output folder: {filename}")
|
||||
return _format_response(403, "访问被拒绝")
|
||||
|
||||
if not file_path.exists():
|
||||
logger.warning(f"File not found: {filename}")
|
||||
return _format_response(404, "文件未找到")
|
||||
|
||||
if not file_path.is_file():
|
||||
logger.warning(f"Path is not a file: {filename}")
|
||||
return _format_response(400, "不是文件")
|
||||
|
||||
file_size = file_path.stat().st_size
|
||||
logger.info(f"Serving file: {filename} ({file_size} bytes)")
|
||||
|
||||
return send_file(file_path)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error serving file {filename}: {str(e)}", exc_info=True)
|
||||
return _format_response(500, "内部服务器错误")
|
||||
Reference in New Issue
Block a user