Annotation of embedaddon/lighttpd/src/mod_magnet.c, revision 1.1.1.2
1.1 misho 1: #include "base.h"
2: #include "log.h"
3: #include "buffer.h"
4:
5: #include "plugin.h"
6:
7: #include "mod_magnet_cache.h"
8: #include "response.h"
9: #include "stat_cache.h"
10: #include "status_counter.h"
11: #include "etag.h"
12:
13: #include <ctype.h>
14: #include <stdlib.h>
15: #include <string.h>
16: #include <assert.h>
17: #include <setjmp.h>
18:
19: #ifdef HAVE_LUA_H
20: #include <lua.h>
21: #include <lauxlib.h>
22:
23: #define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to"
24: #define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to"
25: #define MAGNET_RESTART_REQUEST 99
26:
27: /* plugin config for all request/connections */
28:
29: static jmp_buf exceptionjmp;
30:
31: typedef struct {
32: array *url_raw;
33: array *physical_path;
34: } plugin_config;
35:
36: typedef struct {
37: PLUGIN_DATA;
38:
39: script_cache *cache;
40:
41: buffer *encode_buf;
42:
43: plugin_config **config_storage;
44:
45: plugin_config conf;
46: } plugin_data;
47:
48: /* init the plugin data */
49: INIT_FUNC(mod_magnet_init) {
50: plugin_data *p;
51:
52: p = calloc(1, sizeof(*p));
53:
54: p->cache = script_cache_init();
55: p->encode_buf = buffer_init();
56:
57: return p;
58: }
59:
60: /* detroy the plugin data */
61: FREE_FUNC(mod_magnet_free) {
62: plugin_data *p = p_d;
63:
64: UNUSED(srv);
65:
66: if (!p) return HANDLER_GO_ON;
67:
68: if (p->config_storage) {
69: size_t i;
70:
71: for (i = 0; i < srv->config_context->used; i++) {
72: plugin_config *s = p->config_storage[i];
73:
74: if (!s) continue;
75:
76: array_free(s->url_raw);
77: array_free(s->physical_path);
78:
79: free(s);
80: }
81: free(p->config_storage);
82: }
83:
84: script_cache_free(p->cache);
85: buffer_free(p->encode_buf);
86:
87: free(p);
88:
89: return HANDLER_GO_ON;
90: }
91:
92: /* handle plugin config and check values */
93:
94: SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
95: plugin_data *p = p_d;
96: size_t i = 0;
97:
98: config_values_t cv[] = {
99: { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
100: { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
101: { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
102: };
103:
104: if (!p) return HANDLER_ERROR;
105:
1.1.1.2 ! misho 106: p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1 misho 107:
108: for (i = 0; i < srv->config_context->used; i++) {
109: plugin_config *s;
110:
111: s = calloc(1, sizeof(plugin_config));
112: s->url_raw = array_init();
113: s->physical_path = array_init();
114:
115: cv[0].destination = s->url_raw;
116: cv[1].destination = s->physical_path;
117:
118: p->config_storage[i] = s;
119:
120: if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
121: return HANDLER_ERROR;
122: }
123: }
124:
125: return HANDLER_GO_ON;
126: }
127:
128: #define PATCH(x) \
129: p->conf.x = s->x;
130: static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
131: size_t i, j;
132: plugin_config *s = p->config_storage[0];
133:
134: PATCH(url_raw);
135: PATCH(physical_path);
136:
137: /* skip the first, the global context */
138: for (i = 1; i < srv->config_context->used; i++) {
139: data_config *dc = (data_config *)srv->config_context->data[i];
140: s = p->config_storage[i];
141:
142: /* condition didn't match */
143: if (!config_check_cond(srv, con, dc)) continue;
144:
145: /* merge config */
146: for (j = 0; j < dc->value->used; j++) {
147: data_unset *du = dc->value->data[j];
148:
149: if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_RAW_URL))) {
150: PATCH(url_raw);
151: } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) {
152: PATCH(physical_path);
153: }
154: }
155: }
156:
157: return 0;
158: }
159: #undef PATCH
160:
161: /* See http://lua-users.org/wiki/GeneralizedPairsAndIpairs for implementation details. */
162:
163: /* Override the default pairs() function to allow us to use a __pairs metakey */
164: static int magnet_pairs(lua_State *L) {
165: luaL_checkany(L, 1);
166:
167: if (luaL_getmetafield(L, 1, "__pairs")) {
168: lua_insert(L, 1);
169: lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
170: return lua_gettop(L);
171: } else {
172: lua_pushvalue(L, lua_upvalueindex(1));
173: lua_insert(L, 1);
174: lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
175: return lua_gettop(L);
176: }
177: }
178:
179: /* Define a function that will iterate over an array* (in upval 1) using current position (upval 2) */
180: static int magnet_array_next(lua_State *L) {
181: data_unset *du;
182: data_string *ds;
183: data_integer *di;
184:
185: size_t pos = lua_tointeger(L, lua_upvalueindex(1));
186: array *a = lua_touserdata(L, lua_upvalueindex(2));
187:
188: lua_settop(L, 0);
189:
190: if (pos >= a->used) return 0;
191: if (NULL != (du = a->data[pos])) {
192: if (du->key->used) {
193: lua_pushlstring(L, du->key->ptr, du->key->used - 1);
194: }
195: else {
196: lua_pushlstring(L, "", 0);
197: }
198: switch (du->type) {
199: case TYPE_STRING:
200: ds = (data_string *)du;
201: if (ds->value && ds->value->used) {
202: lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
203: } else {
204: lua_pushnil(L);
205: }
206: break;
207: case TYPE_COUNT:
208: case TYPE_INTEGER:
209: di = (data_integer *)du;
210: lua_pushinteger(L, di->value);
211: break;
212: default:
213: lua_pushnil(L);
214: break;
215: }
216:
217: /* Update our positional upval to reflect our new current position */
218: pos++;
219: lua_pushinteger(L, pos);
220: lua_replace(L, lua_upvalueindex(1));
221:
222: /* Returning 2 items on the stack (key, value) */
223: return 2;
224: }
225: return 0;
226: }
227:
228: /* Create the closure necessary to iterate over the array *a with the above function */
229: static int magnet_array_pairs(lua_State *L, array *a) {
230: lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
231: lua_pushlightuserdata(L, a); /* Push our array *a into upval 2 */
232: lua_pushcclosure(L, magnet_array_next, 2); /* Push our new closure with 2 upvals */
233: return 1;
234: }
235:
236: static int magnet_print(lua_State *L) {
237: const char *s = luaL_checkstring(L, 1);
238: server *srv;
239:
240: lua_pushstring(L, "lighty.srv");
241: lua_gettable(L, LUA_REGISTRYINDEX);
242: srv = lua_touserdata(L, -1);
243: lua_pop(L, 1);
244:
245: log_error_write(srv, __FILE__, __LINE__, "ss",
246: "(lua-print)", s);
247:
248: return 0;
249: }
250:
251: static int magnet_stat(lua_State *L) {
252: const char *s = luaL_checkstring(L, 1);
253: server *srv;
254: connection *con;
255: buffer sb;
256: stat_cache_entry *sce = NULL;
257:
258: lua_pushstring(L, "lighty.srv");
259: lua_gettable(L, LUA_REGISTRYINDEX);
260: srv = lua_touserdata(L, -1);
261: lua_pop(L, 1);
262:
263: lua_pushstring(L, "lighty.con");
264: lua_gettable(L, LUA_REGISTRYINDEX);
265: con = lua_touserdata(L, -1);
266: lua_pop(L, 1);
267:
268: sb.ptr = (char *)s;
269: sb.used = sb.size = strlen(s) + 1;
270:
271: if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) {
272: lua_pushnil(L);
273:
274: return 1;
275: }
276:
277: lua_newtable(L);
278:
279: lua_pushboolean(L, S_ISREG(sce->st.st_mode));
280: lua_setfield(L, -2, "is_file");
281:
282: lua_pushboolean(L, S_ISDIR(sce->st.st_mode));
283: lua_setfield(L, -2, "is_dir");
284:
285: lua_pushboolean(L, S_ISCHR(sce->st.st_mode));
286: lua_setfield(L, -2, "is_char");
287:
288: lua_pushboolean(L, S_ISBLK(sce->st.st_mode));
289: lua_setfield(L, -2, "is_block");
290:
291: lua_pushboolean(L, S_ISSOCK(sce->st.st_mode));
292: lua_setfield(L, -2, "is_socket");
293:
294: lua_pushboolean(L, S_ISLNK(sce->st.st_mode));
295: lua_setfield(L, -2, "is_link");
296:
297: lua_pushboolean(L, S_ISFIFO(sce->st.st_mode));
298: lua_setfield(L, -2, "is_fifo");
299:
300: lua_pushinteger(L, sce->st.st_mtime);
301: lua_setfield(L, -2, "st_mtime");
302:
303: lua_pushinteger(L, sce->st.st_ctime);
304: lua_setfield(L, -2, "st_ctime");
305:
306: lua_pushinteger(L, sce->st.st_atime);
307: lua_setfield(L, -2, "st_atime");
308:
309: lua_pushinteger(L, sce->st.st_uid);
310: lua_setfield(L, -2, "st_uid");
311:
312: lua_pushinteger(L, sce->st.st_gid);
313: lua_setfield(L, -2, "st_gid");
314:
315: lua_pushinteger(L, sce->st.st_size);
316: lua_setfield(L, -2, "st_size");
317:
318: lua_pushinteger(L, sce->st.st_ino);
319: lua_setfield(L, -2, "st_ino");
320:
321:
322: if (!buffer_is_empty(sce->etag)) {
323: /* we have to mutate the etag */
324: buffer *b = buffer_init();
325: etag_mutate(b, sce->etag);
326:
327: lua_pushlstring(L, b->ptr, b->used - 1);
328: buffer_free(b);
329: } else {
330: lua_pushnil(L);
331: }
332: lua_setfield(L, -2, "etag");
333:
334: if (!buffer_is_empty(sce->content_type)) {
335: lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
336: } else {
337: lua_pushnil(L);
338: }
339: lua_setfield(L, -2, "content-type");
340:
341: return 1;
342: }
343:
344:
345: static int magnet_atpanic(lua_State *L) {
346: const char *s = luaL_checkstring(L, 1);
347: server *srv;
348:
349: lua_pushstring(L, "lighty.srv");
350: lua_gettable(L, LUA_REGISTRYINDEX);
351: srv = lua_touserdata(L, -1);
352: lua_pop(L, 1);
353:
354: log_error_write(srv, __FILE__, __LINE__, "ss",
355: "(lua-atpanic)", s);
356:
357: longjmp(exceptionjmp, 1);
358: }
359:
360: static int magnet_reqhdr_get(lua_State *L) {
361: connection *con;
362: data_string *ds;
363:
364: const char *key = luaL_checkstring(L, 2);
365:
366: lua_pushstring(L, "lighty.con");
367: lua_gettable(L, LUA_REGISTRYINDEX);
368: con = lua_touserdata(L, -1);
369: lua_pop(L, 1);
370:
371: if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) {
372: if (ds->value->used) {
373: lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
374: } else {
375: lua_pushnil(L);
376: }
377: } else {
378: lua_pushnil(L);
379: }
380: return 1;
381: }
382:
383: static int magnet_reqhdr_pairs(lua_State *L) {
384: connection *con;
385:
386: lua_pushstring(L, "lighty.con");
387: lua_gettable(L, LUA_REGISTRYINDEX);
388: con = lua_touserdata(L, -1);
389: lua_pop(L, 1);
390:
391: return magnet_array_pairs(L, con->request.headers);
392: }
393:
394: static int magnet_status_get(lua_State *L) {
395: data_integer *di;
396: server *srv;
397: size_t key_len = 0;
398:
399: const char *key = luaL_checklstring(L, 2, &key_len);
400:
401: lua_pushstring(L, "lighty.srv");
402: lua_gettable(L, LUA_REGISTRYINDEX);
403: srv = lua_touserdata(L, -1);
404: lua_pop(L, 1);
405:
406: di = status_counter_get_counter(srv, key, key_len);
407:
408: lua_pushnumber(L, (double)di->value);
409:
410: return 1;
411: }
412:
413: static int magnet_status_set(lua_State *L) {
414: size_t key_len = 0;
415: server *srv;
416:
417: const char *key = luaL_checklstring(L, 2, &key_len);
418: int counter = luaL_checkint(L, 3);
419:
420: lua_pushstring(L, "lighty.srv");
421: lua_gettable(L, LUA_REGISTRYINDEX);
422: srv = lua_touserdata(L, -1);
423: lua_pop(L, 1);
424:
425: status_counter_set(srv, key, key_len, counter);
426:
427: return 0;
428: }
429:
430: static int magnet_status_pairs(lua_State *L) {
431: server *srv;
432:
433: lua_pushstring(L, "lighty.srv");
434: lua_gettable(L, LUA_REGISTRYINDEX);
435: srv = lua_touserdata(L, -1);
436: lua_pop(L, 1);
437:
438: return magnet_array_pairs(L, srv->status);
439: }
440:
441: typedef struct {
442: const char *name;
443: enum {
444: MAGNET_ENV_UNSET,
445:
446: MAGNET_ENV_PHYICAL_PATH,
447: MAGNET_ENV_PHYICAL_REL_PATH,
448: MAGNET_ENV_PHYICAL_DOC_ROOT,
1.1.1.2 ! misho 449: MAGNET_ENV_PHYICAL_BASEDIR,
1.1 misho 450:
451: MAGNET_ENV_URI_PATH,
452: MAGNET_ENV_URI_PATH_RAW,
453: MAGNET_ENV_URI_SCHEME,
454: MAGNET_ENV_URI_AUTHORITY,
455: MAGNET_ENV_URI_QUERY,
456:
457: MAGNET_ENV_REQUEST_METHOD,
458: MAGNET_ENV_REQUEST_URI,
459: MAGNET_ENV_REQUEST_ORIG_URI,
460: MAGNET_ENV_REQUEST_PATH_INFO,
461: MAGNET_ENV_REQUEST_REMOTE_IP,
462: MAGNET_ENV_REQUEST_PROTOCOL
463: } type;
464: } magnet_env_t;
465:
466: static const magnet_env_t magnet_env[] = {
467: { "physical.path", MAGNET_ENV_PHYICAL_PATH },
468: { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
469: { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
1.1.1.2 ! misho 470: { "physical.basedir", MAGNET_ENV_PHYICAL_BASEDIR },
1.1 misho 471:
472: { "uri.path", MAGNET_ENV_URI_PATH },
473: { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
474: { "uri.scheme", MAGNET_ENV_URI_SCHEME },
475: { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
476: { "uri.query", MAGNET_ENV_URI_QUERY },
477:
478: { "request.method", MAGNET_ENV_REQUEST_METHOD },
479: { "request.uri", MAGNET_ENV_REQUEST_URI },
480: { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
481: { "request.path-info", MAGNET_ENV_REQUEST_PATH_INFO },
482: { "request.remote-ip", MAGNET_ENV_REQUEST_REMOTE_IP },
483: { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
484:
485: { NULL, MAGNET_ENV_UNSET }
486: };
487:
488: static buffer *magnet_env_get_buffer_by_id(server *srv, connection *con, int id) {
489: buffer *dest = NULL;
490:
491: UNUSED(srv);
492:
493: /**
494: * map all internal variables to lua
495: *
496: */
497:
498: switch (id) {
499: case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
500: case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
501: case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
1.1.1.2 ! misho 502: case MAGNET_ENV_PHYICAL_BASEDIR: dest = con->physical.basedir; break;
1.1 misho 503:
504: case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
505: case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
506: case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
507: case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
508: case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
509:
510: case MAGNET_ENV_REQUEST_METHOD:
511: buffer_copy_string(srv->tmp_buf, get_http_method_name(con->request.http_method));
512: dest = srv->tmp_buf;
513: break;
514: case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
515: case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
516: case MAGNET_ENV_REQUEST_PATH_INFO: dest = con->request.pathinfo; break;
517: case MAGNET_ENV_REQUEST_REMOTE_IP: dest = con->dst_addr_buf; break;
518: case MAGNET_ENV_REQUEST_PROTOCOL:
519: buffer_copy_string(srv->tmp_buf, get_http_version_name(con->request.http_version));
520: dest = srv->tmp_buf;
521: break;
522:
523: case MAGNET_ENV_UNSET: break;
524: }
525:
526: return dest;
527: }
528:
529: static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
530: size_t i;
531:
532: for (i = 0; magnet_env[i].name; i++) {
533: if (0 == strcmp(key, magnet_env[i].name)) break;
534: }
535:
536: return magnet_env_get_buffer_by_id(srv, con, magnet_env[i].type);
537: }
538:
539: static int magnet_env_get(lua_State *L) {
540: server *srv;
541: connection *con;
542:
543: const char *key = luaL_checkstring(L, 2);
544: buffer *dest = NULL;
545:
546: lua_pushstring(L, "lighty.srv");
547: lua_gettable(L, LUA_REGISTRYINDEX);
548: srv = lua_touserdata(L, -1);
549: lua_pop(L, 1);
550:
551: lua_pushstring(L, "lighty.con");
552: lua_gettable(L, LUA_REGISTRYINDEX);
553: con = lua_touserdata(L, -1);
554: lua_pop(L, 1);
555:
556: dest = magnet_env_get_buffer(srv, con, key);
557:
558: if (dest && dest->used) {
559: lua_pushlstring(L, dest->ptr, dest->used - 1);
560: } else {
561: lua_pushnil(L);
562: }
563:
564: return 1;
565: }
566:
567: static int magnet_env_set(lua_State *L) {
568: server *srv;
569: connection *con;
570:
571: const char *key = luaL_checkstring(L, 2);
572: const char *val = luaL_checkstring(L, 3);
573: buffer *dest = NULL;
574:
575: lua_pushstring(L, "lighty.srv");
576: lua_gettable(L, LUA_REGISTRYINDEX);
577: srv = lua_touserdata(L, -1);
578: lua_pop(L, 1);
579:
580: lua_pushstring(L, "lighty.con");
581: lua_gettable(L, LUA_REGISTRYINDEX);
582: con = lua_touserdata(L, -1);
583: lua_pop(L, 1);
584:
585: if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
586: buffer_copy_string(dest, val);
587: } else {
588: /* couldn't save */
589:
590: return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
591: }
592:
593: return 0;
594: }
595:
596: static int magnet_env_next(lua_State *L) {
597: server *srv;
598: connection *con;
599: int pos = lua_tointeger(L, lua_upvalueindex(1));
600:
601: buffer *dest;
602:
603: lua_pushstring(L, "lighty.srv");
604: lua_gettable(L, LUA_REGISTRYINDEX);
605: srv = lua_touserdata(L, -1);
606: lua_pop(L, 1);
607:
608: lua_pushstring(L, "lighty.con");
609: lua_gettable(L, LUA_REGISTRYINDEX);
610: con = lua_touserdata(L, -1);
611: lua_pop(L, 1);
612:
613: lua_settop(L, 0);
614:
615: if (NULL == magnet_env[pos].name) return 0; /* end of list */
616:
617: lua_pushstring(L, magnet_env[pos].name);
618:
619: dest = magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type);
620: if (dest && dest->used) {
621: lua_pushlstring(L, dest->ptr, dest->used - 1);
622: } else {
623: lua_pushnil(L);
624: }
625:
626: /* Update our positional upval to reflect our new current position */
627: pos++;
628: lua_pushinteger(L, pos);
629: lua_replace(L, lua_upvalueindex(1));
630:
631: /* Returning 2 items on the stack (key, value) */
632: return 2;
633: }
634:
635: static int magnet_env_pairs(lua_State *L) {
636: lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
637: lua_pushcclosure(L, magnet_env_next, 1); /* Push our new closure with 1 upvals */
638: return 1;
639: }
640:
641: static int magnet_cgi_get(lua_State *L) {
642: connection *con;
643: data_string *ds;
644:
645: const char *key = luaL_checkstring(L, 2);
646:
647: lua_pushstring(L, "lighty.con");
648: lua_gettable(L, LUA_REGISTRYINDEX);
649: con = lua_touserdata(L, -1);
650: lua_pop(L, 1);
651:
652: if (NULL != (ds = (data_string *)array_get_element(con->environment, key)) && ds->value->used)
653: lua_pushlstring(L, CONST_BUF_LEN(ds->value));
654: else
655: lua_pushnil(L);
656:
657: return 1;
658: }
659:
660: static int magnet_cgi_set(lua_State *L) {
661: connection *con;
662:
663: const char *key = luaL_checkstring(L, 2);
664: const char *val = luaL_checkstring(L, 3);
665:
666: lua_pushstring(L, "lighty.con");
667: lua_gettable(L, LUA_REGISTRYINDEX);
668: con = lua_touserdata(L, -1);
669: lua_pop(L, 1);
670:
671: array_set_key_value(con->environment, key, strlen(key), val, strlen(val));
672:
673: return 0;
674: }
675:
676: static int magnet_cgi_pairs(lua_State *L) {
677: connection *con;
678:
679: lua_pushstring(L, "lighty.con");
680: lua_gettable(L, LUA_REGISTRYINDEX);
681: con = lua_touserdata(L, -1);
682: lua_pop(L, 1);
683:
684: return magnet_array_pairs(L, con->environment);
685: }
686:
687:
688: static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
689: UNUSED(p);
690: /**
691: * get the environment of the function
692: */
693:
694: lua_getfenv(L, -1); /* -1 is the function */
695:
696: /* lighty.header */
697:
698: lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
1.1.1.2 ! misho 699: force_assert(lua_istable(L, -1));
1.1 misho 700:
701: lua_getfield(L, -1, "header"); /* lighty.header */
702: if (lua_istable(L, -1)) {
703: /* header is found, and is a table */
704:
705: lua_pushnil(L);
706: while (lua_next(L, -2) != 0) {
707: if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
708: const char *key, *val;
709: size_t key_len, val_len;
710:
711: key = lua_tolstring(L, -2, &key_len);
712: val = lua_tolstring(L, -1, &val_len);
713:
714: response_header_overwrite(srv, con, key, key_len, val, val_len);
715: }
716:
717: lua_pop(L, 1);
718: }
719: }
720:
721: lua_pop(L, 1); /* pop the header-table */
722: lua_pop(L, 1); /* pop the lighty-env */
723: lua_pop(L, 1); /* pop the function env */
724:
725: return 0;
726: }
727:
728: /**
729: * walk through the content array
730: *
731: * content = { "<pre>", { file = "/content" } , "</pre>" }
732: *
733: * header["Content-Type"] = "text/html"
734: *
735: * return 200
736: */
737: static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
738: UNUSED(p);
739: /**
740: * get the environment of the function
741: */
742:
1.1.1.2 ! misho 743: force_assert(lua_isfunction(L, -1));
1.1 misho 744: lua_getfenv(L, -1); /* -1 is the function */
745:
746: lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
1.1.1.2 ! misho 747: force_assert(lua_istable(L, -1));
1.1 misho 748:
749: lua_getfield(L, -1, "content"); /* lighty.content */
750: if (lua_istable(L, -1)) {
751: int i;
752: /* header is found, and is a table */
753:
754: for (i = 1; ; i++) {
755: lua_rawgeti(L, -1, i);
756:
757: /* -1 is the value and should be the value ... aka a table */
758: if (lua_isstring(L, -1)) {
759: size_t s_len = 0;
760: const char *s = lua_tolstring(L, -1, &s_len);
761:
762: chunkqueue_append_mem(con->write_queue, s, s_len + 1);
763: } else if (lua_istable(L, -1)) {
764: lua_getfield(L, -1, "filename");
765: lua_getfield(L, -2, "length");
766: lua_getfield(L, -3, "offset");
767:
768: if (lua_isstring(L, -3)) { /* filename has to be a string */
1.1.1.2 ! misho 769: buffer *fn;
1.1 misho 770: stat_cache_entry *sce;
1.1.1.2 ! misho 771: const char *fn_str;
! 772: handler_t res;
1.1 misho 773:
1.1.1.2 ! misho 774: fn_str = lua_tostring(L, -3);
! 775: fn = buffer_init_string(fn_str);
1.1 misho 776:
1.1.1.2 ! misho 777: res = stat_cache_get_entry(srv, con, fn, &sce);
! 778:
! 779: if (HANDLER_GO_ON == res) {
1.1 misho 780: off_t off = 0;
781: off_t len = 0;
782:
783: if (lua_isnumber(L, -1)) {
784: off = lua_tonumber(L, -1);
785: }
786:
787: if (lua_isnumber(L, -2)) {
788: len = lua_tonumber(L, -2);
789: } else {
790: len = sce->st.st_size;
791: }
792:
793: if (off < 0) {
1.1.1.2 ! misho 794: buffer_free(fn);
! 795: return luaL_error(L, "offset for '%s' is negative", fn_str);
1.1 misho 796: }
797:
798: if (len < off) {
1.1.1.2 ! misho 799: buffer_free(fn);
! 800: return luaL_error(L, "offset > length for '%s'", fn_str);
1.1 misho 801: }
802:
803: chunkqueue_append_file(con->write_queue, fn, off, len - off);
804: }
805:
806: buffer_free(fn);
807: } else {
808: lua_pop(L, 3 + 2); /* correct the stack */
809:
810: return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
811: }
812:
813: lua_pop(L, 3);
814: } else if (lua_isnil(L, -1)) {
815: /* oops, end of list */
816:
817: lua_pop(L, 1);
818:
819: break;
820: } else {
821: lua_pop(L, 4);
822:
823: return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
824: }
825:
826: lua_pop(L, 1); /* pop the content[...] table */
827: }
828: } else {
829: return luaL_error(L, "lighty.content has to be a table");
830: }
831: lua_pop(L, 1); /* pop the header-table */
832: lua_pop(L, 1); /* pop the lighty-table */
833: lua_pop(L, 1); /* php the function env */
834:
835: return 0;
836: }
837:
838: static int traceback (lua_State *L) {
839: if (!lua_isstring(L, 1)) /* 'message' not a string? */
840: return 1; /* keep it intact */
841: lua_getfield(L, LUA_GLOBALSINDEX, "debug");
842: if (!lua_istable(L, -1)) {
843: lua_pop(L, 1);
844: return 1;
845: }
846: lua_getfield(L, -1, "traceback");
847: if (!lua_isfunction(L, -1)) {
848: lua_pop(L, 2);
849: return 1;
850: }
851: lua_pushvalue(L, 1); /* pass error message */
852: lua_pushinteger(L, 2); /* skip this function and traceback */
853: lua_call(L, 2, 1); /* call debug.traceback */
854: return 1;
855: }
856:
857: static int push_traceback(lua_State *L, int narg) {
858: int base = lua_gettop(L) - narg; /* function index */
859: lua_pushcfunction(L, traceback);
860: lua_insert(L, base);
861: return base;
862: }
863:
864: static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
865: lua_State *L;
866: int lua_return_value = -1;
867: int errfunc;
868: /* get the script-context */
869:
870:
871: L = script_cache_get_script(srv, con, p->cache, name);
872:
873: if (lua_isstring(L, -1)) {
874: log_error_write(srv, __FILE__, __LINE__,
875: "sbss",
876: "loading script",
877: name,
878: "failed:",
879: lua_tostring(L, -1));
880:
881: lua_pop(L, 1);
882:
1.1.1.2 ! misho 883: force_assert(lua_gettop(L) == 0); /* only the function should be on the stack */
1.1 misho 884:
885: con->http_status = 500;
886: con->mode = DIRECT;
887:
888: return HANDLER_FINISHED;
889: }
890:
891: lua_pushstring(L, "lighty.srv");
892: lua_pushlightuserdata(L, srv);
893: lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
894:
895: lua_pushstring(L, "lighty.con");
896: lua_pushlightuserdata(L, con);
897: lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
898:
899: lua_atpanic(L, magnet_atpanic);
900:
901: /**
902: * we want to create empty environment for our script
903: *
904: * setmetatable({}, {__index = _G})
905: *
906: * if a function, symbol is not defined in our env, __index will lookup
907: * in the global env.
908: *
909: * all variables created in the script-env will be thrown
910: * away at the end of the script run.
911: */
912: lua_newtable(L); /* my empty environment aka {} (sp += 1) */
913:
914: /* we have to overwrite the print function */
915: lua_pushcfunction(L, magnet_print); /* (sp += 1) */
916: lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
917:
918: /**
919: * lighty.request[] has the HTTP-request headers
920: * lighty.content[] is a table of string/file
921: * lighty.header[] is a array to set response headers
922: */
923:
924: lua_newtable(L); /* lighty.* (sp += 1) */
925:
926: lua_newtable(L); /* {} (sp += 1) */
927: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
928: lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
929: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
930: lua_pushcfunction(L, magnet_reqhdr_pairs); /* (sp += 1) */
931: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
932: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
933: lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
934:
935: lua_newtable(L); /* {} (sp += 1) */
936: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
937: lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
938: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
939: lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
940: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
941: lua_pushcfunction(L, magnet_env_pairs); /* (sp += 1) */
942: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
943: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
944: lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
945:
946: lua_newtable(L); /* {} (sp += 1) */
947: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
948: lua_pushcfunction(L, magnet_cgi_get); /* (sp += 1) */
949: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
950: lua_pushcfunction(L, magnet_cgi_set); /* (sp += 1) */
951: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
952: lua_pushcfunction(L, magnet_cgi_pairs); /* (sp += 1) */
953: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
954: lua_setmetatable(L, -2); /* tie the metatable to req_env (sp -= 1) */
955: lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */
956:
957: lua_newtable(L); /* {} (sp += 1) */
958: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
959: lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
960: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
961: lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
962: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
963: lua_pushcfunction(L, magnet_status_pairs); /* (sp += 1) */
964: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
965: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
966: lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
967:
968: /* add empty 'content' and 'header' tables */
969: lua_newtable(L); /* {} (sp += 1) */
970: lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
971:
972: lua_newtable(L); /* {} (sp += 1) */
973: lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
974:
975: lua_pushinteger(L, MAGNET_RESTART_REQUEST);
976: lua_setfield(L, -2, "RESTART_REQUEST");
977:
978: lua_pushcfunction(L, magnet_stat); /* (sp += 1) */
979: lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
980:
981: lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
982:
983: /* override the default pairs() function to our __pairs capable version */
984: lua_getglobal(L, "pairs"); /* push original pairs() (sp += 1) */
985: lua_pushcclosure(L, magnet_pairs, 1);
986: lua_setfield(L, -2, "pairs"); /* (sp -= 1) */
987:
988: lua_newtable(L); /* the meta-table for the new env (sp += 1) */
989: lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */
990: lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
991: lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
992:
993:
994: lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
995:
996: errfunc = push_traceback(L, 0);
997: if (lua_pcall(L, 0, 1, errfunc)) {
998: lua_remove(L, errfunc);
999: log_error_write(srv, __FILE__, __LINE__,
1000: "ss",
1001: "lua_pcall():",
1002: lua_tostring(L, -1));
1003: lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
1004:
1.1.1.2 ! misho 1005: force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1.1 misho 1006:
1007: con->http_status = 500;
1008: con->mode = DIRECT;
1009:
1010: return HANDLER_FINISHED;
1011: }
1012: lua_remove(L, errfunc);
1013:
1014: /* we should have the function-copy and the return value on the stack */
1.1.1.2 ! misho 1015: force_assert(lua_gettop(L) == 2);
1.1 misho 1016:
1017: if (lua_isnumber(L, -1)) {
1018: /* if the ret-value is a number, take it */
1019: lua_return_value = (int)lua_tonumber(L, -1);
1020: }
1021: lua_pop(L, 1); /* pop the ret-value */
1022:
1023: magnet_copy_response_header(srv, con, p, L);
1024:
1025: if (lua_return_value > 99) {
1026: con->http_status = lua_return_value;
1027: con->file_finished = 1;
1028:
1029: /* try { ...*/
1030: if (0 == setjmp(exceptionjmp)) {
1031: magnet_attach_content(srv, con, p, L);
1032: if (!chunkqueue_is_empty(con->write_queue)) {
1033: con->mode = p->id;
1034: }
1035: } else {
1036: /* } catch () { */
1037: con->http_status = 500;
1038: con->mode = DIRECT;
1039: }
1040:
1.1.1.2 ! misho 1041: force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1.1 misho 1042:
1043: /* we are finished */
1044: return HANDLER_FINISHED;
1045: } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
1.1.1.2 ! misho 1046: force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1.1 misho 1047:
1048: return HANDLER_COMEBACK;
1049: } else {
1.1.1.2 ! misho 1050: force_assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1.1 misho 1051:
1052: return HANDLER_GO_ON;
1053: }
1054: }
1055:
1056: static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
1057: size_t i;
1058:
1059: /* no filename set */
1060: if (files->used == 0) return HANDLER_GO_ON;
1061:
1062: /**
1063: * execute all files and jump out on the first !HANDLER_GO_ON
1064: */
1065: for (i = 0; i < files->used; i++) {
1066: data_string *ds = (data_string *)files->data[i];
1067: handler_t ret;
1068:
1069: if (buffer_is_empty(ds->value)) continue;
1070:
1071: ret = magnet_attract(srv, con, p, ds->value);
1072:
1073: if (ret != HANDLER_GO_ON) return ret;
1074: }
1075:
1076: return HANDLER_GO_ON;
1077: }
1078:
1079: URIHANDLER_FUNC(mod_magnet_uri_handler) {
1080: plugin_data *p = p_d;
1081:
1082: mod_magnet_patch_connection(srv, con, p);
1083:
1084: return magnet_attract_array(srv, con, p, p->conf.url_raw);
1085: }
1086:
1087: URIHANDLER_FUNC(mod_magnet_physical) {
1088: plugin_data *p = p_d;
1089:
1090: mod_magnet_patch_connection(srv, con, p);
1091:
1092: return magnet_attract_array(srv, con, p, p->conf.physical_path);
1093: }
1094:
1095:
1096: /* this function is called at dlopen() time and inits the callbacks */
1097:
1098: int mod_magnet_plugin_init(plugin *p);
1099: int mod_magnet_plugin_init(plugin *p) {
1100: p->version = LIGHTTPD_VERSION_ID;
1101: p->name = buffer_init_string("magnet");
1102:
1103: p->init = mod_magnet_init;
1104: p->handle_uri_clean = mod_magnet_uri_handler;
1105: p->handle_physical = mod_magnet_physical;
1106: p->set_defaults = mod_magnet_set_defaults;
1107: p->cleanup = mod_magnet_free;
1108:
1109: p->data = NULL;
1110:
1111: return 0;
1112: }
1113:
1114: #else
1115: int mod_magnet_plugin_init(plugin *p);
1116: int mod_magnet_plugin_init(plugin *p) {
1117: UNUSED(p);
1118: return -1;
1119: }
1120: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>