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/&/\&/' \
-e 's/</\</' \
@@ -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