MINOR: lua: map system integration in Lua
This patch cretes a new Map class that permits to do some lookup in HAProxy maps. This Map class is integration in the HAProxy update system, so we can modify the map throught the socket.
This commit is contained in:
parent
04c57b3357
commit
3def393f8d
|
@ -1096,6 +1096,125 @@ Socket class
|
|||
:param class_socket socket: Is the manipulated Socket.
|
||||
:param integer value: The timeout value.
|
||||
|
||||
Map class
|
||||
=========
|
||||
|
||||
.. js:class:: Map
|
||||
|
||||
This class permits to do some lookup in HAProxy maps. The declared maps can
|
||||
be modified during the runtime throught the HAProxy management socket.
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
default = "usa"
|
||||
|
||||
-- Create and load map
|
||||
geo = Map.new("geo.map", Map.ip);
|
||||
|
||||
-- Create new fetch that returns the user country
|
||||
core.register_fetches("country", function(txn)
|
||||
local src;
|
||||
local loc;
|
||||
|
||||
src = txn.f:fhdr("x-forwarded-for");
|
||||
if (src == nil) then
|
||||
src = txn.f:src()
|
||||
if (src == nil) then
|
||||
return default;
|
||||
end
|
||||
end
|
||||
|
||||
-- Perform lookup
|
||||
loc = geo:lookup(src);
|
||||
|
||||
if (loc == nil) then
|
||||
return default;
|
||||
end
|
||||
|
||||
return loc;
|
||||
end);
|
||||
|
||||
.. js:attribute:: Map.int
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.ip
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.str
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.beg
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.sub
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.dir
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.dom
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.end
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
.. js:attribute:: Map.reg
|
||||
|
||||
See the HAProxy configuration.txt file, chapter "Using ACLs and fetching
|
||||
samples" ans subchapter "ACL basics" to understand this pattern matching
|
||||
method.
|
||||
|
||||
|
||||
.. js:function:: Map.new(file, method)
|
||||
|
||||
Creates and load a map.
|
||||
|
||||
:param string file: Is the file containing the map.
|
||||
:param integer method: Is the map pattern matching method. See the attributes
|
||||
of the Map class.
|
||||
:returns: a class Map object.
|
||||
:see: The Map attributes.
|
||||
|
||||
.. js:function:: Map.lookup(map, str)
|
||||
|
||||
Perform a lookup in a map.
|
||||
|
||||
:param class_map map: Is the class Map object.
|
||||
:param string str: Is the string used as key.
|
||||
:returns: a string containing the result or nil if no match.
|
||||
|
||||
.. js:function:: Map.slookup(map, str)
|
||||
|
||||
Perform a lookup in a map.
|
||||
|
||||
:param class_map map: Is the class Map object.
|
||||
:param string str: Is the string used as key.
|
||||
:returns: a string containing the result or empty string if no match.
|
||||
|
||||
External Lua libraries
|
||||
======================
|
||||
|
||||
|
|
|
@ -32,4 +32,7 @@ int map_parse_int(const char *text, struct sample_storage *smp);
|
|||
|
||||
struct map_reference *map_get_reference(const char *reference);
|
||||
|
||||
int sample_load_map(struct arg *arg, struct sample_conv *conv,
|
||||
const char *file, int line, char **err);
|
||||
|
||||
#endif /* _PROTO_PATTERN_H */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CLASS_SOCKET "Socket"
|
||||
#define CLASS_CHANNEL "Channel"
|
||||
#define CLASS_HTTP "HTTP"
|
||||
#define CLASS_MAP "Map"
|
||||
|
||||
struct stream;
|
||||
|
||||
|
|
188
src/hlua.c
188
src/hlua.c
|
@ -23,6 +23,7 @@
|
|||
#include <proto/channel.h>
|
||||
#include <proto/hdr_idx.h>
|
||||
#include <proto/hlua.h>
|
||||
#include <proto/map.h>
|
||||
#include <proto/obj_type.h>
|
||||
#include <proto/pattern.h>
|
||||
#include <proto/payload.h>
|
||||
|
@ -76,6 +77,7 @@ static int class_channel_ref;
|
|||
static int class_fetches_ref;
|
||||
static int class_converters_ref;
|
||||
static int class_http_ref;
|
||||
static int class_map_ref;
|
||||
|
||||
/* Global Lua execution timeout. By default Lua, execution linked
|
||||
* with stream (actions, sample-fetches and converters) have a
|
||||
|
@ -1265,6 +1267,151 @@ static int hlua_set_map(lua_State *L)
|
|||
* __le "<="
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Class Map
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Returns a struct hlua_map if the stack entry "ud" is
|
||||
* a class session, otherwise it throws an error.
|
||||
*/
|
||||
__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
|
||||
{
|
||||
return (struct map_descriptor *)MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
|
||||
}
|
||||
|
||||
/* This function is the map constructor. It don't need
|
||||
* the class Map object. It creates and return a new Map
|
||||
* object. It must be called only during "body" or "init"
|
||||
* context because it process some filesystem accesses.
|
||||
*/
|
||||
__LJMP static int hlua_map_new(struct lua_State *L)
|
||||
{
|
||||
const char *fn;
|
||||
int match = PAT_MATCH_STR;
|
||||
struct sample_conv conv;
|
||||
const char *file = "";
|
||||
int line = 0;
|
||||
lua_Debug ar;
|
||||
char *err = NULL;
|
||||
struct arg args[2];
|
||||
|
||||
if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
|
||||
WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
|
||||
|
||||
fn = MAY_LJMP(luaL_checkstring(L, 1));
|
||||
|
||||
if (lua_gettop(L) >= 2) {
|
||||
match = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
if (match < 0 || match >= PAT_MATCH_NUM)
|
||||
WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
|
||||
}
|
||||
|
||||
/* Get Lua filename and line number. */
|
||||
if (lua_getstack(L, 1, &ar)) { /* check function at level */
|
||||
lua_getinfo(L, "Sl", &ar); /* get info about it */
|
||||
if (ar.currentline > 0) { /* is there info? */
|
||||
file = ar.short_src;
|
||||
line = ar.currentline;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill fake sample_conv struct. */
|
||||
conv.kw = ""; /* unused. */
|
||||
conv.process = NULL; /* unused. */
|
||||
conv.arg_mask = 0; /* unused. */
|
||||
conv.val_args = NULL; /* unused. */
|
||||
conv.out_type = SMP_T_STR;
|
||||
conv.private = (void *)(long)match;
|
||||
switch (match) {
|
||||
case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
|
||||
case PAT_MATCH_INT: conv.in_type = SMP_T_UINT; break;
|
||||
case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
|
||||
default:
|
||||
WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
|
||||
}
|
||||
|
||||
/* fill fake args. */
|
||||
args[0].type = ARGT_STR;
|
||||
args[0].data.str.str = (char *)fn;
|
||||
args[1].type = ARGT_STOP;
|
||||
|
||||
/* load the map. */
|
||||
if (!sample_load_map(args, &conv, file, line, &err)) {
|
||||
/* error case: we cant use luaL_error because we must
|
||||
* free the err variable.
|
||||
*/
|
||||
luaL_where(L, 1);
|
||||
lua_pushfstring(L, "'new': %s.", err);
|
||||
lua_concat(L, 2);
|
||||
free(err);
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
/* create the lua object. */
|
||||
lua_newtable(L);
|
||||
lua_pushlightuserdata(L, args[0].data.map);
|
||||
lua_rawseti(L, -2, 0);
|
||||
|
||||
/* Pop a class Map metatable and affect it to the userdata. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
|
||||
{
|
||||
struct map_descriptor *desc;
|
||||
struct pattern *pat;
|
||||
struct sample smp;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "lookup"));
|
||||
desc = MAY_LJMP(hlua_checkmap(L, 1));
|
||||
if (desc->pat.expect_type == SMP_T_UINT) {
|
||||
smp.type = SMP_T_UINT;
|
||||
smp.data.uint = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
}
|
||||
else {
|
||||
smp.type = SMP_T_STR;
|
||||
smp.flags = SMP_F_CONST;
|
||||
smp.data.str.str = (char *)MAY_LJMP(luaL_checklstring(L, 2, (size_t *)&smp.data.str.len));
|
||||
}
|
||||
|
||||
pat = pattern_exec_match(&desc->pat, &smp, 1);
|
||||
if (!pat || !pat->smp) {
|
||||
if (str)
|
||||
lua_pushstring(L, "");
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The Lua pattern must return a string, so we can't check the returned type */
|
||||
lua_pushlstring(L, pat->smp->data.str.str, pat->smp->data.str.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_map_lookup(struct lua_State *L)
|
||||
{
|
||||
return _hlua_map_lookup(L, 0);
|
||||
}
|
||||
|
||||
__LJMP static int hlua_map_slookup(struct lua_State *L)
|
||||
{
|
||||
return _hlua_map_lookup(L, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
|
@ -4571,6 +4718,47 @@ void hlua_init(void)
|
|||
|
||||
lua_setglobal(gL.T, "core");
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class Map
|
||||
*
|
||||
*/
|
||||
|
||||
/* This table entry is the object "Map" base. */
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* register pattern types. */
|
||||
for (i=0; i<PAT_MATCH_NUM; i++)
|
||||
hlua_class_const_int(gL.T, pat_match_names[i], i);
|
||||
|
||||
/* register constructor. */
|
||||
hlua_class_function(gL.T, "new", hlua_map_new);
|
||||
|
||||
/* Create and fill the metatable. */
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Create and fille the __index entry. */
|
||||
lua_pushstring(gL.T, "__index");
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Register . */
|
||||
hlua_class_function(gL.T, "lookup", hlua_map_lookup);
|
||||
hlua_class_function(gL.T, "slookup", hlua_map_slookup);
|
||||
|
||||
lua_settable(gL.T, -3);
|
||||
|
||||
/* Register previous table in the registry with reference and named entry. */
|
||||
lua_pushvalue(gL.T, -1); /* Copy the -1 entry and push it on the stack. */
|
||||
lua_pushvalue(gL.T, -1); /* Copy the -1 entry and push it on the stack. */
|
||||
lua_setfield(gL.T, LUA_REGISTRYINDEX, CLASS_MAP); /* register class session. */
|
||||
class_map_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX); /* reference class session. */
|
||||
|
||||
/* Assign the metatable to the mai Map object. */
|
||||
lua_setmetatable(gL.T, -2);
|
||||
|
||||
/* Set a name to the table. */
|
||||
lua_setglobal(gL.T, "Map");
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class Channel
|
||||
|
|
|
@ -114,8 +114,8 @@ static struct map_descriptor *map_create_descriptor(struct sample_conv *conv)
|
|||
* This function choose the indexation type (ebtree or list) according with
|
||||
* the type of match needed.
|
||||
*/
|
||||
static int sample_load_map(struct arg *arg, struct sample_conv *conv,
|
||||
const char *file, int line, char **err)
|
||||
int sample_load_map(struct arg *arg, struct sample_conv *conv,
|
||||
const char *file, int line, char **err)
|
||||
{
|
||||
struct map_descriptor *desc;
|
||||
|
||||
|
|
Loading…
Reference in New Issue