tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Dynamic content with bozohttpd



Presenting Lua support for httpd.

httpd gets a new option with a URL prefix (like cgi-bin) and a filename
of a Lua script as parameter.  When httpd starts, it creates a Lua state
per prefix and executes the Lua script within and then resumes normal
operation.  Browsing to a URI with the prefix after the hostname will
trigger Lua processing if a corresponding handler has registered itself.

Example use:

# httpd -L rest printenv.lua -d -b -f /var/www/htdocs

Here 'rest' is the prefix to trigger Lua processing. printenv.lua
registers a handler 'printenv' that will be called when a URL in the
form http://<hostname>/rest/printenv is called.

Lua processing is only triggered when a prefix has been set _and_ a
script actually registered a handler.

The Lua scripts can use a 'httpd' module using the usual require 'http'
or local httpd = require 'httpd' syntax, this module provides three
functions:

httpd.register_handler(name, function)
httpd.print(text)
httpd.flush()

Besides httpd.print(), the normal Lua print() function can be used.

Q&A:

Q: Why the prefix?
A: This way it is possible to have multiple applications in their own
Lua states, as for each prefix a separate Lua state is created.

Q: I want to implement a RESTful API, is there a JSON module?
A: There are several, one can be found at
   https://github.com/mbalmer/luajson

diff attached.  Comments welcome.

- Marc Balmer

Index: libexec/httpd/Makefile
===================================================================
RCS file: /cvsroot/src/libexec/httpd/Makefile,v
retrieving revision 1.14
diff -u -p -r1.14 Makefile
--- libexec/httpd/Makefile      11 Jul 2013 08:51:09 -0000      1.14
+++ libexec/httpd/Makefile      11 Oct 2013 11:17:49 -0000
@@ -13,6 +13,7 @@
 #      NO_DYNAMIC_CONTENT      /* don't support dynamic content updates */
 #      NO_SSL_SUPPORT          /* don't support ssl (https) */
 #      DO_HTPASSWD             /* support .htpasswd files */
+#      NO_LUA_SUPPORT          /* don't support Lua for dynamic content */
 #
 # these are usually set via the "COPTS" variable, or some other method
 # for setting CFLAGS relevant to your make, eg
@@ -23,10 +24,10 @@ PROG=       httpd
 MAN=   httpd.8
 BUILDSYMLINKS+=bozohttpd.8 httpd.8
 SRCS=  bozohttpd.c ssl-bozo.c auth-bozo.c cgi-bozo.c daemon-bozo.c \
-       tilde-luzah-bozo.c dir-index-bozo.c content-bozo.c
+       tilde-luzah-bozo.c dir-index-bozo.c content-bozo.c lua-bozo.c
 SRCS+= main.c
 
-LDADD= -lcrypt
+LDADD= -lcrypt -llua
 DPADD= ${LIBCRYPT}
 
 WARNS?=        4
@@ -48,7 +49,7 @@ COPTS+=       -DNO_SSL_SUPPORT
 # Build release things.
 #
 NROFF?=                nroff
-  
+
 PREHTMLFROB=   sed \
                    -e 's/&/\&amp;/' \
                    -e 's/</\&lt;/' \
@@ -64,7 +65,7 @@ TXTFROB=      col -b
 
 bozohttpd.8.html: bozohttpd.8
        $(PREHTMLFROB) $> | $(NROFF) -mdoc2html | $(HTMLFROB) > $@
-  
+
 bozohttpd.8.txt: bozohttpd.8
        $(NROFF) -mdoc -Tascii $> | $(TXTFROB) > $@
 
Index: libexec/httpd/bozohttpd.c
===================================================================
RCS file: /cvsroot/src/libexec/httpd/bozohttpd.c,v
retrieving revision 1.41
diff -u -p -r1.41 bozohttpd.c
--- libexec/httpd/bozohttpd.c   11 Jul 2013 07:46:37 -0000      1.41
+++ libexec/httpd/bozohttpd.c   11 Oct 2013 11:17:50 -0000
@@ -99,7 +99,7 @@
  *     - 14.9: we aren't a cache.
  *
  *     - 14.15: content-md5 would be nice...
- *     
+ *
  *     - 14.24/14.26/14.27: be nice to support this...
  *
  *     - 14.44: not sure about this Vary: header.  ignore it for now.
