]> source.dussan.org Git - rspamd.git/commitdiff
Rework lua_http.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 21 Aug 2014 16:14:00 +0000 (17:14 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 21 Aug 2014 16:14:00 +0000 (17:14 +0100)
src/lua/lua_http.c

index 8e6617ced589c3a2081e1ec5241454f1bc001218..7f44d8615eff83483ede11e564ef3b90b304840c 100644 (file)
 
 #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