#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