fix(backend): harden write registrar boundaries

This commit is contained in:
2026-07-21 16:12:20 +08:00
parent 1fcbb31301
commit 80bec26839
17 changed files with 639 additions and 42 deletions

View File

@@ -2,6 +2,7 @@ package files
import (
"errors"
"log"
"net/http"
"time"
@@ -26,12 +27,20 @@ type SourceDTO struct {
// Handler 负责 multipart 边界,文件名清理和本地路径构造始终委托给 Service。
type Handler struct {
service *Service
service *Service
maxUploadBytes int64
}
// DefaultMaxUploadBytes 是未显式配置时的请求体上限,覆盖完整 multipart 内容。
const DefaultMaxUploadBytes int64 = 32 << 20
// NewHandler 创建文件资料 HTTP registrar。
func NewHandler(service *Service) *Handler {
return &Handler{service: service}
func NewHandler(service *Service, limits ...int64) *Handler {
limit := DefaultMaxUploadBytes
if len(limits) > 0 && limits[0] > 0 {
limit = limits[0]
}
return &Handler{service: service, maxUploadBytes: limit}
}
// Register 将文件资料上传接口注册到上层提供的 /api/v1 路由组。
@@ -55,8 +64,15 @@ func (h *Handler) upload(c *gin.Context) {
writeSourceError(c, err)
return
}
// MaxBytesReader 必须在任何 multipart 解析前安装,限制字段、边界和文件内容的总请求量。
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, h.maxUploadBytes)
fileHeader, err := c.FormFile("file")
if err != nil {
var maxBytesError *http.MaxBytesError
if errors.As(err, &maxBytesError) {
httpx.Error(c, http.StatusRequestEntityTooLarge, "payload_too_large", "上传内容超过大小限制")
return
}
httpx.Error(c, http.StatusBadRequest, "invalid_request", "请选择要上传的文件")
return
}
@@ -75,6 +91,10 @@ func (h *Handler) upload(c *gin.Context) {
}
source, err := h.service.CreateSource(userID, project, c.PostForm("title"), stored)
if err != nil {
if cleanupErr := h.service.Remove(stored); cleanupErr != nil {
// 清理错误仅写服务端日志,响应继续使用稳定中文错误,不暴露 storage root。
log.Printf("source file cleanup failed: %v", cleanupErr)
}
writeSourceError(c, err)
return
}