Procházet zdrojové kódy

* Add DNS resolver lua bindings.

Make lua http library working without task object.
Fix a problem with resolver in lua_worker.
Added some utility functions to lua api.
tags/0.5.2
Vsevolod Stakhov před 11 roky
rodič
revize
cd85daafe3

+ 2
- 1
src/lua/CMakeLists.txt Zobrazit soubor

@@ -13,7 +13,8 @@ SET(LUASRC lua_common.c
lua_upstream.c
lua_mempool.c
lua_session.c
lua_buffer.c)
lua_buffer.c
lua_dns.c)

ADD_LIBRARY(rspamd-lua ${LINK_TYPE} ${LUASRC})
SET_TARGET_PROPERTIES(rspamd-lua PROPERTIES VERSION ${RSPAMD_VERSION})

+ 2
- 2
src/lua/lua_buffer.c Zobrazit soubor

@@ -100,7 +100,7 @@ lua_io_read_cb (f_str_t * in, void *arg)
msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
}

res = lua_toboolean (cbdata->L, 1);
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);

if (need_unlock) {
@@ -133,7 +133,7 @@ lua_io_write_cb (void *arg)
msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
}

res = lua_toboolean (cbdata->L, 1);
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);

if (need_unlock) {

+ 22
- 0
src/lua/lua_common.c Zobrazit soubor

@@ -444,6 +444,7 @@ init_lua (struct config_file *cfg)
(void)lua_add_actions_global (L);
(void)luaopen_session (L);
(void)luaopen_io_dispatcher (L);
(void)luaopen_dns_resolver (L);

cfg->lua_state = L;
memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)lua_close, L);
@@ -789,3 +790,24 @@ lua_dumpstack (lua_State *L)
}
msg_info (buf);
}

gpointer
lua_check_class (lua_State *L, gint index, const gchar *name)
{
gpointer p;

if (lua_type (L, index) == LUA_TUSERDATA) {
p = lua_touserdata (L, index);
if (p) {
if (lua_getmetatable (L, index)) {
lua_getfield (L, LUA_REGISTRYINDEX, name); /* get correct metatable */
if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */
lua_pop (L, 2); /* remove both metatables */
return p;
}
lua_pop (L, 2);
}
}
}
return NULL;
}

+ 6
- 4
src/lua/lua_common.h Zobrazit soubor

@@ -46,6 +46,11 @@ void lua_set_table_index (lua_State *L, const gchar *index, const gchar *value);
*/
gint lua_class_tostring (lua_State *L);

/**
* Check whether the argument at specified index is of the specified class
*/
gpointer lua_check_class (lua_State *L, gint index, const gchar *name);

/**
* Open libraries functions
*/
@@ -71,11 +76,8 @@ gint luaopen_upstream (lua_State * L);
gint luaopen_mempool (lua_State * L);
gint luaopen_session (lua_State * L);
gint luaopen_io_dispatcher (lua_State * L);
gint luaopen_dns_resolver (lua_State * L);

void init_lua (struct config_file *cfg);
gboolean init_lua_filters (struct config_file *cfg);

/* Filters functions */
gint lua_call_filter (const gchar *function, struct worker_task *task);
gint lua_call_chain_filter (const gchar *function, struct worker_task *task, gint *marks, guint number);
double lua_consolidation_func (struct worker_task *task, const gchar *metric_name, const gchar *function_name);

+ 292
- 0
src/lua/lua_dns.c Zobrazit soubor

@@ -0,0 +1,292 @@
/* Copyright (c) 2010-2012, 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 AUTHOR 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"
#include "dns.h"

/* Public prototypes */
struct rspamd_dns_resolver *lua_check_dns_resolver (lua_State * L);
gint luaopen_dns_resolver (lua_State * L);

/* Lua bindings */
LUA_FUNCTION_DEF (dns_resolver, init);
LUA_FUNCTION_DEF (dns_resolver, resolve_a);
LUA_FUNCTION_DEF (dns_resolver, resolve_ptr);
LUA_FUNCTION_DEF (dns_resolver, resolve_txt);

