]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Add config:add_map table form method, add regexp maps
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 17 Mar 2016 09:57:40 +0000 (09:57 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 17 Mar 2016 09:57:40 +0000 (09:57 +0000)
src/lua/lua_common.h
src/lua/lua_config.c
src/lua/lua_map.c

index 39f578ea693975119d2acd234f00ed9a9280ad2b..54ad9d706bf145f73493200dd503d2ddd95fe057 100644 (file)
@@ -90,6 +90,7 @@ enum rspamd_lua_map_type {
        RSPAMD_LUA_MAP_RADIX = 0,
        RSPAMD_LUA_MAP_SET,
        RSPAMD_LUA_MAP_HASH,
+       RSPAMD_LUA_MAP_REGEXP,
        RSPAMD_LUA_MAP_CALLBACK
 };
 
@@ -104,6 +105,7 @@ struct rspamd_lua_map {
                struct radix_tree_compressed *radix;
                GHashTable *hash;
                struct lua_map_callback_data *cbdata;
+               struct rspamd_regexp_map *re_map;
        } data;
 };
 
index 4237ff97a91de8c848d3c67d9ed64bfb2428e5fb..ea53c53ae2a449241944afe41b693a6e8cf85330 100644 (file)
@@ -65,7 +65,7 @@ LUA_FUNCTION_DEF (config, get_mempool);
  * Creates new dynamic map of IP/mask addresses.
  * @param {string} mapline URL for a map
  * @param {string} description optional map description
- * @return {radix} radix tree object
+ * @return {map} radix tree object
  * @example
 local ip_map = rspamd_config:add_radix_map ('file:///path/to/file', 'my radix map')
 ...
