diff --git a/include/lighttpd/config_lua.h b/include/lighttpd/config_lua.h index 22411a7..da84a3c 100644 --- a/include/lighttpd/config_lua.h +++ b/include/lighttpd/config_lua.h @@ -5,7 +5,7 @@ #include -LI_API gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, liAction **pact, gboolean allow_setup); +LI_API gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, liAction **pact, gboolean allow_setup, liValue *args); LI_API gboolean li_lua_config_publish_str_hash(liServer *srv, lua_State *L, GHashTable *ht, int (*wrapper)(liServer *srv, lua_State *L, gpointer data)); LI_API int li_lua_config_handle_server_action(liServer *srv, lua_State *L, gpointer _sa); diff --git a/src/main/config_lua.c b/src/main/config_lua.c index 38437a5..410481c 100644 --- a/src/main/config_lua.c +++ b/src/main/config_lua.c @@ -23,11 +23,7 @@ static liValue* lua_params_to_value(liServer *srv, lua_State *L) { val = li_value_new_list(); g_array_set_size(val->data.list, lua_gettop(L) - 1); while (lua_gettop(L) > 1) { - if (NULL == (subval = li_value_from_lua(srv, L))) { - ERROR(srv, "Couldn't convert value from lua (lua type '%s')", lua_typename(L, lua_type(L, -1))); - li_value_free(val); - return NULL; - } + subval = li_value_from_lua(srv, L); g_array_index(val->data.list, liValue*, lua_gettop(L) - 1) = subval; } return val; @@ -140,17 +136,18 @@ int li_lua_config_handle_server_action(liServer *srv, lua_State *L, gpointer _sa liServerAction *sa = (liServerAction*) _sa; liValue *val; liAction *a; + gboolean dolock = (L == srv->L); lua_checkstack(L, 16); val = lua_params_to_value(srv, L); - li_lua_unlock(srv); + if (dolock) li_lua_unlock(srv); /* TRACE(srv, "%s", "Creating action"); */ a = sa->create_action(srv, sa->p, val, sa->userdata); li_value_free(val); - li_lua_lock(srv); + if (dolock) li_lua_lock(srv); if (NULL == a) { lua_pushstring(L, "creating action failed"); @@ -164,14 +161,15 @@ int li_lua_config_handle_server_setup(liServer *srv, lua_State *L, gpointer _ss) liServerSetup *ss = (liServerSetup*) _ss; liValue *val; gboolean res; + gboolean dolock = (L == srv->L); lua_checkstack(L, 16); val = lua_params_to_value(srv, L); - li_lua_unlock(srv); + if (dolock) li_lua_unlock(srv); /* TRACE(srv, "%s", "Calling setup"); */ res = ss->setup(srv, ss->p, val, ss->userdata); - li_lua_lock(srv); + if (dolock) li_lua_lock(srv); if (!res) { li_value_free(val); @@ -183,7 +181,7 @@ int li_lua_config_handle_server_setup(liServer *srv, lua_State *L, gpointer _ss) return 0; } -gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, liAction **pact, gboolean allow_setup) { +gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, liAction **pact, gboolean allow_setup, liValue *args) { int errfunc; int lua_stack_top; gboolean dolock = (L == srv->L); @@ -213,8 +211,14 @@ gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, li_lua_push_lvalues_dict(srv, L); - errfunc = li_lua_push_traceback(L, 0); - if (lua_pcall(L, 0, 1, errfunc)) { + /* arguments for config: local filename, args = ... */ + /* 1. filename */ + lua_pushstring(L, filename); + /* 2. args */ + li_lua_push_value(L, args); + + errfunc = li_lua_push_traceback(L, 2); + if (lua_pcall(L, 2, 0, errfunc)) { ERROR(srv, "lua_pcall(): %s", lua_tostring(L, -1)); /* cleanup stack */ @@ -230,8 +234,6 @@ gboolean li_config_lua_load(lua_State *L, liServer *srv, const gchar *filename, } lua_remove(L, errfunc); - lua_pop(L, 1); /* pop the ret-value */ - lua_getfield(L, LUA_GLOBALSINDEX, "actions"); *pact = li_lua_get_action_ref(L, -1); lua_pop(L, 1); diff --git a/src/main/config_parser.rl b/src/main/config_parser.rl index a2209e4..fcd7354 100644 --- a/src/main/config_parser.rl +++ b/src/main/config_parser.rl @@ -750,7 +750,7 @@ return FALSE; } - if (!li_config_lua_load(srv->L, srv, val->data.string->str, &a, TRUE)) { + if (!li_config_lua_load(srv->L, srv, val->data.string->str, &a, TRUE, NULL)) { ERROR(srv, "include_lua '%s' failed", val->data.string->str); li_value_free(name); li_value_free(val); diff --git a/src/main/lighttpd.c b/src/main/lighttpd.c index 7ca81d5..bee4522 100644 --- a/src/main/lighttpd.c +++ b/src/main/lighttpd.c @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) { } else { #ifdef HAVE_LUA_H - li_config_lua_load(srv->L, srv, config_path, &srv->mainaction, TRUE); + li_config_lua_load(srv->L, srv, config_path, &srv->mainaction, TRUE, NULL); /* lua config frontend */ #else g_print("lua config frontend not available\n"); diff --git a/src/main/value_lua.c b/src/main/value_lua.c index 58863dd..d285d53 100644 --- a/src/main/value_lua.c +++ b/src/main/value_lua.c @@ -77,7 +77,7 @@ liValue* li_value_from_lua(liServer *srv, lua_State *L) { switch (lua_type(L, -1)) { case LUA_TNIL: lua_pop(L, 1); - return li_value_new_none(); + return NULL; case LUA_TBOOLEAN: val = li_value_new_bool(lua_toboolean(L, -1)); @@ -155,6 +155,11 @@ GString* li_lua_togstring(lua_State *L, int ndx) { } int li_lua_push_value(lua_State *L, liValue *value) { + if (NULL == value) { + lua_pushnil(L); + return 1; + } + switch (value->type) { case LI_VALUE_NONE: lua_pushnil(L); diff --git a/src/modules/mod_lua.c b/src/modules/mod_lua.c index 264574c..7c487cd 100644 --- a/src/modules/mod_lua.c +++ b/src/modules/mod_lua.c @@ -5,18 +5,20 @@ * mod_lua * * Setups: - * lua.plugin filename, [ options ] + * lua.plugin filename, [ options ], * - No options available yet, can be omitted * - Can register setup.* and action.* callbacks (like any c module) * via creating a setups / actions table in the global lua namespace * Options: * none * Actions: - * lua.handler filename, [ "ttl": 300 ] + * lua.handler filename, [ "ttl": 300 ], * - Basically the same as include_lua (no setup.* calls allowed), but loads the script * in a worker specific lua_State, so it doesn't use the server wide lua lock. * - You can give a ttl, after which the file is checked for modifications * and reloaded. The default value 0 disables reloading. + * - The third parameter is available as second parameter in the lua file: + * local filename, args = ... * * Example config: * lua.handler "/etc/lighttpd/pathrewrite.lua"; @@ -62,6 +64,7 @@ typedef struct lua_config lua_config; struct lua_config { GString *filename; guint ttl; + liValue *args; lua_worker_config *worker_config; GList mconf_link; @@ -101,7 +104,7 @@ static liHandlerResult lua_handle(liVRequest *vr, gpointer param, gpointer *cont li_action_release(vr->wrk->srv, wc->act); wc->act = NULL; - if (!li_config_lua_load(vr->wrk->L, vr->wrk->srv, conf->filename->str, &wc->act, FALSE) || !wc->act) { + if (!li_config_lua_load(vr->wrk->L, vr->wrk->srv, conf->filename->str, &wc->act, FALSE, conf->args) || !wc->act) { VR_ERROR(vr, "lua.handler: couldn't load '%s'", conf->filename->str); return LI_HANDLER_ERROR; } @@ -127,6 +130,7 @@ static void lua_config_free(liServer *srv, gpointer param) { g_slice_free1(sizeof(lua_worker_config) * srv->worker_count, wc); } g_string_free(conf->filename, TRUE); + li_value_free(conf->args); if (conf->mconf_link.prev) { /* still in LI_SERVER_INIT */ module_config *mc = conf->p->data; @@ -136,12 +140,13 @@ static void lua_config_free(liServer *srv, gpointer param) { g_slice_free(lua_config, conf); } -static lua_config* lua_config_new(liServer *srv, liPlugin *p, GString *filename, guint ttl) { +static lua_config* lua_config_new(liServer *srv, liPlugin *p, GString *filename, guint ttl, liValue *args) { module_config *mc = p->data; lua_config *conf = g_slice_new0(lua_config); conf->filename = filename; conf->ttl = ttl; conf->p = p; + conf->args = args; if (LI_SERVER_INIT != g_atomic_int_get(&srv->state)) { conf->worker_config = g_slice_alloc0(sizeof(lua_worker_config) * srv->worker_count); @@ -158,7 +163,7 @@ static const GString /* lua option names */ ; static liAction* lua_handler_create(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { - liValue *v_filename = NULL, *v_options = NULL; + liValue *v_filename = NULL, *v_options = NULL, *v_args = NULL; lua_config *conf; guint ttl = 0; UNUSED(userdata); @@ -170,6 +175,10 @@ static liAction* lua_handler_create(liServer *srv, liPlugin* p, liValue *val, gp GArray *l = val->data.list; if (l->len > 0) v_filename = g_array_index(l, liValue*, 0); if (l->len > 1) v_options = g_array_index(l, liValue*, 1); + if (l->len > 2) { + v_args = g_array_index(l, liValue*, 2); + g_array_index(l, liValue*, 2) = NULL; + } } } @@ -179,10 +188,12 @@ static liAction* lua_handler_create(liServer *srv, liPlugin* p, liValue *val, gp if (!v_filename) { ERROR(srv, "%s", "lua.handler expects at least a filename, or a filename and some options"); + li_value_free(v_args); return NULL; } if (v_options && v_options->type != LI_VALUE_HASH) { ERROR(srv, "%s", "lua.handler expects options in a hash"); + li_value_free(v_args); return NULL; } @@ -209,11 +220,12 @@ static liAction* lua_handler_create(liServer *srv, liPlugin* p, liValue *val, gp } } - conf = lua_config_new(srv, p, li_value_extract_string(v_filename), ttl); + conf = lua_config_new(srv, p, li_value_extract_string(v_filename), ttl, v_args); return li_action_new_function(lua_handle, NULL, lua_config_free, conf); option_failed: + li_value_free(v_args); return NULL; } @@ -227,7 +239,9 @@ struct luaPlugin { }; static int push_args(lua_State *L, liValue *val) { - if (val->type == LI_VALUE_LIST) { + if (NULL == val) { + return 0; + } else if (val->type == LI_VALUE_LIST) { GArray *list = val->data.list; guint i; for (i = 0; i < list->len; i++) { @@ -417,7 +431,7 @@ static void lua_plugin_init(liServer *srv, liPlugin *p, gpointer userdata) { p->free = lua_plugin_free; } -static gboolean lua_plugin_load(liServer *srv, liPlugin *p, GString *filename) { +static gboolean lua_plugin_load(liServer *srv, liPlugin *p, GString *filename, liValue* args) { int errfunc; int lua_stack_top; lua_State *L = srv->L; @@ -449,8 +463,14 @@ static gboolean lua_plugin_load(liServer *srv, liPlugin *p, GString *filename) { lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfenv(L, -2); - errfunc = li_lua_push_traceback(L, 0); - if (lua_pcall(L, 0, 0, errfunc)) { + /* arguments for plugin: local filename, args = ... */ + /* 1. filename */ + lua_pushlstring(L, GSTR_LEN(filename)); + /* 2. args */ + li_lua_push_value(L, args); + + errfunc = li_lua_push_traceback(L, 2); + if (lua_pcall(L, 2, 0, errfunc)) { ERROR(srv, "lua_pcall(): %s", lua_tostring(L, -1)); goto failed_unlock_lua; } @@ -483,7 +503,7 @@ failed_unlock_lua: } static gboolean lua_plugin(liServer *srv, liPlugin *p, liValue *val, gpointer userdata) { - liValue *v_filename = NULL, *v_options = NULL; + liValue *v_filename = NULL, *v_options = NULL, *v_args = NULL; UNUSED(userdata); if (val) { @@ -493,6 +513,7 @@ static gboolean lua_plugin(liServer *srv, liPlugin *p, liValue *val, gpointer us GArray *l = val->data.list; if (l->len > 0) v_filename = g_array_index(l, liValue*, 0); if (l->len > 1) v_options = g_array_index(l, liValue*, 1); + if (l->len > 2) v_args = g_array_index(l, liValue*, 2); } } @@ -525,20 +546,23 @@ static gboolean lua_plugin(liServer *srv, liPlugin *p, liValue *val, gpointer us if (g_string_equal(key, &lon_ttl)) { if (value->type != LI_VALUE_NUMBER || value->data.number <= 0) { ERROR(srv, "lua.plugin option '%s' expects positive integer as parameter", lon_ttl.str); - return FALSE; + goto option_failed; } ttl = value->data.number; } else { */ ERROR(srv, "unknown option for lua.plugin '%s'", key->str); - return FALSE; + goto option_failed; /* } */ } } - return lua_plugin_load(srv, p, li_value_extract_string(v_filename)); + return lua_plugin_load(srv, p, li_value_extract_string(v_filename), v_args); + +option_failed: + return FALSE; } static const liPluginOption options[] = {