commit fe590fd: [Fix] Fix calling of methods in selectors

Vsevolod Stakhov vsevolod at highsecure.ru
Thu May 14 12:21:16 UTC 2020


Author: Vsevolod Stakhov
Date: 2020-05-14 12:15:41 +0100
URL: https://github.com/rspamd/rspamd/commit/fe590fd7b5ea560fd468d57296c4bcf25e6cf320

[Fix] Fix calling of methods in selectors

---
 lualib/lua_selectors/init.lua       | 133 +++++++++++++++++++-----------------
 lualib/lua_selectors/transforms.lua |   3 +-
 2 files changed, 71 insertions(+), 65 deletions(-)

diff --git a/lualib/lua_selectors/init.lua b/lualib/lua_selectors/init.lua
index 11fcd55d1..ba20810c5 100644
--- a/lualib/lua_selectors/init.lua
+++ b/lualib/lua_selectors/init.lua
@@ -35,6 +35,7 @@ local fun = require 'fun'
 local lua_util = require "lua_util"
 local M = "selectors"
 local rspamd_text = require "rspamd_text"
+local unpack_function = table.unpack or unpack
 local E = {}
 
 local extractors = require "lua_selectors/extractors"
@@ -46,6 +47,28 @@ local function pure_type(ltype)
   return ltype:match('^(.*)_list$')
 end
 
+local function implicit_tostring(t, ud_or_table)
+  if t == 'table' then
+    -- Table (very special)
+    if ud_or_table.value then
+      return ud_or_table.value,'string'
+    elseif ud_or_table.addr then
+      return ud_or_table.addr,'string'
+    end
+
+    return logger.slog("%s", ud_or_table),'string'
+  elseif t == 'userdata' then
+    if t.cookie and t.cookie == text_cookie then
+      -- Preserve opaque
+      return ud_or_table,'string'
+    else
+      return tostring(ud_or_table),'string'
+    end
+  else
+    return tostring(ud_or_table),'string'
+  end
+end
+
 local function process_selector(task, sel)
   local function allowed_type(t)
     if t == 'string' or t == 'text' or t == 'string_list' or t == 'text_list' then
@@ -59,28 +82,6 @@ local function process_selector(task, sel)
     return pure_type(t)
   end
 
-  local function implicit_tostring(t, ud_or_table)
-    if t == 'table' then
-      -- Table (very special)
-      if ud_or_table.value then
-        return ud_or_table.value,'string'
-      elseif ud_or_table.addr then
-        return ud_or_table.addr,'string'
-      end
-
-      return logger.slog("%s", ud_or_table),'string'
-    elseif t == 'userdata' then
-      if t.cookie and t.cookie == text_cookie then
-        -- Preserve opaque
-        return ud_or_table,'string'
-      else
-        return tostring(ud_or_table),'string'
-      end
-    else
-      return tostring(ud_or_table),'string'
-    end
-  end
-
   local input,etype = sel.selector.get_value(task, sel.selector.args)
 
   if not input then
@@ -92,55 +93,51 @@ local function process_selector(task, sel)
       sel.selector.name, etype)
 
   local pipe = sel.processor_pipe or E
+  local first_elt = pipe[1]
 
-  if etype:match('^userdata') or etype:match('^table') then
-    -- Apply userdata conversion first
-    local first_elt = pipe[1]
-
-    if first_elt and first_elt.method then
-      -- Explicit conversion
-      local meth = first_elt
-
-      if meth.types[etype] then
-        lua_util.debugm(M, task, 'apply method `%s` to %s',
-            meth.name, etype)
-        input,etype = meth.process(input, etype)
-      else
-        local pt = pure_type(etype)
+  if first_elt and first_elt.method then
+    -- Explicit conversion
+    local meth = first_elt
 
-        if meth.types[pt] then
-          lua_util.debugm(M, task, 'map method `%s` to list of %s',
-              meth.name, pt)
-          -- Map method to a list of inputs, excluding empty elements
-          input = fun.filter(function(map_elt) return map_elt end,
-              fun.map(function(list_elt)
-                local ret, _ = meth.process(list_elt, pt)
-                return ret
-              end, input))
-          etype = 'string_list'
-        end
-      end
-      -- Remove method from the pipeline
-      pipe = fun.drop_n(1, pipe)
+    if meth.types[etype] then
+      lua_util.debugm(M, task, 'apply method `%s` to %s',
+          meth.name, etype)
+      input,etype = meth.process(input, etype)
     else
-      -- Implicit conversion
-
       local pt = pure_type(etype)
 
-      if not pt then
-        lua_util.debugm(M, task, 'apply implicit conversion %s->string', etype)
-        input = implicit_tostring(etype, input)
-        etype = 'string'
-      else
-        lua_util.debugm(M, task, 'apply implicit map %s->string', pt)
+      if meth.types[pt] then
+        lua_util.debugm(M, task, 'map method `%s` to list of %s',
+            meth.name, pt)
+        -- Map method to a list of inputs, excluding empty elements
         input = fun.filter(function(map_elt) return map_elt end,
             fun.map(function(list_elt)
-              local ret = implicit_tostring(pt, list_elt)
+              local ret, _ = meth.process(list_elt, pt)
               return ret
             end, input))
         etype = 'string_list'
       end
     end
+    -- Remove method from the pipeline
+    pipe = fun.drop_n(1, pipe)
+  elseif etype:match('^userdata') or etype:match('^table') then
+    -- Implicit conversion
+
+    local pt = pure_type(etype)
+
+    if not pt then
+      lua_util.debugm(M, task, 'apply implicit conversion %s->string', etype)
+      input = implicit_tostring(etype, input)
+      etype = 'string'
+    else
+      lua_util.debugm(M, task, 'apply implicit map %s->string', pt)
+      input = fun.filter(function(map_elt) return map_elt end,
+          fun.map(function(list_elt)
+            local ret = implicit_tostring(pt, list_elt)
+            return ret
+          end, input))
+      etype = 'string_list'
+    end
   end
 
   -- Now we fold elements using left fold
@@ -337,14 +334,24 @@ exports.parse_selector = function(cfg, str)
           types = {
             userdata = true,
             table = true,
+            string = true,
           },
           map_type = 'string',
           process = function(inp, t, args)
-            if t == 'userdata' then
-              return inp[method_name](inp, args),'string'
-            else
-              -- Table
+            if t == 'table' then
               return inp[method_name],'string'
+            else
+              -- We call method unpacking arguments and dropping all but the first result returned
+              local ret = (inp[method_name](inp, unpack_function(args)))
+              local ret_type = type(ret)
+              -- Now apply types heuristic
+              if ret_type == 'string' then
+                return ret,'string'
+              elseif ret_type == 'table' then
+                return ret,'string_list'
+              else
+                return implicit_tostring(ret_type, ret)
+              end
             end
           end,
         }
diff --git a/lualib/lua_selectors/transforms.lua b/lualib/lua_selectors/transforms.lua
index e47fdcec6..bbf5f510a 100644
--- a/lualib/lua_selectors/transforms.lua
+++ b/lualib/lua_selectors/transforms.lua
@@ -132,9 +132,8 @@ local transform_function = {
     ['types'] = {
       ['string'] = true
     },
-    ['map_type'] = 'hash',
+    ['map_type'] = 'string',
     ['process'] = function(inp, _, args)
-
       return common.create_digest(inp, args),'string'
     end,
     ['description'] = [[Create a digest from a string.


More information about the Commits mailing list