@@ -867,7 +867,7 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, 
                buflen = len * 3 + 1;
                buf = bozorealloc(httpd, buf, buflen);
        }
-       
+
        if (url == NULL) {
                buf[0] = 0;
                return buf;
@@ -958,7 +958,7 @@ handle_redirect(bozo_httpreq_t *request,
        char portbuf[20];
        const char *hostname = BOZOHOST(httpd, request);
        int query = 0;
-       
+
        if (url == NULL) {
                if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0)
                        bozo_err(httpd, 1, "asprintf");
@@ -981,7 +981,7 @@ handle_redirect(bozo_httpreq_t *request,
                bozo_warn(httpd, "redirecting %s%s%s", hostname, portbuf, url);
        debug((httpd, DEBUG_FAT, "redirecting %s", url));
        bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto);
-       if (request->hr_proto != httpd->consts.http_09) 
+       if (request->hr_proto != httpd->consts.http_09)
                bozo_print_header(request, NULL, "text/html", NULL);
        if (request->hr_proto != httpd->consts.http_09) {
                bozo_printf(httpd, "Location: http://";);
@@ -1230,7 +1230,7 @@ fix_url_percent(bozo_httpreq_t *request)
                                        "percent hack was %2f (/)");
                        goto copy_rest;
                }
-                       
+
                buf[0] = *++s;
                buf[1] = *++s;
                buf[2] = '\0';
@@ -1267,7 +1267,7 @@ copy_rest:
  *     - punt if it doesn't start with /
  *     - check httpd->untrustedref / referrer
  *     - look for "http://myname/"; and deal with it.
- *     - maybe call bozo_process_cgi() 
+ *     - maybe call bozo_process_cgi()
  *     - check for ~user and call bozo_user_transform() if so
  *     - if the length > 1, check for trailing slash.  if so,
  *       add the index.html file
@@ -1307,8 +1307,8 @@ transform_request(bozo_httpreq_t *reques
 
 #define TOP_PAGE(x)    (strcmp((x), "/") == 0 || \
                         strcmp((x) + 1, httpd->index_html) == 0 || \
-                        strcmp((x) + 1, "favicon.ico") == 0) 
-               
+                        strcmp((x) + 1, "favicon.ico") == 0)
+
                debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref"));
                /*
                 * first check that this path isn't allowed via .bzdirect file,
@@ -1403,7 +1403,7 @@ transform_request(bozo_httpreq_t *reques
         */
 
        /*
-        * stop traversing outside our domain 
+        * stop traversing outside our domain
         *
         * XXX true security only comes from our parent using chroot(2)
         * before execve(2)'ing us.  or our own built in chroot(2) support.
@@ -1425,6 +1425,9 @@ transform_request(bozo_httpreq_t *reques
        if (bozo_process_cgi(request))
                return 0;
 
+       if (bozo_process_lua(request))
+               return 0;
+
        debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile));
        return 1;
 bad_done:
@@ -1527,7 +1530,7 @@ bozo_process_request(bozo_httpreq_t *req
                        (void)bozo_http_error(httpd, 403, request,
                                                "no permission to open file");
                else if (errno == ENOENT) {
-                       if (!bozo_dir_index(request, file, isindex)) 
+                       if (!bozo_dir_index(request, file, isindex))
                                (void)bozo_http_error(httpd, 404, request,
                                                        "no file");
                } else
@@ -1690,7 +1693,7 @@ debug__(bozohttpd_t *httpd, int level, c
 {
        va_list ap;
        int savederrno;
-       
+
        /* only log if the level is low enough */
        if (httpd->debug < level)
                return;
@@ -2086,6 +2089,9 @@ bozo_init_httpd(bozohttpd_t *httpd)
                        "bozohttpd: memory_allocation failure\n");
                return 0;
        }
+#ifndef NO_LUA_SUPPORT
+       SIMPLEQ_INIT(&httpd->lua_states);
+#endif
        return 1;
 }
 
Index: libexec/httpd/bozohttpd.h
===================================================================
RCS file: /cvsroot/src/libexec/httpd/bozohttpd.h,v
retrieving revision 1.28
diff -u -p -r1.28 bozohttpd.h
--- libexec/httpd/bozohttpd.h   4 Sep 2013 22:59:50 -0000       1.28
+++ libexec/httpd/bozohttpd.h   11 Oct 2013 11:17:50 -0000
@@ -36,6 +36,9 @@
 
 #include <sys/stat.h>
 