@@ -80,10 +80,10 @@ end
 
 /***
  * @method rspamd_config:radix_from_config(mname, optname)
- * Creates new static map of IP/mask addresses from config.
+ * Creates new embedded map of IP/mask addresses from config.
  * @param {string} mname name of module
  * @param {string} optname option to get
- * @return {radix} radix tree object
+ * @return {map} radix tree object
  * @example
 local ip_map = rspamd_config:radix_from_config ('mymodule', 'ips')
 ...
@@ -100,7 +100,7 @@ end
  * Creates new dynamic map string objects.
  * @param {string} mapline URL for a map
  * @param {string} description optional map description
- * @return {hash} hash set object
+ * @return {map} hash set object
  * @example
 local hash_map = rspamd_config:add_hash_map ('file:///path/to/file', 'my hash map')
 ...
@@ -117,7 +117,7 @@ end
  * Creates new dynamic map of key/values associations.
  * @param {string} mapline URL for a map
  * @param {string} description optional map description
- * @return {hash} hash table object
+ * @return {map} hash table object
  * @example
 local kv_map = rspamd_config:add_kv_map ('file:///path/to/file', 'my kv map')
 ...
@@ -133,12 +133,20 @@ local function foo(task)
 end
  */
 /***
- * @method rspamd_config:add_map(mapline[, description], callback)
- * Creates new dynamic map with free-form callback
- * @param {string} mapline URL for a map
- * @param {string} description optional map description
- * @param {function} callback function to be called on map load and/or update
- * @return {bool} `true` if map has been added
+ * @method rspamd_config:add_map({args})
+ * Creates new dynamic map according to the attributes passed.
+ *
+ * - `type`: type of map to be created, can be one of the following set:
+ *   + `set`: set of strings
+ *   + `radix`: map of IP addresses to strings
+ *   + `map`: map of strings to strings
+ *   + `regexp`: map of regexps to strings
+ *   + `callback`: map processed by lua callback
+ * - `url`: url to load map from
+ * - `description`: map's description
+ * - `callback`: lua callback for the map
+ *
+ * @return {map} `true` if map has been added
  * @example
 
 local str = ''
index 51db9f97b35e14f51672df9f59bea2ccc4633e1e..4d4dc2285b1e306ba7a6c98c950df4ed80e729bb 100644 (file)
@@ -342,58 +342,176 @@ gint
 lua_config_add_map (lua_State *L)
 {
        struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *map_line, *description;
+       const gchar *map_line = NULL, *description = NULL;
+       const gchar *type = NULL;
        struct lua_map_callback_data *cbdata;
        struct rspamd_lua_map *map, **pmap;
        struct rspamd_map *m;
-       int cbidx;
+       int cbidx = -1, ret;
+       GError *err = NULL;
 
        if (cfg) {
-               map_line = luaL_checkstring (L, 2);
+               if (lua_type (L, 2) == LUA_TTABLE) {
+                       if (!rspamd_lua_parse_table_arguments (L, 2, &err,
+                                       "type=*S;description=S;callback=F;url=*S",
+                                       &type, &description, &cbidx, &map_line)) {
+                               ret = luaL_error (L, "invalid table arguments: %s", err->message);
+                               g_error_free (err);
+
+                               return ret;
+                       }
 
-               if (lua_gettop (L) == 4) {
-                       description = lua_tostring (L, 3);
-                       cbidx = 4;
-               }
-               else {
-                       description = NULL;
-                       cbidx = 3;
-               }
+                       g_assert (type != NULL && map_line != NULL);
 
-               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
-               map->type = RSPAMD_LUA_MAP_CALLBACK;
-               map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool,
-                               sizeof (*map->data.cbdata));
-               cbdata = map->data.cbdata;
-               cbdata->L = L;
-               cbdata->data = NULL;
-               cbdata->lua_map = map;
-
-               if (lua_type (L, cbidx) == LUA_TFUNCTION) {
-                       lua_pushvalue (L, cbidx);
-                       /* Get a reference */
-                       cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
-               }
-               else {
-                       /*
-                        * Now we can create maps with delayed callbacks, to allow better
-                        * closures generation
-                        */
-                       cbdata->ref = -1;
-               }
+                       if (strcmp (type, "callback") == 0) {
+                               if (cbidx == -1) {
+                                       ret = luaL_error (L, "invalid table arguments: callback missing");
+                                       return ret;
+                               }
+
+                               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                               map->type = RSPAMD_LUA_MAP_CALLBACK;
+                               map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool,
+                                               sizeof (*map->data.cbdata));
+                               cbdata = map->data.cbdata;
+                               cbdata->L = L;
+                               cbdata->data = NULL;
+                               cbdata->lua_map = map;
+                               cbdata->ref = cbidx;
+
+                               if ((m = rspamd_map_add (cfg, map_line, description,
+                                               lua_map_read, lua_map_fin,
+                                               (void **)&map->data.cbdata)) == NULL) {
+                                       msg_warn_config ("invalid map %s", map_line);
+                                       luaL_unref (L, LUA_REGISTRYINDEX, cbidx);
+                                       lua_pushnil (L);
+
+                                       return 1;
+                               }
+                       }
+                       else if (strcmp (type, "set") == 0) {
+                               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
+                                               rspamd_strcase_equal);
+                               map->type = RSPAMD_LUA_MAP_SET;
+
+                               if ((m = rspamd_map_add (cfg, map_line, description,
+                                               rspamd_hosts_read,
+                                               rspamd_hosts_fin,
+                                               (void **)&map->data.hash)) == NULL) {
+                                       msg_warn_config ("invalid set map %s", map_line);
+                                       g_hash_table_destroy (map->data.hash);
+                                       lua_pushnil (L);
+
+                                       return 1;
+                               }
+                       }
+                       else if (strcmp (type, "map") == 0) {
+                               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
+                                               rspamd_strcase_equal);
+                               map->type = RSPAMD_LUA_MAP_HASH;
+
+                               if ((m = rspamd_map_add (cfg, map_line, description,
+                                               rspamd_kv_list_read,
+                                               rspamd_kv_list_fin,
+                                               (void **)&map->data.hash)) == NULL) {
+                                       msg_warn_config ("invalid hash map %s", map_line);
+                                       g_hash_table_destroy (map->data.hash);
+                                       lua_pushnil (L);
+                                       return 1;
+                               }
+                       }
+                       else if (strcmp (type, "radix") == 0) {
+                               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                               map->data.radix = radix_create_compressed ();
+                               map->type = RSPAMD_LUA_MAP_RADIX;
+
+                               if ((m = rspamd_map_add (cfg, map_line, description,
+                                               rspamd_radix_read,
+                                               rspamd_radix_fin,
+                                               (void **)&map->data.radix)) == NULL) {
+                                       msg_warn_config ("invalid radix map %s", map_line);
+                                       radix_destroy_compressed (map->data.radix);
+                                       lua_pushnil (L);
+                                       return 1;
+                               }
+                       }
+                       else if (strcmp (type, "regexp") == 0) {
+                               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                               map->data.radix = radix_create_compressed ();
+                               map->type = RSPAMD_LUA_MAP_RADIX;
+
+                               if ((m = rspamd_map_add (cfg, map_line, description,
+                                               rspamd_regexp_list_read,
+                                               rspamd_regexp_list_fin,
+                                               (void **)&map->data.re_map)) == NULL) {
+                                       msg_warn_config ("invalid regexp map %s", map_line);
+                                       lua_pushnil (L);
+                                       return 1;
+                               }
+                       }
+                       else {
+                               ret = luaL_error (L, "invalid arguments: unknown type '%s'", type);
+
+                               return ret;
+                       }
 
