Annotation of embedaddon/lighttpd/src/mod_magnet.c, revision 1.1.1.1
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:
106: p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
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,
449:
450: MAGNET_ENV_URI_PATH,
451: MAGNET_ENV_URI_PATH_RAW,
452: MAGNET_ENV_URI_SCHEME,
453: MAGNET_ENV_URI_AUTHORITY,
454: MAGNET_ENV_URI_QUERY,
455:
456: MAGNET_ENV_REQUEST_METHOD,
457: MAGNET_ENV_REQUEST_URI,
458: MAGNET_ENV_REQUEST_ORIG_URI,
459: MAGNET_ENV_REQUEST_PATH_INFO,
460: MAGNET_ENV_REQUEST_REMOTE_IP,
461: MAGNET_ENV_REQUEST_PROTOCOL
462: } type;
463: } magnet_env_t;
464:
465: static const magnet_env_t magnet_env[] = {
466: { "physical.path", MAGNET_ENV_PHYICAL_PATH },
467: { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
468: { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
469:
470: { "uri.path", MAGNET_ENV_URI_PATH },
471: { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
472: { "uri.scheme", MAGNET_ENV_URI_SCHEME },
473: { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
474: { "uri.query", MAGNET_ENV_URI_QUERY },
475:
476: { "request.method", MAGNET_ENV_REQUEST_METHOD },
477: { "request.uri", MAGNET_ENV_REQUEST_URI },
478: { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
479: { "request.path-info", MAGNET_ENV_REQUEST_PATH_INFO },
480: { "request.remote-ip", MAGNET_ENV_REQUEST_REMOTE_IP },
481: { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
482:
483: { NULL, MAGNET_ENV_UNSET }
484: };
485:
486: static buffer *magnet_env_get_buffer_by_id(server *srv, connection *con, int id) {
487: buffer *dest = NULL;
488:
489: UNUSED(srv);
490:
491: /**
492: * map all internal variables to lua
493: *
494: */
495:
496: switch (id) {
497: case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
498: case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
499: case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
500:
501: case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
502: case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
503: case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
504: case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
505: case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
506:
507: case MAGNET_ENV_REQUEST_METHOD:
508: buffer_copy_string(srv->tmp_buf, get_http_method_name(con->request.http_method));
509: dest = srv->tmp_buf;
510: break;
511: case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
512: case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
513: case MAGNET_ENV_REQUEST_PATH_INFO: dest = con->request.pathinfo; break;
514: case MAGNET_ENV_REQUEST_REMOTE_IP: dest = con->dst_addr_buf; break;
515: case MAGNET_ENV_REQUEST_PROTOCOL:
516: buffer_copy_string(srv->tmp_buf, get_http_version_name(con->request.http_version));
517: dest = srv->tmp_buf;
518: break;
519:
520: case MAGNET_ENV_UNSET: break;
521: }
522:
523: return dest;
524: }
525:
526: static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
527: size_t i;
528:
529: for (i = 0; magnet_env[i].name; i++) {
530: if (0 == strcmp(key, magnet_env[i].name)) break;
531: }
532:
533: return magnet_env_get_buffer_by_id(srv, con, magnet_env[i].type);
534: }
535:
536: static int magnet_env_get(lua_State *L) {
537: server *srv;
538: connection *con;
539:
540: const char *key = luaL_checkstring(L, 2);
541: buffer *dest = NULL;
542:
543: lua_pushstring(L, "lighty.srv");
544: lua_gettable(L, LUA_REGISTRYINDEX);
545: srv = lua_touserdata(L, -1);
546: lua_pop(L, 1);
547:
548: lua_pushstring(L, "lighty.con");
549: lua_gettable(L, LUA_REGISTRYINDEX);
550: con = lua_touserdata(L, -1);
551: lua_pop(L, 1);
552:
553: dest = magnet_env_get_buffer(srv, con, key);
554:
555: if (dest && dest->used) {
556: lua_pushlstring(L, dest->ptr, dest->used - 1);
557: } else {
558: lua_pushnil(L);
559: }
560:
561: return 1;
562: }
563:
564: static int magnet_env_set(lua_State *L) {
565: server *srv;
566: connection *con;
567:
568: const char *key = luaL_checkstring(L, 2);
569: const char *val = luaL_checkstring(L, 3);
570: buffer *dest = NULL;
571:
572: lua_pushstring(L, "lighty.srv");
573: lua_gettable(L, LUA_REGISTRYINDEX);
574: srv = lua_touserdata(L, -1);
575: lua_pop(L, 1);
576:
577: lua_pushstring(L, "lighty.con");
578: lua_gettable(L, LUA_REGISTRYINDEX);
579: con = lua_touserdata(L, -1);
580: lua_pop(L, 1);
581:
582: if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
583: buffer_copy_string(dest, val);
584: } else {
585: /* couldn't save */
586:
587: return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
588: }
589:
590: return 0;
591: }
592:
593: static int magnet_env_next(lua_State *L) {
594: server *srv;
595: connection *con;
596: int pos = lua_tointeger(L, lua_upvalueindex(1));
597:
598: buffer *dest;
599:
600: lua_pushstring(L, "lighty.srv");
601: lua_gettable(L, LUA_REGISTRYINDEX);
602: srv = lua_touserdata(L, -1);
603: lua_pop(L, 1);
604:
605: lua_pushstring(L, "lighty.con");
606: lua_gettable(L, LUA_REGISTRYINDEX);
607: con = lua_touserdata(L, -1);
608: lua_pop(L, 1);
609:
610: lua_settop(L, 0);
611:
612: if (NULL == magnet_env[pos].name) return 0; /* end of list */
613:
614: lua_pushstring(L, magnet_env[pos].name);
615:
616: dest = magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type);
617: if (dest && dest->used) {
618: lua_pushlstring(L, dest->ptr, dest->used - 1);
619: } else {
620: lua_pushnil(L);
621: }
622:
623: /* Update our positional upval to reflect our new current position */
624: pos++;
625: lua_pushinteger(L, pos);
626: lua_replace(L, lua_upvalueindex(1));
627:
628: /* Returning 2 items on the stack (key, value) */
629: return 2;
630: }
631:
632: static int magnet_env_pairs(lua_State *L) {
633: lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
634: lua_pushcclosure(L, magnet_env_next, 1); /* Push our new closure with 1 upvals */
635: return 1;
636: }
637:
638: static int magnet_cgi_get(lua_State *L) {
639: connection *con;
640: data_string *ds;
641:
642: const char *key = luaL_checkstring(L, 2);
643:
644: lua_pushstring(L, "lighty.con");
645: lua_gettable(L, LUA_REGISTRYINDEX);
646: con = lua_touserdata(L, -1);
647: lua_pop(L, 1);
648:
649: if (NULL != (ds = (data_string *)array_get_element(con->environment, key)) && ds->value->used)
650: lua_pushlstring(L, CONST_BUF_LEN(ds->value));
651: else
652: lua_pushnil(L);
653:
654: return 1;
655: }
656:
657: static int magnet_cgi_set(lua_State *L) {
658: connection *con;
659:
660: const char *key = luaL_checkstring(L, 2);
661: const char *val = luaL_checkstring(L, 3);
662:
663: lua_pushstring(L, "lighty.con");
664: lua_gettable(L, LUA_REGISTRYINDEX);
665: con = lua_touserdata(L, -1);
666: lua_pop(L, 1);
667:
668: array_set_key_value(con->environment, key, strlen(key), val, strlen(val));
669:
670: return 0;
671: }
672:
673: static int magnet_cgi_pairs(lua_State *L) {
674: connection *con;
675:
676: lua_pushstring(L, "lighty.con");
677: lua_gettable(L, LUA_REGISTRYINDEX);
678: con = lua_touserdata(L, -1);
679: lua_pop(L, 1);
680:
681: return magnet_array_pairs(L, con->environment);
682: }
683:
684:
685: static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
686: UNUSED(p);
687: /**
688: * get the environment of the function
689: */
690:
691: lua_getfenv(L, -1); /* -1 is the function */
692:
693: /* lighty.header */
694:
695: lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
696: assert(lua_istable(L, -1));
697:
698: lua_getfield(L, -1, "header"); /* lighty.header */
699: if (lua_istable(L, -1)) {
700: /* header is found, and is a table */
701:
702: lua_pushnil(L);
703: while (lua_next(L, -2) != 0) {
704: if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
705: const char *key, *val;
706: size_t key_len, val_len;
707:
708: key = lua_tolstring(L, -2, &key_len);
709: val = lua_tolstring(L, -1, &val_len);
710:
711: response_header_overwrite(srv, con, key, key_len, val, val_len);
712: }
713:
714: lua_pop(L, 1);
715: }
716: }
717:
718: lua_pop(L, 1); /* pop the header-table */
719: lua_pop(L, 1); /* pop the lighty-env */
720: lua_pop(L, 1); /* pop the function env */
721:
722: return 0;
723: }
724:
725: /**
726: * walk through the content array
727: *
728: * content = { "<pre>", { file = "/content" } , "</pre>" }
729: *
730: * header["Content-Type"] = "text/html"
731: *
732: * return 200
733: */
734: static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
735: UNUSED(p);
736: /**
737: * get the environment of the function
738: */
739:
740: assert(lua_isfunction(L, -1));
741: lua_getfenv(L, -1); /* -1 is the function */
742:
743: lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
744: assert(lua_istable(L, -1));
745:
746: lua_getfield(L, -1, "content"); /* lighty.content */
747: if (lua_istable(L, -1)) {
748: int i;
749: /* header is found, and is a table */
750:
751: for (i = 1; ; i++) {
752: lua_rawgeti(L, -1, i);
753:
754: /* -1 is the value and should be the value ... aka a table */
755: if (lua_isstring(L, -1)) {
756: size_t s_len = 0;
757: const char *s = lua_tolstring(L, -1, &s_len);
758:
759: chunkqueue_append_mem(con->write_queue, s, s_len + 1);
760: } else if (lua_istable(L, -1)) {
761: lua_getfield(L, -1, "filename");
762: lua_getfield(L, -2, "length");
763: lua_getfield(L, -3, "offset");
764:
765: if (lua_isstring(L, -3)) { /* filename has to be a string */
766: buffer *fn = buffer_init();
767: stat_cache_entry *sce;
768:
769: buffer_copy_string(fn, lua_tostring(L, -3));
770:
771: if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) {
772: off_t off = 0;
773: off_t len = 0;
774:
775: if (lua_isnumber(L, -1)) {
776: off = lua_tonumber(L, -1);
777: }
778:
779: if (lua_isnumber(L, -2)) {
780: len = lua_tonumber(L, -2);
781: } else {
782: len = sce->st.st_size;
783: }
784:
785: if (off < 0) {
786: return luaL_error(L, "offset for '%s' is negative", fn->ptr);
787: }
788:
789: if (len < off) {
790: return luaL_error(L, "offset > length for '%s'", fn->ptr);
791: }
792:
793: chunkqueue_append_file(con->write_queue, fn, off, len - off);
794: }
795:
796: buffer_free(fn);
797: } else {
798: lua_pop(L, 3 + 2); /* correct the stack */
799:
800: return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
801: }
802:
803: lua_pop(L, 3);
804: } else if (lua_isnil(L, -1)) {
805: /* oops, end of list */
806:
807: lua_pop(L, 1);
808:
809: break;
810: } else {
811: lua_pop(L, 4);
812:
813: return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
814: }
815:
816: lua_pop(L, 1); /* pop the content[...] table */
817: }
818: } else {
819: return luaL_error(L, "lighty.content has to be a table");
820: }
821: lua_pop(L, 1); /* pop the header-table */
822: lua_pop(L, 1); /* pop the lighty-table */
823: lua_pop(L, 1); /* php the function env */
824:
825: return 0;
826: }
827:
828: static int traceback (lua_State *L) {
829: if (!lua_isstring(L, 1)) /* 'message' not a string? */
830: return 1; /* keep it intact */
831: lua_getfield(L, LUA_GLOBALSINDEX, "debug");
832: if (!lua_istable(L, -1)) {
833: lua_pop(L, 1);
834: return 1;
835: }
836: lua_getfield(L, -1, "traceback");
837: if (!lua_isfunction(L, -1)) {
838: lua_pop(L, 2);
839: return 1;
840: }
841: lua_pushvalue(L, 1); /* pass error message */
842: lua_pushinteger(L, 2); /* skip this function and traceback */
843: lua_call(L, 2, 1); /* call debug.traceback */
844: return 1;
845: }
846:
847: static int push_traceback(lua_State *L, int narg) {
848: int base = lua_gettop(L) - narg; /* function index */
849: lua_pushcfunction(L, traceback);
850: lua_insert(L, base);
851: return base;
852: }
853:
854: static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
855: lua_State *L;
856: int lua_return_value = -1;
857: int errfunc;
858: /* get the script-context */
859:
860:
861: L = script_cache_get_script(srv, con, p->cache, name);
862:
863: if (lua_isstring(L, -1)) {
864: log_error_write(srv, __FILE__, __LINE__,
865: "sbss",
866: "loading script",
867: name,
868: "failed:",
869: lua_tostring(L, -1));
870:
871: lua_pop(L, 1);
872:
873: assert(lua_gettop(L) == 0); /* only the function should be on the stack */
874:
875: con->http_status = 500;
876: con->mode = DIRECT;
877:
878: return HANDLER_FINISHED;
879: }
880:
881: lua_pushstring(L, "lighty.srv");
882: lua_pushlightuserdata(L, srv);
883: lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
884:
885: lua_pushstring(L, "lighty.con");
886: lua_pushlightuserdata(L, con);
887: lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
888:
889: lua_atpanic(L, magnet_atpanic);
890:
891: /**
892: * we want to create empty environment for our script
893: *
894: * setmetatable({}, {__index = _G})
895: *
896: * if a function, symbol is not defined in our env, __index will lookup
897: * in the global env.
898: *
899: * all variables created in the script-env will be thrown
900: * away at the end of the script run.
901: */
902: lua_newtable(L); /* my empty environment aka {} (sp += 1) */
903:
904: /* we have to overwrite the print function */
905: lua_pushcfunction(L, magnet_print); /* (sp += 1) */
906: lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
907:
908: /**
909: * lighty.request[] has the HTTP-request headers
910: * lighty.content[] is a table of string/file
911: * lighty.header[] is a array to set response headers
912: */
913:
914: lua_newtable(L); /* lighty.* (sp += 1) */
915:
916: lua_newtable(L); /* {} (sp += 1) */
917: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
918: lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
919: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
920: lua_pushcfunction(L, magnet_reqhdr_pairs); /* (sp += 1) */
921: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
922: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
923: lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
924:
925: lua_newtable(L); /* {} (sp += 1) */
926: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
927: lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
928: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
929: lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
930: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
931: lua_pushcfunction(L, magnet_env_pairs); /* (sp += 1) */
932: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
933: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
934: lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
935:
936: lua_newtable(L); /* {} (sp += 1) */
937: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
938: lua_pushcfunction(L, magnet_cgi_get); /* (sp += 1) */
939: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
940: lua_pushcfunction(L, magnet_cgi_set); /* (sp += 1) */
941: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
942: lua_pushcfunction(L, magnet_cgi_pairs); /* (sp += 1) */
943: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
944: lua_setmetatable(L, -2); /* tie the metatable to req_env (sp -= 1) */
945: lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */
946:
947: lua_newtable(L); /* {} (sp += 1) */
948: lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
949: lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
950: lua_setfield(L, -2, "__index"); /* (sp -= 1) */
951: lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
952: lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
953: lua_pushcfunction(L, magnet_status_pairs); /* (sp += 1) */
954: lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
955: lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
956: lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
957:
958: /* add empty 'content' and 'header' tables */
959: lua_newtable(L); /* {} (sp += 1) */
960: lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
961:
962: lua_newtable(L); /* {} (sp += 1) */
963: lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
964:
965: lua_pushinteger(L, MAGNET_RESTART_REQUEST);
966: lua_setfield(L, -2, "RESTART_REQUEST");
967:
968: lua_pushcfunction(L, magnet_stat); /* (sp += 1) */
969: lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
970:
971: lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
972:
973: /* override the default pairs() function to our __pairs capable version */
974: lua_getglobal(L, "pairs"); /* push original pairs() (sp += 1) */
975: lua_pushcclosure(L, magnet_pairs, 1);
976: lua_setfield(L, -2, "pairs"); /* (sp -= 1) */
977:
978: lua_newtable(L); /* the meta-table for the new env (sp += 1) */
979: lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */
980: lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
981: lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
982:
983:
984: lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
985:
986: errfunc = push_traceback(L, 0);
987: if (lua_pcall(L, 0, 1, errfunc)) {
988: lua_remove(L, errfunc);
989: log_error_write(srv, __FILE__, __LINE__,
990: "ss",
991: "lua_pcall():",
992: lua_tostring(L, -1));
993: lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
994:
995: assert(lua_gettop(L) == 1); /* only the function should be on the stack */
996:
997: con->http_status = 500;
998: con->mode = DIRECT;
999:
1000: return HANDLER_FINISHED;
1001: }
1002: lua_remove(L, errfunc);
1003:
1004: /* we should have the function-copy and the return value on the stack */
1005: assert(lua_gettop(L) == 2);
1006:
1007: if (lua_isnumber(L, -1)) {
1008: /* if the ret-value is a number, take it */
1009: lua_return_value = (int)lua_tonumber(L, -1);
1010: }
1011: lua_pop(L, 1); /* pop the ret-value */
1012:
1013: magnet_copy_response_header(srv, con, p, L);
1014:
1015: if (lua_return_value > 99) {
1016: con->http_status = lua_return_value;
1017: con->file_finished = 1;
1018:
1019: /* try { ...*/
1020: if (0 == setjmp(exceptionjmp)) {
1021: magnet_attach_content(srv, con, p, L);
1022: if (!chunkqueue_is_empty(con->write_queue)) {
1023: con->mode = p->id;
1024: }
1025: } else {
1026: /* } catch () { */
1027: con->http_status = 500;
1028: con->mode = DIRECT;
1029: }
1030:
1031: assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1032:
1033: /* we are finished */
1034: return HANDLER_FINISHED;
1035: } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
1036: assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1037:
1038: return HANDLER_COMEBACK;
1039: } else {
1040: assert(lua_gettop(L) == 1); /* only the function should be on the stack */
1041:
1042: return HANDLER_GO_ON;
1043: }
1044: }
1045:
1046: static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
1047: size_t i;
1048:
1049: /* no filename set */
1050: if (files->used == 0) return HANDLER_GO_ON;
1051:
1052: /**
1053: * execute all files and jump out on the first !HANDLER_GO_ON
1054: */
1055: for (i = 0; i < files->used; i++) {
1056: data_string *ds = (data_string *)files->data[i];
1057: handler_t ret;
1058:
1059: if (buffer_is_empty(ds->value)) continue;
1060:
1061: ret = magnet_attract(srv, con, p, ds->value);
1062:
1063: if (ret != HANDLER_GO_ON) return ret;
1064: }
1065:
1066: return HANDLER_GO_ON;
1067: }
1068:
1069: URIHANDLER_FUNC(mod_magnet_uri_handler) {
1070: plugin_data *p = p_d;
1071:
1072: mod_magnet_patch_connection(srv, con, p);
1073:
1074: return magnet_attract_array(srv, con, p, p->conf.url_raw);
1075: }
1076:
1077: URIHANDLER_FUNC(mod_magnet_physical) {
1078: plugin_data *p = p_d;
1079:
1080: mod_magnet_patch_connection(srv, con, p);
1081:
1082: return magnet_attract_array(srv, con, p, p->conf.physical_path);
1083: }
1084:
1085:
1086: /* this function is called at dlopen() time and inits the callbacks */
1087:
1088: int mod_magnet_plugin_init(plugin *p);
1089: int mod_magnet_plugin_init(plugin *p) {
1090: p->version = LIGHTTPD_VERSION_ID;
1091: p->name = buffer_init_string("magnet");
1092:
1093: p->init = mod_magnet_init;
1094: p->handle_uri_clean = mod_magnet_uri_handler;
1095: p->handle_physical = mod_magnet_physical;
1096: p->set_defaults = mod_magnet_set_defaults;
1097: p->cleanup = mod_magnet_free;
1098:
1099: p->data = NULL;
1100:
1101: return 0;
1102: }
1103:
1104: #else
1105: int mod_magnet_plugin_init(plugin *p);
1106: int mod_magnet_plugin_init(plugin *p) {
1107: UNUSED(p);
1108: return -1;
1109: }
1110: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>