Module Name:    src
Committed By:   mbalmer
Date:           Sat Oct 12 17:24:07 UTC 2013

Modified Files:
        src/libexec/httpd: Makefile bozohttpd.8 bozohttpd.c bozohttpd.h main.c
Added Files:
        src/libexec/httpd: lua-bozo.c printenv.lua

Log Message:
add Lua scripting support to bozohttpd, see httpd(8) for details


To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/libexec/httpd/Makefile
cvs rdiff -u -r1.38 -r1.39 src/libexec/httpd/bozohttpd.8
cvs rdiff -u -r1.42 -r1.43 src/libexec/httpd/bozohttpd.c
cvs rdiff -u -r1.29 -r1.30 src/libexec/httpd/bozohttpd.h
cvs rdiff -u -r0 -r1.1 src/libexec/httpd/lua-bozo.c \
    src/libexec/httpd/printenv.lua
cvs rdiff -u -r1.5 -r1.6 src/libexec/httpd/main.c

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

Modified files:

Index: src/libexec/httpd/Makefile
diff -u src/libexec/httpd/Makefile:1.15 src/libexec/httpd/Makefile:1.16
--- src/libexec/httpd/Makefile:1.15	Sat Oct 12 07:49:40 2013
+++ src/libexec/httpd/Makefile	Sat Oct 12 17:24:06 2013
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.15 2013/10/12 07:49:40 mbalmer Exp $
+#	$NetBSD: Makefile,v 1.16 2013/10/12 17:24:06 mbalmer Exp $
 #
 #	$eterna: Makefile,v 1.30 2010/07/11 00:34:27 mrg Exp $
 #
@@ -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

Index: src/libexec/httpd/bozohttpd.8
diff -u src/libexec/httpd/bozohttpd.8:1.38 src/libexec/httpd/bozohttpd.8:1.39
--- src/libexec/httpd/bozohttpd.8:1.38	Thu Jul 11 08:19:56 2013
+++ src/libexec/httpd/bozohttpd.8	Sat Oct 12 17:24:06 2013
@@ -1,4 +1,4 @@
-.\"	$NetBSD: bozohttpd.8,v 1.38 2013/07/11 08:19:56 wiz Exp $
+.\"	$NetBSD: bozohttpd.8,v 1.39 2013/10/12 17:24:06 mbalmer Exp $
 .\"
 .\"	$eterna: bozohttpd.8,v 1.101 2011/11/18 01:25:11 mrg Exp $
 .\"
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 11, 2013
+.Dd October 12, 2013
 .Dt HTTPD 8
 .Os
 .Sh NAME
@@ -36,6 +36,7 @@
 .Nm
 .Op Fl CIMPSZciptvx
 .Op Fl C Ar suffix cgihandler
+.Op Fl L Ar prefix script
 .Op Fl I Ar port
 .Op Fl M Ar suffix type encoding encoding11
 .Op Fl P Ar pidfile
@@ -95,6 +96,27 @@ outside of the cgibin directory to be ex
 Multiple
 .Fl C
 options may be passed.
+.It Fl L Ar prefix script
+Adds a new Lua script for a particular prefix.
+The
+.Ar prefix
+should be an arbitrary text, and the
+.Ar script
+should be a full path to a Lua script.
+Multiple
+.Fl L
+options may be passed.
+A separate Lua state is created for each prefix.
+The Lua script can register callbacks using the
+httpd.register_handler('<name>', function) Lua function,
+which will trigger the execution of the Lua function
+.Em function
+when a URL in the form
+.Em http://<hostname>/<prefix>/<name>
+is being accessed.
+The function is passed three tables as arguments, the server
+environment, the request headers, and the decoded query string
+plus any data that was send as application/x-www-form-urlencoded.
 .It Fl c Ar cgibin
 Enables the CGI/1.1 interface.
 The
@@ -494,6 +516,10 @@ was written by Matthew R. Green
 The large list of contributors includes:
 .Bl -dash
 .It
+Marc Balmer
+.Aq mbal...@netbsd.org
+added Lua support for dynamic content creation
+.It
 Arnaud Lacombe
 .Aq a...@netbsd.org
 provided some clean up for memory leaks

Index: src/libexec/httpd/bozohttpd.c
diff -u src/libexec/httpd/bozohttpd.c:1.42 src/libexec/httpd/bozohttpd.c:1.43
--- src/libexec/httpd/bozohttpd.c:1.42	Sat Oct 12 07:49:40 2013
+++ src/libexec/httpd/bozohttpd.c	Sat Oct 12 17:24:06 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: bozohttpd.c,v 1.42 2013/10/12 07:49:40 mbalmer Exp $	*/
+/*	$NetBSD: bozohttpd.c,v 1.43 2013/10/12 17:24:06 mbalmer Exp $	*/
 
 /*	$eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $	*/
 
@@ -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:
@@ -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: src/libexec/httpd/bozohttpd.h
diff -u src/libexec/httpd/bozohttpd.h:1.29 src/libexec/httpd/bozohttpd.h:1.30
--- src/libexec/httpd/bozohttpd.h:1.29	Sat Oct 12 07:49:40 2013
+++ src/libexec/httpd/bozohttpd.h	Sat Oct 12 17:24:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: bozohttpd.h,v 1.29 2013/10/12 07:49:40 mbalmer Exp $	*/
+/*	$NetBSD: bozohttpd.h,v 1.30 2013/10/12 17:24:07 mbalmer Exp $	*/
 
 /*	$eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $	*/
 
