[BACK]Return to lua-bozo.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / httpd

Annotation of src/libexec/httpd/lua-bozo.c, Revision 1.9.6.2

1.9.6.2 ! msaitoh     1: /*     $NetBSD: lua-bozo.c,v 1.9 2014/01/02 08:21:38 mrg Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2013 Marc Balmer <marc@msys.ch>
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer and
        !            14:  *    dedication in the documentation and/or other materials provided
        !            15:  *    with the distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            22:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            23:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            24:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            25:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  *
        !            29:  */
        !            30:
        !            31: /* this code implements dynamic content generation using Lua for bozohttpd */
        !            32:
        !            33: #ifndef NO_LUA_SUPPORT
        !            34:
        !            35: #include <sys/param.h>
        !            36:
        !            37: #include <lua.h>
        !            38: #include <lauxlib.h>
        !            39: #include <lualib.h>
        !            40: #include <stdlib.h>
        !            41: #include <string.h>
        !            42: #include <unistd.h>
        !            43:
        !            44: #include "bozohttpd.h"
        !            45:
        !            46: /* Lua binding for bozohttp */
        !            47:
        !            48: #if LUA_VERSION_NUM < 502
        !            49: #define LUA_HTTPDLIBNAME "httpd"
        !            50: #endif
        !            51:
        !            52: #define FORM   "application/x-www-form-urlencoded"
        !            53:
        !            54: static int
        !            55: lua_flush(lua_State *L)
        !            56: {
        !            57:        bozohttpd_t *httpd;
        !            58:
        !            59:        lua_pushstring(L, "bozohttpd");
        !            60:        lua_gettable(L, LUA_REGISTRYINDEX);
        !            61:        httpd = lua_touserdata(L, -1);
        !            62:        lua_pop(L, 1);
        !            63:
        !            64:        bozo_flush(httpd, stdout);
        !            65:        return 0;
        !            66: }
        !            67:
        !            68: static int
        !            69: lua_print(lua_State *L)
        !            70: {
        !            71:        bozohttpd_t *httpd;
        !            72:
        !            73:        lua_pushstring(L, "bozohttpd");
        !            74:        lua_gettable(L, LUA_REGISTRYINDEX);
        !            75:        httpd = lua_touserdata(L, -1);
        !            76:        lua_pop(L, 1);
        !            77:
        !            78:        bozo_printf(httpd, "%s\r\n", lua_tostring(L, -1));
        !            79:        return 0;
        !            80: }
        !            81:
        !            82: static int
        !            83: lua_read(lua_State *L)
        !            84: {
        !            85:        bozohttpd_t *httpd;
        !            86:        int n, len;
        !            87:        char *data;
        !            88:
        !            89:        lua_pushstring(L, "bozohttpd");
        !            90:        lua_gettable(L, LUA_REGISTRYINDEX);
        !            91:        httpd = lua_touserdata(L, -1);
        !            92:        lua_pop(L, 1);
        !            93:
        !            94:        len = luaL_checkinteger(L, -1);
        !            95:        data = bozomalloc(httpd, len + 1);
        !            96:        n = bozo_read(httpd, STDIN_FILENO, data, len);
        !            97:        if (n >= 0) {
        !            98:                data[n] = '\0';
        !            99:                lua_pushstring(L, data);
        !           100:        } else
        !           101:                lua_pushnil(L);
        !           102:        free(data);
        !           103:        return 1;
        !           104: }
        !           105:
        !           106: static int
        !           107: lua_register_handler(lua_State *L)
        !           108: {
        !           109:        lua_state_map_t *map;
        !           110:        lua_handler_t *handler;
        !           111:        bozohttpd_t *httpd;
        !           112:
        !           113:        lua_pushstring(L, "lua_state_map");
        !           114:        lua_gettable(L, LUA_REGISTRYINDEX);
        !           115:        map = lua_touserdata(L, -1);
        !           116:        lua_pushstring(L, "bozohttpd");
        !           117:        lua_gettable(L, LUA_REGISTRYINDEX);
        !           118:        httpd = lua_touserdata(L, -1);
        !           119:        lua_pop(L, 2);
        !           120:
        !           121:        luaL_checkstring(L, 1);
        !           122:        luaL_checktype(L, 2, LUA_TFUNCTION);
        !           123:
        !           124:        handler = bozomalloc(httpd, sizeof(lua_handler_t));
        !           125:
        !           126:        handler->name = bozostrdup(httpd, lua_tostring(L, 1));
        !           127:        handler->ref = luaL_ref(L, LUA_REGISTRYINDEX);
        !           128:        SIMPLEQ_INSERT_TAIL(&map->handlers, handler, h_next);
        !           129:        httpd->process_lua = 1;
        !           130:        return 0;
        !           131: }
        !           132:
        !           133: static int
        !           134: lua_write(lua_State *L)
        !           135: {
        !           136:        bozohttpd_t *httpd;
        !           137:        const char *data;
        !           138:
        !           139:        lua_pushstring(L, "bozohttpd");
        !           140:        lua_gettable(L, LUA_REGISTRYINDEX);
        !           141:        httpd = lua_touserdata(L, -1);
        !           142:        lua_pop(L, 1);
        !           143:
        !           144:        data = luaL_checkstring(L, -1);
        !           145:        lua_pushinteger(L, bozo_write(httpd, STDIN_FILENO, data, strlen(data)));
        !           146:        return 1;
        !           147: }
        !           148:
        !           149: static int
        !           150: luaopen_httpd(lua_State *L)
        !           151: {
        !           152:        struct luaL_Reg functions[] = {
        !           153:                { "flush",              lua_flush },
        !           154:                { "print",              lua_print },
        !           155:                { "read",               lua_read },
        !           156:                { "register_handler",   lua_register_handler },
        !           157:                { "write",              lua_write },
        !           158:                { NULL, NULL }
        !           159:        };
        !           160: #if LUA_VERSION_NUM >= 502
        !           161:        luaL_newlib(L, functions);
        !           162: #else
        !           163:        luaL_register(L, LUA_HTTPDLIBNAME, functions);
        !           164: #endif
        !           165:        lua_pushstring(L, "httpd 1.0.0");
        !           166:        lua_setfield(L, -2, "_VERSION");
        !           167:        return 1;
        !           168: }
        !           169:
        !           170: #if LUA_VERSION_NUM < 502
        !           171: static void
        !           172: lua_openlib(lua_State *L, const char *name, lua_CFunction fn)
        !           173: {
        !           174:        lua_pushcfunction(L, fn);
        !           175:        lua_pushstring(L, name);
        !           176:        lua_call(L, 1, 0);
        !           177: }
        !           178: #endif
        !           179:
        !           180: /* bozohttpd integration */
        !           181: void
        !           182: bozo_add_lua_map(bozohttpd_t *httpd, const char *prefix, const char *script)
        !           183: {
        !           184:        lua_state_map_t *map;
        !           185:
        !           186:        map = bozomalloc(httpd, sizeof(lua_state_map_t));
        !           187:        map->prefix = bozostrdup(httpd, prefix);
        !           188:        if (*script == '/')
        !           189:                map->script = bozostrdup(httpd, script);
        !           190:        else {
        !           191:                char cwd[MAXPATHLEN], *path;
        !           192:
        !           193:                getcwd(cwd, sizeof(cwd) - 1);
        !           194:                asprintf(&path, "%s/%s", cwd, script);
        !           195:                map->script = path;
        !           196:        }
        !           197:        map->L = luaL_newstate();
        !           198:        if (map->L == NULL)
        !           199:                bozo_err(httpd, 1, "can't create Lua state");
        !           200:        SIMPLEQ_INIT(&map->handlers);
        !           201:
        !           202: #if LUA_VERSION_NUM >= 502
        !           203:        luaL_openlibs(map->L);
        !           204:        lua_getglobal(L, "package");
        !           205:        lua_getfield(L, -1, "preload");
        !           206:        lua_pushcfunction(L, luaopen_httpd);
        !           207:        lua_setfield(L, -2, "httpd");
        !           208:        lua_pop(L, 2);
        !           209: #else
        !           210:        lua_openlib(map->L, "", luaopen_base);
        !           211:        lua_openlib(map->L, LUA_LOADLIBNAME, luaopen_package);
        !           212:        lua_openlib(map->L, LUA_TABLIBNAME, luaopen_table);
        !           213:        lua_openlib(map->L, LUA_STRLIBNAME, luaopen_string);
        !           214:        lua_openlib(map->L, LUA_MATHLIBNAME, luaopen_math);
        !           215:        lua_openlib(map->L, LUA_OSLIBNAME, luaopen_os);
        !           216:        lua_openlib(map->L, LUA_IOLIBNAME, luaopen_io);
        !           217:        lua_openlib(map->L, LUA_HTTPDLIBNAME, luaopen_httpd);
        !           218: #endif
        !           219:        lua_pushstring(map->L, "lua_state_map");
        !           220:        lua_pushlightuserdata(map->L, map);
        !           221:        lua_settable(map->L, LUA_REGISTRYINDEX);
        !           222:
        !           223:        lua_pushstring(map->L, "bozohttpd");
        !           224:        lua_pushlightuserdata(map->L, httpd);
        !           225:        lua_settable(map->L, LUA_REGISTRYINDEX);
        !           226:
        !           227:        if (luaL_loadfile(map->L, script))
        !           228:                bozo_err(httpd, 1, "failed to load script %s: %s", script,
        !           229:                    lua_tostring(map->L, -1));
        !           230:        if (lua_pcall(map->L, 0, 0, 0))
        !           231:                bozo_err(httpd, 1, "failed to execute script %s: %s", script,
        !           232:                    lua_tostring(map->L, -1));
        !           233:        SIMPLEQ_INSERT_TAIL(&httpd->lua_states, map, s_next);
        !           234: }
        !           235:
        !           236: static void
        !           237: lua_env(lua_State *L, const char *name, const char *value)
        !           238: {
        !           239:        lua_pushstring(L, value);
        !           240:        lua_setfield(L, -2, name);
        !           241: }
        !           242:
        !           243: /* decode query string */
        !           244: static void
        !           245: lua_url_decode(lua_State *L, char *s)
        !           246: {
        !           247:        char *v, *p, *val, *q;
        !           248:        char buf[3];
        !           249:        int c;
        !           250:
        !           251:        v = strchr(s, '=');
        !           252:        if (v == NULL)
        !           253:                return;
        !           254:        *v++ = '\0';
        !           255:        val = malloc(strlen(v) + 1);
        !           256:        if (val == NULL)
        !           257:                return;
        !           258:
        !           259:        for (p = v, q = val; *p; p++) {
        !           260:                switch (*p) {
        !           261:                case '%':
        !           262:                        if (*(p + 1) == '\0' || *(p + 2) == '\0') {
        !           263:                                free(val);
        !           264:                                return;
        !           265:                        }
        !           266:                        buf[0] = *++p;
        !           267:                        buf[1] = *++p;
        !           268:                        buf[2] = '\0';
        !           269:                        sscanf(buf, "%2x", &c);
        !           270:                        *q++ = (char)c;
        !           271:                        break;
        !           272:                case '+':
        !           273:                        *q++ = ' ';
        !           274:                        break;
        !           275:                default:
        !           276:                        *q++ = *p;
        !           277:                }
        !           278:        }
        !           279:        lua_pushstring(L, val);
        !           280:        lua_setfield(L, -2, s);
        !           281:        free(val);
        !           282: }
        !           283:
        !           284: static void
        !           285: lua_decode_query(lua_State *L, char *query)
        !           286: {
        !           287:        char *s;
        !           288:
        !           289:        s = strtok(query, "&");
        !           290:        while (s) {
        !           291:                lua_url_decode(L, s);
        !           292:                s = strtok(NULL, "&");
        !           293:        }
        !           294: }
        !           295:
        !           296: int
        !           297: bozo_process_lua(bozo_httpreq_t *request)
        !           298: {
        !           299:        bozohttpd_t *httpd = request->hr_httpd;
        !           300:        lua_state_map_t *map;
        !           301:        lua_handler_t *hndlr;
        !           302:        int n, ret, length;
        !           303:        char date[40];
        !           304:        bozoheaders_t *headp;
        !           305:        char *s, *query, *uri, *file, *command, *info, *content;
        !           306:        const char *type, *clen;
        !           307:        char *prefix, *handler, *p;
        !           308:        int rv = 0;
        !           309:
        !           310:        if (!httpd->process_lua)
        !           311:                return 0;
        !           312:
        !           313:        uri = request->hr_oldfile ? request->hr_oldfile : request->hr_file;
        !           314:
        !           315:        if (*uri == '/') {
        !           316:                file = bozostrdup(httpd, uri);
        !           317:                prefix = bozostrdup(httpd, &uri[1]);
        !           318:        } else {
        !           319:                prefix = bozostrdup(httpd, uri);
        !           320:                asprintf(&file, "/%s", uri);
        !           321:        }
        !           322:        if (file == NULL) {
        !           323:                free(prefix);
        !           324:                return 0;
        !           325:        }
        !           326:
        !           327:        if (request->hr_query && strlen(request->hr_query))
        !           328:                query = bozostrdup(httpd, request->hr_query);
        !           329:        else
        !           330:                query = NULL;
        !           331:
        !           332:        p = strchr(prefix, '/');
        !           333:        if (p == NULL){
        !           334:                free(prefix);
        !           335:                return 0;
        !           336:        }
        !           337:        *p++ = '\0';
        !           338:        handler = p;
        !           339:        if (!*handler) {
        !           340:                free(prefix);
        !           341:                return 0;
        !           342:        }
        !           343:        p = strchr(handler, '/');
        !           344:        if (p != NULL)
        !           345:                *p++ = '\0';
        !           346:
        !           347:        info = NULL;
        !           348:        command = file + 1;
        !           349:        if ((s = strchr(command, '/')) != NULL) {
        !           350:                info = bozostrdup(httpd, s);
        !           351:                *s = '\0';
        !           352:        }
        !           353:
        !           354:        type = request->hr_content_type;
        !           355:        clen = request->hr_content_length;
        !           356:
        !           357:        SIMPLEQ_FOREACH(map, &httpd->lua_states, s_next) {
        !           358:                if (strcmp(map->prefix, prefix))
        !           359:                        continue;
        !           360:
        !           361:                SIMPLEQ_FOREACH(hndlr, &map->handlers, h_next) {
        !           362:                        if (strcmp(hndlr->name, handler))
        !           363:                                continue;
        !           364:
        !           365:                        lua_rawgeti(map->L, LUA_REGISTRYINDEX, hndlr->ref);
        !           366:
        !           367:                        /* Create the "environment" */
        !           368:                        lua_newtable(map->L);
        !           369:                        lua_env(map->L, "SERVER_NAME",
        !           370:                            BOZOHOST(httpd, request));
        !           371:                        lua_env(map->L, "GATEWAY_INTERFACE", "Luigi/1.0");
        !           372:                        lua_env(map->L, "SERVER_PROTOCOL", request->hr_proto);
        !           373:                        lua_env(map->L, "REQUEST_METHOD",
        !           374:                            request->hr_methodstr);
        !           375:                        lua_env(map->L, "SCRIPT_PREFIX", map->prefix);
        !           376:                        lua_env(map->L, "SCRIPT_NAME", file);
        !           377:                        lua_env(map->L, "HANDLER_NAME", hndlr->name);
        !           378:                        lua_env(map->L, "SCRIPT_FILENAME", map->script);
        !           379:                        lua_env(map->L, "SERVER_SOFTWARE",
        !           380:                            httpd->server_software);
        !           381:                        lua_env(map->L, "REQUEST_URI", uri);
        !           382:                        lua_env(map->L, "DATE_GMT",
        !           383:                            bozo_http_date(date, sizeof(date)));
        !           384:                        if (query && *query)
        !           385:                                lua_env(map->L, "QUERY_STRING", query);
        !           386:                        if (info && *info)
        !           387:                                lua_env(map->L, "PATH_INFO", info);
        !           388:                        if (type && *type)
        !           389:                                lua_env(map->L, "CONTENT_TYPE", type);
        !           390:                        if (clen && *clen)
        !           391:                                lua_env(map->L, "CONTENT_LENGTH", clen);
        !           392:                        if (request->hr_serverport && *request->hr_serverport)
        !           393:                                lua_env(map->L, "SERVER_PORT",
        !           394:                                    request->hr_serverport);
        !           395:                        if (request->hr_remotehost && *request->hr_remotehost)
        !           396:                                lua_env(map->L, "REMOTE_HOST",
        !           397:                                    request->hr_remotehost);
        !           398:                        if (request->hr_remoteaddr && *request->hr_remoteaddr)
        !           399:                                lua_env(map->L, "REMOTE_ADDR",
        !           400:                                    request->hr_remoteaddr);
        !           401:
        !           402:                        /* Pass the headers in a separate table */
        !           403:                        lua_newtable(map->L);
        !           404:                        SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next)
        !           405:                                lua_env(map->L, headp->h_header,
        !           406:                                    headp->h_value);
        !           407:
        !           408:                        /* Pass the query variables */
        !           409:                        if ((query && *query) ||
        !           410:                            (type && *type && !strcmp(type, FORM))) {
        !           411:                                lua_newtable(map->L);
        !           412:                                if (query && *query)
        !           413:                                        lua_decode_query(map->L, query);
        !           414:                                if (type && *type && !strcmp(type, FORM)) {
        !           415:                                        if (clen && *clen && atol(clen) > 0) {
        !           416:                                                length = atol(clen);
        !           417:                                                content = bozomalloc(httpd,
        !           418:                                                    length + 1);
        !           419:                                                n = bozo_read(httpd,
        !           420:                                                    STDIN_FILENO, content,
        !           421:                                                    length);
        !           422:                                                if (n >= 0) {
        !           423:                                                        content[n] = '\0';
        !           424:                                                        lua_decode_query(map->L,
        !           425:                                                            content);
        !           426:                                                } else {
        !           427:                                                        lua_pop(map->L, 1);
        !           428:                                                        lua_pushnil(map->L);
        !           429:                                                }
        !           430:                                                free(content);
        !           431:                                        }
        !           432:                                }
        !           433:                        } else
        !           434:                                lua_pushnil(map->L);
        !           435:
        !           436:                        ret = lua_pcall(map->L, 3, 0, 0);
        !           437:                        if (ret)
        !           438:                                printf("<br>Lua error: %s\n",
        !           439:                                    lua_tostring(map->L, -1));
        !           440:                        bozo_flush(httpd, stdout);
        !           441:                        rv = 1;
        !           442:                        goto out;
        !           443:                }
        !           444:        }
        !           445: out:
        !           446:        free(prefix);
        !           447:        free(uri);
        !           448:        free(info);
        !           449:        free(query);
        !           450:        free(file);
        !           451:        return rv;
        !           452: }
        !           453:
        !           454: #endif /* NO_LUA_SUPPORT */

CVSweb <webmaster@jp.NetBSD.org>