commit 5de3696: [Fix] Spamassassin: Rework metas processing
Vsevolod Stakhov
vsevolod at highsecure.ru
Wed May 27 16:21:38 UTC 2020
Author: Vsevolod Stakhov
Date: 2020-05-27 17:15:13 +0100
URL: https://github.com/rspamd/rspamd/commit/5de369678bd0b1314bdbf9ac056042ba4655cf5e (HEAD -> master)
[Fix] Spamassassin: Rework metas processing
---
src/plugins/lua/spamassassin.lua | 126 ++++++++++++++++++++++++++-------------
1 file changed, 83 insertions(+), 43 deletions(-)
diff --git a/src/plugins/lua/spamassassin.lua b/src/plugins/lua/spamassassin.lua
index 798578856..2ecc39835 100644
--- a/src/plugins/lua/spamassassin.lua
+++ b/src/plugins/lua/spamassassin.lua
@@ -1166,31 +1166,33 @@ local function parse_atom(str)
return atom
end
-local function process_atom(atom, task)
- local atom_cb = atoms[atom]
+local function gen_process_atom_cb(result_name, task)
+ return function (atom)
+ local atom_cb = atoms[atom]
- if atom_cb then
- local res = atom_cb(task)
+ if atom_cb then
+ local res = atom_cb(task, result_name)
- if not res then
- lua_util.debugm(N, task, 'atom: %1, NULL result', atom)
- elseif res > 0 then
- lua_util.debugm(N, task, 'atom: %1, result: %2', atom, res)
- end
- return res
- else
- -- This is likely external atom
- local real_sym = atom
- if symbols_replacements[atom] then
- real_sym = symbols_replacements[atom]
- end
- if task:has_symbol(real_sym) then
- lua_util.debugm(N, task, 'external atom: %1, result: 1', real_sym)
- return 1
+ if not res then
+ lua_util.debugm(N, task, 'atom: %1, NULL result', atom)
+ elseif res > 0 then
+ lua_util.debugm(N, task, 'atom: %1, result: %2', atom, res)
+ end
+ return res
+ else
+ -- This is likely external atom
+ local real_sym = atom
+ if symbols_replacements[atom] then
+ real_sym = symbols_replacements[atom]
+ end
+ if task:has_symbol(real_sym, result_name) then
+ lua_util.debugm(N, task, 'external atom: %1, result: 1, named_result: %s', real_sym, result_name)
+ return 1
+ end
+ lua_util.debugm(N, task, 'external atom: %1, result: 0, , named_result: %s', real_sym, result_name)
end
- lua_util.debugm(N, task, 'external atom: %1, result: 0', real_sym)
+ return 0
end
- return 0
end
local function post_process()
@@ -1462,49 +1464,87 @@ local function post_process()
fun.each(function(k, r)
local expression = nil
-- Meta function callback
- local meta_cb = function(task)
- local res = 0
- local trace = {}
- -- XXX: need to memoize result for better performance
- local has_sym = task:has_symbol(k)
- if not has_sym then
- if expression then
- res,trace = expression:process_traced(task)
+ -- Here are dragons!
+ -- This function can be called from 2 DIFFERENT type of invocations:
+ -- 1) Invocation from Rspamd itself where `res_name` will be nil
+ -- 2) Invocation from other meta during expression:process_traced call
+ -- So we need to distinguish that and return different stuff to be able to deal with atoms
+ local meta_cb = function(task, res_name)
+ local cached = task:cache_get('sa_metas_processed')
+
+ -- We avoid many task methods invocations here (likely)
+ if not cached then
+ cached = {}
+ task:cache_set('sa_metas_processed', cached)
+ end
+
+ local already_processed = cached[k]
+
+ -- Exclude elements that are named in the same way as the symbol itself
+ local function exclude_sym_filter(sopt)
+ return sopt ~= k
+ end
+
+ if not already_processed or (not res_name or not already_processed[res_name])then
+ -- Execute symbol
+ local function exec_symbol(cur_res)
+ local res,trace = expression:process_traced(gen_process_atom_cb(cur_res, task))
+ if res > 0 then
+ -- Symbol should be one shot to make it working properly
+ task:insert_result_named(cur_res, k, res, fun.totable(fun.filter(exclude_sym_filter, trace)))
+ end
+
+ if not cached[k] then
+ cached[k] = {
+ cur_res = res
+ }
+ else
+ cached[k][cur_res] = res
+ end
end
- if res > 0 then
- -- Symbol should be one shot to make it working properly
- -- Exclude elements that are named in the same way as the symbol itself
- local function exclude_sym_filter(sopt)
- return sopt ~= k
+ if not res_name then
+ -- Invoke for all named results
+ local named_results = task:get_all_named_results()
+ for _,cur_res in ipairs(named_results) do
+ exec_symbol(cur_res)
end
- task:insert_result(k, res, fun.totable(fun.filter(exclude_sym_filter, trace)))
+ else
+ -- Invoked from another meta
+ exec_symbol(res_name)
end
else
- res = 1
+ -- We have cached the result
+ if res_name then
+ return cached[k][res_name] or 0
+ end
end
- return res
+ -- No return if invoked directly from Rspamd as we use task:insert_result_named directly
end
- expression = rspamd_expression.create(r['meta'],
- {parse_atom, process_atom}, rspamd_config:get_mempool())
+
+ expression = rspamd_expression.create(r['meta'], parse_atom, rspamd_config:get_mempool())
if not expression then
rspamd_logger.errx(rspamd_config, 'Cannot parse expression ' .. r['meta'])
else
if r['score'] then
- rspamd_config:set_metric_symbol({
+ rspamd_config:set_metric_symbol{
name = k, score = r['score'],
description = r['description'],
priority = 2,
- one_shot = true })
+ one_shot = true
+ }
scores_added[k] = 1
end
- rspamd_config:register_symbol({
+
+ rspamd_config:register_symbol{
name = k,
weight = calculate_score(k, r),
callback = meta_cb
- })
+ }
+
r['expression'] = expression
+
if not atoms[k] then
atoms[k] = meta_cb
end
More information about the Commits
mailing list