[mod_openssl] remove erroneous SSL_set_shutdown()
[lighttpd.git] / src / mod_cml_lua.c
blobde344fd1cc3c78b5504e391850c3b2500179eae6
1 #include "first.h"
3 #include <lua.h>
4 #include <lualib.h>
5 #include <lauxlib.h>
7 #include <errno.h>
8 #include <time.h>
9 #include <string.h>
11 #include "mod_cml_funcs.h"
12 #include "mod_cml.h"
14 #include "log.h"
15 #include "stat_cache.h"
17 #define HASHLEN 16
18 typedef unsigned char HASH[HASHLEN];
19 #define HASHHEXLEN 32
20 typedef char HASHHEX[HASHHEXLEN+1];
22 static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
23 int curelem = lua_gettop(L);
24 int result;
26 lua_getglobal(L, varname);
28 if (lua_isstring(L, curelem)) {
29 buffer_copy_string(b, lua_tostring(L, curelem));
30 result = 0;
31 } else {
32 result = -1;
35 lua_pop(L, 1);
36 force_assert(curelem == lua_gettop(L));
37 return result;
40 static int lua_to_c_is_table(lua_State *L, const char *varname) {
41 int curelem = lua_gettop(L);
42 int result;
44 lua_getglobal(L, varname);
46 result = lua_istable(L, curelem) ? 1 : 0;
48 lua_pop(L, 1);
49 force_assert(curelem == lua_gettop(L));
50 return result;
53 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) {
54 lua_pushlstring(L, key, key_len);
55 lua_pushlstring(L, val, val_len);
56 lua_settable(L, tbl);
58 return 0;
61 static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
62 size_t is_key = 1;
63 size_t i, len;
64 char *key = NULL, *val = NULL;
66 key = qrystr->ptr;
68 /* we need the \0 */
69 len = buffer_string_length(qrystr);
70 for (i = 0; i <= len; i++) {
71 switch(qrystr->ptr[i]) {
72 case '=':
73 if (is_key) {
74 val = qrystr->ptr + i + 1;
76 qrystr->ptr[i] = '\0';
78 is_key = 0;
81 break;
82 case '&':
83 case '\0': /* fin symbol */
84 if (!is_key) {
85 /* we need at least a = since the last & */
87 /* terminate the value */
88 qrystr->ptr[i] = '\0';
90 c_to_lua_push(L, tbl,
91 key, strlen(key),
92 val, strlen(val));
95 key = qrystr->ptr + i + 1;
96 val = NULL;
97 is_key = 1;
98 break;
102 return 0;
105 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
106 lua_State *L;
107 int ret = -1;
108 buffer *b;
110 b = buffer_init();
111 /* push the lua file to the interpreter and see what happends */
112 L = luaL_newstate();
113 luaL_openlibs(L);
115 /* register functions */
116 lua_register(L, "md5", f_crypto_md5);
117 lua_register(L, "file_mtime", f_file_mtime);
118 lua_register(L, "file_isreg", f_file_isreg);
119 lua_register(L, "file_isdir", f_file_isreg);
120 lua_register(L, "dir_files", f_dir_files);
122 #ifdef USE_MEMCACHED
123 lua_pushlightuserdata(L, p->conf.memc);
124 lua_pushcclosure(L, f_memcache_get_long, 1);
125 lua_setglobal(L, "memcache_get_long");
127 lua_pushlightuserdata(L, p->conf.memc);
128 lua_pushcclosure(L, f_memcache_get_string, 1);
129 lua_setglobal(L, "memcache_get_string");
131 lua_pushlightuserdata(L, p->conf.memc);
132 lua_pushcclosure(L, f_memcache_exists, 1);
133 lua_setglobal(L, "memcache_exists");
134 #endif
136 /* register CGI environment */
137 lua_newtable(L);
139 int header_tbl = lua_gettop(L);
141 c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
142 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
143 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
144 c_to_lua_push(L, header_tbl, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
145 if (!buffer_string_is_empty(con->request.pathinfo)) {
146 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
149 c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
150 c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
152 lua_setglobal(L, "request");
154 /* register GET parameter */
155 lua_newtable(L);
157 int get_tbl = lua_gettop(L);
159 buffer_copy_buffer(b, con->uri.query);
160 cache_export_get_params(L, get_tbl, b);
161 buffer_reset(b);
163 lua_setglobal(L, "get");
165 /* 2 default constants */
166 lua_pushinteger(L, 0);
167 lua_setglobal(L, "CACHE_HIT");
169 lua_pushinteger(L, 1);
170 lua_setglobal(L, "CACHE_MISS");
172 /* load lua program */
173 ret = luaL_loadfile(L, fn->ptr);
174 if (0 != ret) {
175 log_error_write(srv, __FILE__, __LINE__, "sbsS",
176 "failed loading cml_lua script",
178 ":",
179 lua_tostring(L, -1));
180 goto error;
183 if (lua_pcall(L, 0, 1, 0)) {
184 log_error_write(srv, __FILE__, __LINE__, "sbsS",
185 "failed running cml_lua script",
187 ":",
188 lua_tostring(L, -1));
189 goto error;
192 /* get return value */
193 ret = (int)lua_tointeger(L, -1);
194 lua_pop(L, 1);
196 /* fetch the data from lua */
197 lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
199 if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
200 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
203 if (ret == 0) {
204 /* up to now it is a cache-hit, check if all files exist */
206 int curelem;
207 time_t mtime = 0;
209 if (!lua_to_c_is_table(L, "output_include")) {
210 log_error_write(srv, __FILE__, __LINE__, "s",
211 "output_include is missing or not a table");
212 ret = -1;
214 goto error;
217 lua_getglobal(L, "output_include");
218 curelem = lua_gettop(L);
220 /* HOW-TO build a etag ?
221 * as we don't just have one file we have to take the stat()
222 * from all base files, merge them and build the etag from
223 * it later.
225 * The mtime of the content is the mtime of the freshest base file
227 * */
229 lua_pushnil(L); /* first key */
230 while (lua_next(L, curelem) != 0) {
231 /* key' is at index -2 and value' at index -1 */
233 if (lua_isstring(L, -1)) {
234 const char *s = lua_tostring(L, -1);
235 struct stat st;
236 int fd;
238 /* the file is relative, make it absolute */
239 if (s[0] != '/') {
240 buffer_copy_buffer(b, p->basedir);
241 buffer_append_string(b, lua_tostring(L, -1));
242 } else {
243 buffer_copy_string(b, lua_tostring(L, -1));
246 fd = stat_cache_open_rdonly_fstat(srv, con, b, &st);
247 if (fd < 0) {
248 /* stat failed */
250 switch(errno) {
251 case ENOENT:
252 /* a file is missing, call the handler to generate it */
253 if (!buffer_string_is_empty(p->trigger_handler)) {
254 ret = 1; /* cache-miss */
256 log_error_write(srv, __FILE__, __LINE__, "s",
257 "a file is missing, calling handler");
259 break;
260 } else {
261 /* handler not set -> 500 */
262 ret = -1;
264 log_error_write(srv, __FILE__, __LINE__, "s",
265 "a file missing and no handler set");
267 break;
269 break;
270 default:
271 break;
273 } else {
274 chunkqueue_append_file_fd(con->write_queue, b, fd, 0, st.st_size);
275 if (st.st_mtime > mtime) mtime = st.st_mtime;
277 } else {
278 /* not a string */
279 ret = -1;
280 log_error_write(srv, __FILE__, __LINE__, "s",
281 "not a string");
282 break;
285 lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
288 lua_settop(L, curelem - 1);
290 if (ret == 0) {
291 data_string *ds;
292 char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
294 con->file_finished = 1;
296 ds = (data_string *)array_get_element(con->response.headers, "Last-Modified");
297 if (0 == mtime) mtime = time(NULL); /* default last-modified to now */
299 /* no Last-Modified specified */
300 if (NULL == ds) {
302 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
304 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
305 ds = (data_string *)array_get_element(con->response.headers, "Last-Modified");
306 force_assert(NULL != ds);
309 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, ds->value)) {
310 /* ok, the client already has our content,
311 * no need to send it again */
313 chunkqueue_reset(con->write_queue);
314 ret = 0; /* cache-hit */
316 } else {
317 chunkqueue_reset(con->write_queue);
321 if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) {
322 /* cache-miss */
323 buffer_copy_buffer(con->uri.path, p->baseurl);
324 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
326 buffer_copy_buffer(con->physical.path, p->basedir);
327 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
329 chunkqueue_reset(con->write_queue);
332 error:
333 lua_close(L);
335 buffer_free(b);
337 return ret /* cache-error */;