Browse Source

Add core lua support to handle requests

personal/stbuehler/wip
Stefan Bühler 13 years ago
parent
commit
659ebfdd16
  1. 7
      include/lighttpd/actions_lua.h
  2. 6
      include/lighttpd/condition_lua.h
  3. 73
      include/lighttpd/core_lua.h
  4. 11
      include/lighttpd/server.h
  5. 10
      src/CMakeLists.txt
  6. 25
      src/main/Makefile.am
  7. 108
      src/main/actions_lua.c
  8. 108
      src/main/chunk_lua.c
  9. 6
      src/main/condition_lua.c
  10. 42
      src/main/config_lua.c
  11. 44
      src/main/connection_lua.c
  12. 201
      src/main/core_lua.c
  13. 152
      src/main/environment_lua.c
  14. 240
      src/main/http_headers_lua.c
  15. 165
      src/main/physical_lua.c
  16. 348
      src/main/request_lua.c
  17. 160
      src/main/response_lua.c
  18. 23
      src/main/server.c
  19. 7
      src/main/value_lua.c
  20. 259
      src/main/virtualrequest_lua.c
  21. 4
      src/modules/mod_accesslog.c

7
include/lighttpd/actions_lua.h

@ -4,7 +4,10 @@
#include <lighttpd/base.h>
#include <lua.h>
liAction* lua_get_action(lua_State *L, int ndx);
int lua_push_action(liServer *srv, lua_State *L, liAction *a);
LI_API liAction* lua_get_action(lua_State *L, int ndx);
LI_API int lua_push_action(liServer *srv, lua_State *L, liAction *a);
/* create new action from lua function */
LI_API liAction* lua_make_action(liServer *srv, lua_State *L, int ndx);
#endif

6
include/lighttpd/condition_lua.h

@ -4,9 +4,9 @@
#include <lighttpd/base.h>
#include <lua.h>
liCondition* lua_get_condition(lua_State *L, int ndx);
int lua_push_condition(liServer *srv, lua_State *L, liCondition *c);
LI_API liCondition* lua_get_condition(lua_State *L, int ndx);
LI_API int lua_push_condition(liServer *srv, lua_State *L, liCondition *c);
void lua_push_lvalues_dict(liServer *srv, lua_State *L);
LI_API void lua_push_lvalues_dict(liServer *srv, lua_State *L);
#endif

73
include/lighttpd/core_lua.h

@ -0,0 +1,73 @@
#ifndef _LIGHTTPD_CORE_LUA_H_
#define _LIGHTTPD_CORE_LUA_H_
#include <lighttpd/base.h>
#include <lua.h>
#define li_lua_lock(srv) g_mutex_lock((srv)->lualock);
#define li_lua_unlock(srv) g_mutex_unlock((srv)->lualock);
LI_API void lua_init_chunk_mt(lua_State *L);
LI_API liChunk* lua_get_chunk(lua_State *L, int ndx);
LI_API int lua_push_chunk(lua_State *L, liChunk *c);
LI_API liChunkQueue* lua_get_chunkqueue(lua_State *L, int ndx);
LI_API int lua_push_chunkqueue(lua_State *L, liChunkQueue *cq);
LI_API void lua_init_connection_mt(lua_State *L);
LI_API liConnection* lua_get_connection(lua_State *L, int ndx);
LI_API int lua_push_connection(lua_State *L, liConnection *con);
LI_API void lua_init_environment_mt(lua_State *L);
LI_API liEnvironment* lua_get_environment(lua_State *L, int ndx);
LI_API int lua_push_environment(lua_State *L, liEnvironment *env);
LI_API void lua_init_http_headers_mt(lua_State *L);
LI_API liHttpHeaders* lua_get_http_headers(lua_State *L, int ndx);
LI_API int lua_push_http_headers(lua_State *L, liHttpHeaders *headers);
LI_API void lua_init_physical_mt(lua_State *L);
LI_API liPhysical* lua_get_physical(lua_State *L, int ndx);
LI_API int lua_push_physical(lua_State *L, liPhysical *phys);
LI_API void lua_init_request_mt(lua_State *L);
LI_API liRequest* lua_get_request(lua_State *L, int ndx);
LI_API int lua_push_request(lua_State *L, liRequest *req);
LI_API liRequestUri* lua_get_requesturi(lua_State *L, int ndx);
LI_API int lua_push_requesturi(lua_State *L, liRequestUri *uri);
LI_API void lua_init_response_mt(lua_State *L);
LI_API liResponse* lua_get_response(lua_State *L, int ndx);
LI_API int lua_push_response(lua_State *L, liResponse *resp);
LI_API void lua_init_vrequest_mt(lua_State *L);
LI_API liVRequest* lua_get_vrequest(lua_State *L, int ndx);
LI_API int lua_push_vrequest(lua_State *L, liVRequest *vr);
/* return 1 if value is found in mt (on top of the stack), 0 if it is not found (stack balance = 0)
* table, key on stack at pos 0 and 1 (i.e. __index metho)
*/
LI_API int li_lua_metatable_index(lua_State *L);
LI_API void li_lua_init(liServer *srv, lua_State *L);
LI_API int li_lua_push_traceback(lua_State *L, int narg);
LI_API void li_lua_restore_globals(lua_State *L);
LI_API void li_lua_new_globals(lua_State *L);
/* joinWith " " (map tostring parameter[from..to]) */
LI_API GString* lua_print_get_string(lua_State *L, int from, int to);
/* pairs() for a GHashTable GString -> GString:
* Don't modify the hastable while iterating:
* - no new keys
* - no delete
* Modifying values is fine; g_hash_table_insert() as long as the key already exists too.
* The returned "next" function has an internal state, it ignores the table/state and previous key parameter.
* returns: <next>, nil, nil on the stack (and 3 as c function)
*/
LI_API int li_lua_ghashtable_gstring_pairs(lua_State *L, GHashTable *ht);
#endif