static const struct luaL_reg dns_resolverlib_f[] = {
LUA_INTERFACE_DEF (dns_resolver, init),
{NULL, NULL}
};

static const struct luaL_reg dns_resolverlib_m[] = {
LUA_INTERFACE_DEF (dns_resolver, resolve_a),
LUA_INTERFACE_DEF (dns_resolver, resolve_ptr),
LUA_INTERFACE_DEF (dns_resolver, resolve_txt),
{"__tostring", lua_class_tostring},
{NULL, NULL}
};

struct rspamd_dns_resolver *
lua_check_dns_resolver (lua_State * L)
{
void *ud = luaL_checkudata (L, 1, "rspamd{resolver}");
luaL_argcheck (L, ud != NULL, 1, "'resolver' expected");
return ud ? *((struct rspamd_dns_resolver **)ud) : NULL;
}

struct lua_dns_cbdata {
lua_State *L;
struct rspamd_dns_resolver *resolver;
gint cbref;
const gchar *to_resolve;
};

static void
lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
{
struct lua_dns_cbdata *cd = arg;
gint i = 0;
struct in_addr ina;
struct rspamd_dns_resolver **presolver;
union rspamd_reply_element *elt;
GList *cur;
gboolean need_unlock = FALSE;

/* Avoid LOR here as mutex can be acquired before in lua_call */
if (g_mutex_trylock (lua_mtx)) {
need_unlock = TRUE;
}

lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->cbref);
presolver = lua_newuserdata (cd->L, sizeof (gpointer));
lua_setclass (cd->L, "rspamd{resolver}", -1);

*presolver = cd->resolver;
lua_pushstring (cd->L, cd->to_resolve);

if (reply->code == DNS_RC_NOERROR) {
if (reply->type == DNS_REQUEST_A) {

lua_newtable (cd->L);
cur = reply->elements;
while (cur) {
elt = cur->data;
memcpy (&ina, &elt->a.addr[0], sizeof (struct in_addr));
/* Actually this copy memory, so using of inet_ntoa is valid */
lua_pushstring (cd->L, inet_ntoa (ina));
lua_rawseti (cd->L, -2, ++i);
cur = g_list_next (cur);
}
lua_pushnil (cd->L);
}
else if (reply->type == DNS_REQUEST_PTR) {
lua_newtable (cd->L);
cur = reply->elements;
while (cur) {
elt = cur->data;
lua_pushstring (cd->L, elt->ptr.name);
lua_rawseti (cd->L, -2, ++i);
cur = g_list_next (cur);
}
lua_pushnil (cd->L);

}
else if (reply->type == DNS_REQUEST_TXT) {
lua_newtable (cd->L);
cur = reply->elements;
while (cur) {
elt = cur->data;
lua_pushstring (cd->L, elt->txt.data);
lua_rawseti (cd->L, -2, ++i);
cur = g_list_next (cur);
}
lua_pushnil (cd->L);

}
else {
lua_pushnil (cd->L);
lua_pushstring (cd->L, "Unknown reply type");
}
}
else {
lua_pushnil (cd->L);
lua_pushstring (cd->L, dns_strerror (reply->code));
}

if (lua_pcall (cd->L, 4, 0, 0) != 0) {
msg_info ("call to dns_callback failed: %s", lua_tostring (cd->L, -1));
}

/* Unref function */
luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->cbref);

if (need_unlock) {
g_mutex_unlock (lua_mtx);
}
}

static int
lua_dns_resolver_init (lua_State *L)
{
struct rspamd_dns_resolver *resolver, **presolver;
struct config_file *cfg, **pcfg;
struct event_base *base, **pbase;

/* Check args */
pbase = luaL_checkudata (L, 1, "rspamd{ev_base}");
luaL_argcheck (L, pbase != NULL, 1, "'ev_base' expected");
base = pbase ? *(pbase) : NULL;
pcfg = luaL_checkudata (L, 2, "rspamd{config}");
luaL_argcheck (L, pcfg != NULL, 2, "'config' expected");
cfg = pcfg ? *(pcfg) : NULL;

if (base != NULL && cfg != NULL) {
resolver = dns_resolver_init (base, cfg);
if (resolver) {
presolver = lua_newuserdata (L, sizeof (gpointer));
lua_setclass (L, "rspamd{resolver}", -1);
*presolver = resolver;
}
else {
lua_pushnil (L);
}
}
else {
lua_pushnil (L);
}

return 1;
}

