in plugins/wasm-go/extensions/traffic-tag/content.go [40:144]
func matchCondition(conditionGroup *ConditionGroup, log wrapper.Log) bool {
for _, condition := range conditionGroup.Conditions {
conditionKeyValue, err := getConditionValue(condition, log)
if err != nil {
log.Debugf("failed to get condition value: %s", err)
if conditionGroup.Logic == "and" {
return false
}
continue
}
switch condition.Operator {
case Op_Equal:
if conditionKeyValue == condition.Value[0] && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s == %s", conditionKeyValue, condition.Value[0])
return true
} else if conditionKeyValue != condition.Value[0] && conditionGroup.Logic == "and" {
return false
}
case Op_NotEqual:
if conditionKeyValue != condition.Value[0] && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s != %s", conditionKeyValue, condition.Value[0])
return true
} else if conditionKeyValue == condition.Value[0] && conditionGroup.Logic == "and" {
return false
}
case Op_Prefix:
if strings.HasPrefix(conditionKeyValue, condition.Value[0]) && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s prefix %s", conditionKeyValue, condition.Value[0])
return true
} else if !strings.HasPrefix(conditionKeyValue, condition.Value[0]) && conditionGroup.Logic == "and" {
return false
}
case Op_Regex:
if _, ok := regexCache[condition.Value[0]]; !ok {
err := compileRegex(condition.Value[0])
if err != nil {
log.Warnf("failed to compile regex: %s", err)
return false
}
}
regex := regexCache[condition.Value[0]]
if regex.MatchString(conditionKeyValue) && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s regex %s", conditionKeyValue, condition.Value[0])
return true
} else if !regex.MatchString(conditionKeyValue) && conditionGroup.Logic == "and" {
log.Debugf("condition not match: %s regex %s", conditionKeyValue, condition.Value[0])
return false
}
case Op_In:
isMatch := false
for _, v := range condition.Value {
if v == conditionKeyValue {
isMatch = true
break
}
}
if isMatch && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s in %v", conditionKeyValue, condition.Value)
return true
} else if !isMatch && conditionGroup.Logic == "and" {
return false
}
case Op_NotIn:
isMatch := false
for _, v := range condition.Value {
if v == conditionKeyValue {
isMatch = true
break
}
}
if !isMatch && conditionGroup.Logic == "or" {
log.Debugf("condition match: %s not in %v", conditionKeyValue, condition.Value)
return true
} else if isMatch && conditionGroup.Logic == "and" {
return false
}
case Op_Percent:
percentThresholdInt, err := strconv.Atoi(condition.Value[0])
if err != nil {
log.Infof("invalid percent threshold config: %s", err)
return false
}
// hash(value) % 100 < percent
hash := sha256.Sum256([]byte(conditionKeyValue))
hashInt64 := int64(binary.BigEndian.Uint64(hash[:8]) % 100)
log.Debugf("hashInt64: %d", hashInt64)
if hashInt64 < int64(percentThresholdInt) && conditionGroup.Logic == "or" {
log.Debugf("condition match: %d < %d", hashInt64, percentThresholdInt)
return true
} else if hashInt64 >= int64(percentThresholdInt) && conditionGroup.Logic == "and" {
log.Debugf("condition not match: %d >= %d", hashInt64, percentThresholdInt)
return false
}
default:
log.Criticalf("invalid operator: %s", condition.Operator)
return false
}
}
return len(conditionGroup.Conditions) > 0 && conditionGroup.Logic == "and" // all conditions are matched
}