mirror of
https://github.com/haproxy/haproxy.git
synced 2026-06-13 19:00:25 -04:00
REORG: httpclient/lua: move the lua httpclient code to http_client.c
Some checks are pending
Contrib / admin/halog/ (push) Waiting to run
Contrib / dev/flags/ (push) Waiting to run
Contrib / dev/haring/ (push) Waiting to run
Contrib / dev/hpack/ (push) Waiting to run
Contrib / dev/poll/ (push) Waiting to run
FreeBSD / clang (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Some checks are pending
Contrib / admin/halog/ (push) Waiting to run
Contrib / dev/flags/ (push) Waiting to run
Contrib / dev/haring/ (push) Waiting to run
Contrib / dev/hpack/ (push) Waiting to run
Contrib / dev/poll/ (push) Waiting to run
FreeBSD / clang (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Move the lua httpclient code from hlua.c to http_client.c The code is almost the same but the registering of the class which is done in hlua_http_client_init_state(), from REGISTER_HLUA_STATE_INIT() check_args() calls have been replaced by hlua_check_args(). hlua_httpclient_destroy_all() is exported so it can be called in hlua.c. hlua_httpclient_table_to_hdrs() is made static.
This commit is contained in:
parent
974560128d
commit
339d25636d
3 changed files with 560 additions and 536 deletions
|
|
@ -38,4 +38,9 @@ static inline int httpclient_started(struct httpclient *hc)
|
|||
return !!(hc->flags & HTTPCLIENT_FS_STARTED);
|
||||
}
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include <haproxy/hlua-t.h>
|
||||
void hlua_httpclient_destroy_all(struct hlua *hlua);
|
||||
#endif
|
||||
|
||||
#endif /* !_HAPROXY_HTTPCLIENT_H */
|
||||
|
|
|
|||
536
src/hlua.c
536
src/hlua.c
|
|
@ -510,7 +510,6 @@ static int class_fetches_ref;
|
|||
static int class_converters_ref;
|
||||
static int class_http_ref;
|
||||
static int class_http_msg_ref;
|
||||
static int class_httpclient_ref;
|
||||
static int class_map_ref;
|
||||
static int class_applet_tcp_ref;
|
||||
static int class_applet_http_ref;
|
||||
|
|
@ -1787,34 +1786,6 @@ int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* kill all associated httpclient to this hlua task
|
||||
* We must take extra precautions as we're manipulating lua-exposed
|
||||
* objects without the main lua lock.
|
||||
*/
|
||||
static void hlua_httpclient_destroy_all(struct hlua *hlua)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
|
||||
/* use thread-safe accessors for hc_list since GC cycle initiated by
|
||||
* another thread sharing the same main lua stack (lua coroutine)
|
||||
* could execute hlua_httpclient_gc() on the hlua->hc_list items
|
||||
* in parallel: Lua GC applies on the main stack, it is not limited to
|
||||
* a single coroutine stack, see Github issue #2037 for reference.
|
||||
* Remember, coroutines created using lua_newthread() are not meant to
|
||||
* be thread safe in Lua. (From lua co-author:
|
||||
* http://lua-users.org/lists/lua-l/2011-07/msg00072.html)
|
||||
*
|
||||
* This security measure is superfluous when 'lua-load-per-thread' is used
|
||||
* since in this case coroutines exclusively run on the same thread
|
||||
* (main stack is not shared between OS threads).
|
||||
*/
|
||||
while ((hlua_hc = MT_LIST_POP(&hlua->hc_list, typeof(hlua_hc), by_hlua))) {
|
||||
httpclient_stop_and_destroy(hlua_hc->hc);
|
||||
hlua_hc->hc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Used to destroy the Lua coroutine when the attached stream or task
|
||||
* is destroyed. The destroy also the memory context. The struct "lua"
|
||||
* will be freed.
|
||||
|
|
@ -7954,488 +7925,6 @@ __LJMP static int hlua_http_msg_unset_eom(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Class HTTPClient
|
||||
*
|
||||
*
|
||||
*/
|
||||
__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
|
||||
{
|
||||
return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
|
||||
}
|
||||
|
||||
|
||||
/* stops the httpclient and ask it to kill itself */
|
||||
__LJMP static int hlua_httpclient_gc(lua_State *L)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "__gc"));
|
||||
|
||||
hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
|
||||
|
||||
if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
|
||||
/* we won the race against hlua_httpclient_destroy_all() */
|
||||
httpclient_stop_and_destroy(hlua_hc->hc);
|
||||
hlua_hc->hc = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__LJMP static int hlua_httpclient_new(lua_State *L)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
struct hlua *hlua;
|
||||
|
||||
/* Get hlua struct, or NULL if we execute from main lua state */
|
||||
hlua = hlua_gethlua(L);
|
||||
if (!hlua)
|
||||
return 0;
|
||||
|
||||
/* Check stack size. */
|
||||
if (!lua_checkstack(L, 3)) {
|
||||
hlua_pusherror(L, "httpclient: full stack");
|
||||
goto err;
|
||||
}
|
||||
/* Create the object: obj[0] = userdata. */
|
||||
lua_newtable(L);
|
||||
hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
|
||||
lua_rawseti(L, -2, 0);
|
||||
memset(hlua_hc, 0, sizeof(*hlua_hc));
|
||||
|
||||
hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
|
||||
if (!hlua_hc->hc)
|
||||
goto err;
|
||||
|
||||
MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
|
||||
|
||||
/* Pop a class stream metatable and affect it to the userdata. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
WILL_LJMP(lua_error(L));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callback of the httpclient, this callback wakes the lua task up, once the
|
||||
* httpclient receives some data
|
||||
*
|
||||
*/
|
||||
|
||||
static void hlua_httpclient_cb(struct httpclient *hc)
|
||||
{
|
||||
struct hlua *hlua = hc->caller;
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
return;
|
||||
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the lua stack with headers from the httpclient response
|
||||
* This works the same way as the hlua_http_get_headers() function
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
|
||||
{
|
||||
struct http_hdr *hdr;
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
|
||||
struct ist n, v;
|
||||
int len;
|
||||
|
||||
n = hdr->n;
|
||||
v = hdr->v;
|
||||
|
||||
/* Check for existing entry:
|
||||
* assume that the table is on the top of the stack, and
|
||||
* push the key in the stack, the function lua_gettable()
|
||||
* perform the lookup.
|
||||
*/
|
||||
|
||||
lua_pushlstring(L, n.ptr, n.len);
|
||||
lua_gettable(L, -2);
|
||||
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TNIL:
|
||||
/* Table not found, create it. */
|
||||
lua_pop(L, 1); /* remove the nil value. */
|
||||
lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
|
||||
lua_newtable(L); /* create and push empty table. */
|
||||
lua_pushlstring(L, v.ptr, v.len); /* push header value. */
|
||||
lua_rawseti(L, -2, 0); /* index header value (pop it). */
|
||||
lua_rawset(L, -3); /* index new table with header name (pop the values). */
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
/* Entry found: push the value in the table. */
|
||||
len = lua_rawlen(L, -1);
|
||||
lua_pushlstring(L, v.ptr, v.len); /* push header value. */
|
||||
lua_rawseti(L, -2, len+1); /* index header value (pop it). */
|
||||
lua_pop(L, 1); /* remove the table (it is stored in the main table). */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Other cases are errors. */
|
||||
hlua_pusherror(L, "internal error during the parsing of headers.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and return an array of http_hdr ist extracted from the <headers> lua table
|
||||
*
|
||||
* Caller must free the result
|
||||
*/
|
||||
struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
|
||||
{
|
||||
struct http_hdr hdrs[global.tune.max_http_hdr];
|
||||
struct http_hdr *result = NULL;
|
||||
uint32_t hdr_num = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
struct ist name, value;
|
||||
const char *n, *v;
|
||||
size_t nlen, vlen;
|
||||
|
||||
if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
|
||||
/* Skip element if the key is not a string or if the value is not a table */
|
||||
goto next_hdr;
|
||||
}
|
||||
|
||||
n = lua_tolstring(L, -2, &nlen);
|
||||
name = ist2(n, nlen);
|
||||
|
||||
/* Loop on header's values */
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2)) {
|
||||
if (!lua_isstring(L, -1)) {
|
||||
/* Skip the value if it is not a string */
|
||||
goto next_value;
|
||||
}
|
||||
|
||||
if (hdr_num >= global.tune.max_http_hdr) {
|
||||
lua_pop(L, 2);
|
||||
goto skip_headers;
|
||||
}
|
||||
|
||||
v = lua_tolstring(L, -1, &vlen);
|
||||
value = ist2(v, vlen);
|
||||
name = ist2(n, nlen);
|
||||
|
||||
hdrs[hdr_num].n = istdup(name);
|
||||
hdrs[hdr_num].v = istdup(value);
|
||||
|
||||
hdr_num++;
|
||||
|
||||
next_value:
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
next_hdr:
|
||||
lua_pop(L, 1);
|
||||
|
||||
}
|
||||
|
||||
if (hdr_num) {
|
||||
/* alloc and copy the headers in the httpclient struct */
|
||||
result = calloc((hdr_num + 1), sizeof(*result));
|
||||
if (!result)
|
||||
goto skip_headers;
|
||||
memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
|
||||
|
||||
result[hdr_num].n = IST_NULL;
|
||||
result[hdr_num].v = IST_NULL;
|
||||
}
|
||||
|
||||
skip_headers:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For each yield, checks if there is some data in the httpclient and push them
|
||||
* in the lua buffer, once the httpclient finished its job, push the result on
|
||||
* the stack
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct buffer *tr;
|
||||
int res;
|
||||
struct hlua *hlua = hlua_gethlua(L);
|
||||
struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
|
||||
|
||||
tr = get_trash_chunk();
|
||||
|
||||
res = httpclient_res_xfer(hlua_hc->hc, tr);
|
||||
luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
|
||||
|
||||
if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
|
||||
|
||||
luaL_pushresult(&hlua_hc->b);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "status");
|
||||
lua_pushinteger(L, hlua_hc->hc->res.status);
|
||||
lua_settable(L, -3);
|
||||
|
||||
|
||||
lua_pushstring(L, "reason");
|
||||
lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "headers");
|
||||
hlua_httpclient_get_headers(L, hlua_hc);
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (httpclient_data(hlua_hc->hc))
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this when trying to stream a body during a request
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct hlua *hlua;
|
||||
struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
const char *body_str = NULL;
|
||||
int ret;
|
||||
int end = 0;
|
||||
size_t buf_len;
|
||||
size_t to_send = 0;
|
||||
|
||||
hlua = hlua_gethlua(L);
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
|
||||
"'frontend', 'backend' or 'task'"));
|
||||
|
||||
ret = lua_getfield(L, -1, "body");
|
||||
if (ret != LUA_TSTRING)
|
||||
goto rcv;
|
||||
|
||||
body_str = lua_tolstring(L, -1, &buf_len);
|
||||
lua_pop(L, 1);
|
||||
|
||||
to_send = buf_len - hlua_hc->sent;
|
||||
|
||||
if ((hlua_hc->sent + to_send) >= buf_len)
|
||||
end = 1;
|
||||
|
||||
/* the end flag is always set since we are using the whole remaining size */
|
||||
hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
|
||||
|
||||
if (buf_len > hlua_hc->sent) {
|
||||
/* still need to process the buffer */
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
|
||||
} else {
|
||||
goto rcv;
|
||||
/* we sent the whole request buffer we can recv */
|
||||
}
|
||||
return 0;
|
||||
|
||||
rcv:
|
||||
|
||||
/* we return a "res" object */
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "body");
|
||||
luaL_buffinit(L, &hlua_hc->b);
|
||||
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP request and wait for a response
|
||||
*/
|
||||
|
||||
__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
struct http_hdr *hdrs = NULL;
|
||||
struct http_hdr *hdrs_i = NULL;
|
||||
struct hlua *hlua;
|
||||
const char *url_str = NULL;
|
||||
const char *body_str = NULL;
|
||||
size_t buf_len = 0;
|
||||
int ret;
|
||||
|
||||
hlua = hlua_gethlua(L);
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
|
||||
"'frontend', 'backend' or 'task'"));
|
||||
|
||||
if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
|
||||
WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
|
||||
|
||||
hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
|
||||
/* An HTTPclient instance must never process more that one request. So
|
||||
* at this stage, it must never have been started.
|
||||
*/
|
||||
if (httpclient_started(hlua_hc->hc))
|
||||
WILL_LJMP(luaL_error(L, "httpclient instance cannot be reused. It must process at most one request"));
|
||||
|
||||
lua_pushnil(L); /* first key */
|
||||
while (lua_next(L, 2)) {
|
||||
if (strcmp(lua_tostring(L, -2), "dst") == 0) {
|
||||
if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
|
||||
WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "url") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TSTRING)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
|
||||
url_str = lua_tostring(L, -1);
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TNUMBER)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
|
||||
httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TTABLE)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
|
||||
hdrs = hlua_httpclient_table_to_hdrs(L);
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "body") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TSTRING)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
|
||||
body_str = lua_tolstring(L, -1, &buf_len);
|
||||
|
||||
} else {
|
||||
WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
|
||||
}
|
||||
/* removes 'value'; keeps 'key' for next iteration */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (!url_str) {
|
||||
WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hlua_hc->sent = 0;
|
||||
|
||||
istfree(&hlua_hc->hc->req.url);
|
||||
hlua_hc->hc->req.url = istdup(ist(url_str));
|
||||
hlua_hc->hc->req.meth = meth;
|
||||
|
||||
/* update the httpclient callbacks */
|
||||
hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
|
||||
|
||||
/* a body is available, it will use the request callback */
|
||||
if (body_str && buf_len) {
|
||||
hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
|
||||
}
|
||||
|
||||
ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
|
||||
|
||||
/* free the temporary headers array */
|
||||
hdrs_i = hdrs;
|
||||
while (hdrs_i && isttest(hdrs_i->n)) {
|
||||
istfree(&hdrs_i->n);
|
||||
istfree(&hdrs_i->v);
|
||||
hdrs_i++;
|
||||
}
|
||||
ha_free(&hdrs);
|
||||
|
||||
|
||||
if (ret != ERR_NONE) {
|
||||
WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!httpclient_start(hlua_hc->hc))
|
||||
WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
|
||||
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends an HTTP HEAD request and wait for a response
|
||||
*
|
||||
* httpclient:head(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_head(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_HEAD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP GET request and wait for a response
|
||||
*
|
||||
* httpclient:get(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_get(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_GET);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends an HTTP PUT request and wait for a response
|
||||
*
|
||||
* httpclient:put(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_put(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_PUT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP POST request and wait for a response
|
||||
*
|
||||
* httpclient:post(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_post(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_POST);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sends an HTTP DELETE request and wait for a response
|
||||
*
|
||||
* httpclient:delete(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_delete(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_DELETE);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
|
|
@ -14342,7 +13831,6 @@ lua_State *hlua_init_state(int thread_num)
|
|||
hlua_class_function(L, "get_patref", hlua_get_patref);
|
||||
hlua_class_function(L, "get_var", hlua_core_get_var);
|
||||
hlua_class_function(L, "tcp", hlua_socket_new);
|
||||
hlua_class_function(L, "httpclient", hlua_httpclient_new);
|
||||
hlua_class_function(L, "event_sub", hlua_event_global_sub);
|
||||
hlua_class_function(L, "log", hlua_log);
|
||||
hlua_class_function(L, "Debug", hlua_log_debug);
|
||||
|
|
@ -14664,30 +14152,6 @@ lua_State *hlua_init_state(int thread_num)
|
|||
/* Register previous table in the registry with reference and named entry. */
|
||||
class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class HTTPClient
|
||||
*
|
||||
*/
|
||||
|
||||
/* Create and fill the metatable. */
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, "__index");
|
||||
lua_newtable(L);
|
||||
hlua_class_function(L, "get", hlua_httpclient_get);
|
||||
hlua_class_function(L, "head", hlua_httpclient_head);
|
||||
hlua_class_function(L, "put", hlua_httpclient_put);
|
||||
hlua_class_function(L, "post", hlua_httpclient_post);
|
||||
hlua_class_function(L, "delete", hlua_httpclient_delete);
|
||||
lua_settable(L, -3); /* Sets the __index entry. */
|
||||
/* Register the garbage collector entry. */
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcclosure(L, hlua_httpclient_gc, 0);
|
||||
lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
|
||||
|
||||
|
||||
|
||||
class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
|
||||
/*
|
||||
*
|
||||
* Register class AppletTCP
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@
|
|||
#include <haproxy/global.h>
|
||||
#include <haproxy/istbuf.h>
|
||||
#include <haproxy/h1_htx.h>
|
||||
#ifdef USE_LUA
|
||||
#include <haproxy/chunk.h>
|
||||
#include <haproxy/hlua.h>
|
||||
#include <haproxy/hlua_fcn.h>
|
||||
#include <haproxy/task.h>
|
||||
#endif
|
||||
#include <haproxy/http.h>
|
||||
#include <haproxy/http_ana-t.h>
|
||||
#include <haproxy/http_client.h>
|
||||
|
|
@ -39,6 +45,10 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_LUA
|
||||
static int class_httpclient_ref; /* httpclient LUA class */
|
||||
#endif
|
||||
|
||||
static struct proxy *httpclient_proxy;
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
|
|
@ -1487,3 +1497,548 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
|||
}};
|
||||
|
||||
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Class HTTPClient
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifdef USE_LUA
|
||||
|
||||
/* kill all associated httpclient to this hlua task
|
||||
* We must take extra precautions as we're manipulating lua-exposed
|
||||
* objects without the main lua lock.
|
||||
*/
|
||||
void hlua_httpclient_destroy_all(struct hlua *hlua)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
|
||||
/* use thread-safe accessors for hc_list since GC cycle initiated by
|
||||
* another thread sharing the same main lua stack (lua coroutine)
|
||||
* could execute hlua_httpclient_gc() on the hlua->hc_list items
|
||||
* in parallel: Lua GC applies on the main stack, it is not limited to
|
||||
* a single coroutine stack, see Github issue #2037 for reference.
|
||||
* Remember, coroutines created using lua_newthread() are not meant to
|
||||
* be thread safe in Lua. (From lua co-author:
|
||||
* http://lua-users.org/lists/lua-l/2011-07/msg00072.html)
|
||||
*
|
||||
* This security measure is superfluous when 'lua-load-per-thread' is used
|
||||
* since in this case coroutines exclusively run on the same thread
|
||||
* (main stack is not shared between OS threads).
|
||||
*/
|
||||
while ((hlua_hc = MT_LIST_POP(&hlua->hc_list, typeof(hlua_hc), by_hlua))) {
|
||||
httpclient_stop_and_destroy(hlua_hc->hc);
|
||||
hlua_hc->hc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
|
||||
{
|
||||
return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
|
||||
}
|
||||
|
||||
|
||||
/* stops the httpclient and ask it to kill itself */
|
||||
__LJMP static int hlua_httpclient_gc(lua_State *L)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
|
||||
MAY_LJMP(hlua_check_args(L, 1, "__gc"));
|
||||
|
||||
hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
|
||||
|
||||
if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
|
||||
/* we won the race against hlua_httpclient_destroy_all() */
|
||||
httpclient_stop_and_destroy(hlua_hc->hc);
|
||||
hlua_hc->hc = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__LJMP static int hlua_httpclient_new(lua_State *L)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
struct hlua *hlua;
|
||||
|
||||
/* Get hlua struct, or NULL if we execute from main lua state */
|
||||
hlua = hlua_gethlua(L);
|
||||
if (!hlua)
|
||||
return 0;
|
||||
|
||||
/* Check stack size. */
|
||||
if (!lua_checkstack(L, 3)) {
|
||||
hlua_pusherror(L, "httpclient: full stack");
|
||||
goto err;
|
||||
}
|
||||
/* Create the object: obj[0] = userdata. */
|
||||
lua_newtable(L);
|
||||
hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
|
||||
lua_rawseti(L, -2, 0);
|
||||
memset(hlua_hc, 0, sizeof(*hlua_hc));
|
||||
|
||||
hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
|
||||
if (!hlua_hc->hc)
|
||||
goto err;
|
||||
|
||||
MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
|
||||
|
||||
/* Pop a class stream metatable and affect it to the userdata. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
WILL_LJMP(lua_error(L));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callback of the httpclient, this callback wakes the lua task up, once the
|
||||
* httpclient receives some data
|
||||
*
|
||||
*/
|
||||
|
||||
static void hlua_httpclient_cb(struct httpclient *hc)
|
||||
{
|
||||
struct hlua *hlua = hc->caller;
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
return;
|
||||
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the lua stack with headers from the httpclient response
|
||||
* This works the same way as the hlua_http_get_headers() function
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
|
||||
{
|
||||
struct http_hdr *hdr;
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
|
||||
struct ist n, v;
|
||||
int len;
|
||||
|
||||
n = hdr->n;
|
||||
v = hdr->v;
|
||||
|
||||
/* Check for existing entry:
|
||||
* assume that the table is on the top of the stack, and
|
||||
* push the key in the stack, the function lua_gettable()
|
||||
* perform the lookup.
|
||||
*/
|
||||
|
||||
lua_pushlstring(L, n.ptr, n.len);
|
||||
lua_gettable(L, -2);
|
||||
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TNIL:
|
||||
/* Table not found, create it. */
|
||||
lua_pop(L, 1); /* remove the nil value. */
|
||||
lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
|
||||
lua_newtable(L); /* create and push empty table. */
|
||||
lua_pushlstring(L, v.ptr, v.len); /* push header value. */
|
||||
lua_rawseti(L, -2, 0); /* index header value (pop it). */
|
||||
lua_rawset(L, -3); /* index new table with header name (pop the values). */
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
/* Entry found: push the value in the table. */
|
||||
len = lua_rawlen(L, -1);
|
||||
lua_pushlstring(L, v.ptr, v.len); /* push header value. */
|
||||
lua_rawseti(L, -2, len+1); /* index header value (pop it). */
|
||||
lua_pop(L, 1); /* remove the table (it is stored in the main table). */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Other cases are errors. */
|
||||
hlua_pusherror(L, "internal error during the parsing of headers.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and return an array of http_hdr ist extracted from the <headers> lua table
|
||||
*
|
||||
* Caller must free the result
|
||||
*/
|
||||
static struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
|
||||
{
|
||||
struct http_hdr hdrs[global.tune.max_http_hdr];
|
||||
struct http_hdr *result = NULL;
|
||||
uint32_t hdr_num = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
struct ist name, value;
|
||||
const char *n, *v;
|
||||
size_t nlen, vlen;
|
||||
|
||||
if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
|
||||
/* Skip element if the key is not a string or if the value is not a table */
|
||||
goto next_hdr;
|
||||
}
|
||||
|
||||
n = lua_tolstring(L, -2, &nlen);
|
||||
name = ist2(n, nlen);
|
||||
|
||||
/* Loop on header's values */
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2)) {
|
||||
if (!lua_isstring(L, -1)) {
|
||||
/* Skip the value if it is not a string */
|
||||
goto next_value;
|
||||
}
|
||||
|
||||
if (hdr_num >= global.tune.max_http_hdr) {
|
||||
lua_pop(L, 2);
|
||||
goto skip_headers;
|
||||
}
|
||||
|
||||
v = lua_tolstring(L, -1, &vlen);
|
||||
value = ist2(v, vlen);
|
||||
name = ist2(n, nlen);
|
||||
|
||||
hdrs[hdr_num].n = istdup(name);
|
||||
hdrs[hdr_num].v = istdup(value);
|
||||
|
||||
hdr_num++;
|
||||
|
||||
next_value:
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
next_hdr:
|
||||
lua_pop(L, 1);
|
||||
|
||||
}
|
||||
|
||||
if (hdr_num) {
|
||||
/* alloc and copy the headers in the httpclient struct */
|
||||
result = calloc((hdr_num + 1), sizeof(*result));
|
||||
if (!result)
|
||||
goto skip_headers;
|
||||
memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
|
||||
|
||||
result[hdr_num].n = IST_NULL;
|
||||
result[hdr_num].v = IST_NULL;
|
||||
}
|
||||
|
||||
skip_headers:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For each yield, checks if there is some data in the httpclient and push them
|
||||
* in the lua buffer, once the httpclient finished its job, push the result on
|
||||
* the stack
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct buffer *tr;
|
||||
int res;
|
||||
struct hlua *hlua = hlua_gethlua(L);
|
||||
struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
|
||||
|
||||
tr = get_trash_chunk();
|
||||
|
||||
res = httpclient_res_xfer(hlua_hc->hc, tr);
|
||||
luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
|
||||
|
||||
if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
|
||||
|
||||
luaL_pushresult(&hlua_hc->b);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "status");
|
||||
lua_pushinteger(L, hlua_hc->hc->res.status);
|
||||
lua_settable(L, -3);
|
||||
|
||||
|
||||
lua_pushstring(L, "reason");
|
||||
lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "headers");
|
||||
hlua_httpclient_get_headers(L, hlua_hc);
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (httpclient_data(hlua_hc->hc))
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this when trying to stream a body during a request
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct hlua *hlua;
|
||||
struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
const char *body_str = NULL;
|
||||
int ret;
|
||||
int end = 0;
|
||||
size_t buf_len;
|
||||
size_t to_send = 0;
|
||||
|
||||
hlua = hlua_gethlua(L);
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
|
||||
"'frontend', 'backend' or 'task'"));
|
||||
|
||||
ret = lua_getfield(L, -1, "body");
|
||||
if (ret != LUA_TSTRING)
|
||||
goto rcv;
|
||||
|
||||
body_str = lua_tolstring(L, -1, &buf_len);
|
||||
lua_pop(L, 1);
|
||||
|
||||
to_send = buf_len - hlua_hc->sent;
|
||||
|
||||
if ((hlua_hc->sent + to_send) >= buf_len)
|
||||
end = 1;
|
||||
|
||||
/* the end flag is always set since we are using the whole remaining size */
|
||||
hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
|
||||
|
||||
if (buf_len > hlua_hc->sent) {
|
||||
/* still need to process the buffer */
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
|
||||
} else {
|
||||
goto rcv;
|
||||
/* we sent the whole request buffer we can recv */
|
||||
}
|
||||
return 0;
|
||||
|
||||
rcv:
|
||||
|
||||
/* we return a "res" object */
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "body");
|
||||
luaL_buffinit(L, &hlua_hc->b);
|
||||
|
||||
task_wakeup(hlua->task, TASK_WOKEN_MSG);
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP request and wait for a response
|
||||
*/
|
||||
|
||||
__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
|
||||
{
|
||||
struct hlua_httpclient *hlua_hc;
|
||||
struct http_hdr *hdrs = NULL;
|
||||
struct http_hdr *hdrs_i = NULL;
|
||||
struct hlua *hlua;
|
||||
const char *url_str = NULL;
|
||||
const char *body_str = NULL;
|
||||
size_t buf_len = 0;
|
||||
int ret;
|
||||
|
||||
hlua = hlua_gethlua(L);
|
||||
|
||||
if (!hlua || !hlua->task)
|
||||
WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
|
||||
"'frontend', 'backend' or 'task'"));
|
||||
|
||||
if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
|
||||
WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
|
||||
|
||||
hlua_hc = hlua_checkhttpclient(L, 1);
|
||||
|
||||
/* An HTTPclient instance must never process more that one request. So
|
||||
* at this stage, it must never have been started.
|
||||
*/
|
||||
if (httpclient_started(hlua_hc->hc))
|
||||
WILL_LJMP(luaL_error(L, "httpclient instance cannot be reused. It must process at most one request"));
|
||||
|
||||
lua_pushnil(L); /* first key */
|
||||
while (lua_next(L, 2)) {
|
||||
if (strcmp(lua_tostring(L, -2), "dst") == 0) {
|
||||
if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
|
||||
WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "url") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TSTRING)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
|
||||
url_str = lua_tostring(L, -1);
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TNUMBER)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
|
||||
httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TTABLE)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
|
||||
hdrs = hlua_httpclient_table_to_hdrs(L);
|
||||
|
||||
} else if (strcmp(lua_tostring(L, -2), "body") == 0) {
|
||||
if (lua_type(L, -1) != LUA_TSTRING)
|
||||
WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
|
||||
body_str = lua_tolstring(L, -1, &buf_len);
|
||||
|
||||
} else {
|
||||
WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
|
||||
}
|
||||
/* removes 'value'; keeps 'key' for next iteration */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (!url_str) {
|
||||
WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hlua_hc->sent = 0;
|
||||
|
||||
istfree(&hlua_hc->hc->req.url);
|
||||
hlua_hc->hc->req.url = istdup(ist(url_str));
|
||||
hlua_hc->hc->req.meth = meth;
|
||||
|
||||
/* update the httpclient callbacks */
|
||||
hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
|
||||
hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
|
||||
|
||||
/* a body is available, it will use the request callback */
|
||||
if (body_str && buf_len) {
|
||||
hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
|
||||
}
|
||||
|
||||
ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
|
||||
|
||||
/* free the temporary headers array */
|
||||
hdrs_i = hdrs;
|
||||
while (hdrs_i && isttest(hdrs_i->n)) {
|
||||
istfree(&hdrs_i->n);
|
||||
istfree(&hdrs_i->v);
|
||||
hdrs_i++;
|
||||
}
|
||||
ha_free(&hdrs);
|
||||
|
||||
|
||||
if (ret != ERR_NONE) {
|
||||
WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!httpclient_start(hlua_hc->hc))
|
||||
WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
|
||||
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends an HTTP HEAD request and wait for a response
|
||||
*
|
||||
* httpclient:head(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_head(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_HEAD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP GET request and wait for a response
|
||||
*
|
||||
* httpclient:get(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_get(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_GET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends an HTTP PUT request and wait for a response
|
||||
*
|
||||
* httpclient:put(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_put(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_PUT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an HTTP POST request and wait for a response
|
||||
*
|
||||
* httpclient:post(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_post(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_POST);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sends an HTTP DELETE request and wait for a response
|
||||
*
|
||||
* httpclient:delete(url, headers, payload)
|
||||
*/
|
||||
__LJMP static int hlua_httpclient_delete(lua_State *L)
|
||||
{
|
||||
return hlua_httpclient_send(L, HTTP_METH_DELETE);
|
||||
}
|
||||
|
||||
/* Registers the HTTPClient Lua class and exposes core.httpclient constructor.
|
||||
* Called for each new lua_State created by hlua_init_state().
|
||||
*/
|
||||
static int hlua_http_client_init_state(lua_State *L, char **errmsg)
|
||||
{
|
||||
/* Create and fill the metatable. */
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, "__index");
|
||||
lua_newtable(L);
|
||||
hlua_class_function(L, "get", hlua_httpclient_get);
|
||||
hlua_class_function(L, "head", hlua_httpclient_head);
|
||||
hlua_class_function(L, "put", hlua_httpclient_put);
|
||||
hlua_class_function(L, "post", hlua_httpclient_post);
|
||||
hlua_class_function(L, "delete", hlua_httpclient_delete);
|
||||
lua_settable(L, -3); /* Sets the __index entry. */
|
||||
/* Register the garbage collector entry. */
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcclosure(L, hlua_httpclient_gc, 0);
|
||||
lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
|
||||
|
||||
|
||||
|
||||
class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
|
||||
|
||||
lua_getglobal(L, "core");
|
||||
hlua_class_function(L, "httpclient", hlua_httpclient_new);
|
||||
lua_pop(L, 1);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
REGISTER_HLUA_STATE_INIT(hlua_http_client_init_state);
|
||||
|
||||
#endif /* USE_LUA */
|
||||
|
|
|
|||
Loading…
Reference in a new issue