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>