11
include/lighttpd/server.h

@ -1,8 +1,14 @@
#ifndef _LIGHTTPD_SERVER_H_
#define _LIGHTTPD_SERVER_H_
#ifndef _LIGHTTPD_BASE_H_
#error Please include <lighttpd/base.h> instead of this file
#endif
struct lua_State;
#ifndef LIGHTTPD_SERVER_MAGIC
#define LIGHTTPD_SERVER_MAGIC ((guint)0x12AB34CD)
# define LIGHTTPD_SERVER_MAGIC ((guint)0x12AB34CD)
#endif
typedef gboolean (*liConnectionNewCB)(liConnection *con);
@ -41,6 +47,9 @@ struct liServer {
liServerState state, dest_state; /** atomic access */
liAngelConnection *acon;
GMutex *lualock;
struct lua_State *L; /** NULL if compiled without Lua */
liWorker *main_worker;
guint worker_count;
GArray *workers;

10
src/CMakeLists.txt

@ -182,6 +182,16 @@ SET(LIGHTTPD_SHARED_SRC ${LIGHTTPD_SHARED_SRC}
condition_lua.c
config_lua.c
value_lua.c
chunk_lua.c
core_lua.c
connection_lua.c
environment_lua.c
http_headers_lua.c
physical_lua.c
request_lua.c
response_lua.c
virtualrequest_lua.c
)
ENDIF(WITH_LUA)

25
src/main/Makefile.am

@ -38,18 +38,27 @@ lighttpd_shared_src= \
\
plugin_core.c
if USE_LUA
lighttpd_shared_src+= \
lua_src= \
actions_lua.c \
condition_lua.c \
config_lua.c \
value_lua.c
value_lua.c \
\
chunk_lua.c \
connection_lua.c \
core_lua.c \
environment_lua.c \
http_headers_lua.c \
physical_lua.c \
request_lua.c \
response_lua.c \
virtualrequest_lua.c
if USE_LUA
lighttpd_shared_src+=$(lua_src)
endif
EXTRA_lighttpd_SOURCES=\
actions_lua.c \
condition_lua.c \
config_lua.c \
value_lua.c
EXTRA_lighttpd_SOURCES=$(lua_src)
BUILT_SOURCES=config_parser.c http_request_parser.c http_response_parser.c url_parser.c

108
src/main/actions_lua.c

@ -1,10 +1,11 @@
#include <lighttpd/actions_lua.h>
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_ACTION "action*"
#define LUA_ACTION "liAction*"
liAction* lua_get_action(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
@ -43,3 +44,108 @@ int lua_push_action(liServer *srv, lua_State *L, liAction *a) {
lua_setmetatable(L, -2);
return 1;
}
typedef struct lua_action_param lua_action_param;
struct lua_action_param {
int func_ref;
};
typedef struct lua_action_ctx lua_action_ctx;
struct lua_action_ctx {
int g_ref;
};
static liHandlerResult lua_action_func(liVRequest *vr, gpointer param, gpointer *context) {
lua_action_param *par = param;
lua_action_ctx *ctx = *context;
liServer *srv = vr->wrk->srv;
lua_State *L = srv->L;
liHandlerResult res = LI_HANDLER_GO_ON;
int errfunc;
li_lua_lock(srv);
lua_rawgeti(L, LUA_REGISTRYINDEX, par->func_ref);
lua_pushvalue(L, -1);
lua_getfenv(L, -1);
if (!ctx) {
*context = ctx = g_slice_new0(lua_action_ctx);
lua_newtable(L);
lua_pushvalue(L, -1);
ctx->g_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->g_ref);
}
lua_setfield(L, -2, "_G");
lua_pop(L, 1);
lua_push_vrequest(L, vr);
errfunc = li_lua_push_traceback(L, 1);
if (lua_pcall(L, 1, 1, errfunc)) {
ERROR(srv, "lua_pcall(): %s", lua_tostring(L, -1));
lua_pop(L, 1);
res = LI_HANDLER_ERROR;
} else {
lua_pop(L, 1);
}
lua_remove(L, errfunc);
lua_getfenv(L, -1);
lua_pushnil(L);
lua_setfield(L, -2, "_G");
lua_pop(L, 2);
li_lua_unlock(srv);
return res;
}
static liHandlerResult lua_action_cleanup(liVRequest *vr, gpointer param, gpointer context) {
lua_action_ctx *ctx = context;
liServer *srv = vr->wrk->srv;
lua_State *L = srv->L;
UNUSED(param);
li_lua_lock(srv);
luaL_unref(L, LUA_REGISTRYINDEX, ctx->g_ref);
li_lua_unlock(srv);
g_slice_free(lua_action_ctx, ctx);
return LI_HANDLER_GO_ON;
}
static void lua_action_free(liServer *srv, gpointer param) {
lua_action_param *par = param;
lua_State *L = srv->L;
li_lua_lock(srv);
luaL_unref(L, LUA_REGISTRYINDEX, par->func_ref);
li_lua_unlock(srv);
g_slice_free(lua_action_param, par);
}
liAction* lua_make_action(liServer *srv, lua_State *L, int ndx) {
lua_action_param *par = g_slice_new0(lua_action_param);
g_assert(L == srv->L);
lua_pushvalue(L, ndx); /* +1 */
par->func_ref = luaL_ref(L, LUA_REGISTRYINDEX); /* -1 */
/* new environment for function */
lua_pushvalue(L, ndx); /* +1 */
lua_newtable(L); /* +1 */
/* new mt */
lua_newtable(L); /* +1 */
lua_getfield(L, LUA_REGISTRYINDEX, "li_globals"); /* +1 */
lua_setfield(L, -2, "__index"); /* -1 */
lua_setmetatable(L, -2); /* -1 */
lua_setfenv(L, -2); /* -1 */
lua_pop(L, 1); /* -1 */
return li_action_new_function(lua_action_func, lua_action_cleanup, lua_action_free, par);
}

108
src/main/chunk_lua.c

@ -0,0 +1,108 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_CHUNK "liChunk*"
#define LUA_CHUNKQUEUE "liChunkQueue*"
static void init_chunk_mt(lua_State *L) {
/* TODO */
}
static int lua_chunkqueue_add(lua_State *L) {
liChunkQueue *cq;
const char *s;
size_t len;
luaL_checkany(L, 2);
cq = lua_get_chunkqueue(L, 1);
if (cq == NULL) return 0;
if (lua_isstring(L, 2)) {
s = lua_tolstring(L, 2, &len);
li_chunkqueue_append_mem(cq, s, len);
} else {
lua_pushliteral(L, "Wrong type for chunkqueue add");
lua_error(L);
}
return 0;
}
static const luaL_Reg chunkqueue_mt[] = {
{ "add", lua_chunkqueue_add },
{ NULL, NULL }
};
static void init_chunkqueue_mt(lua_State *L) {
luaL_register(L, NULL, chunkqueue_mt);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}
void lua_init_chunk_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_CHUNK)) {
init_chunk_mt(L);
}
lua_pop(L, 1);
if (luaL_newmetatable(L, LUA_CHUNKQUEUE)) {
init_chunkqueue_mt(L);
}
lua_pop(L, 1);
}
liChunk* lua_get_chunk(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_CHUNK);
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 *(liChunk**) lua_touserdata(L, ndx);
}
int lua_push_chunk(lua_State *L, liChunk *c) {
liChunk **pc;
pc = (liChunk**) lua_newuserdata(L, sizeof(liChunk*));
*pc = c;
if (luaL_newmetatable(L, LUA_CHUNK)) {
init_chunk_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}
liChunkQueue* lua_get_chunkqueue(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_CHUNKQUEUE);
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 *(liChunkQueue**) lua_touserdata(L, ndx);
}
int lua_push_chunkqueue(lua_State *L, liChunkQueue *cq) {
liChunkQueue **pcq;
pcq = (liChunkQueue**) lua_newuserdata(L, sizeof(liChunkQueue*));
*pcq = cq;
if (luaL_newmetatable(L, LUA_CHUNKQUEUE)) {
init_chunkqueue_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}

6
src/main/condition_lua.c

@ -5,9 +5,9 @@
#include <lualib.h>
#include <lauxlib.h>
#define LUA_CONDITION "condition*"
#define LUA_COND_LVALUE "cond_lliValue*"
#define LUA_COND_LVALUE_T "cond_lvalue_t"
#define LUA_CONDITION "liCondition*"
#define LUA_COND_LVALUE "liConditionLValue*"
#define LUA_COND_LVALUE_T "liCondLValue"
/* helper */
#define lua_mt_register_srv(srv, L, name, func) do {\

42
src/main/config_lua.c

@ -4,6 +4,8 @@
#include <lighttpd/value_lua.h>
#include <lighttpd/actions_lua.h>
# include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
@ -170,38 +172,13 @@ static int handle_server_setup(liServer *srv, lua_State *L, gpointer _ss) {
return 0;
}
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");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
return 1;
}
static int push_traceback(lua_State *L, int narg) {
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback);
lua_insert(L, base);
return base;
}
gboolean li_config_lua_load(liServer *srv, const gchar *filename) {
lua_State *L;
lua_State *L = srv->L;
int errfunc;
L = luaL_newstate();
luaL_openlibs(L);
li_lua_lock(srv);
li_lua_new_globals(L);
if (0 != luaL_loadfile(L, filename)) {
ERROR(srv, "Loading script '%s' failed: %s", filename, lua_tostring(L, -1));
@ -218,7 +195,7 @@ gboolean li_config_lua_load(liServer *srv, const gchar *filename) {
lua_push_lvalues_dict(srv, L);
errfunc = push_traceback(L, 0);
errfunc = li_lua_push_traceback(L, 0);
if (lua_pcall(L, 0, 1, errfunc)) {
ERROR(srv, "lua_pcall(): %s", lua_tostring(L, -1));
return FALSE;
@ -234,6 +211,9 @@ gboolean li_config_lua_load(liServer *srv, const gchar *filename) {
assert(lua_gettop(L) == 0);
lua_close(L);
li_lua_restore_globals(L);
li_lua_unlock(srv);
return TRUE;
}

44
src/main/connection_lua.c

@ -0,0 +1,44 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_CONNECTION "liConnection*"
static void init_con_mt(lua_State *L) {
/* TODO */
}
void lua_init_connection_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_CONNECTION)) {
init_con_mt(L);
}
lua_pop(L, 1);
}
liConnection* lua_get_connection(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_CONNECTION);
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 *(liConnection**) lua_touserdata(L, ndx);
}
int lua_push_connection(lua_State *L, liConnection *con) {
liConnection **pcon;
pcon = (liConnection**) lua_newuserdata(L, sizeof(liConnection*));
*pcon = con;
if (luaL_newmetatable(L, LUA_CONNECTION)) {
init_con_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}

201
src/main/core_lua.c

@ -0,0 +1,201 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
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");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
return 1;
}
int li_lua_push_traceback(lua_State *L, int narg) {
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback);
lua_insert(L, base);
return base;
}
int li_lua_metatable_index(lua_State *L) {
/* search for entry in mt, i.e. functions */
if (!lua_getmetatable(L, 1)) return 0; /* +1 */
lua_pushvalue(L, 2); /* +1 */
lua_rawget(L, -2); /* */
if (!lua_isnil(L, -1)) return 1;
lua_pop(L, 2); /* -2 */
return 0;
}
static void li_lua_store_globals(lua_State *L) {
/* backup global table reference */
lua_pushvalue(L, LUA_GLOBALSINDEX); /* +1 */
lua_setfield(L, LUA_REGISTRYINDEX, "li_globals"); /* -1 */
}
GString* lua_print_get_string(lua_State *L, int from, int to) {
int i, n = lua_gettop(L);
GString *buf = g_string_sized_new(0);
lua_getfield(L, LUA_GLOBALSINDEX, "tostring");
for (i = from; i <= to; i++) {
const char *s;
size_t len;
lua_pushvalue(L, n+1);
lua_pushvalue(L, i);
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &len);
lua_pop(L, 1);
if (NULL == s) {
g_string_free(buf, TRUE);
lua_pushliteral(L, "lua_print_get_string: Couldn't convert parameter to string");
lua_error(L);
}
if (0 == len) continue;
if (buf->len > 0) {
g_string_append_c(buf, ' ');
g_string_append_len(buf, s, len);
} else {
g_string_append_len(buf, s, len);
}
}
lua_pop(L, 1);
return buf;
}
static int li_lua_error(lua_State *L) {
liServer *srv = lua_touserdata(L, lua_upvalueindex(1));
GString *buf = lua_print_get_string(L, 1, lua_gettop(L));
ERROR(srv, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int li_lua_warning(lua_State *L) {
liServer *srv = lua_touserdata(L, lua_upvalueindex(1));
GString *buf = lua_print_get_string(L, 1, lua_gettop(L));
WARNING(srv, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int li_lua_info(lua_State *L) {
liServer *srv = lua_touserdata(L, lua_upvalueindex(1));
GString *buf = lua_print_get_string(L, 1, lua_gettop(L));
INFO(srv, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int li_lua_debug(lua_State *L) {
liServer *srv = lua_touserdata(L, lua_upvalueindex(1));
GString *buf = lua_print_get_string(L, 1, lua_gettop(L));
DEBUG(srv, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
void li_lua_init(liServer *srv, lua_State *L) {
lua_init_chunk_mt(L);
lua_init_connection_mt(L);
lua_init_environment_mt(L);
lua_init_physical_mt(L);
lua_init_request_mt(L);
lua_init_response_mt(L);
lua_init_vrequest_mt(L);
/* prefer closure, but just in case */
lua_pushlightuserdata(L, srv);
lua_setfield(L, LUA_REGISTRYINDEX, "lighty.srv");
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, li_lua_error, 1);
lua_setfield(L, LUA_GLOBALSINDEX, "print");
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, li_lua_warning, 1);
lua_setfield(L, LUA_GLOBALSINDEX, "warning");
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, li_lua_info, 1);
lua_setfield(L, LUA_GLOBALSINDEX, "info");
lua_pushlightuserdata(L, srv);
lua_pushcclosure(L, li_lua_debug, 1);
lua_setfield(L, LUA_GLOBALSINDEX, "debug");
li_lua_store_globals(L);
}
void li_lua_restore_globals(lua_State *L) {
lua_getfield(L, LUA_REGISTRYINDEX, "li_globals"); /* +1 */
lua_replace(L, LUA_GLOBALSINDEX); /* -1 */
}
void li_lua_new_globals(lua_State *L) {
lua_newtable(L); /* +1 */
/* metatable for new global env, link old globals as readonly */
lua_newtable(L); /* +1 */
lua_pushvalue(L, LUA_GLOBALSINDEX); /* +1 */
lua_setfield(L, -2, "__index"); /* -1 */
lua_setmetatable(L, -2); /* -1 */
lua_replace(L, LUA_GLOBALSINDEX); /* -1 */
}
static int ghashtable_gstring_next(lua_State *L) {
GHashTableIter *it = lua_touserdata(L, lua_upvalueindex(1));
gpointer pkey = NULL, pvalue = NULL;
/* ignore arguments */
if (g_hash_table_iter_next(it, &pkey, &pvalue)) {
GString *key = pkey, *value = pvalue;
lua_pushlstring(L, key->str, key->len);
lua_pushlstring(L, value->str, value->len);
return 2;
}
lua_pushnil(L);
return 1;
}
int li_lua_ghashtable_gstring_pairs(lua_State *L, GHashTable *ht) {
GHashTableIter *it = lua_newuserdata(L, sizeof(GHashTableIter)); /* +1 */
g_hash_table_iter_init(it, ht);
lua_pushcclosure(L, ghashtable_gstring_next, 1); /* -1, +1 */
lua_pushnil(L); lua_pushnil(L); /* +2 */
return 3;
}

152
src/main/environment_lua.c

@ -0,0 +1,152 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_ENVIRONMENT "liEnvironment*"
static int lua_environment_get(lua_State *L) {
liEnvironment *env;
const char *ckey;
size_t keylen;
GString *val;
luaL_checkany(L, 2);
if (NULL == (env = lua_get_environment(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
val = li_environment_get(env, ckey, keylen);
if (val) {
lua_pushlstring(L, val->str, val->len);
} else {
lua_pushnil(L);
}
return 1;
}
static int lua_environment_index(lua_State *L) {
if (li_lua_metatable_index(L)) return 1;
return lua_environment_get(L);
}
static int lua_environment_set(lua_State *L) {
liEnvironment *env;
const char *ckey, *cval;
size_t keylen, vallen;
luaL_checkany(L, 3);
if (NULL == (env = lua_get_environment(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
if (lua_isnil(L, 3)) {
li_environment_remove(env, ckey, keylen);
return 0;
}
if (NULL == (cval = lua_tolstring(L, 3, &vallen))) return 0;
li_environment_set(env, ckey, keylen, cval, vallen);
return 0;
}
static int lua_environment_unset(lua_State *L) {
liEnvironment *env;
const char *ckey;
size_t keylen;
luaL_checkany(L, 2);
if (NULL == (env = lua_get_environment(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
li_environment_remove(env, ckey, keylen);
return 0;
}
static int lua_environment_weak_set(lua_State *L) {
liEnvironment *env;
const char *ckey, *cval;
size_t keylen, vallen;
luaL_checkany(L, 3);
if (NULL == (env = lua_get_environment(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
if (NULL == (cval = lua_tolstring(L, 3, &vallen))) return 0;
li_environment_insert(env, ckey, keylen, cval, vallen);
return 0;
}
static int lua_environment_clear(lua_State *L) {
liEnvironment *env;
luaL_checkany(L, 1);
if (NULL == (env = lua_get_environment(L, 1))) return 0;
li_environment_reset(env);
return 0;
}
static int lua_environment_pairs(lua_State *L) {
liEnvironment *env;
luaL_checkany(L, 1);
env = lua_get_environment(L, 1);
if (!env) return 0;
return li_lua_ghashtable_gstring_pairs(L, env->table);
}
static const luaL_Reg environment_mt[] = {
{ "__index", lua_environment_index },
{ "get", lua_environment_get },
{ "__newindex", lua_environment_set },
{ "set", lua_environment_set },
{ "unset", lua_environment_unset },
{ "weak_set", lua_environment_weak_set },
{ "__pairs", lua_environment_pairs },
{ "pairs", lua_environment_pairs },
{ "clear", lua_environment_clear },
{ NULL, NULL }
};
static void init_env_mt(lua_State *L) {
luaL_register(L, NULL, environment_mt);
}
void lua_init_environment_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_ENVIRONMENT)) {
init_env_mt(L);
}
lua_pop(L, 1);
}
liEnvironment* lua_get_environment(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_ENVIRONMENT);
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 *(liEnvironment**) lua_touserdata(L, ndx);
}
int lua_push_environment(lua_State *L, liEnvironment *env) {
liEnvironment **penv;
penv = (liEnvironment**) lua_newuserdata(L, sizeof(liEnvironment*));
*penv = env;
if (luaL_newmetatable(L, LUA_ENVIRONMENT)) {
init_env_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}

240
src/main/http_headers_lua.c

@ -0,0 +1,240 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_HTTPHEADERS "liHttpHeaders*"
static int lua_http_headers_get(lua_State *L) {
liHttpHeaders *headers;
const char *ckey;
size_t keylen;
GString *val;
luaL_checkany(L, 2);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
val = g_string_sized_new(0);
li_http_header_get_all(val, headers, ckey, keylen);
lua_pushlstring(L, val->str, val->len);
g_string_free(val, TRUE);
return 1;
}
static int lua_http_headers_index(lua_State *L) {
if (li_lua_metatable_index(L)) return 1;
return lua_http_headers_get(L);
}
static int lua_http_headers_set(lua_State *L) {
liHttpHeaders *headers;
const char *ckey, *cval;
size_t keylen, vallen;
luaL_checkany(L, 3);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
if (lua_isnil(L, 3)) {
li_http_header_remove(headers, ckey, keylen);
return 0;
}
if (NULL == (cval = lua_tolstring(L, 3, &vallen))) return 0;
li_http_header_remove(headers, ckey, keylen);
li_http_header_insert(headers, ckey, keylen, cval, vallen);
return 0;
}
static int lua_http_headers_append(lua_State *L) {
liHttpHeaders *headers;
const char *ckey, *cval;
size_t keylen, vallen;
luaL_checkany(L, 3);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
if (lua_isnil(L, 3)) {
return 0;
}
if (NULL == (cval = lua_tolstring(L, 3, &vallen))) return 0;
li_http_header_append(headers, ckey, keylen, cval, vallen);
return 0;
}
static int lua_http_headers_insert(lua_State *L) {
liHttpHeaders *headers;
const char *ckey, *cval;
size_t keylen, vallen;
luaL_checkany(L, 3);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
if (lua_isnil(L, 3)) {
return 0;
}
if (NULL == (cval = lua_tolstring(L, 3, &vallen))) return 0;
li_http_header_insert(headers, ckey, keylen, cval, vallen);
return 0;
}
static int lua_http_headers_unset(lua_State *L) {
liHttpHeaders *headers;
const char *ckey;
size_t keylen;
luaL_checkany(L, 2);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
if (NULL == (ckey = lua_tolstring(L, 2, &keylen))) return 0;
li_http_header_remove(headers, ckey, keylen);
return 0;
}
static int lua_http_headers_clear(lua_State *L) {
liHttpHeaders *headers;
luaL_checkany(L, 1);
if (NULL == (headers = lua_get_http_headers(L, 1))) return 0;
li_http_headers_reset(headers);
return 0;
}
static int lua_http_headers_next(lua_State *L) {
liHttpHeader *h;
liHttpHeaders *headers = lua_touserdata(L, lua_upvalueindex(1));
GList *l = lua_touserdata(L, lua_upvalueindex(2));
const char *ckey;
size_t keylen;
ckey = lua_tolstring(L, lua_upvalueindex(3), &keylen);
if (!headers && !l) goto endoflist;
if (headers) {
lua_pushnil(L);
lua_replace(L, lua_upvalueindex(1));
if (ckey) {
l = li_http_header_find_first(headers, ckey, keylen);
} else {
l = headers->entries.head;
}
} else {
if (ckey) {
l = li_http_header_find_next(l, ckey, keylen);
} else {
l = g_list_next(l);
}
}
if (!l) goto endoflist;
h = l->data;
lua_pushlstring(L, h->data->str, h->keylen);
if (h->data->len > h->keylen + 2) {
lua_pushlstring(L, h->data->str + (h->keylen + 2), h->data->len - (h->keylen + 2));
} else {
lua_pushliteral(L, "");
}
lua_pushlightuserdata(L, l);
lua_replace(L, lua_upvalueindex(2));
return 2;
endoflist:
lua_pushnil(L);
lua_replace(L, lua_upvalueindex(1));
lua_pushnil(L);
lua_replace(L, lua_upvalueindex(2));
lua_pushnil(L);
lua_replace(L, lua_upvalueindex(3));
lua_pushnil(L);
return 1;
}
static int lua_http_headers_pairs(lua_State *L) {
liHttpHeaders *headers;
gboolean haskey = FALSE;
luaL_checkany(L, 1);
headers = lua_get_http_headers(L, 1);
if (lua_gettop(L) == 2) {
luaL_checkstring(L, 2);
haskey = TRUE;
}
if (!headers) return 0;
lua_pushlightuserdata(L, headers);
lua_pushlightuserdata(L, NULL);
if (haskey) {
lua_pushvalue(L, 2);
} else {
lua_pushnil(L);
}
lua_pushcclosure(L, lua_http_headers_next, 3);
return 1;
// return li_lua_ghashtable_gstring_pairs(L, env->table);
}
static const luaL_Reg http_headers_mt[] = {
{ "__index", lua_http_headers_index },
{ "get", lua_http_headers_get },
{ "__newindex", lua_http_headers_set },
{ "set", lua_http_headers_set },
{ "append", lua_http_headers_append },
{ "insert", lua_http_headers_insert },
{ "unset", lua_http_headers_unset },
{ "__pairs", lua_http_headers_pairs },
{ "pairs", lua_http_headers_pairs },
{ "list", lua_http_headers_pairs },
{ "clear", lua_http_headers_clear },
{ NULL, NULL }
};
static void init_http_headers_mt(lua_State *L) {
luaL_register(L, NULL, http_headers_mt);
}
void lua_init_http_headers_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_HTTPHEADERS)) {
init_http_headers_mt(L);
}
lua_pop(L, 1);
}
liHttpHeaders* lua_get_http_headers(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_HTTPHEADERS);
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 *(liHttpHeaders**) lua_touserdata(L, ndx);
}
int lua_push_http_headers(lua_State *L, liHttpHeaders *headers) {
liHttpHeaders **pheaders;
pheaders = (liHttpHeaders**) lua_newuserdata(L, sizeof(liHttpHeaders*));
*pheaders = headers;
if (luaL_newmetatable(L, LUA_HTTPHEADERS)) {
init_http_headers_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}

165
src/main/physical_lua.c

@ -0,0 +1,165 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_PHYSICAL "liPhysical*"
typedef int (*lua_Physical_Attrib)(liPhysical *phys, lua_State *L);
#define DEF_LUA_MODIFY_GSTRING(attr) \
static int lua_physical_attr_read_##attr(liPhysical *phys, lua_State *L) { \
lua_pushlstring(L, phys->attr->str, phys->attr->len); \
return 1; \
} \
\
static int lua_physical_attr_write_##attr(liPhysical *phys, lua_State *L) { \
const char *s; size_t len; \
luaL_checkstring(L, 3); \
s = lua_tolstring(L, 3, &len); \
g_string_truncate(phys->attr, 0); \
g_string_append_len(phys->attr, s, len); \
return 0; \
}
DEF_LUA_MODIFY_GSTRING(path)
DEF_LUA_MODIFY_GSTRING(doc_root)
DEF_LUA_MODIFY_GSTRING(pathinfo)
#undef DEF_LUA_MODIFY_GSTRING
#define AR(m) { #m, lua_physical_attr_read_##m, NULL }
#define AW(m) { #m, NULL, lua_physical_attr_write_##m }
#define ARW(m) { #m, lua_physical_attr_read_##m, lua_physical_attr_write_##m }
static const struct {
const char* key;
lua_Physical_Attrib read_attr, write_attr;
} physical_attribs[] = {
ARW(path),
ARW(doc_root),
ARW(pathinfo),
{ NULL, NULL, NULL }
};
#undef AR
#undef AW
#undef ARW
static int lua_physical_index(lua_State *L) {
liPhysical *phys;
const char *key;
int i;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
if (li_lua_metatable_index(L)) return 1;
phys = lua_get_physical(L, 1);
if (!phys) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; physical_attribs[i].key ; i++) {
if (0 == strcmp(key, physical_attribs[i].key)) {
if (physical_attribs[i].read_attr)
return physical_attribs[i].read_attr(phys, L);
break;
}
}
lua_pushstring(L, "cannot read attribute ");
lua_pushstring(L, key);
lua_pushstring(L, " in physical");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static int lua_physical_newindex(lua_State *L) {
liPhysical *phys;
const char *key;
int i;
if (lua_gettop(L) != 3) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
phys = lua_get_physical(L, 1);
if (!phys) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; physical_attribs[i].key ; i++) {
if (0 == strcmp(key, physical_attribs[i].key)) {
if (physical_attribs[i].write_attr)
return physical_attribs[i].write_attr(phys, L);
break;
}
}
lua_pushstring(L, "cannot write attribute ");
lua_pushstring(L, key);
lua_pushstring(L, "in physical");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static const luaL_Reg physical_mt[] = {
{ "__index", lua_physical_index },
{ "__newindex", lua_physical_newindex },
{ NULL, NULL }
};
static void init_physical_mt(lua_State *L) {
luaL_register(L, NULL, physical_mt);
}
void lua_init_physical_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_PHYSICAL)) {
init_physical_mt(L);
}
lua_pop(L, 1);
}
liPhysical* lua_get_physical(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_PHYSICAL);
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 *(liPhysical**) lua_touserdata(L, ndx);
}
int lua_push_physical(lua_State *L, liPhysical *phys) {
liPhysical **pphys;
pphys = (liPhysical**) lua_newuserdata(L, sizeof(liPhysical*));
*pphys = phys;
if (luaL_newmetatable(L, LUA_PHYSICAL)) {
init_physical_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}

348
src/main/request_lua.c

@ -0,0 +1,348 @@
#include <lighttpd/core_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_REQUEST "liRequest*"
#define LUA_REQUESTURI "liRequestUri*"
typedef int (*lua_Request_Attrib)(liRequest *req, lua_State *L);
static int lua_request_attr_read_headers(liRequest *req, lua_State *L) {
lua_push_http_headers(L, req->headers);
return 1;
}
static int lua_request_attr_read_http_method(liRequest *req, lua_State *L) {
lua_pushlstring(L, req->http_method_str->str, req->http_method_str->len);
return 1;
}
static int lua_request_attr_read_http_version(liRequest *req, lua_State *L) {
switch (req->http_version) {
case LI_HTTP_VERSION_1_0:
lua_pushliteral(L, "HTTP/1.0");
break;
case LI_HTTP_VERSION_1_1:
lua_pushliteral(L, "HTTP/1.1");
break;
case LI_HTTP_VERSION_UNSET:
default:
lua_pushnil(L);
}
return 1;
}
static int lua_request_attr_read_content_length(liRequest *req, lua_State *L) {
lua_pushinteger(L, req->content_length);
return 1;
}
static int lua_request_attr_read_uri(liRequest *req, lua_State *L) {
lua_push_requesturi(L, &req->uri);
return 1;
}
#define AR(m) { #m, lua_request_attr_read_##m, NULL }
#define AW(m) { #m, NULL, lua_request_attr_write_##m }
#define ARW(m) { #m, lua_request_attr_read_##m, lua_request_attr_write_##m }
static const struct {
const char* key;
lua_Request_Attrib read_attr, write_attr;
} request_attribs[] = {
AR(headers),
AR(http_method),
AR(http_version),
AR(content_length),
AR(uri),
{ NULL, NULL, NULL }
};
#undef AR
#undef AW
#undef ARW
static int lua_request_index(lua_State *L) {
liRequest *req;
const char *key;
int i;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
if (li_lua_metatable_index(L)) return 1;
req = lua_get_request(L, 1);
if (!req) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; request_attribs[i].key ; i++) {
if (0 == strcmp(key, request_attribs[i].key)) {
if (request_attribs[i].read_attr)
return request_attribs[i].read_attr(req, L);
break;
}
}
lua_pushstring(L, "cannot read attribute ");
lua_pushstring(L, key);
lua_pushstring(L, " in request");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static int lua_request_newindex(lua_State *L) {
liRequest *req;
const char *key;
int i;
if (lua_gettop(L) != 3) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
req = lua_get_request(L, 1);
if (!req) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; request_attribs[i].key ; i++) {
if (0 == strcmp(key, request_attribs[i].key)) {
if (request_attribs[i].write_attr)
return request_attribs[i].write_attr(req, L);
break;
}
}
lua_pushstring(L, "cannot write attribute ");
lua_pushstring(L, key);
lua_pushstring(L, "in request");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static const luaL_Reg request_mt[] = {
{ "__index", lua_request_index },
{ "__newindex", lua_request_newindex },
{ NULL, NULL }
};
static void init_request_mt(lua_State *L) {
luaL_register(L, NULL, request_mt);
}
typedef int (*lua_RequestUri_Attrib)(liRequestUri *uri, lua_State *L);
#define DEF_LUA_MODIFY_GSTRING(attr) \
static int lua_requesturi_attr_read_##attr(liRequestUri *uri, lua_State *L) { \
lua_pushlstring(L, uri->attr->str, uri->attr->len); \
return 1; \
} \
\
static int lua_requesturi_attr_write_##attr(liRequestUri *uri, lua_State *L) { \
const char *s; size_t len; \
luaL_checkstring(L, 3); \
s = lua_tolstring(L, 3, &len); \
g_string_truncate(uri->attr, 0); \
g_string_append_len(uri->attr, s, len); \
return 0; \
}
DEF_LUA_MODIFY_GSTRING(raw)
DEF_LUA_MODIFY_GSTRING(raw_path)
DEF_LUA_MODIFY_GSTRING(raw_orig_path)
DEF_LUA_MODIFY_GSTRING(scheme)
DEF_LUA_MODIFY_GSTRING(authority)
DEF_LUA_MODIFY_GSTRING(path)
DEF_LUA_MODIFY_GSTRING(query)
DEF_LUA_MODIFY_GSTRING(host)
#undef DEF_LUA_MODIFY_GSTRING
#define AR(m) { #m, lua_requesturi_attr_read_##m, NULL }
#define AW(m) { #m, NULL, lua_requesturi_attr_write_##m }
#define ARW(m) { #m, lua_requesturi_attr_read_##m, lua_requesturi_attr_write_##m }
static const struct {
const char* key;
lua_RequestUri_Attrib read_attr, write_attr;
} requesturi_attribs[] = {
ARW(raw),
ARW(raw_path),
ARW(raw_orig_path),
ARW(scheme),
ARW(authority),
ARW(path),
ARW(query),
ARW(host),
{ NULL, NULL, NULL }
};
#undef AR
#undef AW
#undef ARW
static int lua_requesturi_index(lua_State *L) {
liRequestUri *uri;
const char *key;
int i;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
if (li_lua_metatable_index(L)) return 1;
uri = lua_get_requesturi(L, 1);
if (!uri) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; requesturi_attribs[i].key ; i++) {
if (0 == strcmp(key, requesturi_attribs[i].key)) {
if (requesturi_attribs[i].read_attr)
return requesturi_attribs[i].read_attr(uri, L);
break;
}
}
lua_pushstring(L, "cannot read attribute ");
lua_pushstring(L, key);