version 1.1.1.1, 2013/10/14 10:32:48
|
version 1.1.1.3, 2016/11/02 10:35:00
|
Line 1
|
Line 1
|
|
#include "first.h" |
|
|
#include "mod_cml.h" |
#include "mod_cml.h" |
#include "mod_cml_funcs.h" |
#include "mod_cml_funcs.h" |
#include "log.h" |
#include "log.h" |
Line 28 typedef char HASHHEX[HASHHEXLEN+1];
|
Line 30 typedef char HASHHEX[HASHHEXLEN+1];
|
#include <lualib.h> |
#include <lualib.h> |
#include <lauxlib.h> |
#include <lauxlib.h> |
|
|
typedef struct { |
|
stream st; |
|
int done; |
|
} readme; |
|
|
|
static const char * load_file(lua_State *L, void *data, size_t *size) { |
|
readme *rm = data; |
|
|
|
UNUSED(L); |
|
|
|
if (rm->done) return 0; |
|
|
|
*size = rm->st.size; |
|
rm->done = 1; |
|
return rm->st.start; |
|
} |
|
|
|
static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) { |
static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) { |
int curelem; | int curelem = lua_gettop(L); |
| int result; |
|
|
lua_pushstring(L, varname); | lua_getglobal(L, varname); |
|
|
curelem = lua_gettop(L); | if (lua_isstring(L, curelem)) { |
lua_gettable(L, LUA_GLOBALSINDEX); | buffer_copy_string(b, lua_tostring(L, curelem)); |
| result = 0; |
/* it should be a table */ | } else { |
if (!lua_isstring(L, curelem)) { | result = -1; |
lua_settop(L, curelem - 1); | |
| |
return -1; | |
} |
} |
|
|
buffer_copy_string(b, lua_tostring(L, curelem)); |
|
|
|
lua_pop(L, 1); |
lua_pop(L, 1); |
| force_assert(curelem == lua_gettop(L)); |
assert(curelem - 1 == lua_gettop(L)); | return result; |
| |
return 0; | |
} |
} |
|
|
static int lua_to_c_is_table(lua_State *L, const char *varname) { |
static int lua_to_c_is_table(lua_State *L, const char *varname) { |
int curelem; | int curelem = lua_gettop(L); |
| int result; |
|
|
lua_pushstring(L, varname); | lua_getglobal(L, varname); |
|
|
curelem = lua_gettop(L); | result = lua_istable(L, curelem) ? 1 : 0; |
lua_gettable(L, LUA_GLOBALSINDEX); | |
|
|
/* it should be a table */ | lua_pop(L, 1); |
if (!lua_istable(L, curelem)) { | force_assert(curelem == lua_gettop(L)); |
lua_settop(L, curelem - 1); | return result; |
| |
return 0; | |
} | |
| |
lua_settop(L, curelem - 1); | |
| |
assert(curelem - 1 == lua_gettop(L)); | |
| |
return 1; | |
} |
} |
|
|
static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len, const char *val, size_t val_len) { |
static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len, const char *val, size_t val_len) { |
Line 99 static int c_to_lua_push(lua_State *L, int tbl, const
|
Line 69 static int c_to_lua_push(lua_State *L, int tbl, const
|
return 0; |
return 0; |
} |
} |
|
|
|
|
static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) { |
static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) { |
size_t is_key = 1; |
size_t is_key = 1; |
size_t i; | size_t i, len; |
char *key = NULL, *val = NULL; |
char *key = NULL, *val = NULL; |
|
|
key = qrystr->ptr; |
key = qrystr->ptr; |
|
|
/* we need the \0 */ |
/* we need the \0 */ |
for (i = 0; i < qrystr->used; i++) { | len = buffer_string_length(qrystr); |
| for (i = 0; i <= len; i++) { |
switch(qrystr->ptr[i]) { |
switch(qrystr->ptr[i]) { |
case '=': |
case '=': |
if (is_key) { |
if (is_key) { |
Line 129 static int cache_export_get_params(lua_State *L, int t
|
Line 99 static int cache_export_get_params(lua_State *L, int t
|
qrystr->ptr[i] = '\0'; |
qrystr->ptr[i] = '\0'; |
|
|
c_to_lua_push(L, tbl, |
c_to_lua_push(L, tbl, |
key, strlen(key), | key, strlen(key), |
val, strlen(val)); | val, strlen(val)); |
} |
} |
|
|
key = qrystr->ptr + i + 1; |
key = qrystr->ptr + i + 1; |
Line 142 static int cache_export_get_params(lua_State *L, int t
|
Line 112 static int cache_export_get_params(lua_State *L, int t
|
|
|
return 0; |
return 0; |
} |
} |
#if 0 |
|
int cache_export_cookie_params(server *srv, connection *con, plugin_data *p) { |
|
data_unset *d; |
|
|
|
UNUSED(srv); |
|
|
|
if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) { |
|
data_string *ds = (data_string *)d; |
|
size_t key = 0, value = 0; |
|
size_t is_key = 1, is_sid = 0; |
|
size_t i; |
|
|
|
/* found COOKIE */ |
|
if (!DATA_IS_STRING(d)) return -1; |
|
if (ds->value->used == 0) return -1; |
|
|
|
if (ds->value->ptr[0] == '\0' || |
|
ds->value->ptr[0] == '=' || |
|
ds->value->ptr[0] == ';') return -1; |
|
|
|
buffer_reset(p->session_id); |
|
for (i = 0; i < ds->value->used; i++) { |
|
switch(ds->value->ptr[i]) { |
|
case '=': |
|
if (is_key) { |
|
if (0 == strncmp(ds->value->ptr + key, "PHPSESSID", i - key)) { |
|
/* found PHP-session-id-key */ |
|
is_sid = 1; |
|
} |
|
value = i + 1; |
|
|
|
is_key = 0; |
|
} |
|
|
|
break; |
|
case ';': |
|
if (is_sid) { |
|
buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value); |
|
} |
|
|
|
is_sid = 0; |
|
key = i + 1; |
|
value = 0; |
|
is_key = 1; |
|
break; |
|
case ' ': |
|
if (is_key == 1 && key == i) key = i + 1; |
|
if (is_key == 0 && value == i) value = i + 1; |
|
break; |
|
case '\0': |
|
if (is_sid) { |
|
buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value); |
|
} |
|
/* fin */ |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
#endif |
|
|
|
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { |
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { |
lua_State *L; |
lua_State *L; |
readme rm; |
|
int ret = -1; |
int ret = -1; |
buffer *b = buffer_init(); | buffer *b; |
int header_tbl = 0; | |
|
|
rm.done = 0; | b = buffer_init(); |
stream_open(&rm.st, fn); | |
| |
/* push the lua file to the interpreter and see what happends */ |
/* push the lua file to the interpreter and see what happends */ |
L = luaL_newstate(); |
L = luaL_newstate(); |
luaL_openlibs(L); |
luaL_openlibs(L); |
Line 226 int cache_parse_lua(server *srv, connection *con, plug
|
Line 130 int cache_parse_lua(server *srv, connection *con, plug
|
lua_register(L, "file_isdir", f_file_isreg); |
lua_register(L, "file_isdir", f_file_isreg); |
lua_register(L, "dir_files", f_dir_files); |
lua_register(L, "dir_files", f_dir_files); |
|
|
#ifdef HAVE_MEMCACHE_H | #ifdef USE_MEMCACHED |
lua_pushliteral(L, "memcache_get_long"); | lua_pushlightuserdata(L, p->conf.memc); |
lua_pushlightuserdata(L, p->conf.mc); | |
lua_pushcclosure(L, f_memcache_get_long, 1); |
lua_pushcclosure(L, f_memcache_get_long, 1); |
lua_settable(L, LUA_GLOBALSINDEX); | lua_setglobal(L, "memcache_get_long"); |
|
|
lua_pushliteral(L, "memcache_get_string"); | lua_pushlightuserdata(L, p->conf.memc); |
lua_pushlightuserdata(L, p->conf.mc); | |
lua_pushcclosure(L, f_memcache_get_string, 1); |
lua_pushcclosure(L, f_memcache_get_string, 1); |
lua_settable(L, LUA_GLOBALSINDEX); | lua_setglobal(L, "memcache_get_string"); |
|
|
lua_pushliteral(L, "memcache_exists"); | lua_pushlightuserdata(L, p->conf.memc); |
lua_pushlightuserdata(L, p->conf.mc); | |
lua_pushcclosure(L, f_memcache_exists, 1); |
lua_pushcclosure(L, f_memcache_exists, 1); |
lua_settable(L, LUA_GLOBALSINDEX); | lua_setglobal(L, "memcache_exists"); |
#endif |
#endif |
|
|
/* register CGI environment */ |
/* register CGI environment */ |
lua_pushliteral(L, "request"); |
|
lua_newtable(L); |
lua_newtable(L); |
lua_settable(L, LUA_GLOBALSINDEX); | { |
| int header_tbl = lua_gettop(L); |
|
|
lua_pushliteral(L, "request"); | c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); |
header_tbl = lua_gettop(L); | c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); |
lua_gettable(L, LUA_GLOBALSINDEX); | c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); |
| c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)); |
| if (!buffer_string_is_empty(con->request.pathinfo)) { |
| c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); |
| } |
|
|
c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); | c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir)); |
c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); | c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl)); |
c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); | |
c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); | |
if (!buffer_is_empty(con->request.pathinfo)) { | |
c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); | |
} |
} |
|
lua_setglobal(L, "request"); |
|
|
c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir)); |
|
c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl)); |
|
|
|
/* register GET parameter */ |
/* register GET parameter */ |
lua_pushliteral(L, "get"); |
|
lua_newtable(L); |
lua_newtable(L); |
lua_settable(L, LUA_GLOBALSINDEX); | { |
| int get_tbl = lua_gettop(L); |
|
|
lua_pushliteral(L, "get"); | buffer_copy_buffer(b, con->uri.query); |
header_tbl = lua_gettop(L); | cache_export_get_params(L, get_tbl, b); |
lua_gettable(L, LUA_GLOBALSINDEX); | buffer_reset(b); |
| } |
| lua_setglobal(L, "get"); |
|
|
buffer_copy_string_buffer(b, con->uri.query); |
|
cache_export_get_params(L, header_tbl, b); |
|
buffer_reset(b); |
|
|
|
/* 2 default constants */ |
/* 2 default constants */ |
lua_pushliteral(L, "CACHE_HIT"); | lua_pushinteger(L, 0); |
lua_pushnumber(L, 0); | lua_setglobal(L, "CACHE_HIT"); |
lua_settable(L, LUA_GLOBALSINDEX); | |
|
|
lua_pushliteral(L, "CACHE_MISS"); | lua_pushinteger(L, 1); |
lua_pushnumber(L, 1); | lua_setglobal(L, "CACHE_MISS"); |
lua_settable(L, LUA_GLOBALSINDEX); | |
|
|
/* load lua program */ |
/* load lua program */ |
if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) { | ret = luaL_loadfile(L, fn->ptr); |
log_error_write(srv, __FILE__, __LINE__, "s", | if (0 != ret) { |
lua_tostring(L,-1)); | log_error_write(srv, __FILE__, __LINE__, "sbsS", |
| "failed loading cml_lua script", |
| fn, |
| ":", |
| lua_tostring(L, -1)); |
| goto error; |
| } |
|
|
|
if (lua_pcall(L, 0, 1, 0)) { |
|
log_error_write(srv, __FILE__, __LINE__, "sbsS", |
|
"failed running cml_lua script", |
|
fn, |
|
":", |
|
lua_tostring(L, -1)); |
goto error; |
goto error; |
} |
} |
|
|
/* get return value */ |
/* get return value */ |
ret = (int)lua_tonumber(L, -1); | ret = (int)lua_tointeger(L, -1); |
lua_pop(L, 1); |
lua_pop(L, 1); |
|
|
/* fetch the data from lua */ |
/* fetch the data from lua */ |
Line 317 int cache_parse_lua(server *srv, connection *con, plug
|
Line 225 int cache_parse_lua(server *srv, connection *con, plug
|
goto error; |
goto error; |
} |
} |
|
|
lua_pushstring(L, "output_include"); | lua_getglobal(L, "output_include"); |
| |
curelem = lua_gettop(L); |
curelem = lua_gettop(L); |
lua_gettable(L, LUA_GLOBALSINDEX); |
|
|
|
/* HOW-TO build a etag ? |
/* HOW-TO build a etag ? |
* as we don't just have one file we have to take the stat() |
* as we don't just have one file we have to take the stat() |
Line 333 int cache_parse_lua(server *srv, connection *con, plug
|
Line 239 int cache_parse_lua(server *srv, connection *con, plug
|
|
|
lua_pushnil(L); /* first key */ |
lua_pushnil(L); /* first key */ |
while (lua_next(L, curelem) != 0) { |
while (lua_next(L, curelem) != 0) { |
stat_cache_entry *sce = NULL; |
|
/* key' is at index -2 and value' at index -1 */ |
/* key' is at index -2 and value' at index -1 */ |
|
|
if (lua_isstring(L, -1)) { |
if (lua_isstring(L, -1)) { |
const char *s = lua_tostring(L, -1); |
const char *s = lua_tostring(L, -1); |
|
struct stat st; |
|
int fd; |
|
|
/* the file is relative, make it absolute */ |
/* the file is relative, make it absolute */ |
if (s[0] != '/') { |
if (s[0] != '/') { |
buffer_copy_string_buffer(b, p->basedir); | buffer_copy_buffer(b, p->basedir); |
buffer_append_string(b, lua_tostring(L, -1)); |
buffer_append_string(b, lua_tostring(L, -1)); |
} else { |
} else { |
buffer_copy_string(b, lua_tostring(L, -1)); |
buffer_copy_string(b, lua_tostring(L, -1)); |
} |
} |
|
|
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, b, &sce)) { | fd = stat_cache_open_rdonly_fstat(srv, con, b, &st); |
| if (fd < 0) { |
/* stat failed */ |
/* stat failed */ |
|
|
switch(errno) { |
switch(errno) { |
case ENOENT: |
case ENOENT: |
/* a file is missing, call the handler to generate it */ |
/* a file is missing, call the handler to generate it */ |
if (!buffer_is_empty(p->trigger_handler)) { | if (!buffer_string_is_empty(p->trigger_handler)) { |
ret = 1; /* cache-miss */ |
ret = 1; /* cache-miss */ |
|
|
log_error_write(srv, __FILE__, __LINE__, "s", |
log_error_write(srv, __FILE__, __LINE__, "s", |
Line 374 int cache_parse_lua(server *srv, connection *con, plug
|
Line 282 int cache_parse_lua(server *srv, connection *con, plug
|
break; |
break; |
} |
} |
} else { |
} else { |
chunkqueue_append_file(con->write_queue, b, 0, sce->st.st_size); | chunkqueue_append_file_fd(con->write_queue, b, fd, 0, st.st_size); |
if (sce->st.st_mtime > mtime) mtime = sce->st.st_mtime; | if (st.st_mtime > mtime) mtime = st.st_mtime; |
} |
} |
} else { |
} else { |
/* not a string */ |
/* not a string */ |
Line 393 int cache_parse_lua(server *srv, connection *con, plug
|
Line 301 int cache_parse_lua(server *srv, connection *con, plug
|
if (ret == 0) { |
if (ret == 0) { |
data_string *ds; |
data_string *ds; |
char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; |
char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; |
buffer tbuf; |
|
|
|
con->file_finished = 1; |
con->file_finished = 1; |
|
|
ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"); |
ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"); |
|
if (0 == mtime) mtime = time(NULL); /* default last-modified to now */ |
|
|
/* no Last-Modified specified */ |
/* no Last-Modified specified */ |
if ((mtime) && (NULL == ds)) { | if (NULL == ds) { |
|
|
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime)); |
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime)); |
|
|
response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1); |
response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1); |
| ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"); |
| force_assert(NULL != ds); |
tbuf.ptr = timebuf; | |
tbuf.used = sizeof(timebuf); | |
tbuf.size = sizeof(timebuf); | |
} else if (ds) { | |
tbuf.ptr = ds->value->ptr; | |
tbuf.used = ds->value->used; | |
tbuf.size = ds->value->size; | |
} else { | |
tbuf.size = 0; | |
tbuf.used = 0; | |
tbuf.ptr = NULL; | |
} |
} |
|
|
if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) { | if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, ds->value)) { |
/* ok, the client already has our content, |
/* ok, the client already has our content, |
* no need to send it again */ |
* no need to send it again */ |
|
|
Line 432 int cache_parse_lua(server *srv, connection *con, plug
|
Line 329 int cache_parse_lua(server *srv, connection *con, plug
|
} |
} |
} |
} |
|
|
if (ret == 1 && !buffer_is_empty(p->trigger_handler)) { | if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) { |
/* cache-miss */ |
/* cache-miss */ |
buffer_copy_string_buffer(con->uri.path, p->baseurl); | buffer_copy_buffer(con->uri.path, p->baseurl); |
buffer_append_string_buffer(con->uri.path, p->trigger_handler); |
buffer_append_string_buffer(con->uri.path, p->trigger_handler); |
|
|
buffer_copy_string_buffer(con->physical.path, p->basedir); | buffer_copy_buffer(con->physical.path, p->basedir); |
buffer_append_string_buffer(con->physical.path, p->trigger_handler); |
buffer_append_string_buffer(con->physical.path, p->trigger_handler); |
|
|
chunkqueue_reset(con->write_queue); |
chunkqueue_reset(con->write_queue); |
Line 446 int cache_parse_lua(server *srv, connection *con, plug
|
Line 343 int cache_parse_lua(server *srv, connection *con, plug
|
error: |
error: |
lua_close(L); |
lua_close(L); |
|
|
stream_close(&rm.st); |
|
buffer_free(b); |
buffer_free(b); |
|
|
return ret /* cache-error */; |
return ret /* cache-error */; |