diff --git a/internal/corazawaf/rule.go b/internal/corazawaf/rule.go index b961e2e27..56589f952 100644 --- a/internal/corazawaf/rule.go +++ b/internal/corazawaf/rule.go @@ -161,7 +161,7 @@ const chainLevelZero = 0 // Evaluate will evaluate the current rule for the indicated transaction // If the operator matches, actions will be evaluated, and it will return // the matched variables, keys and values (MatchData) -func (r *Rule) Evaluate(phase types.RulePhase, tx plugintypes.TransactionState, cache map[transformationKey]*transformationValue) { +func (r *Rule) Evaluate(phase types.RulePhase, tx plugintypes.TransactionState, cache map[transformationKey]transformationValue) { // collectiveMatchedValues lives across recursive calls of doEvaluate var collectiveMatchedValues []types.MatchData @@ -180,7 +180,7 @@ func (r *Rule) Evaluate(phase types.RulePhase, tx plugintypes.TransactionState, const noID = 0 -func (r *Rule) doEvaluate(logger debuglog.Logger, phase types.RulePhase, tx *Transaction, collectiveMatchedValues *[]types.MatchData, chainLevel int, cache map[transformationKey]*transformationValue) []types.MatchData { +func (r *Rule) doEvaluate(logger debuglog.Logger, phase types.RulePhase, tx *Transaction, collectiveMatchedValues *[]types.MatchData, chainLevel int, cache map[transformationKey]transformationValue) []types.MatchData { tx.Capture = r.Capture if multiphaseEvaluation { @@ -397,7 +397,7 @@ func (r *Rule) transformMultiMatchArg(arg types.MatchData) ([]string, []error) { return r.executeTransformationsMultimatch(arg.Value()) } -func (r *Rule) transformArg(arg types.MatchData, argIdx int, cache map[transformationKey]*transformationValue) (string, []error) { +func (r *Rule) transformArg(arg types.MatchData, argIdx int, cache map[transformationKey]transformationValue) (string, []error) { switch { case len(r.transformations) == 0: return arg.Value(), nil @@ -419,12 +419,11 @@ func (r *Rule) transformArg(arg types.MatchData, argIdx int, cache map[transform return cached.arg, cached.errs } else { ars, es := r.executeTransformations(arg.Value()) - errs := es - cache[key] = &transformationValue{ + cache[key] = transformationValue{ arg: ars, errs: es, } - return ars, errs + return ars, es } } } diff --git a/internal/corazawaf/rule_test.go b/internal/corazawaf/rule_test.go index 9c6eb247b..8617a4dc6 100644 --- a/internal/corazawaf/rule_test.go +++ b/internal/corazawaf/rule_test.go @@ -574,7 +574,7 @@ func TestExecuteTransformationsMultiMatchReturnsMultipleErrors(t *testing.T) { } func TestTransformArgSimple(t *testing.T) { - transformationCache := map[transformationKey]*transformationValue{} + transformationCache := map[transformationKey]transformationValue{} md := &corazarules.MatchData{ Variable_: variables.RequestURI, Key_: "REQUEST_URI", @@ -609,7 +609,7 @@ func TestTransformArgSimple(t *testing.T) { } func TestTransformArgNoCacheForTXVariable(t *testing.T) { - transformationCache := map[transformationKey]*transformationValue{} + transformationCache := map[transformationKey]transformationValue{} md := &corazarules.MatchData{ Variable_: variables.TX, Key_: "Custom_TX_Variable", diff --git a/internal/corazawaf/transaction.go b/internal/corazawaf/transaction.go index 20c056f22..17dec842c 100644 --- a/internal/corazawaf/transaction.go +++ b/internal/corazawaf/transaction.go @@ -122,7 +122,7 @@ type Transaction struct { variables TransactionVariables - transformationCache map[transformationKey]*transformationValue + transformationCache map[transformationKey]transformationValue } func (tx *Transaction) ID() string { diff --git a/internal/corazawaf/transaction_test.go b/internal/corazawaf/transaction_test.go index ee6059d8b..0a8107dde 100644 --- a/internal/corazawaf/transaction_test.go +++ b/internal/corazawaf/transaction_test.go @@ -22,7 +22,9 @@ import ( "github.com/corazawaf/coraza/v3/internal/collections" "github.com/corazawaf/coraza/v3/internal/corazarules" "github.com/corazawaf/coraza/v3/internal/environment" + "github.com/corazawaf/coraza/v3/internal/operators" utils "github.com/corazawaf/coraza/v3/internal/strings" + "github.com/corazawaf/coraza/v3/internal/transformations" "github.com/corazawaf/coraza/v3/types" "github.com/corazawaf/coraza/v3/types/variables" ) @@ -1864,3 +1866,45 @@ func TestRequestFilename(t *testing.T) { }) } } + +func BenchmarkRuleEvalWithTransformations(b *testing.B) { + waf := NewWAF() + op, err := operators.Get("unconditionalMatch", plugintypes.OperatorOptions{}) + if err != nil { + b.Fatal(err) + } + lowercaseFn, err := transformations.GetTransformation("lowercase") + if err != nil { + b.Fatal(err) + } + + rule := NewRule() + rule.ID_ = 1000 + rule.LogID_ = "1000" + rule.Phase_ = types.PhaseRequestHeaders + rule.operator = &ruleOperatorParams{ + Operator: op, + Function: "@unconditionalMatch", + } + if err := rule.AddTransformation("lowercase", lowercaseFn); err != nil { + b.Fatal(err) + } + rule.variables = append(rule.variables, ruleVariableParams{ + Variable: variables.Args, + }) + if err := waf.Rules.Add(rule); err != nil { + b.Fatal(err) + } + + tx := waf.NewTransaction() + tx.ProcessURI("/test?a=1&b=2&c=3&d=4&e=5", "GET", "HTTP/1.1") + tx.AddRequestHeader("Host", "example.com") + tx.ProcessRequestHeaders() + defer tx.Close() + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + waf.Rules.Eval(types.PhaseRequestHeaders, tx) + } +} diff --git a/internal/corazawaf/waf.go b/internal/corazawaf/waf.go index 0217025a2..6cccb8923 100644 --- a/internal/corazawaf/waf.go +++ b/internal/corazawaf/waf.go @@ -230,7 +230,7 @@ func (w *WAF) newTransaction(opts Options) *Transaction { }) tx.variables = *NewTransactionVariables() - tx.transformationCache = map[transformationKey]*transformationValue{} + tx.transformationCache = map[transformationKey]transformationValue{} } // set capture variables