]> source.dussan.org Git - rspamd.git/commitdiff
* Add lua interface for parsing xmlrpc replies
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 8 Jun 2011 17:08:39 +0000 (21:08 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 8 Jun 2011 17:08:39 +0000 (21:08 +0400)
CMakeLists.txt
src/lua/CMakeLists.txt
src/lua/lua_common.c
src/lua/lua_common.h
src/lua/lua_xmlrpc.c [new file with mode: 0644]

index 78f08344f5a652d866f3289620f80dfb01d8a919..27b088160f4d75718ceaa2aa1a4aaa69e8fb7a43 100644 (file)
@@ -7,7 +7,7 @@ PROJECT(rspamd C)
 
 SET(RSPAMD_VERSION_MAJOR 0)
 SET(RSPAMD_VERSION_MINOR 3)
-SET(RSPAMD_VERSION_PATCH 13)
+SET(RSPAMD_VERSION_PATCH 14)
 
 
 SET(RSPAMD_VERSION         "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}")
index 63ecfe42b043c683a0baed12bee060cc785fa375..5e3ba9ca53db7fed91f0e8f45c53d3fd94d23e21 100644 (file)
@@ -6,7 +6,8 @@ SET(LUASRC                        lua_common.c
                                          lua_classifier.c
                                          lua_cfg_file.c
                                          lua_regexp.c
-                                         lua_cdb.c)
+                                         lua_cdb.c
+                                         lua_xmlrpc.c)
 
 ADD_LIBRARY(rspamd_lua STATIC ${LUASRC})
 TARGET_LINK_LIBRARIES(rspamd_lua ${LUALIB})
index 6d87636824344c4461c366a1b52911d33c5c47a6..2a1783cfb2d61f5635e747d093aca38004779e76 100644 (file)
@@ -239,6 +239,7 @@ init_lua (struct config_file *cfg)
        (void)luaopen_statfile (L);
        (void)luaopen_glib_regexp (L);
        (void)luaopen_cdb (L);
+       (void)luaopen_xmlrpc (L);
        cfg->lua_state = L;
        memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)lua_close, L);
 
index 2879568f05650cbcb819c22cfc1b5f988a0f5af7..82deb0685a9a92451c36c0b4b8fca1b82682492a 100644 (file)
@@ -37,6 +37,7 @@ gint luaopen_classifier (lua_State *L);
 gint luaopen_statfile (lua_State * L);
 gint luaopen_glib_regexp (lua_State *L);
 gint luaopen_cdb (lua_State *L);
+gint luaopen_xmlrpc (lua_State * L);
 void init_lua (struct config_file *cfg);
 gboolean init_lua_filters (struct config_file *cfg);
 