static int
lua_dns_resolver_resolve_common (lua_State *L, struct rspamd_dns_resolver *resolver, enum rspamd_request_type type)
{
struct rspamd_async_session *session, **psession;
memory_pool_t *pool, **ppool;
const gchar *to_resolve;
struct in_addr ina;
struct lua_dns_cbdata *cbdata;

/* Check arguments */
psession = luaL_checkudata (L, 2, "rspamd{session}");
luaL_argcheck (L, psession != NULL, 2, "'session' expected");
session = psession ? *(psession) : NULL;
ppool = luaL_checkudata (L, 3, "rspamd{mempool}");
luaL_argcheck (L, ppool != NULL, 3, "'mempool' expected");
pool = ppool ? *(ppool) : NULL;
to_resolve = luaL_checkstring (L, 4);

if (pool != NULL && session != NULL && to_resolve != NULL && lua_isfunction (L, 5)) {
if (type == DNS_REQUEST_PTR) {
if (inet_aton (to_resolve, &ina) == 0) {
msg_err ("wrong resolve string to PTR request: %s", to_resolve);
lua_pushnil (L);
return 1;
}
}
cbdata = memory_pool_alloc (pool, sizeof (struct lua_dns_cbdata));
cbdata->L = L;
cbdata->resolver = resolver;
lua_pushvalue (L, 5);
cbdata->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
if (type == DNS_REQUEST_PTR) {
make_dns_request (resolver, session, pool, lua_dns_callback, cbdata, type, &ina);
}
else {
make_dns_request (resolver, session, pool, lua_dns_callback, cbdata, type, to_resolve);
}
lua_pushboolean (L, TRUE);
}
else {
msg_err ("invalid arguments to lua_resolve");
lua_pushnil (L);
}

return 1;

}

static int
lua_dns_resolver_resolve_a (lua_State *L)
{
struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L);

if (dns_resolver) {
return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_A);
}
else {
lua_pushnil (L);
}

return 1;
}

static int
lua_dns_resolver_resolve_ptr (lua_State *L)
{
struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L);

if (dns_resolver) {
return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_PTR);
}
else {
lua_pushnil (L);
}

return 1;
}

static int
lua_dns_resolver_resolve_txt (lua_State *L)
{
struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver (L);

if (dns_resolver) {
return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_TXT);
}
else {
lua_pushnil (L);
}

return 1;
}

gint
luaopen_dns_resolver (lua_State * L)
{
luaL_newmetatable (L, "rspamd{resolver}");
lua_pushstring (L, "__index");
lua_pushvalue (L, -2);
lua_settable (L, -3);

lua_pushstring (L, "class");
lua_pushstring (L, "rspamd{resolver}");
lua_rawset (L, -3);

luaL_openlib (L, NULL, dns_resolverlib_m, 0);
luaL_openlib(L, "rspamd_resolver", dns_resolverlib_f, 0);

lua_pop (L, 1); /* remove metatable from stack */
return 1;
}

+ 250
- 45
src/lua/lua_http.c Zobrazit soubor

@@ -43,10 +43,15 @@ struct lua_http_header {
};

