From: Thierry FOURNIER Date: Fri, 23 Jan 2015 10:36:30 +0000 (+0100) Subject: MINOR: lua: add sample and args type converters X-Git-Tag: v1.6-dev1~99 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=55da165301b4de213dacf57f1902c2142e867775;p=thirdparty%2Fhaproxy.git MINOR: lua: add sample and args type converters These function are used for converting LUA value in HAProxy values. This is helpful with sample-fetch and converter wrappers. --- diff --git a/src/hlua.c b/src/hlua.c index a3aa05b747..cb30b75075 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -9,6 +9,7 @@ #include #include +#include #include /* Lua uses longjmp to perform yield or throwing errors. This @@ -45,6 +46,17 @@ struct eb_root hlua_ctx = EB_ROOT_UNIQUE; */ static int class_core_ref; +/* These functions converts types between HAProxy internal args or + * sample and LUA types. Another function permits to check if the + * LUA stack contains arguments according with an required ARG_T + * format. + */ +static int hlua_arg2lua(lua_State *L, const struct arg *arg); +static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg); +__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, unsigned int mask); +static int hlua_smp2lua(lua_State *L, const struct sample *smp); +static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp); + /* Used to check an Lua function type in the stack. It creates and * returns a reference of the function. This function throws an * error if the rgument is not a "function". @@ -201,6 +213,231 @@ static void hlua_com_wake(struct list *wake) } } +/* This functions is used with sample fetch and converters. It + * converts the HAProxy configuration argument in a lua stack + * values. + * + * It takes an array of "arg", and each entry of the array is + * converted and pushed in the LUA stack. + */ +static int hlua_arg2lua(lua_State *L, const struct arg *arg) +{ + switch (arg->type) { + case ARGT_SINT: + lua_pushinteger(L, arg->data.sint); + break; + + case ARGT_UINT: + case ARGT_TIME: + case ARGT_SIZE: + lua_pushunsigned(L, arg->data.sint); + break; + + case ARGT_STR: + lua_pushlstring(L, arg->data.str.str, arg->data.str.len); + break; + + case ARGT_IPV4: + case ARGT_IPV6: + case ARGT_MSK4: + case ARGT_MSK6: + case ARGT_FE: + case ARGT_BE: + case ARGT_TAB: + case ARGT_SRV: + case ARGT_USR: + case ARGT_MAP: + default: + lua_pushnil(L); + break; + } + return 1; +} + +/* This function take one entrie in an LUA stack at the index "ud", + * and try to convert it in an HAProxy argument entry. This is useful + * with sample fetch wrappers. The input arguments are gived to the + * lua wrapper and converted as arg list by thi function. + */ +static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg) +{ + switch (lua_type(L, ud)) { + + case LUA_TNUMBER: + case LUA_TBOOLEAN: + arg->type = ARGT_SINT; + arg->data.sint = lua_tointeger(L, ud); + break; + + case LUA_TSTRING: + arg->type = ARGT_STR; + arg->data.str.str = (char *)lua_tolstring(L, ud, (size_t *)&arg->data.str.len); + break; + + case LUA_TUSERDATA: + case LUA_TNIL: + case LUA_TTABLE: + case LUA_TFUNCTION: + case LUA_TTHREAD: + case LUA_TLIGHTUSERDATA: + arg->type = ARGT_SINT; + arg->data.uint = 0; + break; + } + return 1; +} + +/* the following functions are used to convert a struct sample + * in Lua type. This useful to convert the return of the + * fetchs or converters. + */ +static int hlua_smp2lua(lua_State *L, const struct sample *smp) +{ + switch (smp->type) { + case SMP_T_SINT: + lua_pushinteger(L, smp->data.sint); + break; + + case SMP_T_BOOL: + case SMP_T_UINT: + lua_pushunsigned(L, smp->data.uint); + break; + + case SMP_T_BIN: + case SMP_T_STR: + lua_pushlstring(L, smp->data.str.str, smp->data.str.len); + break; + + case SMP_T_METH: + switch (smp->data.meth.meth) { + case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break; + case HTTP_METH_GET: lua_pushstring(L, "GET"); break; + case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break; + case HTTP_METH_POST: lua_pushstring(L, "POST"); break; + case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break; + case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break; + case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break; + case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break; + case HTTP_METH_OTHER: + lua_pushlstring(L, smp->data.meth.str.str, smp->data.meth.str.len); + break; + default: + lua_pushnil(L); + break; + } + break; + + case SMP_T_IPV4: + case SMP_T_IPV6: + case SMP_T_ADDR: /* This type is never used to qualify a sample. */ + default: + lua_pushnil(L); + break; + } + return 1; +} + +/* the following functions are used to convert an Lua type in a + * struct sample. This is useful to provide data from a converter + * to the LUA code. + */ +static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp) +{ + switch (lua_type(L, ud)) { + + case LUA_TNUMBER: + smp->type = SMP_T_SINT; + smp->data.sint = lua_tointeger(L, ud); + break; + + + case LUA_TBOOLEAN: + smp->type = SMP_T_BOOL; + smp->data.uint = lua_toboolean(L, ud); + break; + + case LUA_TSTRING: + smp->type = SMP_T_STR; + smp->flags |= SMP_F_CONST; + smp->data.str.str = (char *)lua_tolstring(L, ud, (size_t *)&smp->data.str.len); + break; + + case LUA_TUSERDATA: + case LUA_TNIL: + case LUA_TTABLE: + case LUA_TFUNCTION: + case LUA_TTHREAD: + case LUA_TLIGHTUSERDATA: + smp->type = SMP_T_BOOL; + smp->data.uint = 0; + break; + } + return 1; +} + +/* This function check the "argp" builded by another conversion function + * is in accord with the expected argp defined by the "mask". The fucntion + * returns true or false. It can be adjust the types if there compatibles. + */ +__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, unsigned int mask) +{ + int min_arg; + int idx; + + idx = 0; + min_arg = ARGM(mask); + mask >>= ARGM_BITS; + + while (1) { + + /* Check oversize. */ + if (idx >= ARGM_NBARGS && argp[idx].type != ARGT_STOP) { + WILL_LJMP(luaL_argerror(L, first + idx, "Malformad argument mask")); + } + + /* Check for mandatory arguments. */ + if (argp[idx].type == ARGT_STOP) { + if (idx + 1 < min_arg) + WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected")); + return 0; + } + + /* Check for exceed the number of requiered argument. */ + if ((mask & ARGT_MASK) == ARGT_STOP && + argp[idx].type != ARGT_STOP) { + WILL_LJMP(luaL_argerror(L, first + idx, "Last argument expected")); + } + + if ((mask & ARGT_MASK) == ARGT_STOP && + argp[idx].type == ARGT_STOP) { + return 0; + } + + /* Compatibility mask. */ + switch (argp[idx].type) { + case ARGT_SINT: + switch (mask & ARGT_MASK) { + case ARGT_UINT: argp[idx].type = mask & ARGT_MASK; break; + case ARGT_TIME: argp[idx].type = mask & ARGT_MASK; break; + case ARGT_SIZE: argp[idx].type = mask & ARGT_MASK; break; + } + break; + } + + /* Check for type of argument. */ + if ((mask & ARGT_MASK) != argp[idx].type) { + const char *msg = lua_pushfstring(L, "'%s' expected, got '%s'", + arg_type_names[(mask & ARGT_MASK)], + arg_type_names[argp[idx].type & ARGT_MASK]); + WILL_LJMP(luaL_argerror(L, first + idx, msg)); + } + + /* Next argument. */ + mask >>= ARGT_BITS; + idx++; + } +} + /* * The following functions are used to make correspondance between the the * executed lua pointer and the "struct hlua *" that contain the context.