Files
lijiaoqiao/gateway/internal/compliance/rules/engine.go
Your Name 90490ce86d fix(gateway): 修复RuleEngine中regexp编译错误和并发安全问题
P0-05: regexp.Compile错误被静默忽略
- extractMatch函数现在返回(string, error)
- 正确处理regexp.Compile错误,返回格式化错误信息
- 修复无效正则导致的panic问题

P0-06: compiledPatterns非线程安全
- 添加sync.RWMutex保护map并发访问
- matchRegex和extractMatch使用读锁/写锁保护
- 实现双重检查锁定模式优化性能

测试验证:
- 使用-race flag验证无数据竞争
- 并发100个goroutine测试通过
2026-04-03 07:48:05 +08:00

173 lines
3.8 KiB
Go

package rules
import (
"fmt"
"regexp"
"sync"
)
// MatchResult 匹配结果
type MatchResult struct {
Matched bool
RuleID string
Matchers []MatcherResult
}
// MatcherResult 单个匹配器的结果
type MatcherResult struct {
MatcherIndex int
MatcherType string
Pattern string
MatchValue string
IsMatch bool
}
// RuleEngine 规则引擎
type RuleEngine struct {
loader *RuleLoader
compiledPatterns map[string][]*regexp.Regexp
patternMu sync.RWMutex
}
// NewRuleEngine 创建新的规则引擎
func NewRuleEngine(loader *RuleLoader) *RuleEngine {
return &RuleEngine{
loader: loader,
compiledPatterns: make(map[string][]*regexp.Regexp),
}
}
// Match 执行规则匹配
func (e *RuleEngine) Match(rule Rule, content string) MatchResult {
result := MatchResult{
Matched: false,
RuleID: rule.ID,
Matchers: make([]MatcherResult, len(rule.Matchers)),
}
for i, matcher := range rule.Matchers {
matcherResult := MatcherResult{
MatcherIndex: i,
MatcherType: matcher.Type,
Pattern: matcher.Pattern,
IsMatch: false,
}
switch matcher.Type {
case "regex_match":
matcherResult.IsMatch = e.matchRegex(matcher.Pattern, content)
if matcherResult.IsMatch {
matcherResult.MatchValue, _ = e.extractMatch(matcher.Pattern, content)
}
default:
// 未知匹配器类型,默认不匹配
}
result.Matchers[i] = matcherResult
if matcherResult.IsMatch {
result.Matched = true
}
}
return result
}
// matchRegex 执行正则表达式匹配
func (e *RuleEngine) matchRegex(pattern string, content string) bool {
// 先尝试读取缓存(使用读锁)
e.patternMu.RLock()
regex, ok := e.compiledPatterns[pattern]
e.patternMu.RUnlock()
if ok {
return regex[0].MatchString(content)
}
// 未命中,需要编译(使用写锁)
e.patternMu.Lock()
defer e.patternMu.Unlock()
// 双重检查
regex, ok = e.compiledPatterns[pattern]
if ok {
return regex[0].MatchString(content)
}
var err error
regex = make([]*regexp.Regexp, 1)
regex[0], err = regexp.Compile(pattern)
if err != nil {
return false
}
e.compiledPatterns[pattern] = regex
return regex[0].MatchString(content)
}
// extractMatch 提取匹配值
func (e *RuleEngine) extractMatch(pattern string, content string) (string, error) {
// 先尝试读取缓存(使用读锁)
e.patternMu.RLock()
regex, ok := e.compiledPatterns[pattern]
e.patternMu.RUnlock()
if ok {
return regex[0].FindString(content), nil
}
// 未命中,需要编译(使用写锁)
e.patternMu.Lock()
defer e.patternMu.Unlock()
// 双重检查
regex, ok = e.compiledPatterns[pattern]
if ok {
return regex[0].FindString(content), nil
}
var err error
regex = make([]*regexp.Regexp, 1)
regex[0], err = regexp.Compile(pattern)
if err != nil {
return "", fmt.Errorf("invalid regex pattern '%s': %w", pattern, err)
}
e.compiledPatterns[pattern] = regex
return regex[0].FindString(content), nil
}
// MatchFromConfig 从规则配置执行匹配
func (e *RuleEngine) MatchFromConfig(ruleID string, ruleConfig Rule, content string) (bool, error) {
// 验证规则
if err := e.validateRuleForMatch(ruleConfig); err != nil {
return false, err
}
result := e.Match(ruleConfig, content)
return result.Matched, nil
}
// validateRuleForMatch 验证规则是否可用于匹配
func (e *RuleEngine) validateRuleForMatch(rule Rule) error {
if rule.ID == "" {
return ErrInvalidRule
}
if len(rule.Matchers) == 0 {
return ErrNoMatchers
}
return nil
}
// Custom errors
var (
ErrInvalidRule = &RuleEngineError{"invalid rule: missing required fields"}
ErrNoMatchers = &RuleEngineError{"invalid rule: no matchers defined"}
)
// RuleEngineError 规则引擎错误
type RuleEngineError struct {
Message string
}
func (e *RuleEngineError) Error() string {
return e.Message
}