Annotation of embedaddon/lighttpd/src/mod_magnet.c, revision 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>