struct lua_http_ud {
gint parser_state;
struct worker_task *task;
gint parser_state;
struct rspamd_async_session *s;
memory_pool_t *pool;
struct rspamd_dns_resolver *resolver;
struct event_base *ev_base;
lua_State *L;
const gchar *callback;
gint cbref;
gchar *req_buf;
gint req_len;
gint port;
@@ -58,19 +63,15 @@ struct lua_http_ud {
GList *headers;
};

static struct worker_task *
lua_check_task (lua_State * L)
{
void *ud = luaL_checkudata (L, 1, "rspamd{task}");
luaL_argcheck (L, ud != NULL, 1, "'task' expected");
return ud ? *((struct worker_task **)ud) : NULL;
}

static void
lua_http_fin (void *arg)
{
struct lua_http_ud *ud = arg;

if (ud->callback == NULL) {
/* Unref callback */
luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
}
rspamd_remove_dispatcher (ud->io_dispatcher);
close (ud->fd);
}
@@ -79,21 +80,35 @@ static void
lua_http_push_error (gint code, struct lua_http_ud *ud)
{
struct worker_task **ptask;
gint num;
gboolean need_unlock = FALSE;

/* Avoid LOR here as mutex can be acquired before in lua_call */
if (g_mutex_trylock (lua_mtx)) {
need_unlock = TRUE;
}

/* Push error */
lua_getglobal (ud->L, ud->callback);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
lua_setclass (ud->L, "rspamd{task}", -1);
if (ud->callback) {
lua_getglobal (ud->L, ud->callback);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
lua_setclass (ud->L, "rspamd{task}", -1);
*ptask = ud->task;
num = 4;
}
else {
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
num = 3;
}

*ptask = ud->task;
/* Code */
lua_pushnumber (ud->L, code);
/* Headers */
lua_pushnil (ud->L);
/* Reply */
lua_pushnil (ud->L);
if (lua_pcall (ud->L, 4, 0, 0) != 0) {
msg_info ("call to %s failed: %s", ud->callback, lua_tostring (ud->L, -1));
if (lua_pcall (ud->L, num, 0, 0) != 0) {
msg_info ("call to %s failed: %s", ud->callback ? ud->callback : "local function", lua_tostring (ud->L, -1));
}

if (ud->headers != NULL) {
@@ -102,7 +117,10 @@ lua_http_push_error (gint code, struct lua_http_ud *ud)
}

ud->parser_state = 3;
remove_normal_event (ud->task->s, lua_http_fin, ud);
remove_normal_event (ud->s, lua_http_fin, ud);
if (need_unlock) {
g_mutex_unlock (lua_mtx);
}
}

static void
@@ -111,13 +129,27 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
GList *cur;
struct lua_http_header *header;
struct worker_task **ptask;
gint num;
gboolean need_unlock = FALSE;

/* Push error */
lua_getglobal (ud->L, ud->callback);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
lua_setclass (ud->L, "rspamd{task}", -1);
/* Avoid LOR here as mutex can be acquired before in lua_call */
if (g_mutex_trylock (lua_mtx)) {
need_unlock = TRUE;
}

if (ud->callback) {
/* Push error */
lua_getglobal (ud->L, ud->callback);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
lua_setclass (ud->L, "rspamd{task}", -1);

*ptask = ud->task;
*ptask = ud->task;
num = 4;
}
else {
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
num = 3;
}
/* Code */
lua_pushnumber (ud->L, ud->code);
/* Headers */
@@ -134,8 +166,8 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
/* Reply */
lua_pushlstring (ud->L, in->begin, in->len);

if (lua_pcall (ud->L, 4, 0, 0) != 0) {
msg_info ("call to %s failed: %s", ud->callback, lua_tostring (ud->L, -1));
if (lua_pcall (ud->L, num, 0, 0) != 0) {
msg_info ("call to %s failed: %s", ud->callback ? ud->callback : "local function", lua_tostring (ud->L, -1));
}

if (ud->headers != NULL) {
@@ -143,7 +175,10 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
ud->headers = NULL;
}

remove_normal_event (ud->task->s, lua_http_fin, ud);
remove_normal_event (ud->s, lua_http_fin, ud);
if (need_unlock) {
g_mutex_unlock (lua_mtx);
}
}

/*
@@ -184,8 +219,8 @@ lua_http_parse_header_line (struct lua_http_ud *ud, f_str_t *in)
return FALSE;
}
/* Copy name */
new = memory_pool_alloc (ud->task->task_pool, sizeof (struct lua_http_header));
new->name = memory_pool_alloc (ud->task->task_pool, p - in->begin + 1);
new = memory_pool_alloc (ud->pool, sizeof (struct lua_http_header));
new->name = memory_pool_alloc (ud->pool, p - in->begin + 1);
rspamd_strlcpy (new->name, in->begin, p - in->begin + 1);

p ++;
@@ -193,7 +228,7 @@ lua_http_parse_header_line (struct lua_http_ud *ud, f_str_t *in)
while (p < in->begin + in->len && g_ascii_isspace (*p)) {
p ++;
}
new->value = memory_pool_alloc (ud->task->task_pool, in->begin + in->len - p + 1);
new->value = memory_pool_alloc (ud->pool, in->begin + in->len - p + 1);
rspamd_strlcpy (new->value, p, in->begin + in->len - p + 1);

/* Check content-length */
@@ -260,7 +295,7 @@ lua_http_err_cb (GError * err, void *arg)
lua_http_push_error (500, ud);
}
else {
remove_normal_event (ud->task->s, lua_http_fin, ud);
remove_normal_event (ud->s, lua_http_fin, ud);
}
}

