You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lighttpd2/src/main/virtualrequest_lua.c

536 lines
11 KiB
C

#include <lighttpd/core_lua.h>
#include <lighttpd/actions_lua.h>
#include <lualib.h>
#include <lauxlib.h>
#define LUA_VREQUEST "liVRequest*"
typedef int (*lua_VRequest_Attrib)(liVRequest *vr, lua_State *L);
static int lua_vrequest_attr_read_in(liVRequest *vr, lua_State *L) {
li_lua_push_chunkqueue(L, (NULL != vr->backend_drain) ? vr->backend_drain->out : NULL);
return 1;
}
static int lua_vrequest_attr_read_out(liVRequest *vr, lua_State *L) {
li_lua_push_chunkqueue(L, (NULL != vr->backend_source) ? vr->backend_source->out : NULL);
return 1;
}
static int lua_vrequest_attr_read_con(liVRequest *vr, lua_State *L) {
li_lua_push_coninfo(L, vr->coninfo);
return 1;
}
static int lua_vrequest_attr_read_env(liVRequest *vr, lua_State *L) {
li_lua_push_environment(L, &vr->env);
return 1;
}
static int lua_vrequest_attr_read_req(liVRequest *vr, lua_State *L) {
li_lua_push_request(L, &vr->request);
return 1;
}
static int lua_vrequest_attr_read_resp(liVRequest *vr, lua_State *L) {
li_lua_push_response(L, &vr->response);
return 1;
}
static int lua_vrequest_attr_read_phys(liVRequest *vr, lua_State *L) {
li_lua_push_physical(L, &vr->physical);
return 1;
}
static int lua_vrequest_attr_read_is_handled(liVRequest *vr, lua_State *L) {
lua_pushboolean(L, li_vrequest_is_handled(vr));
return 1;
}
static int lua_vrequest_attr_read_has_response(liVRequest *vr, lua_State *L) {
lua_pushboolean(L, vr->state >= LI_VRS_HANDLE_RESPONSE_HEADERS);
return 1;
}
#define AR(m) { #m, lua_vrequest_attr_read_##m, NULL }
#define AW(m) { #m, NULL, lua_vrequest_attr_write_##m }
#define ARW(m) { #m, lua_vrequest_attr_read_##m, lua_vrequest_attr_write_##m }
static const struct {
const char* key;
lua_VRequest_Attrib read_attr, write_attr;
} vrequest_attribs[] = {
AR(con),
AR(in),
AR(out),
AR(env),
AR(req),
AR(resp),
AR(phys),
AR(is_handled),
AR(has_response),
{ NULL, NULL, NULL }
};
#undef AR
#undef AW
#undef ARW
static int lua_vrequest_index(lua_State *L) {
liVRequest *vr;
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;
vr = li_lua_get_vrequest(L, 1);
if (!vr) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; vrequest_attribs[i].key ; i++) {
if (0 == strcmp(key, vrequest_attribs[i].key)) {
if (vrequest_attribs[i].read_attr)
return vrequest_attribs[i].read_attr(vr, L);
break;
}
}
lua_pushstring(L, "cannot read attribute ");
lua_pushstring(L, key);
lua_pushstring(L, " in vrequest");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static int lua_vrequest_newindex(lua_State *L) {
liVRequest *vr;
const char *key;
int i;
if (lua_gettop(L) != 3) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
vr = li_lua_get_vrequest(L, 1);
if (!vr) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; vrequest_attribs[i].key ; i++) {
if (0 == strcmp(key, vrequest_attribs[i].key)) {
if (vrequest_attribs[i].write_attr)
return vrequest_attribs[i].write_attr(vr, L);
break;
}
}
lua_pushstring(L, "cannot write attribute ");
lua_pushstring(L, key);
lua_pushstring(L, "in vrequest");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static int lua_vrequest_error(lua_State *L) {
liVRequest *vr;
GString *buf;
vr = li_lua_get_vrequest(L, 1);
buf = li_lua_print_get_string(L, 2, lua_gettop(L));
VR_ERROR(vr, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int lua_vrequest_warning(lua_State *L) {
liVRequest *vr;
GString *buf;
vr = li_lua_get_vrequest(L, 1);
buf = li_lua_print_get_string(L, 2, lua_gettop(L));
VR_WARNING(vr, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int lua_vrequest_info(lua_State *L) {
liVRequest *vr;
GString *buf;
vr = li_lua_get_vrequest(L, 1);
buf = li_lua_print_get_string(L, 2, lua_gettop(L));
VR_INFO(vr, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
static int lua_vrequest_debug(lua_State *L) {
liVRequest *vr;
GString *buf;
vr = li_lua_get_vrequest(L, 1);
buf = li_lua_print_get_string(L, 2, lua_gettop(L));
VR_DEBUG(vr, "(lua): %s", buf->str);
g_string_free(buf, TRUE);
return 0;
}
/* st, res, errno, msg = vr:stat(filename)
* st: stat data (nil if not available (yet))
* res: error code (HANDLE_GO_ON if successful)
* errno: errno returned by stat() (only for HANDLER_ERROR)
* msg: error message for errno
*/
static int lua_vrequest_stat(lua_State *L) {
liVRequest *vr;
GString path;
const char *filename;
size_t filename_len;
liHandlerResult res;
int err = 0;
struct stat st;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "vr:stat(filename): incorrect number of arguments");
lua_error(L);
}
vr = li_lua_get_vrequest(L, 1);
if (!vr || !lua_isstring(L, 2)) {
lua_pushstring(L, "vr:stat(filename): wrong argument types");
lua_error(L);
}
filename = lua_tolstring(L, 2, &filename_len);
path = li_const_gstring(filename, filename_len);
res = li_stat_cache_get(vr, &path, &st, &err, NULL);
switch (res) {
case LI_HANDLER_GO_ON:
li_lua_push_stat(L, &st);
lua_pushinteger(L, res);
return 2;
case LI_HANDLER_WAIT_FOR_EVENT:
lua_pushnil(L);
lua_pushinteger(L, res);
return 2;
case LI_HANDLER_ERROR:
lua_pushnil(L);
lua_pushinteger(L, res);
lua_pushinteger(L, err);
lua_pushstring(L, g_strerror(err));
return 4;
case LI_HANDLER_COMEBACK:
VR_ERROR(vr, "%s", "Unexpected return value from li_stat_cache_get: LI_HANDLER_COMEBACK");
lua_pushnil(L);
lua_pushinteger(L, LI_HANDLER_ERROR);
return 2;
}
return 0;
}
static int lua_vrequest_handle_direct(lua_State *L) {
liVRequest *vr;
vr = li_lua_get_vrequest(L, 1);
lua_pushboolean(L, li_vrequest_handle_direct(vr));
return 1;
}
static int lua_vrequest_enter_action(lua_State *L) {
liVRequest *vr;
liAction *act;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
vr = li_lua_get_vrequest(L, 1);
act = li_lua_get_action(L, 2);
if (!vr || !act) {
lua_pushstring(L, "wrong arguments");
lua_error(L);
}
li_action_enter(vr, act);
return 0;
}
static int lua_vrequest_add_filter_in(lua_State *L) {
liVRequest *vr;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
vr = li_lua_get_vrequest(L, 1);
return li_lua_push_filter(L, li_lua_vrequest_add_filter_in(L, vr, 2));
}
static int lua_vrequest_add_filter_out(lua_State *L) {
liVRequest *vr;
if (lua_gettop(L) != 2) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
vr = li_lua_get_vrequest(L, 1);
return li_lua_push_filter(L, li_lua_vrequest_add_filter_out(L, vr, 2));
}
static const luaL_Reg vrequest_mt[] = {
{ "__index", lua_vrequest_index },
{ "__newindex", lua_vrequest_newindex },
{ "print", lua_vrequest_error },
{ "warning", lua_vrequest_warning },
{ "info", lua_vrequest_info },
{ "debug", lua_vrequest_debug },
{ "stat", lua_vrequest_stat },
{ "handle_direct", lua_vrequest_handle_direct },
{ "enter_action", lua_vrequest_enter_action },
{ "add_filter_in", lua_vrequest_add_filter_in },
{ "add_filter_out", lua_vrequest_add_filter_out },
{ "subrequest", li_lua_vrequest_subrequest },
{ NULL, NULL }
};
static void init_vrequest_mt(lua_State *L) {
luaL_register(L, NULL, vrequest_mt);
}
void li_lua_init_vrequest_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_VREQUEST)) {
init_vrequest_mt(L);
}
lua_pop(L, 1);
}
liVRequest* li_lua_get_vrequest(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_VREQUEST);
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 *(liVRequest**) lua_touserdata(L, ndx);
}
int li_lua_push_vrequest(lua_State *L, liVRequest *vr) {
liVRequest **pvr;
if (NULL == vr) {
lua_pushnil(L);
return 1;
}
pvr = (liVRequest**) lua_newuserdata(L, sizeof(liVRequest*));
*pvr = vr;
if (luaL_newmetatable(L, LUA_VREQUEST)) {
init_vrequest_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}
#define LUA_CONINFO "liConInfo*"
typedef int (*lua_ConInfo_Attrib)(liConInfo *coninfo, lua_State *L);
static int lua_coninfo_attr_read_local(liConInfo *coninfo, lua_State *L) {
lua_pushlstring(L, GSTR_LEN(coninfo->local_addr_str));
return 1;
}
static int lua_coninfo_attr_read_remote(liConInfo *coninfo, lua_State *L) {
lua_pushlstring(L, GSTR_LEN(coninfo->remote_addr_str));
return 1;
}
#define AR(m) { #m, lua_coninfo_attr_read_##m, NULL }
#define AW(m) { #m, NULL, lua_coninfo_attr_write_##m }
#define ARW(m) { #m, lua_coninfo_attr_read_##m, lua_coninfo_attr_write_##m }
static const struct {
const char* key;
lua_ConInfo_Attrib read_attr, write_attr;
} coninfo_attribs[] = {
AR(local),
AR(remote),
{ NULL, NULL, NULL }
};
#undef AR
#undef AW
#undef ARW
static int lua_coninfo_index(lua_State *L) {
liConInfo *coninfo;
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;
coninfo = li_lua_get_coninfo(L, 1);
if (!coninfo) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; coninfo_attribs[i].key ; i++) {
if (0 == strcmp(key, coninfo_attribs[i].key)) {
if (coninfo_attribs[i].read_attr)
return coninfo_attribs[i].read_attr(coninfo, L);
break;
}
}
lua_pushstring(L, "cannot read attribute ");
lua_pushstring(L, key);
lua_pushstring(L, " in coninfo");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static int lua_coninfo_newindex(lua_State *L) {
liConInfo *coninfo;
const char *key;
int i;
if (lua_gettop(L) != 3) {
lua_pushstring(L, "incorrect number of arguments");
lua_error(L);
}
coninfo = li_lua_get_coninfo(L, 1);
if (!coninfo) return 0;
if (lua_isnumber(L, 2)) return 0;
if (!lua_isstring(L, 2)) return 0;
key = lua_tostring(L, 2);
for (i = 0; coninfo_attribs[i].key ; i++) {
if (0 == strcmp(key, coninfo_attribs[i].key)) {
if (coninfo_attribs[i].write_attr)
return coninfo_attribs[i].write_attr(coninfo, L);
break;
}
}
lua_pushstring(L, "cannot write attribute ");
lua_pushstring(L, key);
lua_pushstring(L, "in coninfo");
lua_concat(L, 3);
lua_error(L);
return 0;
}
static const luaL_Reg coninfo_mt[] = {
{ "__index", lua_coninfo_index },
{ "__newindex", lua_coninfo_newindex },
{ NULL, NULL }
};
static void init_coninfo_mt(lua_State *L) {
luaL_register(L, NULL, coninfo_mt);
}
void li_lua_init_coninfo_mt(lua_State *L) {
if (luaL_newmetatable(L, LUA_CONINFO)) {
init_coninfo_mt(L);
}
lua_pop(L, 1);
}
liConInfo* li_lua_get_coninfo(lua_State *L, int ndx) {
if (!lua_isuserdata(L, ndx)) return NULL;
if (!lua_getmetatable(L, ndx)) return NULL;
luaL_getmetatable(L, LUA_CONINFO);
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 *(liConInfo**) lua_touserdata(L, ndx);
}
int li_lua_push_coninfo(lua_State *L, liConInfo *coninfo) {
liConInfo **pconinfo;
if (NULL == coninfo) {
lua_pushnil(L);
return 1;
}
pconinfo = (liConInfo**) lua_newuserdata(L, sizeof(liConInfo*));
*pconinfo = coninfo;
if (luaL_newmetatable(L, LUA_CONINFO)) {
init_coninfo_mt(L);
}
lua_setmetatable(L, -2);
return 1;
}