diff --git a/src/lua/lua_xmlrpc.c b/src/lua/lua_xmlrpc.c
new file mode 100644 (file)
index 0000000..7f08eef
--- /dev/null
@@ -0,0 +1,406 @@
+/* Copyright (c) 2010, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *       * Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *       * Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "lua_common.h"
+
+
+LUA_FUNCTION_DEF (xmlrpc, parse_reply);
+
+static const struct luaL_reg    xmlrpclib_m[] = {
+       LUA_INTERFACE_DEF (xmlrpc, parse_reply),
+       {"__tostring", lua_class_tostring},
+       {NULL, NULL}
+};
+
+struct lua_xmlrpc_ud {
+       gint parser_state;
+       gint depth;
+       gint param_count;
+       lua_State *L;
+};
+
+static void xmlrpc_start_element (GMarkupParseContext *context, const gchar *name, const gchar **attribute_names,
+                                                               const gchar **attribute_values, gpointer user_data, GError **error);
+static void xmlrpc_end_element (GMarkupParseContext    *context, const gchar *element_name, gpointer user_data,
+                                                               GError **error);
+static void xmlrpc_error (GMarkupParseContext *context, GError *error, gpointer user_data);
+static void xmlrpc_text (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data,
+                                                               GError **error);
+
+static GMarkupParser xmlrpc_parser = {
+       .start_element = xmlrpc_start_element,
+       .end_element = xmlrpc_end_element,
+       .passthrough = NULL,
+       .text = xmlrpc_text,
+       .error = xmlrpc_error,
+};
+
+static GQuark
+xmlrpc_error_quark (void)
+{
+       return g_quark_from_static_string ("xmlrpc-error-quark");
+}
+
+static void
+xmlrpc_start_element (GMarkupParseContext *context, const gchar *name, const gchar **attribute_names,
+                                                               const gchar **attribute_values, gpointer user_data, GError **error)
+{
+       struct lua_xmlrpc_ud           *ud = user_data;
+       int                             last_state;
+
+       last_state = ud->parser_state;
+
+       switch (ud->parser_state) {
+       case 0:
+               /* Expect tag methodResponse */
+               if (g_ascii_strcasecmp (name, "methodResponse") == 0) {
+                       ud->parser_state = 1;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 1:
+               /* Expect tag params */
+               if (g_ascii_strcasecmp (name, "params") == 0) {
+                       ud->parser_state = 2;
+                       /* result -> table of params indexed by int */
+                       lua_newtable (ud->L);
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 2:
+               /* Expect tag param */
+               if (g_ascii_strcasecmp (name, "param") == 0) {
+                       ud->parser_state = 3;
+                       /* Create new param */
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 3:
+               /* Expect tag value */
+               if (g_ascii_strcasecmp (name, "value") == 0) {
+                       ud->parser_state = 4;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 4:
+               /* Expect tag struct */
+               if (g_ascii_strcasecmp (name, "struct") == 0) {
+                       ud->parser_state = 5;
+                       /* Create new param of table type */
+                       lua_newtable (ud->L);
+                       ud->depth ++;
+               }
+               else if (g_ascii_strcasecmp (name, "string") == 0) {
+                       ud->parser_state = 11;
+               }
+               else if (g_ascii_strcasecmp (name, "int") == 0) {
+                       ud->parser_state = 12;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 5:
+               /* Parse structure */
+               /* Expect tag member */
+               if (g_ascii_strcasecmp (name, "member") == 0) {
+                       ud->parser_state = 6;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 6:
+               /* Expect tag name */
+               if (g_ascii_strcasecmp (name, "name") == 0) {
+                       ud->parser_state = 7;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 7:
+               /* Accept value */
+               if (g_ascii_strcasecmp (name, "value") == 0) {
+                       ud->parser_state = 8;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 8:
+               /* Parse any values */
+               /* Primitives */
+               if (g_ascii_strcasecmp (name, "string") == 0) {
+                       ud->parser_state = 11;
+               }
+               else if (g_ascii_strcasecmp (name, "int") == 0) {
+                       ud->parser_state = 12;
+               }
+               /* Structure */
+               else if (g_ascii_strcasecmp (name, "struct") == 0) {
+                       ud->parser_state = 5;
+                       /* Create new param of table type */
+                       lua_newtable (ud->L);
+                       ud->depth ++;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       }
+
+       if (ud->parser_state == 99) {
+               g_set_error (error, xmlrpc_error_quark(), 1, "xmlrpc parse error on state: %d, while parsing start tag: %s",
+                               last_state, name);
+       }
+}
+
+static void
+xmlrpc_end_element (GMarkupParseContext        *context, const gchar *name, gpointer user_data, GError **error)
+{
+       struct lua_xmlrpc_ud           *ud = user_data;
+       int                             last_state;
+
+       last_state = ud->parser_state;
+
+       switch (ud->parser_state) {
+       case 0:
+               ud->parser_state = 99;
+               break;
+       case 1:
+               /* Got methodResponse */
+               if (g_ascii_strcasecmp (name, "methodResponse") == 0) {
+                       /* End processing */
+                       ud->parser_state = 100;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 2:
+               /* Got tag params */
+               if (g_ascii_strcasecmp (name, "params") == 0) {
+                       ud->parser_state = 1;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 3:
+               /* Got tag param */
+               if (g_ascii_strcasecmp (name, "param") == 0) {
+                       ud->parser_state = 2;
+                       lua_rawseti (ud->L, -2, ++ud->param_count);
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 4:
+               /* Got tag value */
+               if (g_ascii_strcasecmp (name, "value") == 0) {
+                       if (ud->depth == 0) {
+                               ud->parser_state = 3;
+                       }
+                       else {
+                               /* Parse other members */
+                               ud->parser_state = 6;
+                       }
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 5:
+               /* Got tag struct */
+               if (g_ascii_strcasecmp (name, "struct") == 0) {
+                       ud->parser_state = 4;
+                       ud->depth --;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 6:
+               /* Got tag member */
+               if (g_ascii_strcasecmp (name, "member") == 0) {
+                       ud->parser_state = 5;
+                       /* Set table */
+                       lua_settable (ud->L, -3);
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 7:
+               /* Got tag name */
+               if (g_ascii_strcasecmp (name, "name") == 0) {
+                       ud->parser_state = 7;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 8:
+               /* Got tag value */
+               if (g_ascii_strcasecmp (name, "value") == 0) {
+                       ud->parser_state = 6;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       case 11:
+       case 12:
+               /* Parse any values */
+               /* Primitives */
+               if (g_ascii_strcasecmp (name, "string") == 0) {
+                       ud->parser_state = 8;
+               }
+               else if (g_ascii_strcasecmp (name, "int") == 0) {
+                       ud->parser_state = 8;
+               }
+               else {
+                       /* Error state */
+                       ud->parser_state = 99;
+               }
+               break;
+       }
+
+       if (ud->parser_state == 99) {
+               g_set_error (error, xmlrpc_error_quark(), 1, "xmlrpc parse error on state: %d, while parsing end tag: %s",
+                               last_state, name);
+       }
+}
+
+static void
+xmlrpc_text (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
+{
+       struct lua_xmlrpc_ud           *ud = user_data;
+       gint                            num;
+
+       /* Strip line */
+       while (g_ascii_isspace (*text) && text_len > 0) {
+               text ++;
+               text_len --;
+       }
+       while (g_ascii_isspace (text[text_len - 1]) && text_len > 0) {
+               text_len --;
+       }
+
+       if (text_len > 0) {
+
+               switch (ud->parser_state) {
+               case 7:
+                       /* Push key */
+                       lua_pushlstring (ud->L, text, text_len);
+                       break;
+               case 11:
+                       /* Push string value */
+                       lua_pushlstring (ud->L, text, text_len);
+                       break;
+               case 12:
+                       /* Push integer value */
+                       num = strtoul (text, NULL, 10);
+                       lua_pushinteger (ud->L, num);
+                       break;
+               }
+       }
+}
+
+static void
+xmlrpc_error (GMarkupParseContext *context, GError *error, gpointer user_data)
+{
+       struct lua_xmlrpc_ud           *ud = user_data;
+
+       msg_err ("xmlrpc parser error: %s", error->message, ud->parser_state);
+}
+
+gint
+lua_xmlrpc_parse_reply (lua_State *L)
+{
+       const gchar                    *data;
+       GMarkupParseContext            *ctx;
+       GError                         *err = NULL;
+       struct lua_xmlrpc_ud            ud;
+       gsize                           s;
+       gboolean                        res;
+
+       data = luaL_checklstring (L, 1, &s);
+
+       if (data != NULL) {
+               ud.L = L;
+               ud.parser_state = 0;
+               ud.depth = 0;
+               ud.param_count = 0;
+
+               ctx = g_markup_parse_context_new (&xmlrpc_parser,
+                               G_MARKUP_TREAT_CDATA_AS_TEXT | G_MARKUP_PREFIX_ERROR_POSITION, &ud, NULL);
+               res = g_markup_parse_context_parse (ctx, data, s, &err);
+
+               if (! res) {
+                       lua_pushnil (L);
+               }
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+gint
+luaopen_xmlrpc (lua_State * L)
+{
+
+       luaL_openlib (L, "rspamd_xmlrpc", xmlrpclib_m, 0);
+
+       return 1;
+}
+