From 54c2f784b7848b15f0a12329dd282e24fad87c04 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 6 Jan 2013 17:26:17 +0400 Subject: [PATCH] * Add symbols command for webui. --- src/cfg_file.h | 18 ++++++++++ src/cfg_utils.c | 16 +++++++++ src/cfg_xml.c | 51 +++++++++++++++++++++++---- src/webui.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 166 insertions(+), 10 deletions(-) diff --git a/src/cfg_file.h b/src/cfg_file.h index c6c8487ce..538167ea8 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -138,6 +138,23 @@ struct module_opt { enum lua_var_type lua_type; /**< type of lua variable */ }; +/** + * Symbol definition + */ +struct symbol_def { + gchar *name; + gchar *description; + gdouble weight; +}; + +/** + * Symbols group + */ +struct symbols_group { + gchar *name; + GList *symbols; +}; + /** * Statfile section definition */ @@ -308,6 +325,7 @@ struct config_file { GHashTable* modules_opts; /**< hash for module options indexed by module name */ GHashTable* variables; /**< hash of $variables defined in config, indexed by variable name */ GHashTable* metrics; /**< hash of metrics indexed by metric name */ + GList* symbols_groups; /**< groups of symbols */ GList* metrics_list; /**< linked list of metrics */ GHashTable* metrics_symbols; /**< hash table of metrics indexed by symbol */ GHashTable* c_modules; /**< hash of c modules indexed by module name */ diff --git a/src/cfg_utils.c b/src/cfg_utils.c index ae0971d6a..7b1910324 100644 --- a/src/cfg_utils.c +++ b/src/cfg_utils.c @@ -236,6 +236,9 @@ init_defaults (struct config_file *cfg) void free_config (struct config_file *cfg) { + GList *cur; + struct symbols_group *gr; + remove_all_maps (cfg); g_hash_table_remove_all (cfg->modules_opts); g_hash_table_unref (cfg->modules_opts); @@ -251,6 +254,19 @@ free_config (struct config_file *cfg) g_hash_table_unref (cfg->cfg_params); g_hash_table_destroy (cfg->metrics_symbols); g_hash_table_destroy (cfg->classifiers_symbols); + /* Free symbols groups */ + cur = cfg->symbols_groups; + while (cur) { + gr = cur->data; + if (gr->symbols) { + g_list_free (gr->symbols); + } + cur = g_list_next (cur); + } + if (cfg->symbols_groups) { + g_list_free (cfg->symbols_groups); + } + if (cfg->checksum) { g_free (cfg->checksum); } diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 88650c990..6ae3ce7c3 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -1050,15 +1050,28 @@ handle_metric_action (struct config_file *cfg, struct rspamd_xml_userdata *ctx, return TRUE; } +static gint +symbols_group_find_func (gconstpointer a, gconstpointer b) +{ + const struct symbols_group *gr = a; + const gchar *uv = b; + + return g_ascii_strcasecmp (gr->name, uv); +} + gboolean handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) { - gchar *strval, *err, *desc; + gchar *strval, *err, *desc, *group; double *value; - GList *metric_list; + GList *metric_list, *group_list; struct metric *metric = ctx->section_pointer; + struct symbols_group *sym_group; + struct symbol_def *sym_def; + sym_def = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbol_def)); value = memory_pool_alloc (cfg->cfg_pool, sizeof (double)); + if (attrs == NULL || (strval = g_hash_table_lookup (attrs, "weight")) == NULL) { msg_info ("symbol tag should have \"weight\" attribute, assume weight 1.0"); *value = 1.0; @@ -1072,19 +1085,30 @@ handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, } } + sym_def->weight = *value; + sym_def->name = memory_pool_strdup (cfg->cfg_pool, data); + if (attrs != NULL) { desc = g_hash_table_lookup (attrs, "description"); if (desc) { - g_hash_table_insert (metric->descriptions, data, memory_pool_strdup (cfg->cfg_pool, desc)); + sym_def->description = memory_pool_strdup (cfg->cfg_pool, desc); + g_hash_table_insert (metric->descriptions, data, sym_def->description); + } + else { + sym_def->description = NULL; + } + group = g_hash_table_lookup (attrs, "group"); + if (group == NULL) { + group = "ungrouped"; } } - g_hash_table_insert (metric->symbols, data, value); + g_hash_table_insert (metric->symbols, sym_def->name, value); - if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, data)) == NULL) { + if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) { metric_list = g_list_prepend (NULL, metric); memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_list_free, metric_list); - g_hash_table_insert (cfg->metrics_symbols, data, metric_list); + g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list); } else { /* Slow but keep start element of list in safe */ @@ -1093,6 +1117,21 @@ handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, } } + /* Search for symbol group */ + group_list = g_list_find_custom (cfg->symbols_groups, group, symbols_group_find_func); + if (group_list == NULL) { + /* Create new group */ + sym_group = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbols_group)); + sym_group->name = memory_pool_strdup (cfg->cfg_pool, group); + sym_group->symbols = NULL; + cfg->symbols_groups = g_list_prepend (cfg->symbols_groups, sym_group); + } + else { + sym_group = group_list->data; + } + /* Insert symbol */ + sym_group->symbols = g_list_prepend (sym_group->symbols, sym_def); + return TRUE; } diff --git a/src/webui.c b/src/webui.c index 36eb47fda..92b8c601c 100644 --- a/src/webui.c +++ b/src/webui.c @@ -57,6 +57,7 @@ /* HTTP paths */ #define PATH_AUTH "/login" +#define PATH_SYMBOLS "/symbols" gpointer init_webui_worker (void); void start_webui_worker (struct rspamd_worker *worker); @@ -218,6 +219,16 @@ webui_ssl_init (struct rspamd_webui_worker_ctx *ctx) } #endif +/* Calculate and set content-length header */ +static void +http_calculate_content_length (struct evbuffer *evb, struct evhttp_request *req) +{ + gchar numbuf[64]; + + rspamd_snprintf (numbuf, sizeof (numbuf), "%z", evbuffer_get_length (evb)); + evhttp_add_header(req->output_headers, "Content-Length", numbuf); +} + /* Command handlers */ /* @@ -266,15 +277,86 @@ http_handle_auth (struct evhttp_request *req, gpointer arg) hours = uptime / 3600; minutes = uptime / 60 - hours * 60; uptime -= hours * 3600 + minutes * 60; - rspamd_snprintf (uptime_buf, sizeof (uptime_buf), "%d hour%s %d minute%s %d second%s", hours, hours > 1 ? "s" : " ", minutes, minutes > 1 ? "s" : " ", (gint)uptime, uptime > 1 ? "s" : " "); + rspamd_snprintf (uptime_buf, sizeof (uptime_buf), "%d hour%s %d minute%s %d second%s", hours, hours != 1 ? "s" : " ", minutes, minutes != 1 ? "s" : " ", (gint)uptime, uptime != 1 ? "s" : " "); } evbuffer_add_printf (evb, "{\"auth\": \"%s\", \"version\": \"%s\", \"uptime\": \"%s\", \"error\": \"%s\"}" CRLF, auth, RVERSION, uptime_buf, error); - evhttp_add_header(req->output_headers, "Connection", "close"); + evhttp_add_header (req->output_headers, "Connection", "close"); + http_calculate_content_length (evb, req); + + evhttp_send_reply (req, HTTP_OK, "OK", evb); + evbuffer_free (evb); +} + +/* + * Symbols command handler: + * request: /symbols + * reply: json [{ + * "name": "group_name", + * "symbols": [ + * { + * "name": "name", + * "weight": 0.1, + * "description": "description of symbol" + * }, + * {...} + * }, + * {...}] + */ +static void +http_handle_symbols (struct evhttp_request *req, gpointer arg) +{ + struct rspamd_webui_worker_ctx *ctx = arg; + struct evbuffer *evb; + GList *cur_gr, *cur_sym; + struct symbols_group *gr; + struct symbol_def *sym; + + evb = evbuffer_new (); + if (!evb) { + msg_err ("cannot allocate evbuffer for reply"); + return; + } + + /* Trailer */ + evbuffer_add (evb, "[", 1); + + /* Go throught all symbols groups */ + cur_gr = ctx->cfg->symbols_groups; + while (cur_gr) { + gr = cur_gr->data; + evbuffer_add_printf (evb, "{\"group\":\"%s\",\"rules\":[", gr->name); + /* Iterate throught all symbols */ + cur_sym = gr->symbols; + while (cur_sym) { + sym = cur_sym->data; + + if (sym->description) { + evbuffer_add_printf (evb, "{\"symbol\":\"%s\",\"weight\":%.2f,\"description\":\"%s\"%s", sym->name, sym->weight, + sym->description, g_list_next (cur_sym) ? "}," : "}"); + } + else { + evbuffer_add_printf (evb, "{\"symbol\":\"%s\",\"weight\":%.2f%s", sym->name, sym->weight, + g_list_next (cur_sym) ? "}," : "}"); + } + + cur_sym = g_list_next (cur_sym); + } + if (g_list_next (cur_gr)) { + evbuffer_add (evb, "]},", 3); + } + else { + evbuffer_add (evb, "]},", 2); + } + cur_gr = g_list_next (cur_gr); + } + evbuffer_add (evb, "]" CRLF, 3); + evhttp_add_header (req->output_headers, "Connection", "close"); + http_calculate_content_length (evb, req); - evhttp_send_reply(req, HTTP_OK, "OK", evb); - evbuffer_free(evb); + evhttp_send_reply (req, HTTP_OK, "OK", evb); + evbuffer_free (evb); } gpointer @@ -351,6 +433,7 @@ start_webui_worker (struct rspamd_worker *worker) /* Add callbacks for different methods */ evhttp_set_cb (ctx->http, PATH_AUTH, http_handle_auth, ctx); + evhttp_set_cb (ctx->http, PATH_SYMBOLS, http_handle_symbols, ctx); ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg); -- 2.39.5