package handler import ( "fmt" "io" "mime" "mime/multipart" "path/filepath" "strings" "github.com/enterprise-ai-platform/server/internal/config" ) // ValidateFile checks file size, extension, and MIME type. // Returns nil if valid, or an error message if invalid. func ValidateFile(header *multipart.FileHeader, allowedExtensions []string, maxSize int64) string { if header.Size > maxSize { return fmt.Sprintf("文件大小超出限制,最大支持 %dMB", maxSize/(1024*1024)) } ext := strings.ToLower(filepath.Ext(header.Filename)) if ext != "" { ext = ext[1:] // strip leading "." } extAllowed := false for _, e := range allowedExtensions { if strings.EqualFold(e, ext) { extAllowed = true break } } if !extAllowed { return fmt.Sprintf("不支持的文件类型:.%s,仅支持:%s", ext, strings.Join(allowedExtensions, "、")) } // Verify MIME type matches extension mimeType := header.Header.Get("Content-Type") if mimeType != "" { extMime, err := mime.ExtensionsByType(mimeType) if err == nil && len(extMime) > 0 { mimeAllowed := false for _, e := range extMime { if strings.EqualFold(strings.TrimPrefix(e, "."), ext) { mimeAllowed = true break } } if !mimeAllowed && !strings.HasPrefix(mimeType, "text/") && !strings.HasPrefix(mimeType, "application/") { return "文件类型与实际内容不匹配" } } } return "" // valid } // AllowedDocumentExtensions returns the list of allowed document file extensions. func AllowedDocumentExtensions() []string { return []string{"pdf", "docx", "txt", "md", "csv", "xlsx"} } // AllowedDocumentMaxSize returns the max file size for document uploads. func AllowedDocumentMaxSize() int64 { return config.MaxFileSize } // ReadAllWithLimit reads all content from r up to maxSize bytes. // Returns error if content exceeds maxSize. func ReadAllWithLimit(r io.Reader, maxSize int64) ([]byte, error) { limited := &io.LimitedReader{R: r, N: maxSize + 1} data, err := io.ReadAll(limited) if err != nil { return nil, err } if limited.N == 0 { return nil, fmt.Errorf("文件内容超出 %dMB 限制", maxSize/(1024*1024)) } return data, nil }