+#ifndef NO_LUA_SUPPORT
+#include <lua.h>
+#endif
 #include <stdio.h>
 
 /* lots of "const" but gets free()'ed etc at times, sigh */
@@ -47,6 +50,22 @@ typedef struct bozoheaders {
        SIMPLEQ_ENTRY(bozoheaders)      h_next;
 } bozoheaders_t;
 
+#ifndef NO_LUA_SUPPORT
+typedef struct lua_handler {
+       const char      *name;
+       int              ref;
+       SIMPLEQ_ENTRY(lua_handler)      h_next;
+} lua_handler_t;
+
+typedef struct lua_state_map {
+       const char      *script;
+       const char      *prefix;
+       lua_State       *L;
+       SIMPLEQ_HEAD(, lua_handler)     handlers;
+       SIMPLEQ_ENTRY(lua_state_map)    s_next;
+} lua_state_map_t;
+#endif
+
 typedef struct bozo_content_map_t {
        const char      *name;          /* postfix of file */
        size_t           namelen;       /* length of postfix */
@@ -94,6 +113,10 @@ typedef struct bozohttpd_t {
        int              hide_dots;     /* hide .* */
        int              process_cgi;   /* use the cgi handler */
        char            *cgibin;        /* cgi-bin directory */
+#ifndef NO_LUA_SUPPORT
+       int              process_lua;   /* use the Lua handler */
+       SIMPLEQ_HEAD(, lua_state_map)   lua_states;
+#endif
        void            *sslinfo;       /* pointer to ssl struct */
        int             dynamic_content_map_size;/* size of dyn cont map */
        bozo_content_map_t      *dynamic_content_map;/* dynamic content map */
@@ -121,7 +144,7 @@ typedef struct bozo_httpreq_t {
                                           to hr_httpd->virthostname) */
        char    *hr_file;
        char    *hr_oldfile;    /* if we added an index_html */
-       char    *hr_query;  
+       char    *hr_query;
        const char *hr_proto;
        const char *hr_content_type;
        const char *hr_content_length;
@@ -184,7 +207,7 @@ typedef struct bozoprefs_t {
 void   debug__(bozohttpd_t *, int, const char *, ...) BOZO_PRINTFLIKE(3, 4);
 #define debug(x)       debug__ x
 #else
-#define        debug(x)        
+#define        debug(x)
 #endif /* NO_DEBUG */
 
 void   bozo_warn(bozohttpd_t *, const char *, ...)
@@ -252,6 +275,15 @@ void       bozo_add_content_map_cgi(bozohttpd_
 #endif /* NO_CGIBIN_SUPPORT */
 
 
+/* lua-bozo.c */
+#ifdef NO_LUA_SUPPORT
+#define bozo_process_lua(h)                            0
+#else
+void   bozo_add_lua_map(bozohttpd_t *, const char *, const char *);
+int    bozo_process_lua(bozo_httpreq_t *);
+#endif /* NO_LUA_SUPPORT */
+
+
 /* daemon-bozo.c */
 #ifdef NO_DAEMON_MODE
 #define bozo_daemon_init(x)                            do { /* nothing */ } 
while (0)
Index: libexec/httpd/lua-bozo.c
===================================================================
RCS file: libexec/httpd/lua-bozo.c
diff -N libexec/httpd/lua-bozo.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libexec/httpd/lua-bozo.c    11 Oct 2013 11:17:50 -0000
@@ -0,0 +1,287 @@
+/*     $NetBSD$        */
+
+/*
+ * Copyright (c) 2013 Marc Balmer <marc%msys.ch@localhost>
+ * 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 <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
+
+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_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
+luaopen_httpd(lua_State *L)
+{
+       struct luaL_Reg functions[] = {
+               { "flush",              lua_flush },
+               { "print",              lua_print },
+               { "register_handler",   lua_register_handler },
+               { NULL, NULL }
+       };
+#if LUA_VERSION_NUM >= 502
+       luaL_newlib(L, functions);
+#else
+       luaL_register(L, LUA_HTTPDLIBNAME, functions);
+#endif
+       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);
+       map->script = bozostrdup(httpd, script);
+       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, LUA_MULTRET, 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);
+}
+
+int
+bozo_process_lua(bozo_httpreq_t *request)
+{
+       bozohttpd_t *httpd = request->hr_httpd;
+       lua_state_map_t *map;
+       lua_handler_t *hndlr;
+       int ret;
+       char date[40];
+       char *query, *uri;
+       const char *type, *clen;
+       char *prefix, *handler, *p;
+
+       if (!httpd->process_lua)
+               return 0;
+       uri = request->hr_oldfile ? request->hr_oldfile : request->hr_file;
+       if (*uri == '/')
+               prefix = bozostrdup(httpd, &uri[1]);
+       else
+               prefix = bozostrdup(httpd, uri);
+
+       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';
+
+       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, "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", map->script);
+                       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 (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);
+
+                       ret = lua_pcall(map->L, 1, 0, 0);
+                       if (ret)
+                               printf("<br>Lua error: %s\n",
+                                   lua_tostring(map->L, -1));
+                       bozo_flush(httpd, stdout);
+                       free(prefix);
+                       free(uri);
+                       return 1;
+               }
+       }
+       free(prefix);
+       free(uri);
+       return 0;
+}
+
+#endif /* NO_LUA_SUPPORT */
Index: libexec/httpd/main.c
===================================================================
RCS file: /cvsroot/src/libexec/httpd/main.c,v
retrieving revision 1.5
diff -u -p -r1.5 main.c
--- libexec/httpd/main.c        18 Nov 2011 09:51:31 -0000      1.5
+++ libexec/httpd/main.c        11 Oct 2013 11:17:50 -0000
@@ -79,6 +79,9 @@ usage(bozohttpd_t *httpd, char *progname
        bozo_warn(httpd,
                "   -c cgibin\t\tenable cgi-bin support in this directory");
 #endif
+#ifndef NO_LUA_SUPPORT
+       bozo_warn(httpd, "   -L arg script\tadd this Lua script");
+#endif
        bozo_warn(httpd, "   -I port\t\tbind or use on this port");
 #ifndef NO_DAEMON_MODE
        bozo_warn(httpd, "   -b\t\t\tbackground and go into daemon mode");
@@ -138,9 +141,22 @@ main(int argc, char **argv)
        bozo_set_defaults(&httpd, &prefs);
 
        while ((c = getopt(argc, argv,
-                          "C:HI:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) {
+           "C:HI:L:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) {
                switch(c) {
 
+               case 'L':
+#ifdef NO_LUA_SUPPORT
+                       bozo_err(&httpd, 1,
+                               "Lua support is not enabled");
+                       /* NOTREACHED */
+#else
+                       /* make sure there's two argument */
+                       if (argc - optind < 1)
+                               usage(&httpd, progname);
+                       bozo_add_lua_map(&httpd, optarg, argv[optind]);
+                       optind++;
+                       break;
+#endif /* NO_LUA_SUPPORT */
                case 'M':
 #ifdef NO_DYNAMIC_CONTENT
                        bozo_err(&httpd, 1,
Index: libexec/httpd/printenv.lua
===================================================================
RCS file: libexec/httpd/printenv.lua
diff -N libexec/httpd/printenv.lua
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ libexec/httpd/printenv.lua  11 Oct 2013 11:17:50 -0000
@@ -0,0 +1,34 @@
+-- this small Lua script demonstrates the use of Lua in (bozo)httpd
+-- it will simply output the "environment"
+
+local httpd = require 'httpd'
+
+function printenv(env)
+
+       -- we get the "environment" in the env table, the values are more
+       -- or less the same as the variable for a CGI program
+
+       -- output a header
+       print([[
+               <html>
+                       <head>
+                               <title>Lua Environment</title>
+                       </head>
+                       <body>
+                               <h1>Lua Environment</h1>
+       ]])
+
+       -- print the list of "environment" variables
+       for k, v in pairs(env) do
+               print(k .. '=' .. v .. '<br/>')
+       end
+
+       -- output a footer
+       print([[
+               </body>
+       </html>
+       ]])
+end
+
+-- register this handler for http://<hostname>/<prefix>/printenv
+httpd.register_handler('printenv', printenv)


Home | Main Index | Thread Index | Old Index