]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Rework map reading state machine
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Mar 2016 17:21:31 +0000 (17:21 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 14 Mar 2016 17:21:31 +0000 (17:21 +0000)
src/libserver/dynamic_cfg.c
src/libutil/map.c
src/libutil/map.h
src/lua/lua_map.c
src/plugins/surbl.c

index 27fec9da96afd4a0b0fbf039cd4aed6fa824e64d..48ce0725af68578a125cceeaa923a948c527cea8 100644 (file)
@@ -133,11 +133,12 @@ apply_dynamic_conf (const ucl_object_t *top, struct rspamd_config *cfg)
 }
 
 /* Callbacks for reading json dynamic rules */
-gchar *
+static gchar *
 json_config_read_cb (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        struct config_json_buf *jb, *pd;
 
@@ -165,7 +166,7 @@ json_config_read_cb (rspamd_mempool_t * pool,
        return NULL;
 }
 
-void
+static void
 json_config_fin_cb (rspamd_mempool_t * pool, struct map_cb_data *data)
 {
        struct config_json_buf *jb;
index 3d965c5a5f907242660979f22fd83266742ec002..972cae2d2375728f780c00d29199855961b19c00 100644 (file)
@@ -377,7 +377,7 @@ http_map_finish (struct rspamd_http_connection *conn,
 
                g_assert (in != NULL);
 
-               map->read_callback (map->pool, in, inlen, &cbd->cbdata);
+               map->read_callback (map->pool, in, inlen, &cbd->cbdata, TRUE);
                map->fin_callback (map->pool, &cbd->cbdata);
 
                *map->user_data = cbd->cbdata.cur_data;
@@ -473,9 +473,8 @@ read_map_file (struct rspamd_map *map, struct file_map_data *data)
                }
        }
 
-       map->read_callback (map->pool, bytes, len, &cbdata);
-
        if (len > 0) {
+               map->read_callback (map->pool, bytes, len, &cbdata, TRUE);
                map->fin_callback (map->pool, &cbdata);
                *map->user_data = cbdata.cur_data;
        }
@@ -949,14 +948,40 @@ rspamd_map_add (struct rspamd_config *cfg,
 /**
  * FSM for parsing lists
  */
+
+#define MAP_STORE_KEY do { \
+       key = rspamd_mempool_alloc (pool, p - c + 1); \
+       rspamd_strlcpy (key, c, p - c + 1); \
+} while (0)
+
+#define MAP_STORE_VALUE do { \
+       value = rspamd_mempool_alloc (pool, p - c + 1); \
+       rspamd_strlcpy (value, c, p - c + 1); \
+       value = g_strstrip (value); \
+} while (0)
+
 gchar *
 rspamd_parse_kv_list (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
        struct map_cb_data *data,
        insert_func func,
-       const gchar *default_value)
+       const gchar *default_value,
+       gboolean final)
 {
+       enum {
+               map_skip_spaces_before_key = 0,
+               map_read_key,
+               map_read_key_quoted,
+               map_read_key_slashed,
+               map_skip_spaces_after_key,
+               map_read_value,
+               map_read_value_quoted,
+               map_read_comment_start,
+               map_skip_comment,
+               map_read_eol,
+       };
+
        gchar *c, *p, *key = NULL, *value = NULL, *end;
 
        p = chunk;
@@ -965,99 +990,174 @@ rspamd_parse_kv_list (rspamd_mempool_t * pool,
 
        while (p < end) {
                switch (data->state) {
-               case 0:
+               case map_skip_spaces_before_key:
+                       if (g_ascii_isspace (*p)) {
+                               p ++;
+                       }
+                       else {
+                               c = p;
+                               data->state = map_read_key;
+                       }
+                       break;
+               case map_read_key:
                        /* read key */
                        /* Check here comments, eol and end of buffer */
                        if (*p == '#') {
-                               if (key != NULL && p - c  >= 0) {
-                                       value = rspamd_mempool_alloc (pool, p - c + 1);
-                                       memcpy (value, c, p - c);
-                                       value[p - c] = '\0';
-                                       value = g_strstrip (value);
-                                       func (data->cur_data, key, value);
-                                       msg_debug_pool ("insert kv pair: %s -> %s", key, value);
-                               }
-                               else if (key == NULL && p - c > 0) {
+                               if (p - c > 0) {
+                                       /* Store a single key */
+                                       MAP_STORE_KEY;
                                        func (data->cur_data, key, default_value);
                                        msg_debug_pool ("insert key only pair: %s -> %s",
                                                        key, default_value);
+                                       key = NULL;
                                }
 
-                               data->state = 99;
+                               data->state = map_read_comment_start;
                        }
                        else if (*p == '\r' || *p == '\n') {
-                               if (key != NULL && p - c >= 0) {
-                                       value = rspamd_mempool_alloc (pool, p - c + 1);
-                                       memcpy (value, c, p - c);
-                                       value[p - c] = '\0';
-
-                                       value = g_strstrip (value);
-                                       func (data->cur_data, key, value);
-                                       msg_debug_pool ("insert kv pair: %s -> %s", key, value);
-                               }
-                               else if (key == NULL && p - c > 0) {
-                                       /* Key only line */
-                                       key = rspamd_mempool_alloc (pool, p - c + 1);
-                                       memcpy (key, c, p - c);
-                                       key[p - c] = '\0';
-                                       key = g_strstrip (key);
+                               if (p - c > 0) {
+                                       /* Store a single key */
+                                       MAP_STORE_KEY;
                                        func (data->cur_data, key, default_value);
                                        msg_debug_pool ("insert key only pair: %s -> %s",
                                                        key, default_value);
+                                       key = NULL;
                                }
-                               data->state = 100;
+
+                               data->state = map_read_eol;
                                key = NULL;
                        }
                        else if (g_ascii_isspace (*p)) {
                                if (p - c > 0) {
-                                       key = rspamd_mempool_alloc (pool, p - c + 1);
-                                       memcpy (key, c, p - c);
-                                       key[p - c] = '\0';
-                                       key = g_strstrip (key);
-                                       data->state = 2;
+                                       MAP_STORE_KEY;
+                                       data->state = map_skip_spaces_after_key;
                                }
                                else {
-                                       key = NULL;
+                                       /* Should not happen */
+                                       g_assert_not_reached ();
                                }
                        }
                        else {
                                p++;
                        }
                        break;
-               case 2:
-                       /* Skip spaces before value */
-                       if (!g_ascii_isspace (*p)) {
-                               c = p;
-                               data->state = 0;
+               case map_skip_spaces_after_key:
+                       if (g_ascii_isspace (*p)) {
+                               p ++;
                        }
                        else {
-                               p++;
+                               c = p;
+                               data->state = map_read_value;
                        }
                        break;
-               case 99:
-                       /* SKIP_COMMENT */
-                       /* Skip comment till end of line */
-                       if (*p == '\r' || *p == '\n') {
-                               while ((*p == '\r' || *p == '\n') && p < end) {
-                                       p++;
+               case map_read_value:
+                       g_assert (key != NULL);
+                       if (*p == '#') {
+                               if (p - c > 0) {
+                                       /* Store a single key */
+                                       MAP_STORE_VALUE;
+                                       func (data->cur_data, key, value);
+                                       msg_debug_pool ("insert key value pair: %s -> %s",
+                                                       key, value);
+                                       key = NULL;
+                                       value = NULL;
                                }
-                               c = p;
+                               else {
+                                       func (data->cur_data, key, default_value);
+                                       msg_debug_pool ("insert key only pair: %s -> %s",
+                                                       key, default_value);
+                                       key = NULL;
+                               }
+
+                               data->state = map_read_comment_start;
+                       }
+                       else if (*p == '\r' || *p == '\n') {
+                               if (p - c > 0) {
+                                       /* Store a single key */
+                                       MAP_STORE_VALUE;
+                                       func (data->cur_data, key, value);
+                                       msg_debug_pool ("insert key value pair: %s -> %s",
+                                                       key, value);
+                                       key = NULL;
+                                       value = NULL;
+                               }
+                               else {
+                                       func (data->cur_data, key, default_value);
+                                       msg_debug_pool ("insert key only pair: %s -> %s",
+                                                       key, default_value);
+                                       key = NULL;
+                               }
+
+                               data->state = map_read_eol;
                                key = NULL;
-                               data->state = 0;
                        }
                        else {
-                               p++;
+                               p ++;
+                       }
+                       break;
+               case map_read_comment_start:
+                       if (*p == '#') {
+                               data->state = map_skip_comment;
+                               p ++;
+                               key = NULL;
+                               value = NULL;
+                       }
+                       else {
+                               g_assert_not_reached ();
+                       }
+                       break;
+               case map_skip_comment:
+                       if (*p == '\r' || *p == '\n') {
+                               data->state = map_read_eol;
+                       }
+                       else {
+                               p ++;
                        }
                        break;
-               case 100:
+               case map_read_eol:
                        /* Skip \r\n and whitespaces */
-                       if (*p == '\r' || *p == '\n' || g_ascii_isspace (*p)) {
+                       if (*p == '\r' || *p == '\n') {
                                p++;
                        }
                        else {
-                               c = p;
+                               data->state = map_skip_spaces_before_key;
+                       }
+                       break;
+               default:
+                       g_assert_not_reached ();
+                       break;
+               }
+       }
+
+       if (final) {
+               /* Examine the state */
+               switch (data->state) {
+               case map_read_key:
+                       if (p - c > 0) {
+                               /* Store a single key */
+                               MAP_STORE_KEY;
+                               func (data->cur_data, key, default_value);
+                               msg_debug_pool ("insert key only pair: %s -> %s",
+                                               key, default_value);
+                               key = NULL;
+                       }
+                       break;
+               case map_read_value:
+                       g_assert (key != NULL);
+                       if (p - c > 0) {
+                               /* Store a single key */
+                               MAP_STORE_VALUE;
+                               func (data->cur_data, key, value);
+                               msg_debug_pool ("insert key value pair: %s -> %s",
+                                               key, value);
+                               key = NULL;
+                               value = NULL;
+                       }
+                       else {
+                               func (data->cur_data, key, default_value);
+                               msg_debug_pool ("insert key only pair: %s -> %s",
+                                               key, default_value);
                                key = NULL;
-                               data->state = 0;
                        }
                        break;
                }
@@ -1082,7 +1182,8 @@ gchar *
 rspamd_hosts_read (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        if (data->cur_data == NULL) {
                data->cur_data = g_hash_table_new (rspamd_strcase_hash,
@@ -1093,7 +1194,8 @@ rspamd_hosts_read (rspamd_mempool_t * pool,
                           len,
                           data,
                           (insert_func) g_hash_table_insert,
-                          hash_fill);
+                          hash_fill,
+                          final);
 }
 
 void
@@ -1112,7 +1214,8 @@ gchar *
 rspamd_kv_list_read (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        if (data->cur_data == NULL) {
                data->cur_data = g_hash_table_new (rspamd_strcase_hash,
@@ -1123,7 +1226,8 @@ rspamd_kv_list_read (rspamd_mempool_t * pool,
                           len,
                           data,
                           (insert_func) g_hash_table_insert,
-                          "");
+                          "",
+                          final);
 }
 
 void
@@ -1142,7 +1246,8 @@ gchar *
 rspamd_radix_read (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        radix_compressed_t *tree;
        rspamd_mempool_t *rpool;
@@ -1158,7 +1263,8 @@ rspamd_radix_read (rspamd_mempool_t * pool,
                           len,
                           data,
                           (insert_func) radix_tree_insert_helper,
-                          hash_fill);
+                          hash_fill,
+                          final);
 }
 
 void
index 13def079a338856051eb0e12d1afe195ec176eb3..6ceb04e14856589eef054301bcae32a6e973cb62 100644 (file)
@@ -19,7 +19,7 @@ struct map_cb_data;
  * Callback types
  */
 typedef gchar * (*map_cb_t)(rspamd_mempool_t *pool, gchar *chunk, gint len,
-       struct map_cb_data *data);
+       struct map_cb_data *data, gboolean final);
 typedef void (*map_fin_cb_t)(rspamd_mempool_t *pool, struct map_cb_data *data);
 
 /**
@@ -80,7 +80,8 @@ typedef void (*insert_func) (gpointer st, gconstpointer key,
 gchar * rspamd_radix_read (rspamd_mempool_t *pool,
        gchar *chunk,
        gint len,
-       struct map_cb_data *data);
+       struct map_cb_data *data,
+       gboolean final);
 void rspamd_radix_fin (rspamd_mempool_t *pool, struct map_cb_data *data);
 
 /**
@@ -89,7 +90,8 @@ void rspamd_radix_fin (rspamd_mempool_t *pool, struct map_cb_data *data);
 gchar * rspamd_hosts_read (rspamd_mempool_t *pool,
        gchar *chunk,
        gint len,
-       struct map_cb_data *data);
+       struct map_cb_data *data,
+       gboolean final);
 void rspamd_hosts_fin (rspamd_mempool_t *pool, struct map_cb_data *data);
 
 /**
@@ -98,7 +100,8 @@ void rspamd_hosts_fin (rspamd_mempool_t *pool, struct map_cb_data *data);
 gchar * rspamd_kv_list_read (rspamd_mempool_t *pool,
        gchar *chunk,
        gint len,
-       struct map_cb_data *data);
+       struct map_cb_data *data,
+       gboolean final);
 void rspamd_kv_list_fin (rspamd_mempool_t *pool, struct map_cb_data *data);
 
 /**
@@ -109,6 +112,7 @@ gchar * rspamd_parse_kv_list (rspamd_mempool_t * pool,
        gint len,
        struct map_cb_data *data,
        insert_func func,
-       const gchar *default_value);
+       const gchar *default_value,
+       gboolean final);
 
 #endif
index 04c0af005e95d70ca29a1a5814eee04305324807..51db9f97b35e14f51672df9f59bea2ccc4633e1e 100644 (file)
@@ -272,7 +272,8 @@ lua_config_add_kv_map (lua_State *L)
 
 static gchar *
 lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        struct lua_map_callback_data *cbdata, *old;
 
index df22b1610a6052bd8972b9807d1d20b87bf654ed..dcf69f8f2ff4197bedf73bc94601a18321328075 100644 (file)
@@ -114,7 +114,8 @@ static gchar *
 read_exceptions_list (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        if (data->cur_data == NULL) {
                data->cur_data = rspamd_mempool_alloc0 (pool,
@@ -125,7 +126,8 @@ read_exceptions_list (rspamd_mempool_t * pool,
                           len,
                           data,
                           (insert_func) exception_insert,
-                          "");
+                          "",
+                          final);
 }
 
 static void
@@ -208,7 +210,8 @@ static gchar *
 read_redirectors_list (rspamd_mempool_t * pool,
        gchar * chunk,
        gint len,
-       struct map_cb_data *data)
+       struct map_cb_data *data,
+       gboolean final)
 {
        struct rspamd_redirector_map_cb *cbdata;
 
@@ -229,7 +232,8 @@ read_redirectors_list (rspamd_mempool_t * pool,
                           len,
                           data,
                           (insert_func) redirector_insert,
-                          "");
+                          "",
+                          final);
 }
 
 void