changed some apis, implemented some todos, added support for lua actions/conditions.

personal/stbuehler/wip
Stefan Bühler 14 years ago
parent 2537bb9d82
commit 2f7359b14c
  1. 101
      src/actions.c
  2. 21
      src/actions.h
  3. 54
      src/actions_lua.c
  4. 11
      src/actions_lua.h
  5. 1
      src/base.h
  6. 18
      src/condition.c
  7. 6
      src/condition.h
  8. 46
      src/condition_lua.c
  9. 10
      src/condition_lua.h
  10. 220
      src/config_lua.c
  11. 2
      src/connection.h
  12. 1
      src/lighttpd.c
  13. 36
      src/options.c
  14. 14
      src/options.h
  15. 28
      src/options_lua.c
  16. 1
      src/options_lua.h
  17. 155
      src/plugin.c
  18. 10
      src/plugin.h
  19. 71
      src/plugin_core.c
  20. 8
      src/server.h
  21. 5
      src/wscript

@ -11,10 +11,9 @@ struct action_stack_element {
guint pos;
};
action *action_new_setting(server *srv, GString *name, option *value) {
action *action_new_setting(server *srv, const gchar *name, option *value) {
option_set setting;
if (!parse_option(srv, name->str, value, &setting)) {
if (!parse_option(srv, name, value, &setting)) {
return NULL;
}
@ -27,42 +26,59 @@ action *action_new_setting(server *srv, GString *name, option *value) {
return a;
}
action *action_new_function(server *srv, const char *name, option *value) {
action *action_new_function(ActionFunc func, ActionFree free, gpointer param) {
action *a;
action_func af;
server_action *sa;
if (NULL == (sa = (server_action*) g_hash_table_lookup(srv->actions, name))) {
ERROR(srv, "Action '%s' doesn't exist", name);
return NULL;
}
a = g_slice_new(action);
a->refcount = 1;
a->type = ACTION_TFUNCTION;
a->value.function.func = func;
a->value.function.free = free;
a->value.function.param = param;
if (!sa->create_action(srv, sa->p ? sa->p->data : NULL, value, &af)) {
ERROR(srv, "Action '%s' creation failed", name);
return NULL;
}
return a;
}
action *action_new_list() {
action *a;
a = g_slice_new(action);
a->refcount = 1;
a->type = ACTION_TFUNCTION;
a->value.function = af;
a->type = ACTION_TLIST;
a->value.list = action_list_new();
return a;
}
void action_release(action *a) {
action *action_new_condition(condition *cond, action_list *al) {
action *a;
a = g_slice_new(action);
a->refcount = 1;
a->type = ACTION_TCONDITION;
a->value.condition.cond = cond;
a->value.condition.target = al;
return a;
}
void action_release(server *srv, action *a) {
assert(a->refcount > 0);
if (!(--a->refcount)) {
switch (a->type) {
case ACTION_TSETTING:
/* TODO */
release_option(srv, &a->value.setting);
break;
case ACTION_TFUNCTION:
/* TODO */
case ACTION_TFUNCTION:
if (a->value.function.free) {
a->value.function.free(srv, a->value.function.param);
}
break;
case ACTION_TCONDITION:
condition_release(a->value.condition.cond);
action_list_release(a->value.condition.target);
condition_release(srv, a->value.condition.cond);
action_list_release(srv, a->value.condition.target);
break;
case ACTION_TLIST:
action_list_release(srv, a->value.list);
break;
}
g_slice_free(action, a);
@ -85,12 +101,24 @@ action_list *action_list_new() {
return al;
}
void action_list_release(action_list *al) {
action_list *action_list_from_action(action *a) {
action_list *al;
if (a->type == ACTION_TLIST) {
action_list_acquire(a->value.list);
return a->value.list; /* action gets released from lua */
}
action_acquire(a);
al = action_list_new();
g_array_append_val(al->actions, a);
return al;
}
void action_list_release(server *srv, action_list *al) {
assert(al->refcount > 0);
if (!(--al->refcount)) {
guint i;
for (i = al->actions->len; i-- > 0; ) {
action_release(g_array_index(al->actions, action*, i));
action_release(srv, g_array_index(al->actions, action*, i));
}
g_array_free(al->actions, TRUE);
g_slice_free(action_list, al);
@ -102,9 +130,9 @@ void action_list_acquire(action_list *al) {
al->refcount++;
}
void action_stack_element_release(action_stack_element *ase) {
void action_stack_element_release(server *srv, action_stack_element *ase) {
if (!ase || !ase->list) return;
action_list_release(ase->list);
action_list_release(srv, ase->list);
ase->list = NULL;
}
@ -112,18 +140,18 @@ void action_stack_init(action_stack *as) {
as->stack = g_array_sized_new(FALSE, TRUE, sizeof(action_stack_element), 15);
}
void action_stack_reset(action_stack *as) {
void action_stack_reset(server *srv, action_stack *as) {
guint i;
for (i = as->stack->len; i-- > 0; ) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
action_stack_element_release(srv, &g_array_index(as->stack, action_stack_element, i));
}
g_array_set_size(as->stack, 0);
}
void action_stack_clear(action_stack *as) {
void action_stack_clear(server *srv, action_stack *as) {
guint i;
for (i = as->stack->len; i-- > 0; ) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
action_stack_element_release(srv, &g_array_index(as->stack, action_stack_element, i));
}
g_array_free(as->stack, TRUE);
}
@ -139,8 +167,8 @@ static action_stack_element *action_stack_top(action_stack* as) {
return as->stack->len > 0 ? &g_array_index(as->stack, action_stack_element, as->stack->len - 1) : NULL;
}
static void action_stack_pop(action_stack *as) {
action_stack_element_release(&g_array_index(as->stack, action_stack_element, as->stack->len - 1));
static void action_stack_pop(server *srv, action_stack *as) {
action_stack_element_release(srv, &g_array_index(as->stack, action_stack_element, as->stack->len - 1));
g_array_set_size(as->stack, as->stack->len - 1);
}
@ -158,12 +186,12 @@ action_result action_execute(server *srv, connection *con) {
while (NULL != (ase = action_stack_top(as))) {
a = action_stack_element_next(ase);
if (!a) {
action_stack_pop(as);
action_stack_pop(srv, as);
continue;
}
switch (a->type) {
case ACTION_TSETTING:
/* TODO */
con->options[a->value.setting.ndx] = a->value.setting.value;
break;
case ACTION_TFUNCTION:
res = a->value.function.func(srv, con, a->value.function.param);
@ -172,7 +200,7 @@ action_result action_execute(server *srv, connection *con) {
break;
case ACTION_FINISHED:
case ACTION_ERROR:
action_stack_clear(as);
action_stack_clear(srv, as);
return res;
case ACTION_WAIT_FOR_EVENT:
return ACTION_WAIT_FOR_EVENT;
@ -183,6 +211,9 @@ action_result action_execute(server *srv, connection *con) {
action_enter(con, a->value.condition.target);
}
break;
case ACTION_TLIST:
action_enter(con, a->value.list);
break;
}
}
return ACTION_GO_ON;

@ -14,7 +14,8 @@ typedef enum {
typedef enum {
ACTION_TSETTING,
ACTION_TFUNCTION,
ACTION_TCONDITION
ACTION_TCONDITION,
ACTION_TLIST
} action_type;
struct action;
@ -64,25 +65,33 @@ struct action {
} condition;
action_func function;
action_list *list;
} value;
};
LI_API void action_list_release(action_list *al);
LI_API void action_list_release(server *srv, action_list *al);
LI_API void action_list_acquire(action_list *al);
LI_API action_list *action_list_new();
LI_API action_list *action_list_from_action(action *a);
/* no new/free function, so just use the struct direct (i.e. not a pointer) */
LI_API void action_stack_init(action_stack *as);
LI_API void action_stack_reset(action_stack *as);
LI_API void action_stack_clear(action_stack *as);
LI_API void action_stack_reset(server *srv, action_stack *as);
LI_API void action_stack_clear(server *srv, action_stack *as);
/** handle sublist now, remember current position (stack) */
LI_API void action_enter(connection *con, action_list *al);
LI_API action_result action_execute(server *srv, connection *con);
LI_API void action_release(server *srv, action *a);
LI_API void action_acquire(action *a);
/* create new action */
LI_API action *action_new_setting(server *srv, GString *name, option *value);
LI_API action *action_new_function(server *srv, const char *name, option *value);
LI_API action *action_new_setting(server *srv, const gchar *name, option *value);
LI_API action *action_new_function(ActionFunc func, ActionFree free, gpointer param);
LI_API action *action_new_list();
LI_API action *action_new_condition(condition *cond, action_list *al);
LI_API action *action_new_condition_string(comp_key_t comp, comp_operator_t op, GString *str);
LI_API action *action_new_condition_int(comp_key_t comp, comp_operator_t op, guint64 i);
#endif

@ -0,0 +1,54 @@
#include "actions_lua.h"
#include <lualib.h>
#include <lauxlib.h>
#define LUA_ACTION "action*"
action* lua_get_action(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_ACTION);
if (lua_isnil(L, -1) || lua_isnil(L, -2) || !lua_equal(L, -1, -2)) {
lua_pop(L, 2);
return NULL;
}
lua_pop(L, 2);
return *(action**) lua_touserdata(L, ndx);
}
static int lua_action_gc(lua_State *L) {
server *srv;
action **a = (action**) luaL_checkudata(L, 1, LUA_ACTION);
if (!a || !*a) return 0;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
action_release(srv, *a);
return 0;
}
int lua_push_action(server *srv, lua_State *L, action *a) {
action **pa;
pa = (action**) lua_newuserdata(L, sizeof(action*));
action_acquire(a);
*pa = a;
if (luaL_newmetatable(L, LUA_ACTION)) {
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, lua_action_gc, 1);
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, -2);
return 1;
}
action_list* lua_get_actionlist(lua_State *L) {
action *a;
if (lua_isnil(L, -1)) return NULL;
a = lua_get_action(L, 1);
if (!a) return NULL;
return action_list_from_action(a);
}

@ -0,0 +1,11 @@
#ifndef _LIGHTTPD_ACTIONS_LUA_H_
#define _LIGHTTPD_ACTIONS_LUA_H_
#include "actions.h"
#include <lua.h>
action* lua_get_action(lua_State *L, int ndx);
int lua_push_action(server *srv, lua_State *L, action *a);
action_list* lua_get_actionlist(lua_State *L);
#endif

@ -14,6 +14,7 @@ typedef struct connection connection;
#include "server.h"
#include "actions.h"
#include "options.h"
#include "plugin.h"
#include "request.h"
#include "log.h"

@ -148,7 +148,23 @@ static void condition_free(condition *c) {
g_slice_free(condition, c);
}
void condition_release(condition* c) {
condition* condition_from_option(server *srv, option *opt) {
if (opt->type == OPTION_CONDITION) {
assert(srv == opt->value.opt_cond.srv);
condition_acquire(opt->value.opt_cond.cond);
return opt->value.opt_cond.cond;
}
/* TODO: convert triple into condition */
return NULL;
}
void condition_acquire(condition *c) {
assert(c->refcount > 0);
c->refcount++;
}
void condition_release(server *srv, condition* c) {
UNUSED(srv);
/* assert(c->recount > 0); */
if (!(--c->refcount)) {
condition_free(c);

@ -91,7 +91,11 @@ LI_API condition* condition_new_int(server *srv, comp_operator_t op, comp_key_t
LI_API condition* condition_new_string_uncached(server *srv, comp_operator_t op, comp_key_t comp, GString *str);
LI_API condition* condition_new_int_uncached(server *srv, comp_operator_t op, comp_key_t comp, gint i);
LI_API void condition_release(condition* c);
struct option;
LI_API condition* condition_from_option(server *srv, struct option *opt);
LI_API void condition_acquire(condition *c);
LI_API void condition_release(server *srv, condition* c);
LI_API const char* comp_op_to_string(comp_operator_t op);
LI_API const char* comp_key_to_string(comp_key_t comp);

@ -0,0 +1,46 @@
#include "condition_lua.h"
#include <lualib.h>
#include <lauxlib.h>
#define LUA_CONDITION "condition*"
condition* lua_get_condition(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_CONDITION);
if (lua_isnil(L, -1) || lua_isnil(L, -2) || !lua_equal(L, -1, -2)) {
lua_pop(L, 2);
return NULL;
}
lua_pop(L, 2);
return *(condition**) lua_touserdata(L, ndx);
}
static int lua_condition_gc(lua_State *L) {
server *srv;
condition **c = (condition**) luaL_checkudata(L, 1, LUA_CONDITION);
if (!c || !*c) return 0;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
condition_release(srv, *c);
return 0;
}
int lua_push_condition(server *srv, lua_State *L, condition *c) {
condition **pc;
pc = (condition**) lua_newuserdata(L, sizeof(condition*));
condition_acquire(c);
*pc = c;
if (luaL_newmetatable(L, LUA_CONDITION)) {
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, lua_condition_gc, 1);
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, -2);
return 1;
}

@ -0,0 +1,10 @@
#ifndef _LIGHTTPD_CONDITION_LUA_H_
#define _LIGHTTPD_CONDITION_LUA_H_
#include "condition.h"
#include <lua.h>
condition* lua_get_condition(lua_State *L, int ndx);
int lua_push_condition(server *srv, lua_State *L, condition *c);
#endif

@ -0,0 +1,220 @@
#include "base.h"
#include "options_lua.h"
#include "actions_lua.h"
#include <lualib.h>
#include <lauxlib.h>
typedef int (*LuaWrapper)(server *srv, lua_State *L, gpointer data);
option* lua_params_to_option(server *srv, lua_State *L) {
option *opt, *subopt;
switch (lua_gettop(L)) {
case 0:
return NULL;
case 1:
return option_from_lua(srv, L);
default:
opt = option_new_list();
while (lua_gettop(L) > 0) {
if (NULL == (subopt = option_from_lua(srv, L))) {
ERROR(srv, "%s", "Couldn't convert option to lua");
option_free(opt);
return NULL;
}
g_array_append_val(opt->value.opt_list, subopt);
}
return opt;
}
return NULL;
}
static int lua_str_hash_index(lua_State *L) {
server *srv;
GHashTable *ht;
LuaWrapper wrapper;
const char *key;
gpointer d;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
ht = (GHashTable*) lua_touserdata(L, lua_upvalueindex(2));
wrapper = (LuaWrapper)(intptr_t) lua_touserdata(L, lua_upvalueindex(3));
key = luaL_checklstring(L, 2, NULL);
if (key && NULL != (d = g_hash_table_lookup(ht, key))) {
lua_pop(L, lua_gettop(L));
return wrapper(srv, L, d);
}
lua_pop(L, lua_gettop(L));
lua_pushnil(L);
return 1;
}
/* Creates a table on the lua stack */
static gboolean publish_str_hash(server *srv, lua_State *L, GHashTable *ht, LuaWrapper wrapper) {
lua_newtable(L); /* { } */
lua_newtable(L); /* metatable */
lua_pushlightuserdata(L, srv);
lua_pushlightuserdata(L, ht);
lua_pushlightuserdata(L, (void*)(intptr_t)wrapper);
lua_pushcclosure(L, lua_str_hash_index, 3);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
return TRUE;
}
static int handle_server_action(lua_State *L) {
server *srv;
server_action *sa;
option *opt;
action *a;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
sa = (server_action*) lua_touserdata(L, lua_upvalueindex(2));
opt = lua_params_to_option(srv, L);
TRACE(srv, "%s", "Creating action");
if (NULL == (a = sa->create_action(srv, sa->p, opt))) {
lua_pushstring(L, "creating action failed");
lua_error(L);
}
return lua_push_action(srv, L, a);
}
static int wrap_server_action(server *srv, lua_State *L, gpointer sa) {
lua_pushlightuserdata(L, srv);
lua_pushlightuserdata(L, sa);
lua_pushcclosure(L, handle_server_action, 2);
return 1;
}
static int handle_server_setup(lua_State *L) {
server *srv;
server_setup *ss;
option *opt;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
ss = (server_setup*) lua_touserdata(L, lua_upvalueindex(2));
opt = lua_params_to_option(srv, L);
TRACE(srv, "%s", "Calling setup");
if (!ss->setup(srv, ss->p, opt)) {
lua_pushstring(L, "setup failed");
lua_error(L);
}
return 0;
}
static int wrap_server_setup(server *srv, lua_State *L, gpointer ss) {
lua_pushlightuserdata(L, srv);
lua_pushlightuserdata(L, ss);
lua_pushcclosure(L, handle_server_setup, 2);
return 1;
}
static action* action_from_lua(server *srv, lua_State *L) {
const gchar *optname;
option *value;
action *a;
optname = luaL_checklstring(L, -2, NULL);
if (!optname) {
lua_pushstring(L, "wrong config argument, expected string");
lua_error(L);
}
value = option_from_lua(srv, L);
if (!value) {
lua_pushstring(L, "missing config value");
lua_error(L);
}
a = action_new_setting(srv, optname, value);
if (!a) {
option_free(value);
lua_pushstring(L, "couldn't create action from setting");
lua_error(L);
}
return a;
}
static int handle_option(lua_State *L) {
server *srv;
action *a, *suba;
srv = (server*) lua_touserdata(L, lua_upvalueindex(1));
switch (lua_gettop(L)) {
case 1:
if (!lua_istable(L, 1)) {
lua_pushstring(L, "wrong config argument, expected table");
lua_error(L);
}
a = action_new_list();
lua_push_action(srv, L, a);
lua_insert(L, 1);
lua_pushnil(L);
while (lua_next(L, 2) != 0) {
suba = action_from_lua(srv, L);
g_array_append_val(a->value.list->actions, suba);
lua_pop(L, 1);
}
lua_pop(L, 1);
return 1;
case 2:
a = action_from_lua(srv, L);
return lua_push_action(srv, L, a);
default:
lua_pushstring(L, "wrong count of arguments to config()");
lua_error(L);
}
return 0;
}
gboolean config_lua_load(server *srv, const gchar *filename) {
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
if (0 != luaL_loadfile(L, filename)) {
ERROR(srv, "Loading script '%s' failed: %s", filename, lua_tostring(L, -1));
return FALSE;
}
TRACE(srv, "Loaded config script '%s'", filename);
publish_str_hash(srv, L, srv->setups, wrap_server_setup);
lua_setfield(L, LUA_GLOBALSINDEX, "setup");
publish_str_hash(srv, L, srv->actions, wrap_server_action);
lua_setfield(L, LUA_GLOBALSINDEX, "action");
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, handle_option, 1);
lua_setfield(L, LUA_GLOBALSINDEX, "option");
if (lua_pcall(L, 0, 1, 0)) {
ERROR(srv, "lua_pcall(): %s", lua_tostring(L, -1));
return FALSE;
}
lua_pop(L, 1); /* pop the ret-value */
lua_getfield(L, LUA_GLOBALSINDEX, "action");
srv->mainactionlist = lua_get_actionlist(L);
lua_pop(L, 1);
assert(lua_gettop(L) == 0);
lua_close(L);
return TRUE;
}

@ -8,6 +8,8 @@ struct connection {
action_stack action_stack;
gpointer *options;
request request;
physical physical;

@ -63,6 +63,7 @@ int main(int argc, char *argv[]) {
}
}
else {
config_lua_load(srv, config_path);
/* lua config frontend */
}

@ -5,24 +5,28 @@
option* option_new_bool(gboolean val) {
option *opt = g_slice_new0(option);
opt->value.opt_bool = val;
opt->type = OPTION_BOOLEAN;
return opt;
}
option* option_new_int(gint val) {
option *opt = g_slice_new0(option);
opt->value.opt_int = val;
opt->type = OPTION_INT;
return opt;
}
option* option_new_string(GString *val) {
option *opt = g_slice_new0(option);
opt->value.opt_string = val;
opt->type = OPTION_STRING;
return opt;
}
option* option_new_list() {
option *opt = g_slice_new0(option);
opt->value.opt_list = g_array_new(FALSE, TRUE, sizeof(option*));
opt->type = OPTION_LIST;
return opt;
}
@ -39,9 +43,25 @@ option* option_new_hash() {
opt->value.opt_hash = g_hash_table_new_full(
(GHashFunc) g_string_hash, (GEqualFunc) g_string_equal,
_option_hash_free_key, _option_hash_free_value);
opt->type = OPTION_HASH;
return opt;
}
option* option_new_action(server *srv, action *a) {
option *opt = g_slice_new0(option);
opt->value.opt_action.srv = srv;
opt->value.opt_action.action = a;
opt->type = OPTION_ACTION;
return opt;
}
option* option_new_condition(server *srv, condition *c) {
option *opt = g_slice_new0(option);
opt->value.opt_cond.srv = srv;
opt->value.opt_cond.cond = c;
opt->type = OPTION_CONDITION;
return opt;
}
void option_free(option* opt) {
if (!opt) return;
@ -61,6 +81,12 @@ void option_free(option* opt) {
case OPTION_HASH:
g_hash_table_destroy((GHashTable*) opt->value.opt_hash);
break;
case OPTION_ACTION:
action_release(opt->value.opt_action.srv, opt->value.opt_action.action);
break;
case OPTION_CONDITION:
condition_release(opt->value.opt_cond.srv, opt->value.opt_cond.cond);
break;
}
opt->type = OPTION_NONE;
g_slice_free(option, opt);
@ -80,6 +106,10 @@ const char* option_type_string(option_type type) {
return "list";
case OPTION_HASH:
return "hash";
case OPTION_ACTION:
return "action";
case OPTION_CONDITION:
return "condition";
}
return "<unknown>";
}
@ -115,6 +145,12 @@ gpointer option_extract_value(option *opt) {
case OPTION_HASH:
val = opt->value.opt_hash;
break;
case OPTION_ACTION:
val = opt->value.opt_action.action;
break;
case OPTION_CONDITION:
val = opt->value.opt_action.action;
break;
}
opt->type = OPTION_NONE;
g_slice_free(option, opt);

@ -7,7 +7,9 @@ typedef enum {
OPTION_INT,
OPTION_STRING,
OPTION_LIST,
OPTION_HASH
OPTION_HASH,
OPTION_ACTION, /**< shouldn't be used for options, but may be needed for constructing actions */
OPTION_CONDITION /**< shouldn't be used for options, but may be needed for constructing actions */
} option_type;
struct option;
@ -28,6 +30,14 @@ struct option {
GArray *opt_list;
/* hash GString => option */
GHashTable *opt_hash;
struct {
server *srv; /* needed for destruction */
action *action;
} opt_action;
struct {
server *srv; /* needed for destruction */
condition *cond;
} opt_cond;
} value;
};
@ -44,6 +54,8 @@ LI_API option* option_new_int(gint val);
LI_API option* option_new_string(GString *val);
LI_API option* option_new_list();
LI_API option* option_new_hash();
LI_API option* option_new_action(server *srv, action *a);
LI_API option* option_new_condition(server *srv, condition *c);
LI_API void option_free(option* opt);
LI_API const char* option_type_string(option_type type);

@ -1,5 +1,7 @@
#include "options_lua.h"
#include "condition_lua.h"
#include "actions_lua.h"
#include "log.h"
/* replace a negative stack index with a positive one,
@ -35,7 +37,7 @@ static option* option_from_lua_table(server *srv, lua_State *L, int ndx) {
lua_pop(L, 1);
continue;
}
sub_option = option_from_lua(L);
sub_option = option_from_lua(srv, L);
if (!sub_option) continue;
if ((size_t) ikey >= list->len) {
g_array_set_size(list, ikey + 1);
@ -55,7 +57,7 @@ static option* option_from_lua_table(server *srv, lua_State *L, int ndx) {
lua_pop(L, 1);
continue;
}
sub_option = option_from_lua(L);
sub_option = option_from_lua(srv, L);
if (!sub_option) {
g_string_free(skey, TRUE);
continue;
@ -107,9 +109,29 @@ option* option_from_lua(server *srv, lua_State *L) {
lua_pop(L, 1);
return opt;
case LUA_TUSERDATA:
{ /* check for action */
action *a = lua_get_action(L, -1);
if (a) {
action_acquire(a);
lua_pop(L, 1);
return opt = option_new_action(srv, a);
}
}
{ /* check for condition */
condition *c = lua_get_condition(L, -1);
if (c) {
condition_acquire(c);
lua_pop(L, 1);
return opt = option_new_condition(srv, c);
}
}
ERROR(srv, "%s", "Unknown lua userdata");
lua_pop(L, 1);
return NULL;
case LUA_TLIGHTUSERDATA:
case LUA_TFUNCTION:
case LUA_TUSERDATA:
case LUA_TTHREAD:
case LUA_TNONE:
default:

@ -1,6 +1,7 @@
#ifndef _LIGHTTPD_OPTIONS_LUA_H_
#define _LIGHTTPD_OPTIONS_LUA_H_
#include "base.h"
#include "options.h"
#include <lua.h>

@ -58,71 +58,6 @@ void plugin_free(server *srv, plugin *p) {
g_slice_free(plugin, p);
}
static server_option* find_option(server *srv, const char *name) {
return (server_option*) g_hash_table_lookup(srv->options, name);
}
gboolean parse_option(server *srv, const char *name, option *opt, option_set *mark) {
server_option *sopt;
if (!srv || !name || !mark) return FALSE;
sopt = find_option(srv, name);
if (!sopt) {
ERROR(srv, "Unknown option '%s'", name);
return FALSE;
}
if (sopt->type != opt->type) {
ERROR(srv, "Unexpected option type '%s', expected '%s'",
option_type_string(opt->type), option_type_string(sopt->type));
return FALSE;
}
if (!sopt->parse_option) {
mark->value = option_extract_value(opt);
} else {
if (!sopt->parse_option(srv, sopt->p->data, sopt->module_index, opt, &mark->value)) {
/* errors should be logged by parse function */
return FALSE;
}
}
mark->ndx = sopt->index;
mark->sopt = sopt;
return TRUE;
}
void release_option(server *srv, option_set *mark) { /** Does not free the option_set memory */
server_option *sopt = mark->sopt;
if (!srv || !mark || !sopt) return;
mark->sopt = NULL;
if (!sopt->free_option) {
switch (sopt->type) {
case OPTION_NONE:
case OPTION_BOOLEAN:
case OPTION_INT:
/* Nothing to free */
break;
case OPTION_STRING:
g_string_free((GString*) mark->value, TRUE);
break;
case OPTION_LIST:
option_list_free((GArray*) mark->value);
break;
case OPTION_HASH:
g_hash_table_destroy((GHashTable*) mark->value);
break;
}
} else {
sopt->free_option(srv, sopt->p->data, sopt->module_index, mark->value);
}
mark->value = NULL;
}
gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
plugin *p;
@ -211,6 +146,94 @@ gboolean plugin_register(server *srv, const gchar *name, PluginInit init) {
return TRUE;
}
static server_option* find_option(server *srv, const char *name) {
return (server_option*) g_hash_table_lookup(srv->options, name);
}
gboolean parse_option(server *srv, const char *name, option *opt, option_set *mark) {
server_option *sopt;
if (!srv || !name || !mark) return FALSE;
sopt = find_option(srv, name);
if (!sopt) {
ERROR(srv, "Unknown option '%s'", name);
return FALSE;
}
if (sopt->type != opt->type) {
ERROR(srv, "Unexpected option type '%s', expected '%s'",
option_type_string(opt->type), option_type_string(sopt->type));
return FALSE;
}
if (!sopt->parse_option) {
mark->value = option_extract_value(opt);
} else {
if (!sopt->parse_option(srv, sopt->p, sopt->module_index, opt, &mark->value)) {
/* errors should be logged by parse function */
return FALSE;
}
}
mark->ndx = sopt->index;
mark->sopt = sopt;
return TRUE;
}
void release_option(server *srv, option_set *mark) { /** Does not free the option_set memory */
server_option *sopt = mark->sopt;
if (!srv || !mark || !sopt) return;
mark->sopt = NULL;
if (!sopt->free_option) {
switch (sopt->type) {
case OPTION_NONE:
case OPTION_BOOLEAN:
case OPTION_INT:
/* Nothing to free */
break;
case OPTION_STRING:
g_string_free((GString*) mark->value, TRUE);
break;
case OPTION_LIST:
option_list_free((GArray*) mark->value);
break;
case OPTION_HASH:
g_hash_table_destroy((GHashTable*) mark->value);
break;
case OPTION_ACTION:
action_release(srv, (action*) mark->value);
break;
case OPTION_CONDITION:
condition_release(srv, (condition*) mark->value);
break;
}
} else {
sopt->free_option(srv, sopt->p, sopt->module_index, mark->value);
}
mark->value = NULL;
}
action* create_action(server *srv, const gchar *name, option *value) {
action *a;
server_action *sa;
if (NULL == (sa = (server_action*) g_hash_table_lookup(srv->actions, name))) {
ERROR(srv, "Action '%s' doesn't exist", name);
return NULL;
}
if (NULL == (a = sa->create_action(srv, sa->p, value))) {
ERROR(srv, "Action '%s' creation failed", name);
return NULL;
}
return a;
}
gboolean call_setup(server *srv, const char *name, option *opt) {
server_setup *ss;
@ -219,7 +242,7 @@ gboolean call_setup(server *srv, const char *name, option *opt) {
return FALSE;
}
if (!ss->setup(srv, ss->p ? ss->p->data : NULL, opt)) {
if (!ss->setup(srv, ss->p, opt)) {
ERROR(srv, "Setup '%s' failed", name);
return FALSE;
}

@ -36,10 +36,10 @@ typedef struct server_setup server_setup;
typedef void (*PluginInit) (server *srv, plugin *p);
typedef void (*PluginFree) (server *srv, plugin *p);
typedef gboolean (*PluginParseOption) (server *srv, gpointer p_d, size_t ndx, option *opt, gpointer *value);
typedef void (*PluginFreeOption) (server *srv, gpointer p_d, size_t ndx, gpointer value);
typedef gboolean (*PluginCreateAction) (server *srv, gpointer p_d, option *opt, action_func *func);
typedef gboolean (*PluginSetup) (server *srv, gpointer p_d, option *opt);
typedef gboolean (*PluginParseOption) (server *srv, plugin *p, size_t ndx, option *opt, gpointer *value);
typedef void (*PluginFreeOption) (server *srv, plugin *p, size_t ndx, gpointer value);
typedef action* (*PluginCreateAction) (server *srv, plugin *p, option *opt);
typedef gboolean (*PluginSetup) (server *srv, plugin *p, option *opt);
struct plugin {
size_t version;
@ -105,6 +105,8 @@ LI_API gboolean plugin_register(server *srv, const gchar *name, PluginInit init)
LI_API gboolean parse_option(server *srv, const char *name, option *opt, option_set *mark);
LI_API void release_option(server *srv, option_set *mark); /**< Does not free the option_set memory */
LI_API action* create_action(server *srv, const gchar *name, option *value);
LI_API gboolean call_setup(server *srv, const char *name, option *opt);
#endif

@ -1,6 +1,60 @@
#include "base.h"
static action* core_list(server *srv, plugin* p, option *opt) {
action *a;
guint i;
UNUSED(p);
if (opt->type != OPTION_LIST) {
ERROR(srv, "expected list, got %s", option_type_string(opt->type));
return NULL;
}
a = action_new_list();
for (i = 0; i < opt->value.opt_list->len; i++) {
option *oa = g_array_index(opt->value.opt_list, option*, i);
if (oa->type != OPTION_ACTION) {
ERROR(srv, "expected action at entry %u of list, got %s", i, option_type_string(oa->type));
action_release(srv, a);
return NULL;
}
assert(srv == oa->value.opt_action.srv);
action_acquire(oa->value.opt_action.action);
g_array_append_val(a->value.list->actions, oa->value.opt_action.action);
}
option_free(opt);
return a;
}
static action* core_when(server *srv, plugin* p, option *opt) {
option *opt_cond, *opt_act;
condition *c;
action *a;
UNUSED(p);
if (opt->type != OPTION_LIST) {
ERROR(srv, "expected list, got %s", option_type_string(opt->type));
return NULL;
}
if (opt->value.opt_list->len != 2) {
ERROR(srv, "expected list with length 2, has length %u", opt->value.opt_list->len);
return NULL;
}
opt_cond = g_array_index(opt->value.opt_list, option*, 0);
opt_act = g_array_index(opt->value.opt_list, option*, 0);
if (opt_act->type != OPTION_ACTION) {
ERROR(srv, "expected action as second parameter, got %s", option_type_string(opt->type));
return NULL;
}
if (NULL == (c = condition_from_option(srv, opt_cond))) {
ERROR(srv, "expected condition as first parameter, got %s", option_type_string(opt->type));
return NULL;
}
a = action_new_condition(c, action_list_from_action(opt_act->value.opt_action.action));
option_free(opt);
return a;
}
static action_result core_handle_static(server *srv, connection *con, gpointer param) {
UNUSED(param);
/* TODO */
@ -8,21 +62,18 @@ static action_result core_handle_static(server *srv, connection *con, gpointer p
return HANDLER_ERROR;
}
static gboolean core_static(server *srv, gpointer p_d, option *opt, action_func *func) {
UNUSED(p_d);
static action* core_static(server *srv, plugin* p, option *opt) {
UNUSED(p);
if (opt) {
ERROR(srv, "%s", "static action doesn't have parameters");
return FALSE;
return NULL;
}
func->func = core_handle_static;
func->free = NULL;
func->param = NULL;
return TRUE;
return action_new_function(core_handle_static, NULL, NULL);
}
static gboolean core_listen(server *srv, gpointer p_d, option *opt) {
UNUSED(p_d);
static gboolean core_listen(server *srv, plugin* p, option *opt) {
UNUSED(p);
if (opt->type != OPTION_STRING) {
ERROR(srv, "%s", "listen expects a string as parameter");
return FALSE;
@ -38,6 +89,8 @@ static const plugin_option options[] = {
};
static const plugin_action actions[] = {
{ "list", core_list },
{ "when", core_when },
{ "static", core_static },
{ NULL, NULL }
};

@ -6,11 +6,13 @@ struct server {
GHashTable *plugins;
GHashTable *options;
GHashTable *actions;
GHashTable *setups;
/* registered by plugins */
GHashTable *options; /**< const gchar* => server_option* */
GHashTable *actions; /**< const gchar* => server_action* */
GHashTable *setups; /**< const gchar* => server_setup* */
gpointer *option_def_values;
struct action_list *mainactionlist;
gboolean exiting;
GMutex *mutex; /* general mutex for accessing the various members */

@ -27,6 +27,9 @@ common_source='''
'''
common_source_lua='''
actions_lua.c
condition_lua.c
config_lua.c
options_lua.c
'''
@ -83,7 +86,7 @@ def build(bld):
main = bld.new_task_gen('cc', 'program')
main.name = 'lighttpd'
main.source = common_source + main_source
main.source = common_source + common_source_lua + main_source
main.target='lighttpd' + env['APPEND']
main.uselib += 'lighty dl ev openssl pcre lua ' + common_uselib
main.includes = '.'

Loading…
Cancel
Save