@@ -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 */
@@ -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: src/libexec/httpd/main.c
diff -u src/libexec/httpd/main.c:1.5 src/libexec/httpd/main.c:1.6
--- src/libexec/httpd/main.c:1.5	Fri Nov 18 09:51:31 2011
+++ src/libexec/httpd/main.c	Sat Oct 12 17:24:07 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.5 2011/11/18 09:51:31 mrg Exp $	*/
+/*	$NetBSD: main.c,v 1.6 2013/10/12 17:24:07 mbalmer Exp $	*/
 
 /*	$eterna: main.c,v 1.6 2011/11/18 09:21:15 mrg Exp $	*/
 /* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp 	*/
@@ -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,

Added files:

Index: src/libexec/httpd/lua-bozo.c
diff -u /dev/null src/libexec/httpd/lua-bozo.c:1.1
--- /dev/null	Sat Oct 12 17:24:07 2013
+++ src/libexec/httpd/lua-bozo.c	Sat Oct 12 17:24:07 2013
@@ -0,0 +1,437 @@
+/*	$NetBSD: lua-bozo.c,v 1.1 2013/10/12 17:24:07 mbalmer Exp $	*/
+
+/*
+ * Copyright (c) 2013 Marc Balmer <m...@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 <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 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);
+	bozo_read(httpd, STDIN_FILENO, data, len);
+	lua_pushstring(L, data);
+	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;
+	char *cwd, *path;
+
+	map = bozomalloc(httpd, sizeof(lua_state_map_t));
+	map->prefix = bozostrdup(httpd, prefix);
+	if (*script == '/')
+		map->script = bozostrdup(httpd, script);
+	else {
+		cwd = getwd(NULL);
+		asprintf(&path, "%s/%s", cwd, script);
+		map->script = path;
+		free(cwd);
+	}
+	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')
+				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 ret, length;
+	char date[40];
+	bozoheaders_t *headp;
+	char *s, *query, *uri, *file, *command, *info, *content;
+	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 == '/') {
+		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);
+						bozo_read(httpd, STDIN_FILENO,
+						    content, length);
+						lua_decode_query(map->L,
+						    content);
+						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);
+			free(prefix);
+			free(uri);
+			free(info);
+			return 1;
+		}
+	}
+	free(prefix);
+	free(uri);
+	free(info);
+	return 0;
+}
+
+#endif /* NO_LUA_SUPPORT */
Index: src/libexec/httpd/printenv.lua
diff -u /dev/null src/libexec/httpd/printenv.lua:1.1
--- /dev/null	Sat Oct 12 17:24:07 2013
+++ src/libexec/httpd/printenv.lua	Sat Oct 12 17:24:07 2013
@@ -0,0 +1,83 @@
+-- this small Lua script demonstrates the use of Lua in (bozo)httpd
+-- it will simply output the "environment"
+
+-- Keep in mind that bozohttpd forks for each request when started in
+-- daemon mode, you can set global veriables here, but they will have
+-- the same value on each invocation.  You can not keep state between
+-- two calls.
+
+local httpd = require 'httpd'
+
+function printenv(env, headers, query)
+
+	-- we get the "environment" in the env table, the values are more
+	-- or less the same as the variable for a CGI program
+
+	if count == nil then
+		count = 1
+	end
+
+	-- output a header
+	print([[
+		<html>
+			<head>
+				<title>Bozotic Lua Environment</title>
+			</head>
+			<body>
+				<h1>Bozotic Lua Environment</h1>
+	]])
+
+	print('module version: ' .. httpd._VERSION .. '<br>')
+
+	print('<h2>Server Environment</h2>')
+	-- print the list of "environment" variables
+	for k, v in pairs(env) do
+		print(k .. '=' .. v .. '<br/>')
+	end
+
+	print('<h2>Request Headers</h2>')
+	for k, v in pairs(headers) do
+		print(k .. '=' .. v .. '<br/>')
+	end
+
+	if query ~= nil then
+		print('<h2>Query Variables</h2>')
+		for k, v in pairs(query) do
+			print(k .. '=' .. v .. '<br/>')
+		end
+	end
+
+	print('<h2>Form Test</h2>')
+
+	print([[
+	<form method="POST" action="/rest/form?sender=me">
+	<input type="text" name="a_value">
+	<input type="submit">
+	</form>
+	]])
+	-- output a footer
+	print([[
+		</body>
+	</html>
+	]])
+end
+
+function form(env, header, query)
+	if query ~= nil then
+		print('<h2>Form Variables</h2>')
+
+		if env.CONTENT_TYPE ~= nil then
+			print('Content-type: ' .. env.CONTENT_TYPE .. '<br>')
+		end
+
+		for k, v in pairs(query) do
+			print(k .. '=' .. v .. '<br/>')
+		end
+	else
+		print('No values')
+	end
+end
+
+-- register this handler for http://<hostname>/<prefix>/printenv
+httpd.register_handler('printenv', printenv)
+httpd.register_handler('form', form)

Reply via email to