-               if ((m = rspamd_map_add (cfg, map_line, description,
-                               lua_map_read, lua_map_fin,
-                               (void **)&map->data.cbdata)) == NULL) {
-                       msg_warn_config ("invalid map %s", map_line);
-                       lua_pushnil (L);
-               }
-               else {
                        map->map = m;
                        pmap = lua_newuserdata (L, sizeof (void *));
                        *pmap = map;
                        rspamd_lua_setclass (L, "rspamd{map}", -1);
                }
+               else {
+                       /*
+                        * Legacy format add_map(map_line, description, callback)
+                        */
+                       map_line = luaL_checkstring (L, 2);
+
+                       if (lua_gettop (L) == 4) {
+                               description = lua_tostring (L, 3);
+                               cbidx = 4;
+                       }
+                       else {
+                               description = NULL;
+                               cbidx = 3;
+                       }
+
+                       map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                       map->type = RSPAMD_LUA_MAP_CALLBACK;
+                       map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool,
+                                       sizeof (*map->data.cbdata));
+                       cbdata = map->data.cbdata;
+                       cbdata->L = L;
+                       cbdata->data = NULL;
+                       cbdata->lua_map = map;
+
+                       if (lua_type (L, cbidx) == LUA_TFUNCTION) {
+                               lua_pushvalue (L, cbidx);
+                               /* Get a reference */
+                               cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
+                       }
+                       else {
+                               /*
+                                * Now we can create maps with delayed callbacks, to allow better
+                                * closures generation
+                                */
+                               cbdata->ref = -1;
+                       }
+
+                       if ((m = rspamd_map_add (cfg, map_line, description,
+                                       lua_map_read, lua_map_fin,
+                                       (void **)&map->data.cbdata)) == NULL) {
+                               msg_warn_config ("invalid map %s", map_line);
+                               lua_pushnil (L);
+                       }
+                       else {
+                               map->map = m;
+                               pmap = lua_newuserdata (L, sizeof (void *));
+                               *pmap = map;
+                               rspamd_lua_setclass (L, "rspamd{map}", -1);
+                       }
+               }
        }
        else {
                return luaL_error (L, "invalid arguments");
@@ -411,6 +529,7 @@ lua_map_get_key (lua_State * L)
        struct rspamd_lua_ip *addr = NULL;
        const gchar *key, *value = NULL;
        gpointer ud;
+       gsize len;
        guint32 key_num = 0;
        gboolean ret = FALSE;
 
@@ -456,12 +575,11 @@ lua_map_get_key (lua_State * L)
                                ret = g_hash_table_lookup (map->data.hash, key) != NULL;
                        }
                }
-               else {
-                       /* key-value map */
-                       key = lua_tostring (L, 2);
+               else if (map->type == RSPAMD_LUA_MAP_REGEXP) {
+                       key = lua_tolstring (L, 2, &len);
 
                        if (key) {
-                               value = g_hash_table_lookup (map->data.hash, key);
+                               value = rspamd_match_regexp_map (map->data.re_map, key, len);
 
                                if (value) {
                                        lua_pushstring (L, value);
@@ -469,6 +587,19 @@ lua_map_get_key (lua_State * L)
                                }
                        }
                }
+               else {
+                       /* key-value map */
+                       key = lua_tostring (L, 2);
+
+                       if (key) {
+                               value = g_hash_table_lookup (map->data.hash, key);
+                       }
+
+                       if (value) {
+                               lua_pushstring (L, value);
+                               return 1;
+                       }
+               }
        }
        else {
                return luaL_error (L, "invalid arguments");