@@ -292,10 +327,10 @@ lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)

/* Create dispatcher for HTTP protocol */
msec_to_tv (ud->timeout, &tv);
ud->io_dispatcher = rspamd_create_dispatcher (ud->task->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
ud->io_dispatcher = rspamd_create_dispatcher (ud->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
lua_http_err_cb, &tv, ud);
/* Write request */
register_async_event (ud->task->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));
register_async_event (ud->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));

if (!rspamd_dispatcher_write (ud->io_dispatcher, ud->req_buf, ud->req_len, TRUE, TRUE)) {
lua_http_push_error (450, ud);
@@ -320,6 +355,9 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha

ud = memory_pool_alloc0 (task->task_pool, sizeof (struct lua_http_ud));
ud->L = L;
ud->s = task->s;
ud->pool = task->task_pool;
ud->ev_base = task->ev_base;
ud->task = task;
/* Preallocate buffer */
ud->req_buf = memory_pool_alloc (task->task_pool, s);
@@ -376,6 +414,106 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha
return 0;
}

/**
* Common request function (new version)
*/
static gint
lua_http_make_request_common_new (lua_State *L, struct rspamd_async_session *session, memory_pool_t *pool, struct event_base *base, gint cbref,
const gchar *hostname, const gchar *path, const gchar *data, gint top)
{
gint r, s, datalen;
struct lua_http_ud *ud;
struct in_addr ina;
struct timeval tv;

/* Calculate buffer size */
datalen = (data != NULL) ? strlen (data) : 0;
s = MAX_HEADERS_SIZE + sizeof (CRLF) * 3 + strlen (hostname) + strlen (path) + datalen
+ sizeof ("POST HTTP/1.1");

ud = memory_pool_alloc0 (pool, sizeof (struct lua_http_ud));
ud->L = L;
ud->pool = pool;
ud->s = session;
ud->ev_base = base;
/* Preallocate buffer */
ud->req_buf = memory_pool_alloc (pool, s);
ud->callback = NULL;
ud->cbref = cbref;

/* Print request */
r = rspamd_snprintf (ud->req_buf, s, "%s %s HTTP/1.1" CRLF
"Connection: close" CRLF,
(data != NULL) ? "POST" : "GET", path);
if (datalen > 0) {
r += rspamd_snprintf (ud->req_buf + r, s - r, "Content-Length: %d" CRLF, datalen);
}
/* Now assume that we have a table with headers at the top of the stack */

if (lua_gettop (L) > top && lua_istable (L, top + 1)) {
/* Add headers */
lua_pushnil (L); /* first key */
while (lua_next (L, top + 1) != 0) {
r += rspamd_snprintf (ud->req_buf + r, s - r, "%s: %s" CRLF, lua_tostring (L, -2), lua_tostring (L, -1));
lua_pop (L, 1);
}
}
/* Now check port and timeout */
if (lua_gettop (L) > top + 1) {
ud->port = lua_tonumber (L, top + 2);
}
else {
ud->port = 80;
}
if (lua_gettop (L) > top + 2) {
ud->timeout = lua_tonumber (L, top + 3);
}
else {
/* Assume default timeout as 1000 msec */
ud->timeout = 1000;
}

if (datalen > 0) {
r += rspamd_snprintf (ud->req_buf + r, s - r, CRLF "%s", data);
}
else {
r += rspamd_snprintf (ud->req_buf + r, s - r, CRLF);
}

ud->req_len = r;

if (inet_aton (hostname, &ina) == 0) {
msg_err ("%s is not valid ip address", hostname);
luaL_unref (L, LUA_REGISTRYINDEX, cbref);
lua_pushnil (L);
return 1;
}

ud->fd = make_tcp_socket (&ina, ud->port, FALSE, TRUE);

if (ud->fd == -1) {
luaL_unref (L, LUA_REGISTRYINDEX, cbref);
lua_pushnil (L);
return 1;
}

/* Create dispatcher for HTTP protocol */
msec_to_tv (ud->timeout, &tv);
ud->io_dispatcher = rspamd_create_dispatcher (ud->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
lua_http_err_cb, &tv, ud);
/* Write request */
register_async_event (ud->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));

