aboutsummaryrefslogtreecommitdiffstats
path: root/src/webui.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2013-01-09 16:35:03 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2013-01-09 16:35:03 +0400
commit823c263b9d417a9d28344c469b253e0dfe76e640 (patch)
tree9b87cc08829c7a66c5b4181848da8baf53fba415 /src/webui.c
parent86d52c83c8cb219e503704e4ee762a7633431e36 (diff)
downloadrspamd-823c263b9d417a9d28344c469b253e0dfe76e640.tar.gz
rspamd-823c263b9d417a9d28344c469b253e0dfe76e640.zip
Add saving of actions, symbols and maps.
Diffstat (limited to 'src/webui.c')
-rw-r--r--src/webui.c214
1 files changed, 209 insertions, 5 deletions
diff --git a/src/webui.c b/src/webui.c
index e77aeaa95..7e3963b64 100644
--- a/src/webui.c
+++ b/src/webui.c
@@ -36,6 +36,7 @@
#include "classifiers/classifiers.h"
#include "dynamic_cfg.h"
#include "rrd.h"
+#include "json/jansson.h"
#include <evhttp.h>
#if (_EVENT_NUMERIC_VERSION > 0x02010000) && defined(HAVE_OPENSSL)
@@ -453,6 +454,42 @@ http_prepare_learn (struct evhttp_request *req, struct rspamd_webui_worker_ctx *
return cbdata;
}
+/*
+ * Set metric action
+ */
+static gboolean
+http_set_metric_action (struct config_file *cfg,
+ json_t *jv, struct metric *metric, enum rspamd_metric_action act)
+{
+ gdouble actval;
+ GList *cur;
+ struct metric_action *act_found;
+
+ if (!json_is_number (jv)) {
+ msg_err ("json element data error");
+ return FALSE;
+ }
+ actval = json_number_value (jv);
+ if (metric->action == act && metric->required_score != actval) {
+ return add_dynamic_action (cfg, DEFAULT_METRIC, act, actval);
+ }
+
+ /* Try to search in all metrics */
+ /* XXX: clarify this code, currently it looks like a crap */
+ cur = metric->actions;
+ while (cur) {
+ act_found = cur->data;
+ if (act_found->action == act) {
+ if (act_found->score != actval) {
+ return add_dynamic_action (cfg, DEFAULT_METRIC, act, actval);
+ }
+ }
+ cur = g_list_next (cur);
+ }
+
+ return TRUE;
+}
+
/* Command handlers */
/*
@@ -1138,7 +1175,7 @@ http_handle_learn_ham (struct evhttp_request *req, gpointer arg)
* Save actions command handler:
* request: /saveactions
* headers: Password
- * input: json data
+ * input: json array [<spam>,<probable spam>,<greylist>]
* reply: json {"success":true} or {"error":"error message"}
*/
static void
@@ -1146,6 +1183,10 @@ http_handle_save_actions (struct evhttp_request *req, gpointer arg)
{
struct rspamd_webui_worker_ctx *ctx = arg;
struct evbuffer *evb;
+ struct metric *metric;
+ json_t *json, *jv;
+ json_error_t je;
+
evb = evbuffer_new ();
if (!evb) {
@@ -1154,7 +1195,72 @@ http_handle_save_actions (struct evhttp_request *req, gpointer arg)
return;
}
- /* XXX: add real saving */
+ metric = g_hash_table_lookup (ctx->cfg->metrics, DEFAULT_METRIC);
+ if (metric == NULL) {
+ msg_err ("cannot find default metric");
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "500 default metric not defined", NULL);
+ return;
+ }
+
+ /* Now check for dynamic config */
+ if (!ctx->cfg->dynamic_conf) {
+ msg_err ("dynamic conf has not been defined");
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "503 dynamic config not found, cannot save", NULL);
+ return;
+ }
+
+ /* Try to load json */
+ json = json_load_evbuffer (req->input_buffer, &je);
+ if (json == NULL) {
+ msg_err ("json load error: %s", je.text);
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "504 json parse error", NULL);
+ return;
+ }
+
+ if (!json_is_array (json) || json_array_size (json) != 3) {
+ msg_err ("json data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "505 invalid json data", NULL);
+ return;
+ }
+
+ /* Now try to check what we have */
+
+ /* Spam element */
+ jv = json_array_get (json, 0);
+ if (!http_set_metric_action (ctx->cfg, jv, metric, METRIC_ACTION_REJECT)) {
+ msg_err ("json data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "506 cannot set action's value", NULL);
+ return;
+ }
+
+ /* Probable spam */
+ jv = json_array_get (json, 1);
+ if (!http_set_metric_action (ctx->cfg, jv, metric, METRIC_ACTION_ADD_HEADER)) {
+ msg_err ("json data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "506 cannot set action's value", NULL);
+ return;
+ }
+
+ /* Greylist */
+ jv = json_array_get (json, 2);
+ if (!http_set_metric_action (ctx->cfg, jv, metric, METRIC_ACTION_GREYLIST)) {
+ msg_err ("json data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "506 cannot set action's value", NULL);
+ return;
+ }
+
+ dump_dynamic_config (ctx->cfg);
evbuffer_add_printf (evb, "{\"success\":true}" CRLF);
evhttp_add_header (req->output_headers, "Connection", "close");
@@ -1175,6 +1281,12 @@ http_handle_save_symbols (struct evhttp_request *req, gpointer arg)
{
struct rspamd_webui_worker_ctx *ctx = arg;
struct evbuffer *evb;
+ struct metric *metric;
+ struct symbol *sym;
+ json_t *json, *jv, *jname, *jvalue;
+ json_error_t je;
+ guint i, len;
+ gdouble val;
evb = evbuffer_new ();
if (!evb) {
@@ -1183,7 +1295,69 @@ http_handle_save_symbols (struct evhttp_request *req, gpointer arg)
return;
}
- /* XXX: add real saving */
+ metric = g_hash_table_lookup (ctx->cfg->metrics, DEFAULT_METRIC);
+ if (metric == NULL) {
+ msg_err ("cannot find default metric");
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "500 default metric not defined", NULL);
+ return;
+ }
+
+ /* Now check for dynamic config */
+ if (!ctx->cfg->dynamic_conf) {
+ msg_err ("dynamic conf has not been defined");
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "503 dynamic config not found, cannot save", NULL);
+ return;
+ }
+
+ /* Try to load json */
+ json = json_load_evbuffer (req->input_buffer, &je);
+ if (json == NULL) {
+ msg_err ("json load error: %s", je.text);
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "504 json parse error", NULL);
+ return;
+ }
+
+ if (!json_is_array (json) || (len = json_array_size (json)) == 0) {
+ msg_err ("json data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "505 invalid json data", NULL);
+ return;
+ }
+
+ /* Iterate over all elements */
+ for (i = 0; i < len; i ++) {
+ jv = json_array_get (json, i);
+ if (!json_is_object (jv)) {
+ msg_err ("json array data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "505 invalid json data", NULL);
+ return;
+ }
+ jname = json_object_get (jv, "name");
+ jvalue = json_object_get (jv, "value");
+ if (!json_is_string (jname) || !json_is_number (jvalue)) {
+ msg_err ("json object data error");
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "505 invalid json data", NULL);
+ return;
+ }
+ val = json_number_value (jvalue);
+ sym = g_hash_table_lookup (metric->symbols, json_string_value (jname));
+ if (sym && fabs (sym->score - val) > 0.01) {
+ if (!add_dynamic_symbol (ctx->cfg, DEFAULT_METRIC, sym->name, val)) {
+ evbuffer_free (evb);
+ json_delete (json);
+ evhttp_send_reply (req, HTTP_INTERNAL, "506 cannot write symbol's value", NULL);
+ return;
+ }
+ }
+ }
evbuffer_add_printf (evb, "{\"success\":true}" CRLF);
evhttp_add_header (req->output_headers, "Connection", "close");
@@ -1210,6 +1384,7 @@ http_handle_save_map (struct evhttp_request *req, gpointer arg)
gchar *errstr;
guint32 id;
gboolean found = FALSE;
+ gint fd;
if (!http_check_password (ctx, req)) {
@@ -1252,13 +1427,42 @@ http_handle_save_map (struct evhttp_request *req, gpointer arg)
}
if (!found) {
- msg_info ("map not found");
+ msg_info ("map not found: %d", id);
evbuffer_free (evb);
evhttp_send_reply (req, HTTP_NOTFOUND, "404 map not found", NULL);
return;
}
- /* XXX: add real saving */
+ if (g_atomic_int_get (map->locked)) {
+ msg_info ("map locked: %s", map->uri);
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_NOTFOUND, "404 map is locked", NULL);
+ return;
+ }
+
+ /* Set lock */
+ g_atomic_int_set (map->locked, 1);
+ fd = open (map->uri, O_WRONLY | O_TRUNC);
+ if (fd == -1) {
+ g_atomic_int_set (map->locked, 0);
+ msg_info ("map %s open error: %s", map->uri, strerror (errno));
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_NOTFOUND, "404 map open error", NULL);
+ return;
+ }
+
+ if (evbuffer_write (req->input_buffer, fd) == -1) {
+ close (fd);
+ g_atomic_int_set (map->locked, 0);
+ msg_info ("map %s open error: %s", map->uri, strerror (errno));
+ evbuffer_free (evb);
+ evhttp_send_reply (req, HTTP_INTERNAL, "500 map open error", NULL);
+ return;
+ }
+
+ /* Close and unlock */
+ close (fd);
+ g_atomic_int_set (map->locked, 0);
evbuffer_add_printf (evb, "{\"success\":true}" CRLF);
evhttp_add_header (req->output_headers, "Connection", "close");