aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/lua_map.c')
-rw-r--r--src/lua/lua_map.c154
1 files changed, 143 insertions, 11 deletions
diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c
index 5f55ece06..fa375cf63 100644
--- a/src/lua/lua_map.c
+++ b/src/lua/lua_map.c
@@ -56,6 +56,20 @@ rspamd_config:register_symbol{
description = "A sample symbol",
callback = sample_symbol_cb,
}
+
+-- Callback map that processes lines one by one
+local function process_line_cb(key, value, map)
+ -- This callback is called for each key-value pair in the map
+ rspamd_logger.infox('Got key %s with value %s', key, value)
+end
+
+local callback_map = rspamd_config:add_map{
+ type = "callback",
+ urls = ['file:///path/to/file'],
+ description = 'line by line map',
+ callback = process_line_cb,
+ by_line = true, -- Process map line by line instead of loading all data
+}
*/
/***
@@ -156,6 +170,13 @@ LUA_FUNCTION_DEF(map, get_data_digest);
*/
LUA_FUNCTION_DEF(map, get_nelts);
+/***
+ * @method map:trigger_hyperscan_compilation()
+ * Trigger hyperscan compilation for regexp scopes that may have been updated by this map
+ * This should be called after map loading is complete for maps that update regexp scopes
+ */
+LUA_FUNCTION_DEF(map, trigger_hyperscan_compilation);
+
static const struct luaL_reg maplib_m[] = {
LUA_INTERFACE_DEF(map, get_key),
LUA_INTERFACE_DEF(map, is_signed),
@@ -169,6 +190,7 @@ static const struct luaL_reg maplib_m[] = {
LUA_INTERFACE_DEF(map, on_load),
LUA_INTERFACE_DEF(map, get_data_digest),
LUA_INTERFACE_DEF(map, get_nelts),
+ LUA_INTERFACE_DEF(map, trigger_hyperscan_compilation),
{"__tostring", rspamd_lua_class_tostring},
{NULL, NULL}};
@@ -176,6 +198,7 @@ struct lua_map_callback_data {
lua_State *L;
int ref;
gboolean opaque;
+ gboolean by_line;
rspamd_fstring_t *data;
struct rspamd_lua_map *lua_map;
};
@@ -433,6 +456,102 @@ int lua_config_add_kv_map(lua_State *L)
}
+static void
+lua_map_line_insert(gpointer st, gconstpointer key, gconstpointer value)
+{
+ struct lua_map_callback_data *cbdata = st;
+ struct rspamd_lua_map **pmap;
+ struct rspamd_map *map = cbdata->lua_map->map;
+
+ if (cbdata->ref == -1) {
+ msg_err_map("map has no callback set");
+ return;
+ }
+
+ lua_pushcfunction(cbdata->L, &rspamd_lua_traceback);
+ int err_idx = lua_gettop(cbdata->L);
+
+ lua_rawgeti(cbdata->L, LUA_REGISTRYINDEX, cbdata->ref);
+
+ /* Push key */
+ if (!cbdata->opaque) {
+ lua_pushstring(cbdata->L, key);
+ lua_pushstring(cbdata->L, value);
+ }
+ else {
+ /* Key */
+ lua_new_text(cbdata->L, key, strlen(key), 0);
+
+ /* Value */
+ lua_new_text(cbdata->L, value, strlen(value), 0);
+ }
+
+ /* Push map object */
+ pmap = lua_newuserdata(cbdata->L, sizeof(void *));
+ *pmap = cbdata->lua_map;
+ rspamd_lua_setclass(cbdata->L, rspamd_map_classname, -1);
+
+ int ret = lua_pcall(cbdata->L, 3, 0, err_idx);
+
+ if (ret != 0) {
+ msg_info_map("call to line callback failed (%d): %s", ret,
+ lua_tostring(cbdata->L, -1));
+ }
+
+ lua_settop(cbdata->L, err_idx - 1);
+}
+
+static char *
+lua_map_line_read(char *chunk, int len,
+ struct map_cb_data *data,
+ gboolean final)
+{
+ struct lua_map_callback_data *cbdata, *old;
+
+ if (data->cur_data == NULL) {
+ old = (struct lua_map_callback_data *) data->prev_data;
+ cbdata = old;
+ cbdata->L = old->L;
+ cbdata->ref = old->ref;
+ cbdata->lua_map = old->lua_map;
+ cbdata->by_line = old->by_line;
+ cbdata->opaque = old->opaque;
+ data->cur_data = cbdata;
+ data->prev_data = NULL;
+ }
+ else {
+ cbdata = (struct lua_map_callback_data *) data->cur_data;
+ }
+
+ return rspamd_parse_kv_list(chunk, len, data, lua_map_line_insert, "", final);
+}
+
+static void
+lua_map_line_fin(struct map_cb_data *data, void **target)
+{
+ struct lua_map_callback_data *cbdata;
+
+ if (data->errored) {
+ if (data->cur_data) {
+ cbdata = (struct lua_map_callback_data *) data->cur_data;
+ if (cbdata->ref != -1) {
+ luaL_unref(cbdata->L, LUA_REGISTRYINDEX, cbdata->ref);
+ }
+
+ data->cur_data = NULL;
+ }
+ }
+ else {
+ if (target) {
+ *target = data->cur_data;
+ }
+
+ if (data->prev_data) {
+ data->prev_data = NULL;
+ }
+ }
+}
+
static char *
lua_map_read(char *chunk, int len,
struct map_cb_data *data,
@@ -446,6 +565,8 @@ lua_map_read(char *chunk, int len,
cbdata->L = old->L;
cbdata->ref = old->ref;
cbdata->lua_map = old->lua_map;
+ cbdata->by_line = old->by_line;
+ cbdata->opaque = old->opaque;
data->cur_data = cbdata;
data->prev_data = NULL;
}
@@ -509,13 +630,7 @@ lua_map_fin(struct map_cb_data *data, void **target)
lua_pushlstring(cbdata->L, cbdata->data->str, cbdata->data->len);
}
else {
- struct rspamd_lua_text *t;
-
- t = lua_newuserdata(cbdata->L, sizeof(*t));
- rspamd_lua_setclass(cbdata->L, rspamd_text_classname, -1);
- t->flags = 0;
- t->len = cbdata->data->len;
- t->start = cbdata->data->str;
+ lua_new_text(cbdata->L, cbdata->data->str, cbdata->data->len, 0);
}
pmap = lua_newuserdata(cbdata->L, sizeof(void *));
@@ -573,14 +688,15 @@ int lua_config_add_map(lua_State *L)
struct rspamd_lua_map *map, **pmap;
struct rspamd_map *m;
gboolean opaque_data = FALSE;
+ gboolean by_line = FALSE;
int cbidx = -1, ret;
GError *err = NULL;
if (cfg) {
if (!rspamd_lua_parse_table_arguments(L, 2, &err,
RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "*url=O;description=S;callback=F;type=S;opaque_data=B",
- &map_obj, &description, &cbidx, &type, &opaque_data)) {
+ "*url=O;description=S;callback=F;type=S;opaque_data=B;by_line=B",
+ &map_obj, &description, &cbidx, &type, &opaque_data, &by_line)) {
ret = luaL_error(L, "invalid table arguments: %s", err->message);
g_error_free(err);
if (map_obj) {
@@ -610,10 +726,11 @@ int lua_config_add_map(lua_State *L)
cbdata->lua_map = map;
cbdata->ref = cbidx;
cbdata->opaque = opaque_data;
+ cbdata->by_line = by_line;
if ((m = rspamd_map_add_from_ucl(cfg, map_obj, description,
- lua_map_read,
- lua_map_fin,
+ by_line ? lua_map_line_read : lua_map_read,
+ by_line ? lua_map_line_fin : lua_map_fin,
lua_map_dtor,
(void **) &map->data.cbdata,
NULL, RSPAMD_MAP_DEFAULT)) == NULL) {
@@ -1417,6 +1534,21 @@ lua_map_on_load(lua_State *L)
return 0;
}
+static int
+lua_map_trigger_hyperscan_compilation(lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_lua_map *map = lua_check_map(L, 1);
+
+ if (map == NULL) {
+ return luaL_error(L, "invalid arguments");
+ }
+
+ rspamd_map_trigger_hyperscan_compilation(map->map);
+
+ return 0;
+}
+
void luaopen_map(lua_State *L)
{
rspamd_lua_new_class(L, rspamd_map_classname, maplib_m);