if (!rspamd_dispatcher_write (ud->io_dispatcher, ud->req_buf, ud->req_len, TRUE, TRUE)) {
luaL_unref (L, LUA_REGISTRYINDEX, cbref);
lua_pushnil (L);
return 1;
}

return 0;
}


/*
* Typical usage:
* rspamd_http.post_request(task, 'callback', 'hostname', 'path', 'data'[, headers -> { name = 'value' }])
@@ -383,21 +521,55 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha
static gint
lua_http_make_post_request (lua_State *L)
{
struct worker_task *task = lua_check_task (L);
struct worker_task *task, **ptask;
memory_pool_t *pool, **ppool;
struct rspamd_async_session *session, **psession;
struct event_base *base, **pbase;
const gchar *hostname, *path, *data, *callback;
gint cbref;


/* Check whether we have a task object */
ptask = lua_check_class (L, 1, "rspamd{task}");
task = ptask ? *(ptask) : NULL;

if (!task) {
psession = luaL_checkudata (L, 1, "rspamd{session}");
luaL_argcheck (L, psession != NULL, 1, "'session' expected");
session = psession ? *(psession) : NULL;
ppool = luaL_checkudata (L, 2, "rspamd{mempool}");
luaL_argcheck (L, ppool != NULL, 2, "'mempool' expected");
pool = ppool ? *(ppool) : NULL;
pbase = luaL_checkudata (L, 3, "rspamd{ev_base}");
luaL_argcheck (L, ppool != NULL, 3, "'ev_base' expected");
base = pbase ? *(pbase) : NULL;
}

/* Now extract hostname, path and data */

callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
data = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 5));
if (task) {
callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
data = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 5));

if (callback != NULL && hostname != NULL && path != NULL && data != NULL) {
return lua_http_make_request_common (L, task, callback, hostname, path, data, 5);
if (callback != NULL && hostname != NULL && path != NULL && data != NULL) {
return lua_http_make_request_common (L, task, callback, hostname, path, data, 5);
}
else {
msg_info ("invalid arguments number");
}
}
else {
msg_info ("invalid arguments number");
/* Common version */
hostname = memory_pool_strdup (pool, luaL_checkstring (L, 4));
path = memory_pool_strdup (pool, luaL_checkstring (L, 5));
data = memory_pool_strdup (pool, luaL_checkstring (L, 6));
if (session != NULL && pool != NULL && hostname != NULL && path != NULL && data != NULL && lua_isfunction (L, 7)) {
lua_pushvalue (L, 7);
cbref = luaL_ref (L, LUA_REGISTRYINDEX);
return lua_http_make_request_common_new (L, session, pool, base, cbref, hostname, path, data, 7);
}
}

