--- embedaddon/lighttpd/src/mod_magnet.c 2014/06/15 20:20:06 1.1.1.2 +++ embedaddon/lighttpd/src/mod_magnet.c 2016/11/02 10:35:00 1.1.1.3 @@ -1,6 +1,9 @@ +#include "first.h" + #include "base.h" #include "log.h" #include "buffer.h" +#include "http_chunk.h" #include "plugin.h" @@ -20,6 +23,9 @@ #include #include +#define LUA_RIDX_LIGHTTPD_SERVER "lighty.srv" +#define LUA_RIDX_LIGHTTPD_CONNECTION "lighty.con" + #define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to" #define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to" #define MAGNET_RESTART_REQUEST 99 @@ -71,7 +77,7 @@ FREE_FUNC(mod_magnet_free) { for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - if (!s) continue; + if (NULL == s) continue; array_free(s->url_raw); array_free(s->physical_path); @@ -106,6 +112,7 @@ SETDEFAULTS_FUNC(mod_magnet_set_defaults) { p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); for (i = 0; i < srv->config_context->used; i++) { + data_config const* config = (data_config const*)srv->config_context->data[i]; plugin_config *s; s = calloc(1, sizeof(plugin_config)); @@ -117,7 +124,7 @@ SETDEFAULTS_FUNC(mod_magnet_set_defaults) { p->config_storage[i] = s; - if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { + if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { return HANDLER_ERROR; } } @@ -158,23 +165,56 @@ static int mod_magnet_patch_connection(server *srv, co } #undef PATCH -/* See http://lua-users.org/wiki/GeneralizedPairsAndIpairs for implementation details. */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 +/* lua5.1 backward compat definition */ +static void lua_pushglobaltable(lua_State *L) { /* (-0, +1, -) */ + lua_pushvalue(L, LUA_GLOBALSINDEX); +} +#endif -/* Override the default pairs() function to allow us to use a __pairs metakey */ +static void magnet_setfenv_mainfn(lua_State *L, int funcIndex) { /* (-1, 0, -) */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 + /* set "_ENV" upvalue, which should be the first upvalue of a "main" lua + * function if it uses any global names + */ + + const char* first_upvalue_name = lua_getupvalue(L, funcIndex, 1); + if (NULL == first_upvalue_name) return; /* doesn't have any upvalues */ + lua_pop(L, 1); /* only need the name of the upvalue, not the value */ + + if (0 != strcmp(first_upvalue_name, "_ENV")) return; + + if (NULL == lua_setupvalue(L, funcIndex, 1)) { + /* pop value if lua_setupvalue didn't set the (not existing) upvalue */ + lua_pop(L, 1); + } +#else + lua_setfenv(L, funcIndex); +#endif +} + +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 +/* lua 5.2 already supports __pairs */ + +/* See http://lua-users.org/wiki/GeneralizedPairsAndIpairs for implementation details. + * Override the default pairs() function to allow us to use a __pairs metakey + */ static int magnet_pairs(lua_State *L) { - luaL_checkany(L, 1); + luaL_checkany(L, 1); /* "self" */ if (luaL_getmetafield(L, 1, "__pairs")) { - lua_insert(L, 1); - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); - return lua_gettop(L); + /* call __pairs(self) */ + lua_pushvalue(L, 1); + lua_call(L, 1, 3); } else { + /* call (self) */ lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); - return lua_gettop(L); + lua_pushvalue(L, 1); + lua_call(L, 1, 3); } + return 3; } +#endif /* Define a function that will iterate over an array* (in upval 1) using current position (upval 2) */ static int magnet_array_next(lua_State *L) { @@ -189,17 +229,12 @@ static int magnet_array_next(lua_State *L) { if (pos >= a->used) return 0; if (NULL != (du = a->data[pos])) { - if (du->key->used) { - lua_pushlstring(L, du->key->ptr, du->key->used - 1); - } - else { - lua_pushlstring(L, "", 0); - } + lua_pushlstring(L, CONST_BUF_LEN(du->key)); switch (du->type) { case TYPE_STRING: ds = (data_string *)du; - if (ds->value && ds->value->used) { - lua_pushlstring(L, ds->value->ptr, ds->value->used - 1); + if (!buffer_is_empty(ds->value)) { + lua_pushlstring(L, CONST_BUF_LEN(ds->value)); } else { lua_pushnil(L); } @@ -233,52 +268,76 @@ static int magnet_array_pairs(lua_State *L, array *a) return 1; } -static int magnet_print(lua_State *L) { - const char *s = luaL_checkstring(L, 1); +static server* magnet_get_server(lua_State *L) { server *srv; - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_SERVER); srv = lua_touserdata(L, -1); lua_pop(L, 1); - log_error_write(srv, __FILE__, __LINE__, "ss", - "(lua-print)", s); + return srv; +} +static connection* magnet_get_connection(lua_State *L) { + connection *con; + + lua_getfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_CONNECTION); + con = lua_touserdata(L, -1); + lua_pop(L, 1); + + return con; +} + +typedef struct { + const char *ptr; + size_t len; +} const_buffer; + +static const_buffer magnet_checkconstbuffer(lua_State *L, int index) { + const_buffer cb; + cb.ptr = luaL_checklstring(L, index, &cb.len); + return cb; +} + +static buffer* magnet_checkbuffer(lua_State *L, int index) { + const_buffer cb = magnet_checkconstbuffer(L, index); + buffer *b = buffer_init(); + buffer_copy_string_len(b, cb.ptr, cb.len); + return b; +} + +static int magnet_print(lua_State *L) { + buffer *b = magnet_checkbuffer(L, 1); + + log_error_write(magnet_get_server(L), __FILE__, __LINE__, "sB", + "(lua-print)", + b); + + buffer_free(b); + return 0; } static int magnet_stat(lua_State *L) { - const char *s = luaL_checkstring(L, 1); - server *srv; - connection *con; - buffer sb; + buffer *sb = magnet_checkbuffer(L, 1); + server *srv = magnet_get_server(L); + connection *con = magnet_get_connection(L); stat_cache_entry *sce = NULL; + handler_t res; - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); + res = stat_cache_get_entry(srv, con, sb, &sce); + buffer_free(sb); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - - sb.ptr = (char *)s; - sb.used = sb.size = strlen(s) + 1; - - if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) { + if (HANDLER_GO_ON != res) { lua_pushnil(L); - return 1; } - lua_newtable(L); + lua_newtable(L); // return value lua_pushboolean(L, S_ISREG(sce->st.st_mode)); lua_setfield(L, -2, "is_file"); - + lua_pushboolean(L, S_ISDIR(sce->st.st_mode)); lua_setfield(L, -2, "is_dir"); @@ -318,21 +377,20 @@ static int magnet_stat(lua_State *L) { lua_pushinteger(L, sce->st.st_ino); lua_setfield(L, -2, "st_ino"); - - if (!buffer_is_empty(sce->etag)) { + if (!buffer_string_is_empty(sce->etag)) { /* we have to mutate the etag */ buffer *b = buffer_init(); etag_mutate(b, sce->etag); - lua_pushlstring(L, b->ptr, b->used - 1); + lua_pushlstring(L, CONST_BUF_LEN(b)); buffer_free(b); } else { lua_pushnil(L); } lua_setfield(L, -2, "etag"); - if (!buffer_is_empty(sce->content_type)) { - lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1); + if (!buffer_string_is_empty(sce->content_type)) { + lua_pushlstring(L, CONST_BUF_LEN(sce->content_type)); } else { lua_pushnil(L); } @@ -343,34 +401,27 @@ static int magnet_stat(lua_State *L) { static int magnet_atpanic(lua_State *L) { - const char *s = luaL_checkstring(L, 1); - server *srv; + buffer *b = magnet_checkbuffer(L, 1); - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); + log_error_write(magnet_get_server(L), __FILE__, __LINE__, "sB", + "(lua-atpanic)", + b); - log_error_write(srv, __FILE__, __LINE__, "ss", - "(lua-atpanic)", s); + buffer_free(b); longjmp(exceptionjmp, 1); } static int magnet_reqhdr_get(lua_State *L) { - connection *con; + connection *con = magnet_get_connection(L); data_string *ds; + /* __index: param 1 is the (empty) table the value was not found in */ const char *key = luaL_checkstring(L, 2); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) { - if (ds->value->used) { - lua_pushlstring(L, ds->value->ptr, ds->value->used - 1); + if (!buffer_is_empty(ds->value)) { + lua_pushlstring(L, CONST_BUF_LEN(ds->value)); } else { lua_pushnil(L); } @@ -381,60 +432,40 @@ static int magnet_reqhdr_get(lua_State *L) { } static int magnet_reqhdr_pairs(lua_State *L) { - connection *con; + connection *con = magnet_get_connection(L); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - return magnet_array_pairs(L, con->request.headers); } static int magnet_status_get(lua_State *L) { data_integer *di; - server *srv; - size_t key_len = 0; + server *srv = magnet_get_server(L); - const char *key = luaL_checklstring(L, 2, &key_len); + /* __index: param 1 is the (empty) table the value was not found in */ + const_buffer key = magnet_checkconstbuffer(L, 2); - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); + di = status_counter_get_counter(srv, key.ptr, key.len); - di = status_counter_get_counter(srv, key, key_len); + lua_pushinteger(L, (lua_Integer)di->value); - lua_pushnumber(L, (double)di->value); - return 1; } static int magnet_status_set(lua_State *L) { - size_t key_len = 0; - server *srv; + server *srv = magnet_get_server(L); - const char *key = luaL_checklstring(L, 2, &key_len); - int counter = luaL_checkint(L, 3); + /* __newindex: param 1 is the (empty) table the value is supposed to be set in */ + const_buffer key = magnet_checkconstbuffer(L, 2); + int counter = (int) luaL_checkinteger(L, 3); - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); + status_counter_set(srv, key.ptr, key.len, counter); - status_counter_set(srv, key, key_len, counter); - return 0; } static int magnet_status_pairs(lua_State *L) { - server *srv; + server *srv = magnet_get_server(L); - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); - return magnet_array_pairs(L, srv->status); } @@ -537,26 +568,17 @@ static buffer *magnet_env_get_buffer(server *srv, conn } static int magnet_env_get(lua_State *L) { - server *srv; - connection *con; + server *srv = magnet_get_server(L); + connection *con = magnet_get_connection(L); + /* __index: param 1 is the (empty) table the value was not found in */ const char *key = luaL_checkstring(L, 2); buffer *dest = NULL; - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); - - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - dest = magnet_env_get_buffer(srv, con, key); - if (dest && dest->used) { - lua_pushlstring(L, dest->ptr, dest->used - 1); + if (!buffer_is_empty(dest)) { + lua_pushlstring(L, CONST_BUF_LEN(dest)); } else { lua_pushnil(L); } @@ -565,25 +587,22 @@ static int magnet_env_get(lua_State *L) { } static int magnet_env_set(lua_State *L) { - server *srv; - connection *con; + server *srv = magnet_get_server(L); + connection *con = magnet_get_connection(L); + /* __newindex: param 1 is the (empty) table the value is supposed to be set in */ const char *key = luaL_checkstring(L, 2); - const char *val = luaL_checkstring(L, 3); buffer *dest = NULL; - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); + luaL_checkany(L, 3); /* nil or a string */ - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) { - buffer_copy_string(dest, val); + if (lua_isnil(L, 3)) { + buffer_reset(dest); + } else { + const_buffer val = magnet_checkconstbuffer(L, 3); + buffer_copy_string_len(dest, val.ptr, val.len); + } } else { /* couldn't save */ @@ -594,41 +613,32 @@ static int magnet_env_set(lua_State *L) { } static int magnet_env_next(lua_State *L) { - server *srv; - connection *con; - int pos = lua_tointeger(L, lua_upvalueindex(1)); + server *srv = magnet_get_server(L); + connection *con = magnet_get_connection(L); + const int pos = lua_tointeger(L, lua_upvalueindex(1)); buffer *dest; - lua_pushstring(L, "lighty.srv"); - lua_gettable(L, LUA_REGISTRYINDEX); - srv = lua_touserdata(L, -1); - lua_pop(L, 1); - - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - + /* ignore previous key: use upvalue for current pos */ lua_settop(L, 0); if (NULL == magnet_env[pos].name) return 0; /* end of list */ + /* Update our positional upval to reflect our new current position */ + lua_pushinteger(L, pos + 1); + lua_replace(L, lua_upvalueindex(1)); + /* key to return */ lua_pushstring(L, magnet_env[pos].name); + /* get value */ dest = magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type); - if (dest && dest->used) { - lua_pushlstring(L, dest->ptr, dest->used - 1); + if (!buffer_is_empty(dest)) { + lua_pushlstring(L, CONST_BUF_LEN(dest)); } else { lua_pushnil(L); } - /* Update our positional upval to reflect our new current position */ - pos++; - lua_pushinteger(L, pos); - lua_replace(L, lua_upvalueindex(1)); - - /* Returning 2 items on the stack (key, value) */ + /* return 2 items on the stack (key, value) */ return 2; } @@ -639,17 +649,14 @@ static int magnet_env_pairs(lua_State *L) { } static int magnet_cgi_get(lua_State *L) { - connection *con; + connection *con = magnet_get_connection(L); data_string *ds; + /* __index: param 1 is the (empty) table the value was not found in */ const char *key = luaL_checkstring(L, 2); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (NULL != (ds = (data_string *)array_get_element(con->environment, key)) && ds->value->used) + ds = (data_string *)array_get_element(con->environment, key); + if (NULL != ds && !buffer_is_empty(ds->value)) lua_pushlstring(L, CONST_BUF_LEN(ds->value)); else lua_pushnil(L); @@ -658,70 +665,45 @@ static int magnet_cgi_get(lua_State *L) { } static int magnet_cgi_set(lua_State *L) { - connection *con; + connection *con = magnet_get_connection(L); - const char *key = luaL_checkstring(L, 2); - const char *val = luaL_checkstring(L, 3); + /* __newindex: param 1 is the (empty) table the value is supposed to be set in */ + const_buffer key = magnet_checkconstbuffer(L, 2); + const_buffer val = magnet_checkconstbuffer(L, 2); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); + array_set_key_value(con->environment, key.ptr, key.len, val.ptr, val.len); - array_set_key_value(con->environment, key, strlen(key), val, strlen(val)); - return 0; } static int magnet_cgi_pairs(lua_State *L) { - connection *con; + connection *con = magnet_get_connection(L); - lua_pushstring(L, "lighty.con"); - lua_gettable(L, LUA_REGISTRYINDEX); - con = lua_touserdata(L, -1); - lua_pop(L, 1); - return magnet_array_pairs(L, con->environment); } -static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) { - UNUSED(p); - /** - * get the environment of the function - */ +static int magnet_copy_response_header(server *srv, connection *con, lua_State *L, int lighty_table_ndx) { + force_assert(lua_istable(L, lighty_table_ndx)); - lua_getfenv(L, -1); /* -1 is the function */ - - /* lighty.header */ - - lua_getfield(L, -1, "lighty"); /* lighty.* from the env */ - force_assert(lua_istable(L, -1)); - - lua_getfield(L, -1, "header"); /* lighty.header */ + lua_getfield(L, lighty_table_ndx, "header"); /* lighty.header */ if (lua_istable(L, -1)) { /* header is found, and is a table */ lua_pushnil(L); while (lua_next(L, -2) != 0) { if (lua_isstring(L, -1) && lua_isstring(L, -2)) { - const char *key, *val; - size_t key_len, val_len; + const_buffer key = magnet_checkconstbuffer(L, -2); + const_buffer val = magnet_checkconstbuffer(L, -1); - key = lua_tolstring(L, -2, &key_len); - val = lua_tolstring(L, -1, &val_len); - - response_header_overwrite(srv, con, key, key_len, val, val_len); + response_header_overwrite(srv, con, key.ptr, key.len, val.ptr, val.len); } lua_pop(L, 1); } } + lua_pop(L, 1); /* pop lighty.header */ - lua_pop(L, 1); /* pop the header-table */ - lua_pop(L, 1); /* pop the lighty-env */ - lua_pop(L, 1); /* pop the function env */ - return 0; } @@ -734,111 +716,78 @@ static int magnet_copy_response_header(server *srv, co * * return 200 */ -static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) { - UNUSED(p); - /** - * get the environment of the function - */ +static int magnet_attach_content(server *srv, connection *con, lua_State *L, int lighty_table_ndx) { + force_assert(lua_istable(L, lighty_table_ndx)); - force_assert(lua_isfunction(L, -1)); - lua_getfenv(L, -1); /* -1 is the function */ - - lua_getfield(L, -1, "lighty"); /* lighty.* from the env */ - force_assert(lua_istable(L, -1)); - - lua_getfield(L, -1, "content"); /* lighty.content */ + lua_getfield(L, lighty_table_ndx, "content"); /* lighty.content */ if (lua_istable(L, -1)) { int i; - /* header is found, and is a table */ + /* content is found, and is a table */ for (i = 1; ; i++) { lua_rawgeti(L, -1, i); /* -1 is the value and should be the value ... aka a table */ if (lua_isstring(L, -1)) { - size_t s_len = 0; - const char *s = lua_tolstring(L, -1, &s_len); + const_buffer data = magnet_checkconstbuffer(L, -1); - chunkqueue_append_mem(con->write_queue, s, s_len + 1); + chunkqueue_append_mem(con->write_queue, data.ptr, data.len); } else if (lua_istable(L, -1)) { lua_getfield(L, -1, "filename"); - lua_getfield(L, -2, "length"); - lua_getfield(L, -3, "offset"); + lua_getfield(L, -2, "length"); /* (0-based) end of range (not actually "length") */ + lua_getfield(L, -3, "offset"); /* (0-based) start of range */ if (lua_isstring(L, -3)) { /* filename has to be a string */ - buffer *fn; - stat_cache_entry *sce; - const char *fn_str; - handler_t res; + buffer *fn = magnet_checkbuffer(L, -3); + off_t off = (off_t) luaL_optinteger(L, -1, 0); + off_t len = (off_t) luaL_optinteger(L, -2, -1); /*(-1 to http_chunk_append_file_range() uses file size minus offset)*/ + if (off < 0) { + buffer_free(fn); + return luaL_error(L, "offset for '%s' is negative", lua_tostring(L, -3)); + } - fn_str = lua_tostring(L, -3); - fn = buffer_init_string(fn_str); + if (len >= off) { + len -= off; + } else if (-1 != len) { + buffer_free(fn); + return luaL_error(L, "offset > length for '%s'", lua_tostring(L, -3)); + } - res = stat_cache_get_entry(srv, con, fn, &sce); - - if (HANDLER_GO_ON == res) { - off_t off = 0; - off_t len = 0; - - if (lua_isnumber(L, -1)) { - off = lua_tonumber(L, -1); - } - - if (lua_isnumber(L, -2)) { - len = lua_tonumber(L, -2); - } else { - len = sce->st.st_size; - } - - if (off < 0) { - buffer_free(fn); - return luaL_error(L, "offset for '%s' is negative", fn_str); - } - - if (len < off) { - buffer_free(fn); - return luaL_error(L, "offset > length for '%s'", fn_str); - } - - chunkqueue_append_file(con->write_queue, fn, off, len - off); + if (0 != len && 0 != http_chunk_append_file_range(srv, con, fn, off, len)) { + buffer_free(fn); + return luaL_error(L, "error opening file content '%s' at offset %lld", lua_tostring(L, -3), (long long)off); } buffer_free(fn); } else { - lua_pop(L, 3 + 2); /* correct the stack */ - return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i); } lua_pop(L, 3); } else if (lua_isnil(L, -1)) { - /* oops, end of list */ + /* end of list */ lua_pop(L, 1); break; } else { - lua_pop(L, 4); - return luaL_error(L, "content[%d] is neither a string nor a table: ", i); } - lua_pop(L, 1); /* pop the content[...] table */ + lua_pop(L, 1); /* pop the content[...] entry value */ } } else { return luaL_error(L, "lighty.content has to be a table"); } - lua_pop(L, 1); /* pop the header-table */ - lua_pop(L, 1); /* pop the lighty-table */ - lua_pop(L, 1); /* php the function env */ + lua_pop(L, 1); /* pop lighty.content */ return 0; } -static int traceback (lua_State *L) { +static int traceback(lua_State *L) { if (!lua_isstring(L, 1)) /* 'message' not a string? */ return 1; /* keep it intact */ - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + lua_getglobal(L, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; @@ -854,6 +803,10 @@ static int traceback (lua_State *L) { return 1; } +/* push traceback function before calling lua_pcall after narg arguments + * have been pushed (inserts it before the arguments). returns index for + * traceback function ("msgh" in lua_pcall) + */ static int push_traceback(lua_State *L, int narg) { int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback); @@ -863,11 +816,11 @@ static int push_traceback(lua_State *L, int narg) { static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) { lua_State *L; - int lua_return_value = -1; - int errfunc; - /* get the script-context */ + int lua_return_value; + const int func_ndx = 1; + const int lighty_table_ndx = 2; - + /* get the script-context */ L = script_cache_get_script(srv, con, p->cache, name); if (lua_isstring(L, -1)) { @@ -880,7 +833,7 @@ static handler_t magnet_attract(server *srv, connectio lua_pop(L, 1); - force_assert(lua_gettop(L) == 0); /* only the function should be on the stack */ + force_assert(lua_gettop(L) == 0); /* only the error should have been on the stack */ con->http_status = 500; con->mode = DIRECT; @@ -888,13 +841,14 @@ static handler_t magnet_attract(server *srv, connectio return HANDLER_FINISHED; } - lua_pushstring(L, "lighty.srv"); + force_assert(lua_gettop(L) == 1); + force_assert(lua_isfunction(L, func_ndx)); + lua_pushlightuserdata(L, srv); - lua_settable(L, LUA_REGISTRYINDEX); /* registery[] = srv */ + lua_setfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_SERVER); - lua_pushstring(L, "lighty.con"); lua_pushlightuserdata(L, con); - lua_settable(L, LUA_REGISTRYINDEX); /* registery[] = con */ + lua_setfield(L, LUA_REGISTRYINDEX, LUA_RIDX_LIGHTTPD_CONNECTION); lua_atpanic(L, magnet_atpanic); @@ -903,7 +857,7 @@ static handler_t magnet_attract(server *srv, connectio * * setmetatable({}, {__index = _G}) * - * if a function, symbol is not defined in our env, __index will lookup + * if a function symbol is not defined in our env, __index will lookup * in the global env. * * all variables created in the script-env will be thrown @@ -916,9 +870,13 @@ static handler_t magnet_attract(server *srv, connectio lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */ /** - * lighty.request[] has the HTTP-request headers - * lighty.content[] is a table of string/file - * lighty.header[] is a array to set response headers + * lighty.request[] (ro) has the HTTP-request headers + * lighty.env[] (rw) has various url/physical file paths and + * request meta data; might contain nil values + * lighty.req_env[] (ro) has the cgi environment + * lighty.status[] (ro) has the status counters + * lighty.content[] (rw) is a table of string/file + * lighty.header[] (rw) is a array to set response headers */ lua_newtable(L); /* lighty.* (sp += 1) */ @@ -933,18 +891,18 @@ static handler_t magnet_attract(server *srv, connectio lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ - lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_newtable(L); /* the meta-table for the env-table (sp += 1) */ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_env_pairs); /* (sp += 1) */ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */ - lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ + lua_setmetatable(L, -2); /* tie the metatable to env (sp -= 1) */ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ - lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_newtable(L); /* the meta-table for the req_env-table (sp += 1) */ lua_pushcfunction(L, magnet_cgi_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_cgi_set); /* (sp += 1) */ @@ -955,14 +913,14 @@ static handler_t magnet_attract(server *srv, connectio lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ - lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_newtable(L); /* the meta-table for the status-table (sp += 1) */ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_status_pairs); /* (sp += 1) */ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */ - lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ + lua_setmetatable(L, -2); /* tie the metatable to statzs (sp -= 1) */ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */ /* add empty 'content' and 'header' tables */ @@ -978,83 +936,98 @@ static handler_t magnet_attract(server *srv, connectio lua_pushcfunction(L, magnet_stat); /* (sp += 1) */ lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */ + /* insert lighty table at index 2 */ + lua_pushvalue(L, -1); + lua_insert(L, lighty_table_ndx); + lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */ - /* override the default pairs() function to our __pairs capable version */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 + /* override the default pairs() function to our __pairs capable version; + * not needed for lua 5.2+ + */ lua_getglobal(L, "pairs"); /* push original pairs() (sp += 1) */ lua_pushcclosure(L, magnet_pairs, 1); lua_setfield(L, -2, "pairs"); /* (sp -= 1) */ +#endif lua_newtable(L); /* the meta-table for the new env (sp += 1) */ - lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */ + lua_pushglobaltable(L); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */ + magnet_setfenv_mainfn(L, 1); /* (sp -= 1) */ - lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */ - - errfunc = push_traceback(L, 0); - if (lua_pcall(L, 0, 1, errfunc)) { + /* pcall will destroy the func value, duplicate it */ /* (sp += 1) */ + lua_pushvalue(L, func_ndx); + { + int errfunc = push_traceback(L, 0); + int ret = lua_pcall(L, 0, 1, errfunc); lua_remove(L, errfunc); - log_error_write(srv, __FILE__, __LINE__, - "ss", - "lua_pcall():", - lua_tostring(L, -1)); - lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */ - force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + /* reset environment */ + lua_pushglobaltable(L); /* (sp += 1) */ + magnet_setfenv_mainfn(L, 1); /* (sp -= 1) */ - con->http_status = 500; - con->mode = DIRECT; + if (0 != ret) { + log_error_write(srv, __FILE__, __LINE__, + "ss", + "lua_pcall():", + lua_tostring(L, -1)); + lua_pop(L, 2); /* remove the error-msg and the lighty table at index 2 */ - return HANDLER_FINISHED; - } - lua_remove(L, errfunc); + force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */ - /* we should have the function-copy and the return value on the stack */ - force_assert(lua_gettop(L) == 2); + con->http_status = 500; + con->mode = DIRECT; - if (lua_isnumber(L, -1)) { - /* if the ret-value is a number, take it */ - lua_return_value = (int)lua_tonumber(L, -1); + return HANDLER_FINISHED; + } } - lua_pop(L, 1); /* pop the ret-value */ - magnet_copy_response_header(srv, con, p, L); + /* we should have the function, the lighty table and the return value on the stack */ + force_assert(lua_gettop(L) == 3); - if (lua_return_value > 99) { - con->http_status = lua_return_value; - con->file_finished = 1; + lua_return_value = (int) luaL_optinteger(L, -1, -1); + lua_pop(L, 1); /* pop return value */ - /* try { ...*/ - if (0 == setjmp(exceptionjmp)) { - magnet_attach_content(srv, con, p, L); - if (!chunkqueue_is_empty(con->write_queue)) { - con->mode = p->id; - } - } else { - /* } catch () { */ - con->http_status = 500; - con->mode = DIRECT; - } + magnet_copy_response_header(srv, con, L, lighty_table_ndx); - force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + { + handler_t result = HANDLER_GO_ON; - /* we are finished */ - return HANDLER_FINISHED; - } else if (MAGNET_RESTART_REQUEST == lua_return_value) { - force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + if (lua_return_value > 99) { + con->http_status = lua_return_value; + con->file_finished = 1; - return HANDLER_COMEBACK; - } else { - force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + /* try { ...*/ + if (0 == setjmp(exceptionjmp)) { + magnet_attach_content(srv, con, L, lighty_table_ndx); + if (!chunkqueue_is_empty(con->write_queue)) { + con->mode = p->id; + } + } else { + lua_settop(L, 2); /* remove all but function and lighty table */ + /* } catch () { */ + con->http_status = 500; + con->mode = DIRECT; + } - return HANDLER_GO_ON; + result = HANDLER_FINISHED; + } else if (MAGNET_RESTART_REQUEST == lua_return_value) { + result = HANDLER_COMEBACK; + } + + lua_pop(L, 1); /* pop the lighty table */ + force_assert(lua_gettop(L) == 1); /* only the function should remain on the stack */ + + return result; } } static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) { size_t i; + handler_t ret = HANDLER_GO_ON; /* no filename set */ if (files->used == 0) return HANDLER_GO_ON; @@ -1062,18 +1035,25 @@ static handler_t magnet_attract_array(server *srv, con /** * execute all files and jump out on the first !HANDLER_GO_ON */ - for (i = 0; i < files->used; i++) { + for (i = 0; i < files->used && ret == HANDLER_GO_ON; i++) { data_string *ds = (data_string *)files->data[i]; - handler_t ret; - if (buffer_is_empty(ds->value)) continue; + if (buffer_string_is_empty(ds->value)) continue; ret = magnet_attract(srv, con, p, ds->value); + } - if (ret != HANDLER_GO_ON) return ret; + if (con->error_handler_saved_status) { + /* retrieve (possibly modified) REDIRECT_STATUS and store as number */ + unsigned long x; + data_string * const ds = (data_string *)array_get_element(con->environment, "REDIRECT_STATUS"); + if (ds && (x = strtoul(ds->value->ptr, NULL, 10)) < 1000) + /*(simplified validity check x < 1000)*/ + con->error_handler_saved_status = + con->error_handler_saved_status > 0 ? (int)x : -(int)x; } - return HANDLER_GO_ON; + return ret; } URIHANDLER_FUNC(mod_magnet_uri_handler) { @@ -1112,6 +1092,9 @@ int mod_magnet_plugin_init(plugin *p) { } #else + +#pragma message("lua is required, but was not found") + int mod_magnet_plugin_init(plugin *p); int mod_magnet_plugin_init(plugin *p) { UNUSED(p);