]> source.dussan.org Git - rspamd.git/commitdiff
* Add new key-value map
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 25 May 2011 14:04:10 +0000 (18:04 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 25 May 2011 14:04:10 +0000 (18:04 +0400)
* Add lua api support for key-value map
* Fix problem in lua configuration initialization to allow `rspamd_config' global work properly

src/cfg_xml.c
src/lua/lua_common.h
src/lua/lua_config.c
src/map.c
src/map.h

index 00da907f475659a26d579501e5ba7edbc838f06c..fba925cc6f36640d914d28c7f8dae43d72eb1000 100644 (file)
@@ -1001,14 +1001,10 @@ handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, con
        return TRUE;
 }
 
-/* Handle lua tag */
-gboolean 
-handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset)
+static void
+set_lua_globals (struct config_file *cfg, lua_State *L)
 {
-       gchar                        *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
-       lua_State                    *L = cfg->lua_state;
        struct config_file           **pcfg;
-
        /* First check for global variable 'config' */
        lua_getglobal (L, "config");
 
@@ -1017,23 +1013,35 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable
                lua_newtable (L);
                lua_setglobal (L, "config");
        }
+
        lua_getglobal (L, "metrics");
        if (lua_isnil (L, -1)) {
                lua_newtable (L);
                lua_setglobal (L, "metrics");
        }
+
        lua_getglobal (L, "composites");
        if (lua_isnil (L, -1)) {
                lua_newtable (L);
                lua_setglobal (L, "composites");
        }
-       lua_getglobal (L, "rspamd_config");
-       if (lua_isnil (L, -1)) {
-               pcfg = lua_newuserdata (L, sizeof (struct config_file *));
-               lua_setclass (L, "rspamd{config}", -1);
-               *pcfg = cfg;
-               lua_setglobal (L, "rspamd_config");
-       }
+
+       pcfg = lua_newuserdata (L, sizeof (struct config_file *));
+       lua_setclass (L, "rspamd{config}", -1);
+       *pcfg = cfg;
+       lua_setglobal (L, "rspamd_config");
+
+       /* Clear stack from globals */
+       lua_pop (L, 3);
+}
+
+/* Handle lua tag */
+gboolean
+handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset)
+{
+       gchar                        *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
+       lua_State                    *L = cfg->lua_state;
+
        /* Now config tables can be used for configuring rspamd */
        /* First check "src" attribute */
        if (attrs != NULL && (val = g_hash_table_lookup (attrs, "src")) != NULL) {
@@ -1045,7 +1053,8 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable
                if (lua_dir && lua_file) {
                        cur_dir = g_malloc (PATH_MAX);
                        if (getcwd (cur_dir, PATH_MAX) != NULL && chdir (lua_dir) != -1) {
-                               if (luaL_dofile (L, lua_file) != 0) {
+                               /* Load file */
+                               if (luaL_loadfile (L, lua_file) != 0) {
                                        msg_err ("cannot load lua file %s: %s", val, lua_tostring (L, -1));
                                        if (chdir (cur_dir) == -1) {
                                                msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));;
@@ -1055,6 +1064,18 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable
                                        g_free (tmp2);
                                        return FALSE;
                                }
+                               set_lua_globals (cfg, L);
+                               /* Now do it */
+                               if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
+                                       msg_err ("init of %s failed: %s", val, lua_tostring (L, -1));
+                                       if (chdir (cur_dir) == -1) {
+                                               msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));;
+                                       }
+                                       g_free (cur_dir);
+                                       g_free (tmp1);
+                                       g_free (tmp2);
+                                       return FALSE;
+                               }
                        }
                        else {
                                msg_err ("cannot chdir to %s: %s", lua_dir, strerror (errno));;
@@ -1080,10 +1101,17 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable
        }
        else if (data != NULL && *data != '\0') {
                /* Try to load a string */
-               if (luaL_dostring (L, data) != 0) {
+               if (luaL_loadstring (L, data) != 0) {
                        msg_err ("cannot load lua chunk: %s", lua_tostring (L, -1));
                        return FALSE;
                }
+               set_lua_globals (cfg, L);
+               /* Now do it */
+               if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
+                       msg_err ("init of lua chunk failed: %s", lua_tostring (L, -1));
+                       return FALSE;
+               }
+
        }
        return TRUE;
 }
index da3cc254e25d5dfd6d1e23d8cee2b04dd4190c29..2879568f05650cbcb819c22cfc1b5f988a0f5af7 100644 (file)
@@ -16,7 +16,7 @@
 
 extern const luaL_reg null_reg[];
 
-#define RSPAMD_LUA_API_VERSION 5
+#define RSPAMD_LUA_API_VERSION 6
 
 /* Common utility functions */
 void lua_newclass (lua_State *L, const gchar *classname, const struct luaL_reg *func);
index d69036e093c36c743ff99d7109e46df03cbc2289..4ca3b7e45343c4ccf07883182f0db9269cd3ccaa 100644 (file)
@@ -38,6 +38,7 @@ LUA_FUNCTION_DEF (config, get_all_opt);
 LUA_FUNCTION_DEF (config, register_function);
 LUA_FUNCTION_DEF (config, add_radix_map);
 LUA_FUNCTION_DEF (config, add_hash_map);
+LUA_FUNCTION_DEF (config, add_kv_map);
 LUA_FUNCTION_DEF (config, get_classifier);
 LUA_FUNCTION_DEF (config, register_symbol);
 LUA_FUNCTION_DEF (config, register_virtual_symbol);
@@ -53,6 +54,7 @@ static const struct luaL_reg    configlib_m[] = {
        LUA_INTERFACE_DEF (config, register_function),
        LUA_INTERFACE_DEF (config, add_radix_map),
        LUA_INTERFACE_DEF (config, add_hash_map),
+       LUA_INTERFACE_DEF (config, add_kv_map),
        LUA_INTERFACE_DEF (config, get_classifier),
        LUA_INTERFACE_DEF (config, register_symbol),
        LUA_INTERFACE_DEF (config, register_virtual_symbol),
@@ -495,6 +497,36 @@ lua_config_add_hash_map (lua_State *L)
 
 }
 
+static gint
+lua_config_add_kv_map (lua_State *L)
+{
+       struct config_file             *cfg = lua_check_config (L);
+       const gchar                     *map_line;
+       GHashTable                    **r, ***ud;
+
+       if (cfg) {
+               map_line = luaL_checkstring (L, 2);
+               r = g_malloc (sizeof (GHashTable *));
+               *r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
+               if (!add_map (map_line, read_kv_list, fin_kv_list, (void **)r)) {
+                       msg_warn ("invalid hash map %s", map_line);
+                       g_hash_table_destroy (*r);
+                       g_free (r);
+                       lua_pushnil (L);
+                       return 1;
+               }
+               ud = lua_newuserdata (L, sizeof (GHashTable *));
+               *ud = r;
+               lua_setclass (L, "rspamd{hash_table}", -1);
+
+               return 1;
+       }
+
+       lua_pushnil (L);
+       return 1;
+
+}
+
 /*** Metric functions ***/
 
 
@@ -625,18 +657,18 @@ static gint
 lua_hash_table_get_key (lua_State * L)
 {
        GHashTable                    *tbl = lua_check_hash_table (L);
-       const gchar                    *key;
+       const gchar                    *key, *value;
 
        if (tbl) {
                key = luaL_checkstring (L, 2);
 
-               if (g_hash_table_lookup (tbl, key) != NULL) {
-                       lua_pushboolean (L, 1);
+               if ((value = g_hash_table_lookup (tbl, key)) != NULL) {
+                       lua_pushstring (L, value);
                        return 1;
                }
        }
 
-       lua_pushboolean (L, 0);
+       lua_pushnil (L);
        return 1;
 }
 
index 298c0c2e51b9f5c574044d07e0179f352be32712..c680aa28781d67d3efd496130b7b2f89ac33c317 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -552,6 +552,98 @@ add_map (const gchar *map_line, map_cb_t read_callback, map_fin_cb_t fin_callbac
 /**
  * FSM for parsing lists
  */
+u_char                  *
+abstract_parse_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func)
+{
+       u_char                         *c, *p, *key = NULL, *value = NULL;
+
+       p = chunk;
+       c = p;
+
+       while (p - chunk < len) {
+               switch (data->state) {
+               case 0:
+                       /* read key */
+                       /* Check here comments, eol and end of buffer */
+                       if (*p == '#') {
+                               if (key != NULL && p - c > 0) {
+                                       value = memory_pool_alloc (pool, p - c + 1);
+                                       memcpy (value, c, p - c);
+                                       value[p - c] = '\0';
+                                       value = g_strstrip (value);
+                                       func (data->cur_data, key, value);
+                               }
+                               data->state = 99;
+                       }
+                       else if (*p == '\r' || *p == '\n' || p - chunk == len - 1) {
+                               if (key != NULL && p - c > 0) {
+                                       value = memory_pool_alloc (pool, p - c + 1);
+                                       memcpy (value, c, p - c);
+                                       value[p - c] = '\0';
+
+                                       value = g_strstrip (value);
+                                       func (data->cur_data, key, value);
+                               }
+                               data->state = 100;
+                               key = NULL;
+                       }
+                       else if (g_ascii_isspace (*p)) {
+                               if (p - c > 0) {
+                                       key = memory_pool_alloc (pool, p - c + 1);
+                                       memcpy (key, c, p - c);
+                                       key[p - c] = '\0';
+                                       data->state = 2;
+                               }
+                               else {
+                                       key = NULL;
+                               }
+                       }
+                       else {
+                               p ++;
+                       }
+                       break;
+               case 2:
+                       /* Skip spaces before value */
+                       if (!g_ascii_isspace (*p)) {
+                               c = p;
+                               data->state = 0;
+                       }
+                       else {
+                               p ++;
+                       }
+                       break;
+               case 99:
+                       /* SKIP_COMMENT */
+                       /* Skip comment till end of line */
+                       if (*p == '\r' || *p == '\n') {
+                               while ((*p == '\r' || *p == '\n') && p - chunk < len) {
+                                       p++;
+                               }
+                               c = p;
+                               key = NULL;
+                               data->state = 0;
+                       }
+                       else {
+                               p++;
+                       }
+                       break;
+               case 100:
+                       /* Skip \r\n and whitespaces */
+                       if (*p == '\r' || *p == '\n' || g_ascii_isspace (*p)) {
+                               p ++;
+                       }
+                       else {
+                               c = p;
+                               key = NULL;
+                               data->state = 0;
+                       }
+                       break;
+               }
+       }
+
+       return c;
+}
+
 u_char                  *
 abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func)
 {
@@ -708,6 +800,23 @@ fin_host_list (memory_pool_t * pool, struct map_cb_data *data)
        }
 }
 
+u_char                         *
+read_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data)
+{
+       if (data->cur_data == NULL) {
+               data->cur_data = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
+       }
+       return abstract_parse_kv_list (pool, chunk, len, data, (insert_func) g_hash_table_insert);
+}
+
+void
+fin_kv_list (memory_pool_t * pool, struct map_cb_data *data)
+{
+       if (data->prev_data) {
+               g_hash_table_destroy (data->prev_data);
+       }
+}
+
 u_char                         *
 read_radix_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data)
 {
index de95c1153dedc55de03c18ba0511c5ca759d43cb..0ebd7e466a075df77974254182be29858bd2ba73 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -106,6 +106,12 @@ void fin_radix_list (memory_pool_t *pool, struct map_cb_data *data);
 u_char* read_host_list (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data);
 void fin_host_list (memory_pool_t *pool, struct map_cb_data *data);
 
+/**
+ * Kv list is an ordinal list of keys and values separated by whitespace
+ */
+u_char* read_kv_list (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data);
+void fin_kv_list (memory_pool_t *pool, struct map_cb_data *data);
+
 /**
  * FSM for lists parsing (support comments, blank lines and partial replies)
  */