mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-05-13 13:24:50 +00:00
MINOR: hlua_fcn: implement index and pair metamethods for patref class
patref object may now leverage index and pair methamethods to list and access patref elements at a specific index (=key) Also, patref:is_map() method may be used to know if the patref stores acl (key only) or map-style (key:value) patterns.
This commit is contained in:
parent
31784efad2
commit
2021072391
@ -3434,7 +3434,15 @@ Patref class
|
|||||||
(reference) which often is a filename, unless it is prefixed by 'virt@'
|
(reference) which often is a filename, unless it is prefixed by 'virt@'
|
||||||
for virtual references or 'opt@' for references that don't necessarily
|
for virtual references or 'opt@' for references that don't necessarily
|
||||||
point to real file. From Lua, :ref:`patref_class` object may be used to
|
point to real file. From Lua, :ref:`patref_class` object may be used to
|
||||||
directly manipulate existing pattern reference storage.
|
directly manipulate existing pattern reference storage. For convenience,
|
||||||
|
Patref objects may be directly accessed and listed as a table thanks to
|
||||||
|
index and pairs metamethods. Note however that for the index metamethod,
|
||||||
|
in case of duplicated entries, only the first matching entry is returned.
|
||||||
|
|
||||||
|
.. Warning::
|
||||||
|
Not meant to be shared bewteen multiple contexts. If multiple contexts
|
||||||
|
need to work on the same pattern reference, each context should have
|
||||||
|
its own patref object.
|
||||||
|
|
||||||
Patref object is obtained using the :js:func:`core.get_patref()`
|
Patref object is obtained using the :js:func:`core.get_patref()`
|
||||||
function
|
function
|
||||||
@ -3443,6 +3451,11 @@ Patref class
|
|||||||
|
|
||||||
:returns: the name of the pattern reference object.
|
:returns: the name of the pattern reference object.
|
||||||
|
|
||||||
|
.. js:function:: Patref.is_map(ref)
|
||||||
|
|
||||||
|
:returns: true if the pattern reference is used to handle maps instead
|
||||||
|
of acl, false otherwise.
|
||||||
|
|
||||||
.. _applethttp_class:
|
.. _applethttp_class:
|
||||||
|
|
||||||
AppletHTTP class
|
AppletHTTP class
|
||||||
|
@ -234,6 +234,12 @@ struct hlua_server_list_iterator_context {
|
|||||||
struct proxy *px;
|
struct proxy *px;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hlua_patref_iterator_context {
|
||||||
|
struct pat_ref *ref;
|
||||||
|
struct bref bref; /* back-reference from the pat_ref_elt being accessed
|
||||||
|
* during listing */
|
||||||
|
};
|
||||||
|
|
||||||
#else /* USE_LUA */
|
#else /* USE_LUA */
|
||||||
/************************ For use when Lua is disabled ********************/
|
/************************ For use when Lua is disabled ********************/
|
||||||
|
|
||||||
|
143
src/hlua_fcn.c
143
src/hlua_fcn.c
@ -29,7 +29,7 @@
|
|||||||
#include <haproxy/hlua_fcn.h>
|
#include <haproxy/hlua_fcn.h>
|
||||||
#include <haproxy/http.h>
|
#include <haproxy/http.h>
|
||||||
#include <haproxy/net_helper.h>
|
#include <haproxy/net_helper.h>
|
||||||
#include <haproxy/pattern-t.h>
|
#include <haproxy/pattern.h>
|
||||||
#include <haproxy/protocol.h>
|
#include <haproxy/protocol.h>
|
||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
#include <haproxy/regex.h>
|
#include <haproxy/regex.h>
|
||||||
@ -2629,6 +2629,17 @@ int hlua_patref_get_name(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hlua_patref_is_map(lua_State *L)
|
||||||
|
{
|
||||||
|
struct pat_ref *ref;
|
||||||
|
|
||||||
|
ref = hlua_checkudata(L, 1, class_patref_ref);
|
||||||
|
BUG_ON(!ref);
|
||||||
|
|
||||||
|
lua_pushboolean(L, !!(ref->flags & PAT_REF_MAP));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref)
|
void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref)
|
||||||
{
|
{
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
@ -2646,6 +2657,133 @@ void hlua_fcn_new_patref(lua_State *L, struct pat_ref *ref)
|
|||||||
|
|
||||||
/* set public methods */
|
/* set public methods */
|
||||||
hlua_class_function(L, "get_name", hlua_patref_get_name);
|
hlua_class_function(L, "get_name", hlua_patref_get_name);
|
||||||
|
hlua_class_function(L, "is_map", hlua_patref_is_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hlua_listable_patref_newindex(lua_State *L) {
|
||||||
|
/* not yet supported */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first arg is the pat_ref
|
||||||
|
* second arg is the required index, in case of duplicate, only the
|
||||||
|
* first matching entry is returned.
|
||||||
|
*/
|
||||||
|
int hlua_listable_patref_index(lua_State *L)
|
||||||
|
{
|
||||||
|
struct pat_ref *ref;
|
||||||
|
const char *key;
|
||||||
|
struct pat_ref_elt *elt;
|
||||||
|
|
||||||
|
ref = hlua_checkudata(L, 1, class_patref_ref);
|
||||||
|
key = luaL_checkstring(L, 2);
|
||||||
|
|
||||||
|
/* Perform pat ref element lookup by key */
|
||||||
|
HA_RWLOCK_WRLOCK(PATREF_LOCK, &ref->lock);
|
||||||
|
elt = pat_ref_find_elt(ref, key);
|
||||||
|
if (elt == NULL) {
|
||||||
|
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elt->sample)
|
||||||
|
lua_pushstring(L, elt->sample);
|
||||||
|
else
|
||||||
|
lua_pushboolean(L, 1); // acl: just push true to tell that the key exists
|
||||||
|
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->lock);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _hlua_listable_patref_pairs_iterator(lua_State *L, int status, lua_KContext ctx)
|
||||||
|
{
|
||||||
|
int context_index;
|
||||||
|
struct hlua_patref_iterator_context *hctx;
|
||||||
|
struct pat_ref_elt *elt;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
context_index = lua_upvalueindex(1);
|
||||||
|
hctx = lua_touserdata(L, context_index);
|
||||||
|
|
||||||
|
HA_RWLOCK_WRLOCK(PATREF_LOCK, &hctx->ref->lock);
|
||||||
|
|
||||||
|
if (LIST_ISEMPTY(&hctx->bref.users)) {
|
||||||
|
/* first iteration */
|
||||||
|
hctx->bref.ref = hctx->ref->head.n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LIST_DEL_INIT(&hctx->bref.users); // drop back ref from previous iteration
|
||||||
|
|
||||||
|
next:
|
||||||
|
/* reached end of list? */
|
||||||
|
if (hctx->bref.ref == &hctx->ref->head) {
|
||||||
|
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
|
||||||
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
elt = LIST_ELEM(hctx->bref.ref, struct pat_ref_elt *, list);
|
||||||
|
|
||||||
|
if (elt->gen_id != hctx->ref->curr_gen) {
|
||||||
|
/* check if we may do something to try to prevent thread contention,
|
||||||
|
* unless we run from body/init state where hlua_yieldk is no-op
|
||||||
|
*/
|
||||||
|
if (cnt > 10000 && hlua_gethlua(L)) {
|
||||||
|
/* let's yield and wait for being called again to continue where we left off */
|
||||||
|
LIST_APPEND(&elt->back_refs, &hctx->bref.users);
|
||||||
|
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
|
||||||
|
hlua_yieldk(L, 0, 0, _hlua_listable_patref_pairs_iterator, TICK_ETERNITY, HLUA_CTRLYIELD); // continue
|
||||||
|
return 0; // not reached
|
||||||
|
}
|
||||||
|
|
||||||
|
hctx->bref.ref = elt->list.n;
|
||||||
|
cnt++;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_APPEND(&elt->back_refs, &hctx->bref.users);
|
||||||
|
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &hctx->ref->lock);
|
||||||
|
|
||||||
|
hctx->bref.ref = elt->list.n;
|
||||||
|
|
||||||
|
lua_pushstring(L, elt->pattern);
|
||||||
|
if (elt->sample)
|
||||||
|
lua_pushstring(L, elt->sample);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* iterator must return key as string and value as patref
|
||||||
|
* element value (as string), if we reach end of list, it
|
||||||
|
* returns nil. The context knows the last returned patref's
|
||||||
|
* value. if the context contains patref_elem == NULL, we
|
||||||
|
* start enumeration. We use pat_ref element iterator logic
|
||||||
|
* to iterate through the list.
|
||||||
|
*/
|
||||||
|
int hlua_listable_patref_pairs_iterator(lua_State *L)
|
||||||
|
{
|
||||||
|
return _hlua_listable_patref_pairs_iterator(L, LUA_OK, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init the iterator context, return iterator function
|
||||||
|
* with context as closure. The only argument is a
|
||||||
|
* patref list object.
|
||||||
|
*/
|
||||||
|
int hlua_listable_patref_pairs(lua_State *L)
|
||||||
|
{
|
||||||
|
struct hlua_patref_iterator_context *ctx;
|
||||||
|
struct pat_ref *ref;
|
||||||
|
|
||||||
|
ref = hlua_checkudata(L, 1, class_patref_ref);
|
||||||
|
|
||||||
|
ctx = lua_newuserdata(L, sizeof(*ctx));
|
||||||
|
ctx->ref = ref;
|
||||||
|
LIST_INIT(&ctx->bref.users);
|
||||||
|
|
||||||
|
lua_pushcclosure(L, hlua_listable_patref_pairs_iterator, 1);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hlua_fcn_reg_core_fcn(lua_State *L)
|
void hlua_fcn_reg_core_fcn(lua_State *L)
|
||||||
@ -2708,6 +2846,9 @@ void hlua_fcn_reg_core_fcn(lua_State *L)
|
|||||||
|
|
||||||
/* Create patref object. */
|
/* Create patref object. */
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
|
hlua_class_function(L, "__index", hlua_listable_patref_index);
|
||||||
|
hlua_class_function(L, "__newindex", hlua_listable_patref_newindex);
|
||||||
|
hlua_class_function(L, "__pairs", hlua_listable_patref_pairs);
|
||||||
class_patref_ref = hlua_register_metatable(L, CLASS_PATREF);
|
class_patref_ref = hlua_register_metatable(L, CLASS_PATREF);
|
||||||
|
|
||||||
/* Create server object. */
|
/* Create server object. */
|
||||||
|
Loading…
Reference in New Issue
Block a user