From ee9e4a0db4a826731ed7f548ad1f7760f502d88b Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 21 Aug 2014 17:14:00 +0100 Subject: [PATCH] Rework lua_http. --- src/lua/lua_http.c | 827 +++++++++++++-------------------------------- 1 file changed, 230 insertions(+), 597 deletions(-) diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c index 8e6617ced..7f44d8615 100644 --- a/src/lua/lua_http.c +++ b/src/lua/lua_http.c @@ -28,697 +28,330 @@ #define MAX_HEADERS_SIZE 8192 -LUA_FUNCTION_DEF (http, make_post_request); -LUA_FUNCTION_DEF (http, make_get_request); +LUA_FUNCTION_DEF (http, request); static const struct luaL_reg httplib_m[] = { - LUA_INTERFACE_DEF (http, make_post_request), - LUA_INTERFACE_DEF (http, make_get_request), + LUA_INTERFACE_DEF (http, request), {"__tostring", rspamd_lua_class_tostring}, {NULL, NULL} }; -struct lua_http_header { - gchar *name; - gchar *value; -}; - -struct lua_http_ud { - struct rspamd_task *task; - gint parser_state; - struct rspamd_async_session *s; - rspamd_mempool_t *pool; - struct rspamd_dns_resolver *resolver; - struct event_base *ev_base; +struct lua_http_cbdata { lua_State *L; - const gchar *callback; + struct rspamd_http_connection *conn; + struct rspamd_async_session *session; + struct rspamd_http_message *msg; + struct event_base *ev_base; + struct timeval tv; + rspamd_inet_addr_t addr; gint cbref; - gchar *req_buf; - gint req_len; - gint port; - gint timeout; - gint code; - gint fd; - rspamd_io_dispatcher_t *io_dispatcher; - gint rep_len; - time_t date; - GList *headers; }; -static void -lua_http_fin (void *arg) +static const int default_http_timeout = 5000; + +static struct rspamd_dns_resolver * +lua_http_global_resolver (struct event_base *ev_base) { - struct lua_http_ud *ud = arg; + static struct rspamd_dns_resolver *global_resolver; - if (ud->callback == NULL) { - /* Unref callback */ - luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref); + if (global_resolver == NULL) { + global_resolver = dns_resolver_init (NULL, ev_base, NULL); } - rspamd_remove_dispatcher (ud->io_dispatcher); - close (ud->fd); + + return global_resolver; } static void -lua_http_push_error (gint code, struct lua_http_ud *ud) +lua_http_fin (gpointer arg) { - struct rspamd_task **ptask; - gint num; - - /* Push error */ - if (ud->callback) { - lua_getglobal (ud->L, ud->callback); - ptask = lua_newuserdata (ud->L, sizeof (struct rspamd_task *)); - rspamd_lua_setclass (ud->L, "rspamd{task}", -1); - *ptask = ud->task; - num = 4; - } - else { - lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref); - num = 3; - } + struct lua_http_cbdata *cbd = (struct lua_http_cbdata *)arg; - /* Code */ - lua_pushnumber (ud->L, code); - /* Headers */ - lua_pushnil (ud->L); - /* Reply */ - lua_pushnil (ud->L); - 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)); + luaL_unref (cbd->L, LUA_REGISTRYINDEX, cbd->cbref); + if (cbd->conn) { + /* Here we already have a connection, so we need to unref it */ + rspamd_http_connection_unref (cbd->conn); } - - if (ud->headers != NULL) { - g_list_free (ud->headers); - ud->headers = NULL; + else if (cbd->msg != NULL) { + /* We need to free message */ + rspamd_http_message_free (cbd->msg); } - ud->parser_state = 3; - remove_normal_event (ud->s, lua_http_fin, ud); - + g_slice_free1 (sizeof (struct lua_http_cbdata), cbd); } static void -lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud) +lua_http_maybe_free (struct lua_http_cbdata *cbd) { - GList *cur; - struct lua_http_header *header; - struct rspamd_task **ptask; - gint num; - - if (ud->callback) { - /* Push error */ - lua_getglobal (ud->L, ud->callback); - ptask = lua_newuserdata (ud->L, sizeof (struct rspamd_task *)); - rspamd_lua_setclass (ud->L, "rspamd{task}", -1); - - *ptask = ud->task; - num = 4; + if (cbd->session) { + remove_normal_event (cbd->session, lua_http_fin, cbd); } else { - lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref); - num = 3; - } - /* Code */ - lua_pushnumber (ud->L, ud->code); - /* Headers */ - lua_newtable (ud->L); - cur = ud->headers; - - while (cur) { - header = cur->data; - lua_pushstring (ud->L, header->name); - lua_pushstring (ud->L, header->value); - lua_settable (ud->L, -3); - cur = g_list_next (cur); - } - /* Reply */ - lua_pushlstring (ud->L, in->begin, in->len); - - /* Date */ - if (ud->date != (time_t)-1) { - num++; - lua_pushnumber (ud->L, ud->date); - } - - 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) { - g_list_free (ud->headers); - ud->headers = NULL; + lua_http_fin (cbd); } - - remove_normal_event (ud->s, lua_http_fin, ud); - } -/* - * Parsing utils - */ -static gboolean -lua_http_parse_first_line (struct lua_http_ud *ud, f_str_t *in) +static void +lua_http_push_error (struct lua_http_cbdata *cbd, const char *err) { - const gchar *p; + lua_rawgeti (cbd->L, LUA_REGISTRYINDEX, cbd->cbref); + lua_pushstring (cbd->L, err); - /* Assume first line is like this: HTTP/1.1 200 OK */ - if (in->len < sizeof ("HTTP/1.1 OK") + 2) { - msg_info ("bad http string: %V", in); - return FALSE; + if (lua_pcall (cbd->L, 1, 0, 0) != 0) { + msg_info ("callback call failed: %s", lua_tostring (cbd->L, -1)); } - - p = in->begin + sizeof("HTTP/1.1 ") - 1; - ud->code = strtoul (p, NULL, 10); - - ud->parser_state = 1; - return TRUE; } -static gboolean -lua_http_parse_header_line (struct lua_http_ud *ud, f_str_t *in) +static void +lua_http_error_handler (struct rspamd_http_connection *conn, GError *err) { - const gchar *p = in->begin; - struct lua_http_header *new; - - while (p < in->begin + in->len) { - if (*p == ':') { - break; - } - p++; - } + struct lua_http_cbdata *cbd = (struct lua_http_cbdata *)conn->ud; - if (*p != ':') { - return FALSE; - } - /* Copy name */ - new = rspamd_mempool_alloc (ud->pool, sizeof (struct lua_http_header)); - new->name = rspamd_mempool_alloc (ud->pool, p - in->begin + 1); - rspamd_strlcpy (new->name, in->begin, p - in->begin + 1); - - p++; - /* Copy value */ - while (p < in->begin + in->len && g_ascii_isspace (*p)) { - p++; - } - new->value = rspamd_mempool_alloc (ud->pool, in->begin + in->len - p + 1); - rspamd_strlcpy (new->value, p, in->begin + in->len - p + 1); + lua_http_push_error (cbd, err->message); + lua_http_maybe_free (cbd); +} - /* Check content-length */ - if (ud->rep_len == 0 && - g_ascii_strcasecmp (new->name, "content-length") == 0) { - ud->rep_len = strtoul (new->value, NULL, 10); +static int +lua_http_finish_handler (struct rspamd_http_connection *conn, + struct rspamd_http_message *msg) +{ + struct lua_http_cbdata *cbd = (struct lua_http_cbdata *)conn->ud; + struct rspamd_http_header *h; + + lua_rawgeti (cbd->L, LUA_REGISTRYINDEX, cbd->cbref); + /* Error */ + lua_pushnil (cbd->L); + /* Reply code */ + lua_pushinteger (cbd->L, msg->code); + /* Body */ + lua_pushlstring (cbd->L, msg->body->str, msg->body->len); + /* Headers */ + lua_newtable (cbd->L); + LL_FOREACH (msg->headers, h) { + rspamd_lua_table_set (cbd->L, h->name->str, h->value->str); } - - /* Check date */ - if (g_ascii_strcasecmp (new->name, "date") == 0) { - ud->date = rspamd_http_parse_date (new->value, -1); + if (lua_pcall (cbd->L, 4, 0, 0) != 0) { + msg_info ("callback call failed: %s", lua_tostring (cbd->L, -1)); } - /* Insert a header to the list */ - ud->headers = g_list_prepend (ud->headers, new); + lua_http_maybe_free (cbd); - return TRUE; + return 0; } -/* Read callback */ static gboolean -lua_http_read_cb (f_str_t * in, void *arg) +lua_http_make_connection (struct lua_http_cbdata *cbd) { - struct lua_http_ud *ud = arg; - - switch (ud->parser_state) { - case 0: - /* Parse first line */ - return lua_http_parse_first_line (ud, in); - case 1: - if (ud->code != 200) { - lua_http_push_error (ud->code, ud); - return FALSE; - } - /* Parse header */ - if (in->len == 0) { - /* Final line */ - if (ud->rep_len == 0) { - /* No content-length */ - msg_info ("http reply contains no content-length header"); - lua_http_push_error (450, ud); - return FALSE; - } - else { - ud->parser_state = 2; - rspamd_set_dispatcher_policy (ud->io_dispatcher, - BUFFER_CHARACTER, - ud->rep_len); - } - } - else { - return lua_http_parse_header_line (ud, in); - } - break; - case 2: - /* Get reply */ - lua_http_push_reply (in, ud); + int fd; + + rspamd_inet_address_set_port (&cbd->addr, cbd->msg->port); + fd = rspamd_inet_address_connect (&cbd->addr, SOCK_STREAM, TRUE); + + if (fd == -1) { + lua_http_maybe_free (cbd); return FALSE; } + cbd->conn = rspamd_http_connection_new (NULL, lua_http_error_handler, + lua_http_finish_handler, RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT); + + rspamd_http_connection_write_message (cbd->conn, cbd->msg, + NULL, NULL, cbd, fd, &cbd->tv, cbd->ev_base); + /* Message is now owned by a connection object */ + cbd->msg = NULL; return TRUE; } static void -lua_http_err_cb (GError * err, void *arg) +lua_http_dns_handler (struct rdns_reply *reply, gpointer ud) { - struct lua_http_ud *ud = arg; - msg_info ("abnormally closing connection to http server error: %s", - err->message); - g_error_free (err); + struct lua_http_cbdata *cbd = (struct lua_http_cbdata *)ud; - if (ud->parser_state != 3) { - lua_http_push_error (500, ud); + if (reply->code != RDNS_RC_NOERROR) { + lua_http_push_error (cbd, "unable to resolve host"); + lua_http_maybe_free (cbd); } else { - remove_normal_event (ud->s, lua_http_fin, ud); + /* XXX: support ipv6 some day */ + cbd->addr.af = AF_INET; + memcpy (&cbd->addr.addr.s4.sin_addr, &reply->entries->content.a.addr, + sizeof (struct in_addr)); + if (!lua_http_make_connection (cbd)) { + lua_http_push_error (cbd, "unable to make connection to the host"); + lua_http_maybe_free (cbd); + } } } - - static void -lua_http_dns_callback (struct rdns_reply *reply, gpointer arg) +lua_http_push_headers (lua_State *L, struct rspamd_http_message *msg) { - struct lua_http_ud *ud = arg; - struct rdns_reply_entry *elt; - struct in_addr ina; - struct timeval tv; - - if (reply->code != RDNS_RC_NOERROR) { - lua_http_push_error (450, ud); - return; - } - - /* Create socket to server */ - elt = reply->entries; - memcpy (&ina, &elt->content.a.addr, sizeof (struct in_addr)); + const char *name, *value; - ud->fd = make_universal_socket (inet_ntoa ( - ina), ud->port, SOCK_STREAM, TRUE, FALSE, FALSE); + lua_pushnil (L); + while (lua_next (L, -2) != 0) { - if (ud->fd == -1) { - lua_http_push_error (450, ud); - return; - } + name = rspamd_lua_table_get (L, "name"); + value = rspamd_lua_table_get (L, "value"); - /* 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)) { - lua_http_push_error (450, ud); - return; + if (name != NULL && value != NULL) { + rspamd_http_message_add_header (msg, name, value); + } + lua_pop (L, 1); } + lua_pop (L, 1); } -/** - * Common request function - */ static gint -lua_http_make_request_common (lua_State *L, - struct rspamd_task *task, - const gchar *callback, - const gchar *hostname, - const gchar *path, - const gchar *data, - gint top) +lua_http_request (lua_State *L) { - gint r, s, datalen; - struct lua_http_ud *ud; - - /* 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 = rspamd_mempool_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 = rspamd_mempool_alloc (task->task_pool, s); - ud->callback = callback; - - /* Print request */ - r = rspamd_snprintf (ud->req_buf, s, "%s %s HTTP/1.1" CRLF - "Connection: close" CRLF - "Host: %s" CRLF, - (data != NULL) ? "POST" : "GET", path, hostname); - 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); + const gchar *url; + gint cbref; + struct event_base *ev_base; + struct rspamd_http_message *msg; + struct lua_http_cbdata *cbd; + struct rspamd_dns_resolver *resolver; + struct rspamd_async_session *session; + gdouble timeout = default_http_timeout; + + if (lua_gettop (L) >= 2) { + /* url, callback and event_base format */ + url = luaL_checkstring (L, 1); + if (url == NULL || lua_type (L, 2) != LUA_TFUNCTION) { + msg_err ("http request has bad params"); + lua_pushboolean (L, FALSE); + return 1; + } + lua_pushvalue (L, 2); + cbref = luaL_ref (L, LUA_REGISTRYINDEX); + if (lua_gettop (L) >= 3 && luaL_checkudata (L, 3, "rspamd{ev_base}")) { + ev_base = *(struct event_base **)lua_touserdata (L, 3); + } + else { + ev_base = NULL; + } + if (lua_gettop (L) >= 4 && luaL_checkudata (L, 4, "rspamd{resolver}")) { + resolver = *(struct rspamd_dns_resolver **)lua_touserdata (L, 4); + } + else { + resolver = lua_http_global_resolver (ev_base); + } + if (lua_gettop (L) >= 5 && luaL_checkudata (L, 5, "rspamd{session}")) { + session = *(struct rspamd_async_session **)lua_touserdata (L, 5); + } + else { + session = NULL; + } + msg = rspamd_http_message_from_url (url); + if (msg == NULL) { + lua_pushboolean (L, FALSE); + return 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; - - /* Resolve hostname */ - if (make_dns_request (task->resolver, task->s, task->task_pool, - lua_http_dns_callback, ud, - RDNS_REQUEST_A, hostname)) { - task->dns_requests++; - } - - return 0; -} - -/** - * Common request function (new version) - */ -static gint -lua_http_make_request_common_new (lua_State *L, - struct rspamd_async_session *session, - rspamd_mempool_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; + else if (lua_type (L, 1) == LUA_TTABLE) { + lua_pushstring (L, "url"); + lua_gettable (L, -2); + url = luaL_checkstring (L, -1); + lua_pop (L, 1); - /* 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 = rspamd_mempool_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 = rspamd_mempool_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_pushstring (L, "callback"); + lua_gettable (L, -2); + if (url == NULL || lua_type (L, -1) != LUA_TFUNCTION) { lua_pop (L, 1); + msg_err ("http request has bad params"); + lua_pushboolean (L, FALSE); + return 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_universal_socket (inet_ntoa ( - ina), ud->port, SOCK_STREAM, TRUE, FALSE, FALSE); - - if (ud->fd == -1) { - luaL_unref (L, LUA_REGISTRYINDEX, cbref); - lua_pushnil (L); - return 1; - } + cbref = luaL_ref (L, LUA_REGISTRYINDEX); - /* 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; -} + lua_pushstring (L, "ev_base"); + lua_gettable (L, -2); + if (luaL_checkudata (L, -1, "rspamd{ev_base}")) { + ev_base = *(struct event_base **)lua_touserdata (L, -1); + } + else { + ev_base = NULL; + } + lua_pop (L, 1); + lua_pushstring (L, "resolver"); + lua_gettable (L, -2); + if (luaL_checkudata (L, -1, "rspamd{resolver}")) { + resolver = *(struct rspamd_dns_resolver **)lua_touserdata (L, -1); + } + else { + resolver = lua_http_global_resolver (ev_base); + } + lua_pop (L, 1); -/* - * Typical usage: - * rspamd_http.post_request(task, 'callback', 'hostname', 'path', 'data'[, headers -> { name = 'value' }]) - */ -static gint -lua_http_make_post_request (lua_State *L) -{ - struct rspamd_task *task, **ptask; - rspamd_mempool_t *pool, **ppool; - struct rspamd_async_session *session, **psession; - struct event_base *base, **pbase; - const gchar *hostname, *path, *data, *callback; - gint cbref; + lua_pushstring (L, "session"); + lua_gettable (L, -2); + if (luaL_checkudata (L, -1, "rspamd{session}")) { + session = *(struct rspamd_async_session **)lua_touserdata (L, -1); + } + else { + session = NULL; + } + lua_pop (L, 1); + msg = rspamd_http_message_from_url (url); + if (msg == NULL) { + lua_pushboolean (L, FALSE); + return 1; + } - /* Check whether we have a task object */ - ptask = rspamd_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; - } + lua_pushstring (L, "headers"); + lua_gettable (L, -2); + if (lua_type (L, -1) == LUA_TTABLE) { + lua_http_push_headers (L, msg); + } + lua_pop (L, 1); - /* Now extract hostname, path and data */ - - if (task) { - callback = - rspamd_mempool_strdup (task->task_pool, luaL_checkstring (L, 2)); - hostname = - rspamd_mempool_strdup (task->task_pool, luaL_checkstring (L, 3)); - path = rspamd_mempool_strdup (task->task_pool, luaL_checkstring (L, 4)); - data = rspamd_mempool_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); + lua_pushstring (L, "timeout"); + lua_gettable (L, -2); + if (lua_type (L, -1) == LUA_TNUMBER) { + timeout = lua_tonumber (L, -1) * 1000.; } - else { - msg_info ("invalid arguments number"); + lua_pop (L, 1); + + lua_pushstring (L, "body"); + lua_gettable (L, -2); + if (lua_type (L, -1) == LUA_TSTRING) { + msg->body = g_string_new (lua_tostring (L, -1)); } + lua_pop (L, 1); } else { - /* Common version */ - hostname = rspamd_mempool_strdup (pool, luaL_checkstring (L, 4)); - path = rspamd_mempool_strdup (pool, luaL_checkstring (L, 5)); - data = rspamd_mempool_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); - } + msg_err ("http request has bad params"); + lua_pushboolean (L, FALSE); + return 1; } - return 0; -} - -/* - * Typical usage: - * rspamd_http.get_request(task, 'callback', 'hostname', 'path'[, headers -> { name = 'value' }]) - */ -static gint -lua_http_make_get_request (lua_State *L) -{ - struct rspamd_task *task, **ptask; - rspamd_mempool_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 = rspamd_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; + cbd = g_slice_alloc0 (sizeof (*cbd)); + cbd->L = L; + cbd->cbref = cbref; + cbd->msg = msg; + msec_to_tv (timeout, &cbd->tv); + if (session) { + register_async_event (session, + (event_finalizer_t)lua_http_fin, + cbd, + g_quark_from_static_string ("lua http")); } - /* Now extract hostname, path and data */ - - if (task) { - callback = - rspamd_mempool_strdup (task->task_pool, luaL_checkstring (L, 2)); - hostname = - rspamd_mempool_strdup (task->task_pool, luaL_checkstring (L, 3)); - path = rspamd_mempool_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); - } - else { - msg_info ("invalid arguments number"); + if (rspamd_parse_inet_address (&cbd->addr, msg->host->str)) { + /* Host is numeric IP, no need to resolve */ + if (!lua_http_make_connection (cbd)) { + lua_pushboolean (L, FALSE); + return 1; } } else { - /* Common version */ - hostname = rspamd_mempool_strdup (pool, luaL_checkstring (L, 4)); - path = rspamd_mempool_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); - } + make_dns_request (resolver, session, NULL, lua_http_dns_handler, cbd, + RDNS_REQUEST_A, msg->host->str); } - return 0; + lua_pushboolean (L, TRUE); + return 1; } gint -- 2.39.5