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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/libexec/httpd/lua-bozo.c between version 1.9.8.1 and 1.9.8.2

version 1.9.8.1, 2014/01/02 08:21:38 version 1.9.8.2, 2014/07/09 09:44:56
Line 0 
Line 1 
   /*      $NetBSD$        */
   
   /*
    * Copyright (c) 2013 Marc Balmer <marc@msys.ch>
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer and
    *    dedication in the documentation and/or other materials provided
    *    with the distribution.
    *
    * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    * SUCH DAMAGE.
    *
    */
   
   /* this code implements dynamic content generation using Lua for bozohttpd */
   
   #ifndef NO_LUA_SUPPORT
   
   #include <sys/param.h>
   
   #include <lua.h>
   #include <lauxlib.h>
   #include <lualib.h>
   #include <stdlib.h>
   #include <string.h>
   #include <unistd.h>
   
   #include "bozohttpd.h"
   
   /* Lua binding for bozohttp */
   
   #if LUA_VERSION_NUM < 502
   #define LUA_HTTPDLIBNAME "httpd"
   #endif
   
   #define FORM    "application/x-www-form-urlencoded"
   
   static int
   lua_flush(lua_State *L)
   {
           bozohttpd_t *httpd;
   
           lua_pushstring(L, "bozohttpd");
           lua_gettable(L, LUA_REGISTRYINDEX);
           httpd = lua_touserdata(L, -1);
           lua_pop(L, 1);
   
           bozo_flush(httpd, stdout);
           return 0;
   }
   
   static int
   lua_print(lua_State *L)
   {
           bozohttpd_t *httpd;
   
           lua_pushstring(L, "bozohttpd");
           lua_gettable(L, LUA_REGISTRYINDEX);
           httpd = lua_touserdata(L, -1);
           lua_pop(L, 1);
   
           bozo_printf(httpd, "%s\r\n", lua_tostring(L, -1));
           return 0;
   }
   
   static int
   lua_read(lua_State *L)
   {
           bozohttpd_t *httpd;
           int n, len;
           char *data;
   
           lua_pushstring(L, "bozohttpd");
           lua_gettable(L, LUA_REGISTRYINDEX);
           httpd = lua_touserdata(L, -1);
           lua_pop(L, 1);
   
           len = luaL_checkinteger(L, -1);
           data = bozomalloc(httpd, len + 1);
           n = bozo_read(httpd, STDIN_FILENO, data, len);
           if (n >= 0) {
                   data[n] = '\0';
                   lua_pushstring(L, data);
           } else
                   lua_pushnil(L);
           free(data);
           return 1;
   }
   
   static int
   lua_register_handler(lua_State *L)
   {
           lua_state_map_t *map;
           lua_handler_t *handler;
           bozohttpd_t *httpd;
   
           lua_pushstring(L, "lua_state_map");
           lua_gettable(L, LUA_REGISTRYINDEX);
           map = lua_touserdata(L, -1);
           lua_pushstring(L, "bozohttpd");
           lua_gettable(L, LUA_REGISTRYINDEX);
           httpd = lua_touserdata(L, -1);
           lua_pop(L, 2);
   
           luaL_checkstring(L, 1);
           luaL_checktype(L, 2, LUA_TFUNCTION);
   
           handler = bozomalloc(httpd, sizeof(lua_handler_t));
   
           handler->name = bozostrdup(httpd, lua_tostring(L, 1));
           handler->ref = luaL_ref(L, LUA_REGISTRYINDEX);
           SIMPLEQ_INSERT_TAIL(&map->handlers, handler, h_next);
           httpd->process_lua = 1;
           return 0;
   }
   
   static int
   lua_write(lua_State *L)
   {
           bozohttpd_t *httpd;
           const char *data;
   
           lua_pushstring(L, "bozohttpd");
           lua_gettable(L, LUA_REGISTRYINDEX);
           httpd = lua_touserdata(L, -1);
           lua_pop(L, 1);
   
           data = luaL_checkstring(L, -1);
           lua_pushinteger(L, bozo_write(httpd, STDIN_FILENO, data, strlen(data)));
           return 1;
   }
   
   static int
   luaopen_httpd(lua_State *L)
   {
           struct luaL_Reg functions[] = {
                   { "flush",              lua_flush },
                   { "print",              lua_print },
                   { "read",               lua_read },
                   { "register_handler",   lua_register_handler },
                   { "write",              lua_write },
                   { NULL, NULL }
           };
   #if LUA_VERSION_NUM >= 502
           luaL_newlib(L, functions);
   #else
           luaL_register(L, LUA_HTTPDLIBNAME, functions);
   #endif
           lua_pushstring(L, "httpd 1.0.0");
           lua_setfield(L, -2, "_VERSION");
           return 1;
   }
   
   #if LUA_VERSION_NUM < 502
   static void
   lua_openlib(lua_State *L, const char *name, lua_CFunction fn)
   {
           lua_pushcfunction(L, fn);
           lua_pushstring(L, name);
           lua_call(L, 1, 0);
   }
   #endif
   
   /* bozohttpd integration */
   void
   bozo_add_lua_map(bozohttpd_t *httpd, const char *prefix, const char *script)
   {
           lua_state_map_t *map;
   
           map = bozomalloc(httpd, sizeof(lua_state_map_t));
           map->prefix = bozostrdup(httpd, prefix);
           if (*script == '/')
                   map->script = bozostrdup(httpd, script);
           else {
                   char cwd[MAXPATHLEN], *path;
   
                   getcwd(cwd, sizeof(cwd) - 1);
                   asprintf(&path, "%s/%s", cwd, script);
                   map->script = path;
           }
           map->L = luaL_newstate();
           if (map->L == NULL)
                   bozo_err(httpd, 1, "can't create Lua state");
           SIMPLEQ_INIT(&map->handlers);
   
   #if LUA_VERSION_NUM >= 502
           luaL_openlibs(map->L);
           lua_getglobal(L, "package");
           lua_getfield(L, -1, "preload");
           lua_pushcfunction(L, luaopen_httpd);
           lua_setfield(L, -2, "httpd");
           lua_pop(L, 2);
   #else
           lua_openlib(map->L, "", luaopen_base);
           lua_openlib(map->L, LUA_LOADLIBNAME, luaopen_package);
           lua_openlib(map->L, LUA_TABLIBNAME, luaopen_table);
           lua_openlib(map->L, LUA_STRLIBNAME, luaopen_string);
           lua_openlib(map->L, LUA_MATHLIBNAME, luaopen_math);
           lua_openlib(map->L, LUA_OSLIBNAME, luaopen_os);
           lua_openlib(map->L, LUA_IOLIBNAME, luaopen_io);
           lua_openlib(map->L, LUA_HTTPDLIBNAME, luaopen_httpd);
   #endif
           lua_pushstring(map->L, "lua_state_map");
           lua_pushlightuserdata(map->L, map);
           lua_settable(map->L, LUA_REGISTRYINDEX);
   
           lua_pushstring(map->L, "bozohttpd");
           lua_pushlightuserdata(map->L, httpd);
           lua_settable(map->L, LUA_REGISTRYINDEX);
   
           if (luaL_loadfile(map->L, script))
                   bozo_err(httpd, 1, "failed to load script %s: %s", script,
                       lua_tostring(map->L, -1));
           if (lua_pcall(map->L, 0, 0, 0))
                   bozo_err(httpd, 1, "failed to execute script %s: %s", script,
                       lua_tostring(map->L, -1));
           SIMPLEQ_INSERT_TAIL(&httpd->lua_states, map, s_next);
   }
   
   static void
   lua_env(lua_State *L, const char *name, const char *value)
   {
           lua_pushstring(L, value);
           lua_setfield(L, -2, name);
   }
   
   /* decode query string */
   static void
   lua_url_decode(lua_State *L, char *s)
   {
           char *v, *p, *val, *q;
           char buf[3];
           int c;
   
           v = strchr(s, '=');
           if (v == NULL)
                   return;
           *v++ = '\0';
           val = malloc(strlen(v) + 1);
           if (val == NULL)
                   return;
   
           for (p = v, q = val; *p; p++) {
                   switch (*p) {
                   case '%':
                           if (*(p + 1) == '\0' || *(p + 2) == '\0') {
                                   free(val);
                                   return;
                           }
                           buf[0] = *++p;
                           buf[1] = *++p;
                           buf[2] = '\0';
                           sscanf(buf, "%2x", &c);
                           *q++ = (char)c;
                           break;
                   case '+':
                           *q++ = ' ';
                           break;
                   default:
                           *q++ = *p;
                   }
           }
           lua_pushstring(L, val);
           lua_setfield(L, -2, s);
           free(val);
   }
   
   static void
   lua_decode_query(lua_State *L, char *query)
   {
           char *s;
   
           s = strtok(query, "&");
           while (s) {
                   lua_url_decode(L, s);
                   s = strtok(NULL, "&");
           }
   }
   
   int
   bozo_process_lua(bozo_httpreq_t *request)
   {
           bozohttpd_t *httpd = request->hr_httpd;
           lua_state_map_t *map;
           lua_handler_t *hndlr;
           int n, ret, length;
           char date[40];
           bozoheaders_t *headp;
           char *s, *query, *uri, *file, *command, *info, *content;
           const char *type, *clen;
           char *prefix, *handler, *p;
           int rv = 0;
   
           if (!httpd->process_lua)
                   return 0;
   
           uri = request->hr_oldfile ? request->hr_oldfile : request->hr_file;
   
           if (*uri == '/') {
                   file = bozostrdup(httpd, uri);
                   prefix = bozostrdup(httpd, &uri[1]);
           } else {
                   prefix = bozostrdup(httpd, uri);
                   asprintf(&file, "/%s", uri);
           }
           if (file == NULL) {
                   free(prefix);
                   return 0;
           }
   
           if (request->hr_query && strlen(request->hr_query))
                   query = bozostrdup(httpd, request->hr_query);
           else
                   query = NULL;
   
           p = strchr(prefix, '/');
           if (p == NULL){
                   free(prefix);
                   return 0;
           }
           *p++ = '\0';
           handler = p;
           if (!*handler) {
                   free(prefix);
                   return 0;
           }
           p = strchr(handler, '/');
           if (p != NULL)
                   *p++ = '\0';
   
           info = NULL;
           command = file + 1;
           if ((s = strchr(command, '/')) != NULL) {
                   info = bozostrdup(httpd, s);
                   *s = '\0';
           }
   
           type = request->hr_content_type;
           clen = request->hr_content_length;
   
           SIMPLEQ_FOREACH(map, &httpd->lua_states, s_next) {
                   if (strcmp(map->prefix, prefix))
                           continue;
   
                   SIMPLEQ_FOREACH(hndlr, &map->handlers, h_next) {
                           if (strcmp(hndlr->name, handler))
                                   continue;
   
                           lua_rawgeti(map->L, LUA_REGISTRYINDEX, hndlr->ref);
   
                           /* Create the "environment" */
                           lua_newtable(map->L);
                           lua_env(map->L, "SERVER_NAME",
                               BOZOHOST(httpd, request));
                           lua_env(map->L, "GATEWAY_INTERFACE", "Luigi/1.0");
                           lua_env(map->L, "SERVER_PROTOCOL", request->hr_proto);
                           lua_env(map->L, "REQUEST_METHOD",
                               request->hr_methodstr);
                           lua_env(map->L, "SCRIPT_PREFIX", map->prefix);
                           lua_env(map->L, "SCRIPT_NAME", file);
                           lua_env(map->L, "HANDLER_NAME", hndlr->name);
                           lua_env(map->L, "SCRIPT_FILENAME", map->script);
                           lua_env(map->L, "SERVER_SOFTWARE",
                               httpd->server_software);
                           lua_env(map->L, "REQUEST_URI", uri);
                           lua_env(map->L, "DATE_GMT",
                               bozo_http_date(date, sizeof(date)));
                           if (query && *query)
                                   lua_env(map->L, "QUERY_STRING", query);
                           if (info && *info)
                                   lua_env(map->L, "PATH_INFO", info);
                           if (type && *type)
                                   lua_env(map->L, "CONTENT_TYPE", type);
                           if (clen && *clen)
                                   lua_env(map->L, "CONTENT_LENGTH", clen);
                           if (request->hr_serverport && *request->hr_serverport)
                                   lua_env(map->L, "SERVER_PORT",
                                       request->hr_serverport);
                           if (request->hr_remotehost && *request->hr_remotehost)
                                   lua_env(map->L, "REMOTE_HOST",
                                       request->hr_remotehost);
                           if (request->hr_remoteaddr && *request->hr_remoteaddr)
                                   lua_env(map->L, "REMOTE_ADDR",
                                       request->hr_remoteaddr);
   
                           /* Pass the headers in a separate table */
                           lua_newtable(map->L);
                           SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next)
                                   lua_env(map->L, headp->h_header,
                                       headp->h_value);
   
                           /* Pass the query variables */
                           if ((query && *query) ||
                               (type && *type && !strcmp(type, FORM))) {
                                   lua_newtable(map->L);
                                   if (query && *query)
                                           lua_decode_query(map->L, query);
                                   if (type && *type && !strcmp(type, FORM)) {
                                           if (clen && *clen && atol(clen) > 0) {
                                                   length = atol(clen);
                                                   content = bozomalloc(httpd,
                                                       length + 1);
                                                   n = bozo_read(httpd,
                                                       STDIN_FILENO, content,
                                                       length);
                                                   if (n >= 0) {
                                                           content[n] = '\0';
                                                           lua_decode_query(map->L,
                                                               content);
                                                   } else {
                                                           lua_pop(map->L, 1);
                                                           lua_pushnil(map->L);
                                                   }
                                                   free(content);
                                           }
                                   }
                           } else
                                   lua_pushnil(map->L);
   
                           ret = lua_pcall(map->L, 3, 0, 0);
                           if (ret)
                                   printf("<br>Lua error: %s\n",
                                       lua_tostring(map->L, -1));
                           bozo_flush(httpd, stdout);
                           rv = 1;
                           goto out;
                   }
           }
   out:
           free(prefix);
           free(uri);
           free(info);
           free(query);
           free(file);
           return rv;
   }
   
   #endif /* NO_LUA_SUPPORT */

Legend:
Removed from v.1.9.8.1  
changed lines
  Added in v.1.9.8.2

CVSweb <webmaster@jp.NetBSD.org>