return 0;
@@ -410,20 +582,53 @@ lua_http_make_post_request (lua_State *L)
static gint
lua_http_make_get_request (lua_State *L)
{
struct worker_task *task = lua_check_task (L);
struct worker_task *task, **ptask;
memory_pool_t *pool, **ppool;
struct rspamd_async_session *session, **psession;
struct event_base *base, **pbase;
const gchar *hostname, *path, *callback;
gint cbref;


/* Check whether we have a task object */
ptask = lua_check_class (L, 1, "rspamd{task}");
task = ptask ? *(ptask) : NULL;

if (!task) {
psession = luaL_checkudata (L, 1, "rspamd{session}");
luaL_argcheck (L, psession != NULL, 1, "'session' expected");
session = psession ? *(psession) : NULL;
ppool = luaL_checkudata (L, 2, "rspamd{mempool}");
luaL_argcheck (L, ppool != NULL, 2, "'mempool' expected");
pool = ppool ? *(ppool) : NULL;
pbase = luaL_checkudata (L, 3, "rspamd{ev_base}");
luaL_argcheck (L, ppool != NULL, 3, "'ev_base' expected");
base = pbase ? *(pbase) : NULL;
}

/* Now extract hostname, path and data */

callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
if (task) {
callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));

if (callback != NULL && hostname != NULL && path != NULL) {
return lua_http_make_request_common (L, task, callback, hostname, path, NULL, 4);
if (callback != NULL && hostname != NULL && path != NULL) {
return lua_http_make_request_common (L, task, callback, hostname, path, NULL, 4);
}
else {
msg_info ("invalid arguments number");
}
}
else {
msg_info ("invalid arguments number");
/* Common version */
hostname = memory_pool_strdup (pool, luaL_checkstring (L, 4));
path = memory_pool_strdup (pool, luaL_checkstring (L, 5));
if (session != NULL && pool != NULL && hostname != NULL && path != NULL && lua_isfunction (L, 6)) {
lua_pushvalue (L, 6);
cbref = luaL_ref (L, LUA_REGISTRYINDEX);
return lua_http_make_request_common_new (L, session, pool, base, cbref, hostname, path, NULL, 6);
}
}

return 0;

+ 6
- 4
src/lua/lua_session.c Zobrazit soubor

@@ -38,7 +38,7 @@ static const struct luaL_reg sessionlib_m[] = {
LUA_INTERFACE_DEF (session, register_async_event),
LUA_INTERFACE_DEF (session, remove_normal_event),
LUA_INTERFACE_DEF (session, check_session_pending),
{"__gc", lua_session_delete},
LUA_INTERFACE_DEF (session, delete),
{"__tostring", lua_class_tostring},
{NULL, NULL}
};
@@ -89,7 +89,7 @@ static gboolean
lua_session_finalizer (gpointer ud)
{
struct lua_session_udata *cbdata = ud;
gboolean need_unlock = FALSE;
gboolean need_unlock = FALSE, res;

/* Avoid LOR here as mutex can be acquired before in lua_call */
if (g_mutex_trylock (lua_mtx)) {
@@ -98,15 +98,17 @@ lua_session_finalizer (gpointer ud)

/* Call finalizer function */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_fin);
if (lua_pcall (cbdata->L, 0, 0, 0) != 0) {
if (lua_pcall (cbdata->L, 0, 1, 0) != 0) {
msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
}
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_fin);
if (need_unlock) {
g_mutex_unlock (lua_mtx);
}

return TRUE;
return res;
}

static void

+ 6
- 2
src/lua_worker.c Zobrazit soubor

@@ -225,9 +225,12 @@ static int
lua_worker_get_resolver (lua_State *L)
{
struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
struct rspamd_dns_resolver **presolver;

if (ctx) {
/* XXX: implement resolver API */
presolver = lua_newuserdata (L, sizeof (gpointer));
lua_setclass (L, "rspamd{resolver}", -1);
*presolver = ctx->resolver;
}
else {
lua_pushnil (L);
@@ -460,6 +463,8 @@ start_lua_worker (struct rspamd_worker *worker)
event_base_set (ctx->ev_base, &worker->bind_ev);
event_add (&worker->bind_ev, NULL);

ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);

/* Open worker's lib */
luaopen_lua_worker (L);

@@ -489,7 +494,6 @@ start_lua_worker (struct rspamd_worker *worker)

/* Maps events */
start_map_watch (ctx->ev_base);
ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);

event_base_loop (ctx->ev_base, 0);
luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_accept);

Načítá se…
Zrušit
Uložit