those are in the release .15
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.3.x@460 152afb58-edef-0310-8abb-c4023f1b3aa9svn/heads/lighttpd-1.3.x
parent
5f8945246c
commit
d30d9ca055
|
@ -205,7 +205,7 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
|
|||
network_backends.h configfile.h bitset.h \
|
||||
mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
|
||||
configparser.h mod_ssi_exprparser.h \
|
||||
sys-mmap.h sys-socket.h mod_cml.h
|
||||
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h
|
||||
|
||||
DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
|
||||
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mod_cml.h"
|
||||
#include "mod_cml_funcs.h"
|
||||
#include "log.h"
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
# include <openssl/md5.h>
|
||||
#else
|
||||
# include "md5_global.h"
|
||||
# include "md5.h"
|
||||
#endif
|
||||
|
||||
#define HASHLEN 16
|
||||
typedef unsigned char HASH[HASHLEN];
|
||||
#define HASHHEXLEN 32
|
||||
typedef char HASHHEX[HASHHEXLEN+1];
|
||||
#ifdef USE_OPENSSL
|
||||
#define IN const
|
||||
#else
|
||||
#define IN
|
||||
#endif
|
||||
#define OUT
|
||||
|
||||
#ifdef HAVE_LUA_H
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.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) {
|
||||
int curelem;
|
||||
|
||||
lua_pushstring(L, varname);
|
||||
|
||||
curelem = lua_gettop(L);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
/* it should be a table */
|
||||
if (!lua_isstring(L, curelem)) {
|
||||
lua_settop(L, curelem - 1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_copy_string(b, lua_tostring(L, curelem));
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
assert(curelem - 1 == lua_gettop(L));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lua_to_c_is_table(lua_State *L, const char *varname) {
|
||||
int curelem;
|
||||
|
||||
lua_pushstring(L, varname);
|
||||
|
||||
curelem = lua_gettop(L);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
/* it should be a table */
|
||||
if (!lua_istable(L, curelem)) {
|
||||
lua_settop(L, curelem - 1);
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "%*s -> %*s\n", key_len, key, val_len, val);
|
||||
|
||||
lua_pushlstring(L, key, key_len);
|
||||
lua_pushlstring(L, val, val_len);
|
||||
lua_settable(L, tbl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int split_query_string(lua_State *L, int tbl, buffer *qrystr) {
|
||||
size_t is_key = 1;
|
||||
size_t i;
|
||||
char *key = NULL, *val = NULL;
|
||||
|
||||
key = qrystr->ptr;
|
||||
|
||||
/* we need the \0 */
|
||||
for (i = 0; i < qrystr->used; i++) {
|
||||
switch(qrystr->ptr[i]) {
|
||||
case '=':
|
||||
if (is_key) {
|
||||
val = qrystr->ptr + i + 1;
|
||||
|
||||
qrystr->ptr[i] = '\0';
|
||||
|
||||
is_key = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case '&':
|
||||
case '\0': /* fin symbol */
|
||||
if (!is_key) {
|
||||
/* we need at least a = since the last & */
|
||||
|
||||
c_to_lua_push(L, tbl,
|
||||
key, strlen(key),
|
||||
val, strlen(val));
|
||||
}
|
||||
|
||||
key = qrystr->ptr + i + 1;
|
||||
val = NULL;
|
||||
is_key = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
|
||||
lua_State *L;
|
||||
readme rm;
|
||||
int ret = -1;
|
||||
buffer *b = buffer_init();
|
||||
int header_tbl = 0;
|
||||
|
||||
rm.done = 0;
|
||||
stream_open(&rm.st, fn);
|
||||
|
||||
/* push the lua file to the interpreter and see what happends */
|
||||
L = lua_open();
|
||||
|
||||
luaopen_base(L);
|
||||
luaopen_table(L);
|
||||
luaopen_string(L);
|
||||
luaopen_math(L);
|
||||
luaopen_io(L);
|
||||
|
||||
/* register functions */
|
||||
lua_register(L, "md5", f_crypto_md5);
|
||||
lua_register(L, "file_mtime", f_file_mtime);
|
||||
|
||||
#ifdef HAVE_MEMCACHE_H
|
||||
lua_pushliteral(L, "memcache_get_long");
|
||||
lua_pushlightuserdata(L, p->conf.mc);
|
||||
lua_pushcclosure(L, f_memcache_get_long, 1);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
lua_pushliteral(L, "memcache_get_string");
|
||||
lua_pushlightuserdata(L, p->conf.mc);
|
||||
lua_pushcclosure(L, f_memcache_get_string, 1);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
lua_pushliteral(L, "memcache_exists");
|
||||
lua_pushlightuserdata(L, p->conf.mc);
|
||||
lua_pushcclosure(L, f_memcache_exists, 1);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
#endif
|
||||
/* register CGI environment */
|
||||
lua_pushstring(L, "request");
|
||||
lua_newtable(L);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
lua_pushstring(L, "request");
|
||||
header_tbl = lua_gettop(L);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
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("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
|
||||
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));
|
||||
}
|
||||
|
||||
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 */
|
||||
lua_pushstring(L, "get");
|
||||
lua_newtable(L);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
lua_pushstring(L, "get");
|
||||
header_tbl = lua_gettop(L);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
buffer_copy_string_buffer(b, con->uri.query);
|
||||
split_query_string(L, header_tbl, b);
|
||||
buffer_reset(b);
|
||||
|
||||
|
||||
/* load lua program */
|
||||
if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
lua_tostring(L,-1));
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* get return value */
|
||||
ret = (int)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* fetch the data from lua */
|
||||
lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
|
||||
|
||||
if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
|
||||
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
|
||||
}
|
||||
|
||||
if (!lua_to_c_is_table(L, "output_include")) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"output_include is missing or not a table");
|
||||
ret = -1;
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* up to now it is a cache-hit, check if all files exist */
|
||||
|
||||
struct stat st;
|
||||
int curelem;
|
||||
|
||||
lua_pushstring(L, "output_include");
|
||||
|
||||
curelem = lua_gettop(L);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
|
||||
lua_pushnil(L); /* first key */
|
||||
while (lua_next(L, curelem) != 0) {
|
||||
/* key' is at index -2 and value' at index -1 */
|
||||
|
||||
if (lua_isstring(L, -1)) {
|
||||
buffer_copy_string_buffer(b, p->basedir);
|
||||
buffer_append_string(b, lua_tostring(L, -1));
|
||||
|
||||
if (0 != stat(b->ptr, &st)) {
|
||||
/* stat failed */
|
||||
|
||||
if (errno == ENOENT) {
|
||||
/* a file is missing, call the handler to generate it */
|
||||
if (!buffer_is_empty(p->trigger_handler)) {
|
||||
ret = 1; /* cache-miss */
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"a file is missing, calling handler");
|
||||
|
||||
break;
|
||||
} else {
|
||||
/* handler not set -> 500 */
|
||||
ret = -1;
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"a file missing and no handler set");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chunkqueue_append_file(con->write_queue, b, 0, st.st_size);
|
||||
}
|
||||
} else {
|
||||
/* not a string */
|
||||
ret = -1;
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"not a string");
|
||||
break;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
|
||||
}
|
||||
|
||||
lua_settop(L, curelem - 1);
|
||||
|
||||
if (ret == 0) {
|
||||
con->file_finished = 1;
|
||||
} else {
|
||||
chunkqueue_reset(con->write_queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 1 && buffer_is_empty(p->trigger_handler)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"cache-miss, but not trigger_handler set");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
/* cache-miss */
|
||||
buffer_copy_string_buffer(con->uri.path, p->baseurl);
|
||||
buffer_append_string_buffer(con->uri.path, p->trigger_handler);
|
||||
|
||||
buffer_copy_string_buffer(con->physical.path, p->basedir);
|
||||
buffer_append_string_buffer(con->physical.path, p->trigger_handler);
|
||||
|
||||
chunkqueue_reset(con->write_queue);
|
||||
}
|
||||
|
||||
error:
|
||||
lua_close(L);
|
||||
|
||||
stream_close(&rm.st);
|
||||
buffer_free(b);
|
||||
|
||||
return ret /* cache-error */;
|
||||
}
|
||||
#else
|
||||
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
|
||||
/* error */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue