http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/mod_duktape.inl
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.9.1/src/mod_duktape.inl 
b/thirdparty/civetweb-1.9.1/src/mod_duktape.inl
new file mode 100644
index 0000000..d4e53cd
--- /dev/null
+++ b/thirdparty/civetweb-1.9.1/src/mod_duktape.inl
@@ -0,0 +1,250 @@
+/* This file is part of the CivetWeb web server.
+ * See https://github.com/civetweb/civetweb/
+ * (C) 2015-2017 by the CivetWeb authors, MIT license.
+ */
+
+#include "duktape.h"
+
+/* TODO: the mg context should be added to duktape as well */
+/* Alternative: redefine a new, clean API from scratch (instead of using mg),
+ * or at least do not add problematic functions. */
+/* For evaluation purposes, currently only "send" is supported.
+ * All other ~50 functions will be added later. */
+
+/* Note: This is only experimental support, so the API may still change. */
+
+static const char *civetweb_conn_id = "\xFF"
+                                      "civetweb_conn";
+static const char *civetweb_ctx_id = "\xFF"
+                                     "civetweb_ctx";
+
+
+static void *
+mg_duk_mem_alloc(void *udata, duk_size_t size)
+{
+       return mg_malloc(size);
+}
+
+
+static void *
+mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
+{
+       return mg_realloc(ptr, newsize);
+}
+
+
+static void
+mg_duk_mem_free(void *udata, void *ptr)
+{
+       mg_free(ptr);
+}
+
+
+static void
+mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
+{
+       /* Script is called "protected" (duk_peval_file), so script errors 
should
+        * never yield in a call to this function. Maybe calls prior to 
executing
+        * the script could raise a fatal error. */
+       struct mg_connection *conn;
+
+       duk_push_global_stash(ctx);
+       duk_get_prop_string(ctx, -1, civetweb_conn_id);
+       conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+       mg_cry(conn, "%s", msg);
+}
+
+
+static duk_ret_t
+duk_itf_write(duk_context *ctx)
+{
+       struct mg_connection *conn;
+       duk_double_t ret;
+       duk_size_t len = 0;
+       const char *val = duk_require_lstring(ctx, -1, &len);
+
+       /*
+           duk_push_global_stash(ctx);
+           duk_get_prop_string(ctx, -1, civetweb_conn_id);
+           conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+       */
+       duk_push_current_function(ctx);
+       duk_get_prop_string(ctx, -1, civetweb_conn_id);
+       conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+       if (!conn) {
+               duk_error(ctx,
+                         DUK_ERR_INTERNAL_ERROR,
+                         "function not available without connection object");
+               /* probably never reached, but satisfies static code analysis */
+               return DUK_RET_INTERNAL_ERROR;
+       }
+
+       ret = mg_write(conn, val, len);
+
+       duk_push_number(ctx, ret);
+       return 1;
+}
+
+
+static duk_ret_t
+duk_itf_read(duk_context *ctx)
+{
+       struct mg_connection *conn;
+       char buf[1024];
+       int len;
+
+       duk_push_global_stash(ctx);
+       duk_get_prop_string(ctx, -1, civetweb_conn_id);
+       conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+       if (!conn) {
+               duk_error(ctx,
+                         DUK_ERR_INTERNAL_ERROR,
+                         "function not available without connection object");
+               /* probably never reached, but satisfies static code analysis */
+               return DUK_RET_INTERNAL_ERROR;
+       }
+
+       len = mg_read(conn, buf, sizeof(buf));
+
+       duk_push_lstring(ctx, buf, len);
+       return 1;
+}
+
+
+static duk_ret_t
+duk_itf_getoption(duk_context *ctx)
+{
+       struct mg_context *cv_ctx;
+       const char *ret;
+       duk_size_t len = 0;
+       const char *val = duk_require_lstring(ctx, -1, &len);
+
+       duk_push_current_function(ctx);
+       duk_get_prop_string(ctx, -1, civetweb_ctx_id);
+       cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1);
+
+       if (!cv_ctx) {
+               duk_error(ctx,
+                         DUK_ERR_INTERNAL_ERROR,
+                         "function not available without connection object");
+               /* probably never reached, but satisfies static code analysis */
+               return DUK_RET_INTERNAL_ERROR;
+       }
+
+       ret = mg_get_option(cv_ctx, val);
+       if (ret) {
+               duk_push_string(ctx, ret);
+       } else {
+               duk_push_null(ctx);
+       }
+
+       return 1;
+}
+
+
+static void
+mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
+{
+       int i;
+       duk_context *ctx = NULL;
+
+       conn->must_close = 1;
+
+       /* Create Duktape interpreter state */
+       ctx = duk_create_heap(mg_duk_mem_alloc,
+                             mg_duk_mem_realloc,
+                             mg_duk_mem_free,
+                             NULL,
+                             mg_duk_fatal_handler);
+       if (!ctx) {
+               mg_cry(conn, "Failed to create a Duktape heap.");
+               goto exec_duktape_finished;
+       }
+
+       /* Add "conn" object */
+       duk_push_global_object(ctx);
+       duk_push_object(ctx); /* create a new table/object ("conn") */
+
+       duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
+       duk_push_pointer(ctx, (void *)conn);
+       duk_put_prop_string(ctx, -2, civetweb_conn_id);
+       duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */
+
+       duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
+       duk_push_pointer(ctx, (void *)conn);
+       duk_put_prop_string(ctx, -2, civetweb_conn_id);
+       duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */
+
+       duk_push_string(ctx, conn->request_info.request_method);
+       duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... 
*/
+
+       duk_push_string(ctx, conn->request_info.request_uri);
+       duk_put_prop_string(ctx, -2, "request_uri");
+
+       duk_push_string(ctx, conn->request_info.local_uri);
+       duk_put_prop_string(ctx, -2, "uri");
+
+       duk_push_string(ctx, conn->request_info.http_version);
+       duk_put_prop_string(ctx, -2, "http_version");
+
+       duk_push_string(ctx, conn->request_info.query_string);
+       duk_put_prop_string(ctx, -2, "query_string");
+
+       duk_push_string(ctx, conn->request_info.remote_addr);
+       duk_put_prop_string(ctx, -2, "remote_addr");
+
+       duk_push_int(ctx, conn->request_info.remote_port);
+       duk_put_prop_string(ctx, -2, "remote_port");
+
+       duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port));
+       duk_put_prop_string(ctx, -2, "server_port");
+
+       duk_push_object(ctx); /* subfolder "conn.http_headers" */
+       for (i = 0; i < conn->request_info.num_headers; i++) {
+               duk_push_string(ctx, conn->request_info.http_headers[i].value);
+               duk_put_prop_string(ctx, -2, 
conn->request_info.http_headers[i].name);
+       }
+       duk_put_prop_string(ctx, -2, "http_headers");
+
+       duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */
+
+       /* Add "civetweb" object */
+       duk_push_global_object(ctx);
+       duk_push_object(ctx); /* create a new table/object ("conn") */
+
+       duk_push_string(ctx, CIVETWEB_VERSION);
+       duk_put_prop_string(ctx, -2, "version");
+
+       duk_push_string(ctx, script_name);
+       duk_put_prop_string(ctx, -2, "script_name");
+
+       if (conn->ctx != NULL) {
+               duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */);
+               duk_push_pointer(ctx, (void *)(conn->ctx));
+               duk_put_prop_string(ctx, -2, civetweb_ctx_id);
+               duk_put_prop_string(ctx, -2, "getoption"); /* add function 
conn.write */
+
+               if (conn->ctx->systemName != NULL) {
+                       duk_push_string(ctx, conn->ctx->systemName);
+                       duk_put_prop_string(ctx, -2, "system");
+               }
+       }
+
+       duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" 
*/
+
+       duk_push_global_stash(ctx);
+       duk_push_pointer(ctx, (void *)conn);
+       duk_put_prop_string(ctx, -2, civetweb_conn_id);
+
+       if (duk_peval_file(ctx, script_name) != 0) {
+               mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
+               goto exec_duktape_finished;
+       }
+       duk_pop(ctx); /* ignore result */
+
+exec_duktape_finished:
+       duk_destroy_heap(ctx);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/mod_lua.inl
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.9.1/src/mod_lua.inl 
b/thirdparty/civetweb-1.9.1/src/mod_lua.inl
new file mode 100644
index 0000000..58a67dc
--- /dev/null
+++ b/thirdparty/civetweb-1.9.1/src/mod_lua.inl
@@ -0,0 +1,2000 @@
+/* This file is part of the CivetWeb web server.
+ * See https://github.com/civetweb/civetweb/
+ */
+
+#include "civetweb_lua.h"
+#include "civetweb_private_lua.h"
+
+#ifdef _WIN32
+static void *
+mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
+{
+       /* TODO (low): This is an incomplete implementation of mmap for windows.
+        * Currently it is sufficient, but there are a lot of unused parameters.
+        * Better use a function "mg_map" which only has the required 
parameters,
+        * and implement it using mmap in Linux and CreateFileMapping in 
Windows.
+        * Noone should expect a full mmap for Windows here.
+        */
+       HANDLE fh = (HANDLE)_get_osfhandle(fd);
+       HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
+       void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
+       CloseHandle(mh);
+
+       /* unused parameters */
+       (void)addr;
+       (void)prot;
+       (void)flags;
+       (void)offset;
+
+       return p;
+}
+
+static void
+munmap(void *addr, int64_t length)
+{
+       /* unused parameters */
+       (void)length;
+
+       UnmapViewOfFile(addr);
+}
+
+#define MAP_FAILED (NULL)
+#define MAP_PRIVATE (0)
+#define PROT_READ (0)
+#else
+#include <sys/mman.h>
+#endif
+
+static const char *LUASOCKET = "luasocket";
+static const char lua_regkey_ctx = 1;
+static const char lua_regkey_connlist = 2;
+
+/* Forward declarations */
+static void handle_request(struct mg_connection *);
+static int handle_lsp_request(struct mg_connection *,
+                              const char *,
+                              struct mg_file *,
+                              struct lua_State *);
+
+static void
+reg_lstring(struct lua_State *L,
+            const char *name,
+            const void *buffer,
+            size_t buflen)
+{
+       if (name != NULL && buffer != NULL) {
+               lua_pushstring(L, name);
+               lua_pushlstring(L, (const char *)buffer, buflen);
+               lua_rawset(L, -3);
+       }
+}
+
+#define reg_string(L, name, val)                                               
\
+       reg_lstring(L, name, val, val ? strlen(val) : 0)
+
+static void
+reg_int(struct lua_State *L, const char *name, int val)
+{
+       if (name != NULL) {
+               lua_pushstring(L, name);
+               lua_pushinteger(L, val);
+               lua_rawset(L, -3);
+       }
+}
+
+static void
+reg_boolean(struct lua_State *L, const char *name, int val)
+{
+       if (name != NULL) {
+               lua_pushstring(L, name);
+               lua_pushboolean(L, val != 0);
+               lua_rawset(L, -3);
+       }
+}
+
+static void
+reg_conn_function(struct lua_State *L,
+                  const char *name,
+                  lua_CFunction func,
+                  struct mg_connection *conn)
+{
+       if (name != NULL && func != NULL && conn != NULL) {
+               lua_pushstring(L, name);
+               lua_pushlightuserdata(L, conn);
+               lua_pushcclosure(L, func, 1);
+               lua_rawset(L, -3);
+       }
+}
+
+static void
+reg_function(struct lua_State *L, const char *name, lua_CFunction func)
+{
+       if (name != NULL && func != NULL) {
+               lua_pushstring(L, name);
+               lua_pushcclosure(L, func, 0);
+               lua_rawset(L, -3);
+       }
+}
+
+static void
+lua_cry(struct mg_connection *conn,
+        int err,
+        lua_State *L,
+        const char *lua_title,
+        const char *lua_operation)
+{
+       switch (err) {
+       case LUA_OK:
+       case LUA_YIELD:
+               break;
+       case LUA_ERRRUN:
+               mg_cry(conn,
+                      "%s: %s failed: runtime error: %s",
+                      lua_title,
+                      lua_operation,
+                      lua_tostring(L, -1));
+               break;
+       case LUA_ERRSYNTAX:
+               mg_cry(conn,
+                      "%s: %s failed: syntax error: %s",
+                      lua_title,
+                      lua_operation,
+                      lua_tostring(L, -1));
+               break;
+       case LUA_ERRMEM:
+               mg_cry(conn, "%s: %s failed: out of memory", lua_title, 
lua_operation);
+               break;
+       case LUA_ERRGCMM:
+               mg_cry(conn,
+                      "%s: %s failed: error during garbage collection",
+                      lua_title,
+                      lua_operation);
+               break;
+       case LUA_ERRERR:
+               mg_cry(conn,
+                      "%s: %s failed: error in error handling: %s",
+                      lua_title,
+                      lua_operation,
+                      lua_tostring(L, -1));
+               break;
+       default:
+               mg_cry(conn, "%s: %s failed: error %i", lua_title, 
lua_operation, err);
+               break;
+       }
+}
+
+static int
+lsp_sock_close(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       size_t s;
+       SOCKET *psock;
+
+       if ((num_args == 1) && lua_istable(L, -1)) {
+               lua_getfield(L, -1, "sock");
+               psock = (SOCKET *)lua_tolstring(L, -1, &s);
+               if (s != sizeof(SOCKET)) {
+                       return luaL_error(L, "invalid internal state in 
:close() call");
+               }
+               /* Do not closesocket(*psock); here, close it in __gc */
+               (void)psock;
+       } else {
+               return luaL_error(L, "invalid :close() call");
+       }
+       return 0;
+}
+
+static int
+lsp_sock_recv(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       char buf[2000];
+       int n;
+       size_t s;
+       SOCKET *psock;
+
+       if ((num_args == 1) && lua_istable(L, -1)) {
+               lua_getfield(L, -1, "sock");
+               psock = (SOCKET *)lua_tolstring(L, -1, &s);
+               if (s != sizeof(SOCKET)) {
+                       return luaL_error(L, "invalid internal state in :recv() 
call");
+               }
+               n = recv(*psock, buf, sizeof(buf), 0);
+               if (n <= 0) {
+                       lua_pushnil(L);
+               } else {
+                       lua_pushlstring(L, buf, n);
+               }
+       } else {
+               return luaL_error(L, "invalid :recv() call");
+       }
+       return 1;
+}
+
+static int
+lsp_sock_send(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *buf;
+       size_t len, sent = 0;
+       int n = 0;
+       size_t s;
+       SOCKET *psock;
+
+       if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
+               buf = lua_tolstring(L, -1, &len);
+               lua_getfield(L, -2, "sock");
+               psock = (SOCKET *)lua_tolstring(L, -1, &s);
+               if (s != sizeof(SOCKET)) {
+                       return luaL_error(L, "invalid internal state in 
:close() call");
+               }
+
+               while (sent < len) {
+                       if ((n = send(*psock, buf + sent, (int)(len - sent), 
0)) <= 0) {
+                               break;
+                       }
+                       sent += n;
+               }
+               lua_pushnumber(L, n);
+       } else {
+               return luaL_error(L, "invalid :close() call");
+       }
+       return 1;
+}
+
+static int
+lsp_sock_gc(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       size_t s;
+       SOCKET *psock;
+
+       if ((num_args == 1) && lua_istable(L, -1)) {
+               lua_getfield(L, -1, "sock");
+               psock = (SOCKET *)lua_tolstring(L, -1, &s);
+               if (s != sizeof(SOCKET)) {
+                       return luaL_error(
+                           L,
+                           "invalid internal state in __gc for object created 
by connect");
+               }
+               closesocket(*psock);
+       } else {
+               return luaL_error(L, "__gc for object created by connect 
failed");
+       }
+       return 0;
+}
+
+/* Methods and meta-methods supported by the object returned by connect.
+ * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
+static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
+                                                    {"send", lsp_sock_send},
+                                                    {"recv", lsp_sock_recv},
+                                                    {"__gc", lsp_sock_gc},
+                                                    {NULL, NULL}};
+
+static int
+lsp_connect(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       char ebuf[100];
+       SOCKET sock;
+       union usa sa;
+       int ok;
+
+       if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
+           && lua_isnumber(L, -1)) {
+               ok = connect_socket(NULL,
+                                   lua_tostring(L, -3),
+                                   (int)lua_tonumber(L, -2),
+                                   (int)lua_tonumber(L, -1),
+                                   ebuf,
+                                   sizeof(ebuf),
+                                   &sock,
+                                   &sa);
+               if (!ok) {
+                       return luaL_error(L, ebuf);
+               } else {
+                       lua_newtable(L);
+                       reg_lstring(L, "sock", (const char *)&sock, 
sizeof(SOCKET));
+                       reg_string(L, "host", lua_tostring(L, -4));
+                       luaL_getmetatable(L, LUASOCKET);
+                       lua_setmetatable(L, -2);
+               }
+       } else {
+               return luaL_error(
+                   L, "connect(host,port,is_ssl): invalid parameter given.");
+       }
+       return 1;
+}
+
+static int
+lsp_error(lua_State *L)
+{
+       lua_getglobal(L, "mg");
+       lua_getfield(L, -1, "onerror");
+       lua_pushvalue(L, -3);
+       lua_pcall(L, 1, 0, 0);
+       return 0;
+}
+
+/* Silently stop processing chunks. */
+static void
+lsp_abort(lua_State *L)
+{
+       int top = lua_gettop(L);
+       lua_getglobal(L, "mg");
+       lua_pushnil(L);
+       lua_setfield(L, -2, "onerror");
+       lua_settop(L, top);
+       lua_pushstring(L, "aborting");
+       lua_error(L);
+}
+
+struct lsp_var_reader_data {
+       const char *begin;
+       unsigned len;
+       unsigned state;
+};
+
+
+static const char *
+lsp_var_reader(lua_State *L, void *ud, size_t *sz)
+{
+       struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
+       const char *ret;
+       (void)(L); /* unused */
+
+       switch (reader->state) {
+       case 0:
+               ret = "mg.write(";
+               *sz = strlen(ret);
+               break;
+       case 1:
+               ret = reader->begin;
+               *sz = reader->len;
+               break;
+       case 2:
+               ret = ")";
+               *sz = strlen(ret);
+               break;
+       default:
+               ret = 0;
+               *sz = 0;
+       }
+
+       reader->state++;
+       return ret;
+}
+
+
+static int
+lsp(struct mg_connection *conn,
+    const char *path,
+    const char *p,
+    int64_t len,
+    lua_State *L)
+{
+       int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
+       char chunkname[MG_BUF_LEN];
+       struct lsp_var_reader_data data;
+
+       for (i = 0; i < len; i++) {
+               if (p[i] == '\n')
+                       lines++;
+               if (((i + 1) < len) && (p[i] == '<') && (p[i + 1] == '?')) {
+
+                       /* <?= ?> means a variable is enclosed and its value 
should be
+                        * printed */
+                       is_var = (((i + 2) < len) && (p[i + 2] == '='));
+
+                       if (is_var)
+                               j = i + 2;
+                       else
+                               j = i + 1;
+
+                       while (j < len) {
+                               if (p[j] == '\n')
+                                       lualines++;
+                               if (((j + 1) < len) && (p[j] == '?') && (p[j + 
1] == '>')) {
+                                       mg_write(conn, p + pos, i - pos);
+
+                                       mg_snprintf(conn,
+                                                   NULL, /* name only used for 
debugging */
+                                                   chunkname,
+                                                   sizeof(chunkname),
+                                                   "@%s+%i",
+                                                   path,
+                                                   lines);
+                                       lua_pushlightuserdata(L, conn);
+                                       lua_pushcclosure(L, lsp_error, 1);
+
+                                       if (is_var) {
+                                               data.begin = p + (i + 3);
+                                               data.len = j - (i + 3);
+                                               data.state = 0;
+                                               lua_ok = mg_lua_load(
+                                                   L, lsp_var_reader, &data, 
chunkname, NULL);
+                                       } else {
+                                               lua_ok = luaL_loadbuffer(L,
+                                                                        p + (i 
+ 2),
+                                                                        j - (i 
+ 2),
+                                                                        
chunkname);
+                                       }
+
+                                       if (lua_ok) {
+                                               /* Syntax error or OOM. Error 
message is pushed on
+                                                * stack. */
+                                               lua_pcall(L, 1, 0, 0);
+                                       } else {
+                                               /* Success loading chunk. Call 
it. */
+                                               lua_pcall(L, 0, 0, 1);
+                                       }
+
+                                       pos = j + 2;
+                                       i = pos - 1;
+                                       break;
+                               }
+                               j++;
+                       }
+
+                       if (lualines > 0) {
+                               lines += lualines;
+                               lualines = 0;
+                       }
+               }
+       }
+
+       if (i > pos) {
+               mg_write(conn, p + pos, i - pos);
+       }
+
+       return 0;
+}
+
+
+/* mg.write: Send data to the client */
+static int
+lsp_write(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+       const char *str;
+       size_t size;
+       int i;
+       int rv = 1;
+
+       for (i = 1; i <= num_args; i++) {
+               if (lua_isstring(L, i)) {
+                       str = lua_tolstring(L, i, &size);
+                       if (mg_write(conn, str, size) != (int)size) {
+                               rv = 0;
+                       }
+               }
+       }
+       lua_pushboolean(L, rv);
+
+       return 1;
+}
+
+
+/* mg.read: Read data from the client (e.g., from a POST request) */
+static int
+lsp_read(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       char buf[1024];
+       int len = mg_read(conn, buf, sizeof(buf));
+
+       if (len <= 0)
+               return 0;
+       lua_pushlstring(L, buf, len);
+
+       return 1;
+}
+
+
+/* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
+static int
+lsp_keep_alive(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+
+       /* This function may be called with one parameter (boolean) to set the
+       keep_alive state.
+       Or without a parameter to just query the current keep_alive state. */
+       if ((num_args == 1) && lua_isboolean(L, 1)) {
+               conn->must_close = !lua_toboolean(L, 1);
+       } else if (num_args != 0) {
+               /* Syntax error */
+               return luaL_error(L, "invalid keep_alive() call");
+       }
+
+       /* Return the current "keep_alive" state. This may be false, even it
+        * keep_alive(true) has been called. */
+       lua_pushboolean(L, should_keep_alive(conn));
+       return 1;
+}
+
+
+/* mg.include: Include another .lp file */
+static int
+lsp_include(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+       struct mg_file file = STRUCT_FILE_INITIALIZER;
+       const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+       if (filename) {
+               if (handle_lsp_request(conn, filename, &file, L)) {
+                       /* handle_lsp_request returned an error code, meaning 
an error
+                       occured in
+                       the included page and mg.onerror returned non-zero. 
Stop processing.
+                       */
+                       lsp_abort(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid include() call");
+       }
+       return 0;
+}
+
+
+/* mg.cry: Log an error. Default value for mg.onerror. */
+static int
+lsp_cry(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+       const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+       if (text) {
+               mg_cry(conn, "%s", lua_tostring(L, -1));
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid cry() call");
+       }
+       return 0;
+}
+
+
+/* mg.redirect: Redirect the request (internally). */
+static int
+lsp_redirect(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+       const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+       if (target) {
+               conn->request_info.local_uri = target;
+               handle_request(conn);
+               lsp_abort(L);
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid redirect() call");
+       }
+       return 0;
+}
+
+
+/* mg.send_file */
+static int
+lsp_send_file(lua_State *L)
+{
+       struct mg_connection *conn =
+           (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+       int num_args = lua_gettop(L);
+       const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+       if (filename) {
+               mg_send_file(conn, filename);
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid send_file() call");
+       }
+       return 0;
+}
+
+
+/* mg.get_time */
+static int
+lsp_get_time(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
+       struct timespec ts;
+       double d;
+
+       clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
+       d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
+       lua_pushnumber(L, d);
+       return 1;
+}
+
+
+/* mg.get_var */
+static int
+lsp_get_var(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *data, *var_name;
+       size_t data_len, occurrence;
+       int ret;
+       char dst[512];
+
+       if (num_args >= 2 && num_args <= 3) {
+               data = lua_tolstring(L, 1, &data_len);
+               var_name = lua_tostring(L, 2);
+               occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
+
+               ret =
+                   mg_get_var2(data, data_len, var_name, dst, sizeof(dst), 
occurrence);
+               if (ret >= 0) {
+                       /* Variable found: return value to Lua */
+                       lua_pushstring(L, dst);
+               } else {
+                       /* Variable not found (TODO (mid): may be string too 
long) */
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid get_var() call");
+       }
+       return 1;
+}
+
+
+/* mg.get_mime_type */
+static int
+lsp_get_mime_type(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       struct vec mime_type = {0, 0};
+       struct mg_context *ctx;
+       const char *text;
+
+       lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+       lua_gettable(L, LUA_REGISTRYINDEX);
+       ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+       if (num_args == 1) {
+               text = lua_tostring(L, 1);
+               if (text) {
+                       if (ctx) {
+                               get_mime_type(ctx, text, &mime_type);
+                               lua_pushlstring(L, mime_type.ptr, 
mime_type.len);
+                       } else {
+                               text = mg_get_builtin_mime_type(text);
+                               lua_pushstring(L, text);
+                       }
+               } else {
+                       /* Syntax error */
+                       return luaL_error(L, "invalid argument for 
get_mime_type() call");
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid get_mime_type() call");
+       }
+       return 1;
+}
+
+
+/* mg.get_cookie */
+static int
+lsp_get_cookie(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *cookie;
+       const char *var_name;
+       int ret;
+       char dst[512];
+
+       if (num_args == 2) {
+               cookie = lua_tostring(L, 1);
+               var_name = lua_tostring(L, 2);
+               if (cookie != NULL && var_name != NULL) {
+                       ret = mg_get_cookie(cookie, var_name, dst, sizeof(dst));
+               } else {
+                       ret = -1;
+               }
+
+               if (ret >= 0) {
+                       lua_pushlstring(L, dst, ret);
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid get_cookie() call");
+       }
+       return 1;
+}
+
+
+/* mg.md5 */
+static int
+lsp_md5(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *text;
+       md5_byte_t hash[16];
+       md5_state_t ctx;
+       size_t text_len;
+       char buf[40];
+
+       if (num_args == 1) {
+               text = lua_tolstring(L, 1, &text_len);
+               if (text) {
+                       md5_init(&ctx);
+                       md5_append(&ctx, (const md5_byte_t *)text, text_len);
+                       md5_finish(&ctx, hash);
+                       bin2str(buf, hash, sizeof(hash));
+                       lua_pushstring(L, buf);
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid md5() call");
+       }
+       return 1;
+}
+
+
+/* mg.url_encode */
+static int
+lsp_url_encode(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *text;
+       size_t text_len;
+       char dst[512 * 3];
+
+       if (num_args == 1) {
+               text = lua_tolstring(L, 1, &text_len);
+               if (text) {
+                       mg_url_encode(text, dst, sizeof(dst));
+                       lua_pushstring(L, dst);
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid url_encode() call");
+       }
+       return 1;
+}
+
+
+/* mg.url_decode */
+static int
+lsp_url_decode(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *text;
+       size_t text_len;
+       int is_form;
+       char dst[512];
+
+       if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
+               text = lua_tolstring(L, 1, &text_len);
+               is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
+               if (text) {
+                       mg_url_decode(text, (int)text_len, dst, 
(int)sizeof(dst), is_form);
+                       lua_pushstring(L, dst);
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid url_decode() call");
+       }
+       return 1;
+}
+
+
+/* mg.base64_encode */
+static int
+lsp_base64_encode(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *text;
+       size_t text_len;
+       char *dst;
+
+       if (num_args == 1) {
+               text = lua_tolstring(L, 1, &text_len);
+               if (text) {
+                       dst = (char *)mg_malloc(text_len * 8 / 6 + 4);
+                       if (dst) {
+                               base64_encode((const unsigned char *)text, 
(int)text_len, dst);
+                               lua_pushstring(L, dst);
+                               mg_free(dst);
+                       } else {
+                               return luaL_error(L, "out of memory in 
base64_encode() call");
+                       }
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid base64_encode() call");
+       }
+       return 1;
+}
+
+
+/* mg.base64_encode */
+static int
+lsp_base64_decode(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       const char *text;
+       size_t text_len, dst_len;
+       int ret;
+       char *dst;
+
+       if (num_args == 1) {
+               text = lua_tolstring(L, 1, &text_len);
+               if (text) {
+                       dst = (char *)mg_malloc(text_len);
+                       if (dst) {
+                               ret = base64_decode((const unsigned char *)text,
+                                                   (int)text_len,
+                                                   dst,
+                                                   &dst_len);
+                               if (ret != -1) {
+                                       mg_free(dst);
+                                       return luaL_error(
+                                           L, "illegal character in 
lsp_base64_decode() call");
+                               } else {
+                                       lua_pushlstring(L, dst, dst_len);
+                                       mg_free(dst);
+                               }
+                       } else {
+                               return luaL_error(L,
+                                                 "out of memory in 
lsp_base64_decode() call");
+                       }
+               } else {
+                       lua_pushnil(L);
+               }
+       } else {
+               /* Syntax error */
+               return luaL_error(L, "invalid lsp_base64_decode() call");
+       }
+       return 1;
+}
+
+
+/* mg.get_response_code_text */
+static int
+lsp_get_response_code_text(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       int type1;
+       double code;
+       const char *text;
+
+       if (num_args == 1) {
+               type1 = lua_type(L, 1);
+               if (type1 == LUA_TNUMBER) {
+                       /* If the first argument is a number,
+                          convert it to the corresponding text. */
+                       code = lua_tonumber(L, 1);
+                       text = mg_get_response_code_text(NULL, (int)code);
+                       if (text)
+                               lua_pushstring(L, text);
+                       return text ? 1 : 0;
+               }
+       }
+
+       /* Syntax error */
+       return luaL_error(L, "invalid get_response_code_text() call");
+}
+
+
+/* mg.random - might be better than math.random on some systems */
+static int
+lsp_random(lua_State *L)
+{
+       int num_args = lua_gettop(L);
+       if (num_args == 0) {
+               /* The civetweb internal random number generator will generate
+                        * a 64 bit random number. */
+               uint64_t r = get_random();
+               /* Lua "number" is a IEEE 754 double precission float:
+ * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
+                * Thus, mask with 2^53-1 to get an integer with the maximum
+ * precission available. */
+               r &= ((((uint64_t)1) << 53) - 1);
+               lua_pushnumber(L, (double)r);
+               return 1;
+       }
+
+       /* Syntax error */
+       return luaL_error(L, "invalid random() call");
+}
+
+
+union {
+       void *p;
+       void (*f)(unsigned char uuid[16]);
+} pf_uuid_generate;
+
+
+/* mg.uuid */
+static int
+lsp_uuid(lua_State *L)
+{
+       union {
+               unsigned char uuid_array[16];
+               struct uuid_struct_type {
+                       uint32_t data1;
+                       uint16_t data2;
+                       uint16_t data3;
+                       uint8_t data4[8];
+               } uuid_struct;
+       } uuid;
+
+       char uuid_str[40];
+       int num_args = lua_gettop(L);
+
+       memset(&uuid, 0, sizeof(uuid));
+       memset(uuid_str, 0, sizeof(uuid_str));
+
+       if (num_args == 0) {
+
+               pf_uuid_generate.f(uuid.uuid_array);
+
+               sprintf(uuid_str,
+                       "{%08lX-%04X-%04X-%02X%02X-"
+                       "%02X%02X%02X%02X%02X%02X}",
+                       (unsigned long)uuid.uuid_struct.data1,
+                       (unsigned)uuid.uuid_struct.data2,
+                       (unsigned)uuid.uuid_struct.data3,
+                       (unsigned)uuid.uuid_struct.data4[0],
+                       (unsigned)uuid.uuid_struct.data4[1],
+                       (unsigned)uuid.uuid_struct.data4[2],
+                       (unsigned)uuid.uuid_struct.data4[3],
+                       (unsigned)uuid.uuid_struct.data4[4],
+                       (unsigned)uuid.uuid_struct.data4[5],
+                       (unsigned)uuid.uuid_struct.data4[6],
+                       (unsigned)uuid.uuid_struct.data4[7]);
+
+               lua_pushstring(L, uuid_str);
+               return 1;
+       }
+
+       /* Syntax error */
+       return luaL_error(L, "invalid random() call");
+}
+
+
+#ifdef USE_WEBSOCKET
+struct lua_websock_data {
+       lua_State *state;
+       char *script;
+       unsigned references;
+       struct mg_connection *conn[MAX_WORKER_THREADS];
+       pthread_mutex_t ws_mutex;
+};
+#endif
+
+
+/* mg.write for websockets */
+static int
+lwebsock_write(lua_State *L)
+{
+#ifdef USE_WEBSOCKET
+       int num_args = lua_gettop(L);
+       struct lua_websock_data *ws;
+       const char *str;
+       size_t size;
+       int opcode = -1;
+       unsigned i;
+       struct mg_connection *client = NULL;
+
+       lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+       lua_gettable(L, LUA_REGISTRYINDEX);
+       ws = (struct lua_websock_data *)lua_touserdata(L, -1);
+
+       (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+       if (num_args == 1) {
+               /* just one text: send it to all client */
+               if (lua_isstring(L, 1)) {
+                       opcode = WEBSOCKET_OPCODE_TEXT;
+               }
+       } else if (num_args == 2) {
+               if (lua_isnumber(L, 1)) {
+                       /* opcode number and message text */
+                       opcode = (int)lua_tointeger(L, 1);
+               } else if (lua_isstring(L, 1)) {
+                       /* opcode string and message text */
+                       str = lua_tostring(L, 1);
+                       if (!mg_strncasecmp(str, "text", 4))
+                               opcode = WEBSOCKET_OPCODE_TEXT;
+                       else if (!mg_strncasecmp(str, "bin", 3))
+                               opcode = WEBSOCKET_OPCODE_BINARY;
+                       else if (!mg_strncasecmp(str, "close", 5))
+                               opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+                       else if (!mg_strncasecmp(str, "ping", 4))
+                               opcode = WEBSOCKET_OPCODE_PING;
+                       else if (!mg_strncasecmp(str, "pong", 4))
+                               opcode = WEBSOCKET_OPCODE_PONG;
+                       else if (!mg_strncasecmp(str, "cont", 4))
+                               opcode = WEBSOCKET_OPCODE_CONTINUATION;
+               } else if (lua_isuserdata(L, 1)) {
+                       /* client id and message text */
+                       client = (struct mg_connection *)lua_touserdata(L, 1);
+                       opcode = WEBSOCKET_OPCODE_TEXT;
+               }
+       } else if (num_args == 3) {
+               if (lua_isuserdata(L, 1)) {
+                       client = (struct mg_connection *)lua_touserdata(L, 1);
+                       if (lua_isnumber(L, 2)) {
+                               /* client id, opcode number and message text */
+                               opcode = (int)lua_tointeger(L, 2);
+                       } else if (lua_isstring(L, 2)) {
+                               /* client id, opcode string and message text */
+                               str = lua_tostring(L, 2);
+                               if (!mg_strncasecmp(str, "text", 4))
+                                       opcode = WEBSOCKET_OPCODE_TEXT;
+                               else if (!mg_strncasecmp(str, "bin", 3))
+                                       opcode = WEBSOCKET_OPCODE_BINARY;
+                               else if (!mg_strncasecmp(str, "close", 5))
+                                       opcode = 
WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+                               else if (!mg_strncasecmp(str, "ping", 4))
+                                       opcode = WEBSOCKET_OPCODE_PING;
+                               else if (!mg_strncasecmp(str, "pong", 4))
+                                       opcode = WEBSOCKET_OPCODE_PONG;
+                               else if (!mg_strncasecmp(str, "cont", 4))
+                                       opcode = WEBSOCKET_OPCODE_CONTINUATION;
+                       }
+               }
+       }
+
+       if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
+               str = lua_tolstring(L, num_args, &size);
+               if (client) {
+                       for (i = 0; i < ws->references; i++) {
+                               if (client == ws->conn[i]) {
+                                       mg_websocket_write(ws->conn[i], opcode, 
str, size);
+                               }
+                       }
+               } else {
+                       for (i = 0; i < ws->references; i++) {
+                               mg_websocket_write(ws->conn[i], opcode, str, 
size);
+                       }
+               }
+       } else {
+               (void)pthread_mutex_unlock(&(ws->ws_mutex));
+               return luaL_error(L, "invalid websocket write() call");
+       }
+
+       (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+#else
+       (void)(L);           /* unused */
+#endif
+       return 0;
+}
+
+
+struct laction_arg {
+       lua_State *state;
+       const char *script;
+       pthread_mutex_t *pmutex;
+       char txt[1];
+};
+
+
+static int
+lua_action(struct laction_arg *arg)
+{
+       int err, ok;
+       struct mg_context *ctx;
+
+       (void)pthread_mutex_lock(arg->pmutex);
+
+       lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
+       lua_gettable(arg->state, LUA_REGISTRYINDEX);
+       ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
+
+       err = luaL_loadstring(arg->state, arg->txt);
+       if (err != 0) {
+               lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+               (void)pthread_mutex_unlock(arg->pmutex);
+               mg_free(arg);
+               return 0;
+       }
+       err = lua_pcall(arg->state, 0, 1, 0);
+       if (err != 0) {
+               lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+               (void)pthread_mutex_unlock(arg->pmutex);
+               mg_free(arg);
+               return 0;
+       }
+
+       ok = lua_type(arg->state, -1);
+       if (lua_isboolean(arg->state, -1)) {
+               ok = lua_toboolean(arg->state, -1);
+       } else {
+               ok = 0;
+       }
+       lua_pop(arg->state, 1);
+
+       (void)pthread_mutex_unlock(arg->pmutex);
+
+       if (!ok) {
+               mg_free(arg);
+       }
+       return ok;
+}
+
+
+static int
+lua_action_free(struct laction_arg *arg)
+{
+       if (lua_action(arg)) {
+               mg_free(arg);
+       }
+       return 0;
+}
+
+
+static int
+lwebsocket_set_timer(lua_State *L, int is_periodic)
+{
+#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
+       int num_args = lua_gettop(L);
+       struct lua_websock_data *ws;
+       int type1, type2, ok = 0;
+       double timediff;
+       struct mg_context *ctx;
+       struct laction_arg *arg;
+       const char *txt;
+       size_t txt_len;
+
+       lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+       lua_gettable(L, LUA_REGISTRYINDEX);
+       ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+       lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+       lua_gettable(L, LUA_REGISTRYINDEX);
+       ws = (struct lua_websock_data *)lua_touserdata(L, -1);
+
+       if (num_args < 2) {
+               return luaL_error(L,
+                                 "not enough arguments for 
set_timer/interval() call");
+       }
+
+       type1 = lua_type(L, 1);
+       type2 = lua_type(L, 2);
+
+       if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
+               timediff = (double)lua_tonumber(L, 2);
+               txt = lua_tostring(L, 1);
+               txt_len = strlen(txt);
+               arg = (struct laction_arg *)mg_malloc(sizeof(struct laction_arg)
+                                                     + txt_len + 10);
+               arg->state = L;
+               arg->script = ws->script;
+               arg->pmutex = &(ws->ws_mutex);
+               memcpy(arg->txt, "return(", 7);
+               memcpy(arg->txt + 7, txt, txt_len);
+               arg->txt[txt_len + 7] = ')';
+               arg->txt[txt_len + 8] = 0;
+               ok =
+                   (0
+                    == timer_add(ctx,
+                                 timediff,
+                                 is_periodic,
+                                 1,
+                                 (taction)(is_periodic ? lua_action : 
lua_action_free),
+                                 (void *)arg));
+       } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
+               /* TODO (mid): not implemented yet */
+               return luaL_error(L, "invalid arguments for 
set_timer/interval() call");
+       } else {
+               return luaL_error(L, "invalid arguments for 
set_timer/interval() call");
+       }
+
+       lua_pushboolean(L, ok);
+       return 1;
+
+#else
+       (void)(L);           /* unused */
+       (void)(is_periodic); /* unused */
+       return 0;
+#endif
+}
+
+
+/* mg.set_timeout for websockets */
+static int
+lwebsocket_set_timeout(lua_State *L)
+{
+       return lwebsocket_set_timer(L, 0);
+}
+
+
+/* mg.set_interval for websockets */
+static int
+lwebsocket_set_interval(lua_State *L)
+{
+       return lwebsocket_set_timer(L, 1);
+}
+
+enum {
+       LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
+       LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
+       LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
+};
+
+
+static void
+prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
+{
+       const char *s;
+       int i;
+
+       /* Export mg.request_info */
+       lua_pushstring(L, "request_info");
+       lua_newtable(L);
+       reg_string(L, "request_method", conn->request_info.request_method);
+       reg_string(L, "request_uri", conn->request_info.request_uri);
+       reg_string(L, "uri", conn->request_info.local_uri);
+       reg_string(L, "http_version", conn->request_info.http_version);
+       reg_string(L, "query_string", conn->request_info.query_string);
+#if defined(MG_LEGACY_INTERFACE)
+       reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
+                                                                 deprecated, 
use
+                                                                 remote_addr
+                                                                 instead */
+#endif
+       reg_string(L, "remote_addr", conn->request_info.remote_addr);
+       /* TODO (high): ip version */
+       reg_int(L, "remote_port", conn->request_info.remote_port);
+       reg_int(L, "num_headers", conn->request_info.num_headers);
+       reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
+
+       if (conn->path_info != NULL) {
+               reg_string(L, "path_info", conn->path_info);
+       }
+
+       if (conn->request_info.content_length >= 0) {
+               /* reg_int64: content_length */
+               lua_pushstring(L, "content_length");
+               lua_pushnumber(
+                   L,
+                   (lua_Number)conn->request_info
+                       .content_length); /* lua_Number may be used as 52 bit 
integer */
+               lua_rawset(L, -3);
+       }
+       if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
+               reg_string(L, "content_type", s);
+       }
+
+       if (conn->request_info.remote_user != NULL) {
+               reg_string(L, "remote_user", conn->request_info.remote_user);
+               reg_string(L, "auth_type", "Digest");
+       }
+
+       reg_boolean(L, "https", conn->ssl != NULL);
+
+       if (conn->status_code > 0) {
+               /* Lua error handler should show the status code */
+               reg_int(L, "status", conn->status_code);
+       }
+
+       lua_pushstring(L, "http_headers");
+       lua_newtable(L);
+       for (i = 0; i < conn->request_info.num_headers; i++) {
+               reg_string(L,
+                          conn->request_info.http_headers[i].name,
+                          conn->request_info.http_headers[i].value);
+       }
+       lua_rawset(L, -3);
+
+       lua_rawset(L, -3);
+}
+
+
+void
+civetweb_open_lua_libs(lua_State *L)
+{
+       {
+               extern void luaL_openlibs(lua_State *);
+               luaL_openlibs(L);
+       }
+
+#ifdef USE_LUA_SQLITE3
+       {
+               extern int luaopen_lsqlite3(lua_State *);
+               luaopen_lsqlite3(L);
+       }
+#endif
+#ifdef USE_LUA_LUAXML
+       {
+               extern int luaopen_LuaXML_lib(lua_State *);
+               luaopen_LuaXML_lib(L);
+       }
+#endif
+#ifdef USE_LUA_FILE_SYSTEM
+       {
+               extern int luaopen_lfs(lua_State *);
+               luaopen_lfs(L);
+       }
+#endif
+#ifdef USE_LUA_BINARY
+       {
+               /* TODO (low): Test if this could be used as a replacement for 
bit32.
+                * Check again with Lua 5.3 later. */
+               extern int luaopen_binary(lua_State *);
+
+               luaL_requiref(L, "binary", luaopen_binary, 1);
+               lua_pop(L, 1);
+       }
+#endif
+}
+
+
+static void
+prepare_lua_environment(struct mg_context *ctx,
+                        struct mg_connection *conn,
+                        struct lua_websock_data *ws_conn_list,
+                        lua_State *L,
+                        const char *script_name,
+                        int lua_env_type)
+{
+       civetweb_open_lua_libs(L);
+
+#if LUA_VERSION_NUM == 502
+       /* Keep the "connect" method for compatibility,
+        * but do not backport it to Lua 5.1.
+        * TODO: Redesign the interface.
+        */
+       luaL_newmetatable(L, LUASOCKET);
+       lua_pushliteral(L, "__index");
+       luaL_newlib(L, luasocket_methods);
+       lua_rawset(L, -3);
+       lua_pop(L, 1);
+       lua_register(L, "connect", lsp_connect);
+#endif
+
+       /* Store context in the registry */
+       if (ctx != NULL) {
+               lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+               lua_pushlightuserdata(L, (void *)ctx);
+               lua_settable(L, LUA_REGISTRYINDEX);
+       }
+       if (ws_conn_list != NULL) {
+               lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+               lua_pushlightuserdata(L, (void *)ws_conn_list);
+               lua_settable(L, LUA_REGISTRYINDEX);
+       }
+
+       /* Register mg module */
+       lua_newtable(L);
+
+       switch (lua_env_type) {
+       case LUA_ENV_TYPE_LUA_SERVER_PAGE:
+               reg_string(L, "lua_type", "page");
+               break;
+       case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
+               reg_string(L, "lua_type", "script");
+               break;
+       case LUA_ENV_TYPE_LUA_WEBSOCKET:
+               reg_string(L, "lua_type", "websocket");
+               break;
+       }
+
+       if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
+           || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
+               reg_conn_function(L, "cry", lsp_cry, conn);
+               reg_conn_function(L, "read", lsp_read, conn);
+               reg_conn_function(L, "write", lsp_write, conn);
+               reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
+               reg_conn_function(L, "send_file", lsp_send_file, conn);
+       }
+
+       if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
+               reg_conn_function(L, "include", lsp_include, conn);
+               reg_conn_function(L, "redirect", lsp_redirect, conn);
+       }
+
+       if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
+               reg_function(L, "write", lwebsock_write);
+#ifdef USE_TIMERS
+               reg_function(L, "set_timeout", lwebsocket_set_timeout);
+               reg_function(L, "set_interval", lwebsocket_set_interval);
+#endif
+               /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
+       }
+
+       reg_function(L, "time", lsp_get_time);
+       reg_function(L, "get_var", lsp_get_var);
+       reg_function(L, "get_mime_type", lsp_get_mime_type);
+       reg_function(L, "get_cookie", lsp_get_cookie);
+       reg_function(L, "md5", lsp_md5);
+       reg_function(L, "url_encode", lsp_url_encode);
+       reg_function(L, "url_decode", lsp_url_decode);
+       reg_function(L, "base64_encode", lsp_base64_encode);
+       reg_function(L, "base64_decode", lsp_base64_decode);
+       reg_function(L, "get_response_code_text", lsp_get_response_code_text);
+       reg_function(L, "random", lsp_random);
+       if (pf_uuid_generate.f) {
+               reg_function(L, "uuid", lsp_uuid);
+       }
+
+       reg_string(L, "version", CIVETWEB_VERSION);
+
+       reg_string(L, "script_name", script_name);
+
+       if (ctx != NULL) {
+               reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
+               reg_string(L, "auth_domain", 
ctx->config[AUTHENTICATION_DOMAIN]);
+#if defined(USE_WEBSOCKET)
+               if (ctx->config[WEBSOCKET_ROOT]) {
+                       reg_string(L, "websocket_root", 
ctx->config[WEBSOCKET_ROOT]);
+               } else {
+                       reg_string(L, "websocket_root", 
ctx->config[DOCUMENT_ROOT]);
+               }
+#endif
+
+               if (ctx->systemName != NULL) {
+                       reg_string(L, "system", ctx->systemName);
+               }
+       }
+
+       /* Export connection specific info */
+       if (conn != NULL) {
+               prepare_lua_request_info(conn, L);
+       }
+
+       lua_setglobal(L, "mg");
+
+       /* Register default mg.onerror function */
+       IGNORE_UNUSED_RESULT(
+           luaL_dostring(L,
+                         "mg.onerror = function(e) mg.write('\\nLua 
error:\\n', "
+                         "debug.traceback(e, 1)) end"));
+
+       if (ctx != NULL) {
+               /* Preload */
+               if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
+                       IGNORE_UNUSED_RESULT(luaL_dofile(L, 
ctx->config[LUA_PRELOAD_FILE]));
+               }
+
+               if (ctx->callbacks.init_lua != NULL) {
+                       ctx->callbacks.init_lua(conn, L);
+               }
+       }
+}
+
+
+static int
+lua_error_handler(lua_State *L)
+{
+       const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : 
"?\n";
+
+       lua_getglobal(L, "mg");
+       if (!lua_isnil(L, -1)) {
+               lua_getfield(L, -1, "write"); /* call mg.write() */
+               lua_pushstring(L, error_msg);
+               lua_pushliteral(L, "\n");
+               lua_call(L, 2, 0);
+               IGNORE_UNUSED_RESULT(
+                   luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
+       } else {
+               printf("Lua error: [%s]\n", error_msg);
+               IGNORE_UNUSED_RESULT(
+                   luaL_dostring(L, "print(debug.traceback(), '\\n')"));
+       }
+       /* TODO(lsm, low): leave the stack balanced */
+
+       return 0;
+}
+
+
+static void *
+lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+       (void)ud;
+       (void)osize; /* not used */
+
+       if (nsize == 0) {
+               mg_free(ptr);
+               return NULL;
+       }
+       return mg_realloc(ptr, nsize);
+}
+
+
+static void
+mg_exec_lua_script(struct mg_connection *conn,
+                   const char *path,
+                   const void **exports)
+{
+       int i;
+       lua_State *L;
+
+       /* Assume the script does not support keep_alive. The script may change 
this
+        * by calling mg.keep_alive(true). */
+       conn->must_close = 1;
+
+       /* Execute a plain Lua script. */
+       if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
+               prepare_lua_environment(
+                   conn->ctx, conn, NULL, L, path, 
LUA_ENV_TYPE_PLAIN_LUA_PAGE);
+               lua_pushcclosure(L, &lua_error_handler, 0);
+
+               if (exports != NULL) {
+#if LUA_VERSION_NUM > 501
+                       lua_pushglobaltable(L);
+                       for (i = 0; exports[i] != NULL && exports[i + 1] != 
NULL; i += 2) {
+                               lua_CFunction func;
+                               lua_pushstring(L, (const char *)(exports[i]));
+                               *(const void **)(&func) = exports[i + 1];
+                               lua_pushcclosure(L, func, 0);
+                               lua_rawset(L, -3);
+                       }
+#else
+                       for (i = 0; exports[i] != NULL && exports[i + 1] != 
NULL; i += 2) {
+                               lua_CFunction func;
+                               const char *name = (const char *)(exports[i]);
+                               *(const void **)(&func) = exports[i + 1];
+                               lua_register(L, name, func);
+                       }
+#endif
+               }
+
+               if (luaL_loadfile(L, path) != 0) {
+                       lua_error_handler(L);
+               }
+               lua_pcall(L, 0, 0, -2);
+               lua_close(L);
+       }
+}
+
+
+static int
+handle_lsp_request(struct mg_connection *conn,
+                   const char *path,
+                   struct mg_file *filep,
+                   struct lua_State *ls)
+{
+       void *p = NULL;
+       lua_State *L = NULL;
+       int error = 1;
+       struct mg_file filesize = STRUCT_FILE_INITIALIZER;
+
+       /* Assume the script does not support keep_alive. The script may change 
this
+        * by calling mg.keep_alive(true). */
+       conn->must_close = 1;
+
+       /* We need both mg_stat to get file size, and mg_fopen to get fd */
+       if (!mg_stat(conn, path, &filesize.stat)) {
+
+               /* File not found */
+               if (ls == NULL) {
+                       send_http_error(conn, 500, "Error: File %s not found", 
path);
+               } else {
+                       luaL_error(ls, "File [%s] not found", path);
+               }
+
+               goto cleanup_handle_lsp_request;
+       }
+
+       if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
+
+               /* File not found or not accessible */
+               if (ls == NULL) {
+                       send_http_error(conn,
+                                       500,
+                                       "Error: Cannot open script file %s",
+                                       path);
+               } else {
+                       luaL_error(ls, "Cannot  [%s] not found", path);
+               }
+
+               goto cleanup_handle_lsp_request;
+       }
+
+       /* TODO: Operations mg_fopen and mg_stat should do what their names
+        * indicate. They should not fill in different members of the same
+        * struct mg_file.
+        * See Github issue #225 */
+       filep->stat.size = filesize.stat.size;
+
+       if (filep->access.membuf == NULL
+           && (p = mmap(NULL,
+                        (size_t)filep->stat.size,
+                        PROT_READ,
+                        MAP_PRIVATE,
+                        fileno(filep->access.fp),
+                        0)) == MAP_FAILED) {
+
+               /* mmap failed */
+               if (ls == NULL) {
+                       send_http_error(
+                           conn,
+                           500,
+                           "Error: Cannot open script\nFile %s can not be 
mapped",
+                           path);
+               } else {
+                       luaL_error(ls,
+                                  "mmap(%s, %zu, %d): %s",
+                                  path,
+                                  (size_t)filep->stat.size,
+                                  fileno(filep->access.fp),
+                                  strerror(errno));
+               }
+
+               goto cleanup_handle_lsp_request;
+       }
+
+       if (ls != NULL) {
+               L = ls;
+       } else {
+               L = lua_newstate(lua_allocator, NULL);
+               if (L == NULL) {
+                       send_http_error(
+                           conn,
+                           500,
+                           "%s",
+                           "Error: Cannot execute script\nlua_newstate 
failed");
+
+                       goto cleanup_handle_lsp_request;
+               }
+               prepare_lua_environment(
+                   conn->ctx, conn, NULL, L, path, 
LUA_ENV_TYPE_LUA_SERVER_PAGE);
+       }
+
+       /* Lua state is ready to use */
+       /* We're not sending HTTP headers here, Lua page must do it. */
+       error =
+           lsp(conn,
+               path,
+               (filep->access.membuf == NULL) ? (const char *)p
+                                              : (const char 
*)filep->access.membuf,
+               filep->stat.size,
+               L);
+
+cleanup_handle_lsp_request:
+
+       if (L != NULL && ls == NULL)
+               lua_close(L);
+       if (p != NULL)
+               munmap(p, filep->stat.size);
+       (void)mg_fclose(&filep->access);
+
+       return error;
+}
+
+
+#ifdef USE_WEBSOCKET
+struct mg_shared_lua_websocket_list {
+       struct lua_websock_data ws;
+       struct mg_shared_lua_websocket_list *next;
+};
+
+
+static void *
+lua_websocket_new(const char *script, struct mg_connection *conn)
+{
+       struct mg_shared_lua_websocket_list **shared_websock_list =
+           &(conn->ctx->shared_lua_websockets);
+       struct lua_websock_data *ws;
+       int err, ok = 0;
+
+       assert(conn->lua_websocket_state == NULL);
+
+       /* lock list (mg_context global) */
+       mg_lock_context(conn->ctx);
+       while (*shared_websock_list) {
+               /* check if ws already in list */
+               if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
+                       break;
+               }
+               shared_websock_list = &((*shared_websock_list)->next);
+       }
+
+       if (*shared_websock_list == NULL) {
+               /* add ws to list */
+               *shared_websock_list = (struct mg_shared_lua_websocket_list *)
+                   mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
+               if (*shared_websock_list == NULL) {
+                       mg_unlock_context(conn->ctx);
+                       mg_cry(conn, "Cannot create shared websocket struct, 
OOM");
+                       return NULL;
+               }
+               /* init ws list element */
+               ws = &(*shared_websock_list)->ws;
+               ws->script = mg_strdup(script); /* TODO (low): handle OOM */
+               pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
+               (void)pthread_mutex_lock(&(ws->ws_mutex));
+               ws->state = lua_newstate(lua_allocator, NULL);
+               ws->conn[0] = conn;
+               ws->references = 1;
+               prepare_lua_environment(
+                   conn->ctx, NULL, ws, ws->state, script, 
LUA_ENV_TYPE_LUA_WEBSOCKET);
+               err = luaL_loadfile(ws->state, script);
+               if (err != 0) {
+                       lua_cry(conn, err, ws->state, script, "load");
+               }
+               err = lua_pcall(ws->state, 0, 0, 0);
+               if (err != 0) {
+                       lua_cry(conn, err, ws->state, script, "init");
+               }
+       } else {
+               /* inc ref count */
+               ws = &(*shared_websock_list)->ws;
+               (void)pthread_mutex_lock(&(ws->ws_mutex));
+               (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
+       }
+       mg_unlock_context(conn->ctx);
+
+       /* call add */
+       lua_getglobal(ws->state, "open");
+       lua_newtable(ws->state);
+       prepare_lua_request_info(conn, ws->state);
+       lua_pushstring(ws->state, "client");
+       lua_pushlightuserdata(ws->state, (void *)conn);
+       lua_rawset(ws->state, -3);
+
+       err = lua_pcall(ws->state, 1, 1, 0);
+       if (err != 0) {
+               lua_cry(conn, err, ws->state, script, "open handler");
+       } else {
+               if (lua_isboolean(ws->state, -1)) {
+                       ok = lua_toboolean(ws->state, -1);
+               }
+               lua_pop(ws->state, 1);
+       }
+       if (!ok) {
+               /* Remove from ws connection list. */
+               /* TODO (mid): Check if list entry and Lua state needs to be 
deleted
+                * (see websocket_close). */
+               (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
+       }
+
+       (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+       return ok ? (void *)ws : NULL;
+}
+
+
+static int
+lua_websocket_data(struct mg_connection *conn,
+                   int bits,
+                   char *data,
+                   size_t data_len,
+                   void *ws_arg)
+{
+       struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+       int err, ok = 0;
+
+       assert(ws != NULL);
+       assert(ws->state != NULL);
+
+       (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+       lua_getglobal(ws->state, "data");
+       lua_newtable(ws->state);
+       lua_pushstring(ws->state, "client");
+       lua_pushlightuserdata(ws->state, (void *)conn);
+       lua_rawset(ws->state, -3);
+       lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields 
with
+                                             a meaning according to
+                                             
http://tools.ietf.org/html/rfc6455,
+                                             section 5.2 */
+       lua_pushnumber(ws->state, bits);
+       lua_rawset(ws->state, -3);
+       lua_pushstring(ws->state, "data");
+       lua_pushlstring(ws->state, data, data_len);
+       lua_rawset(ws->state, -3);
+
+       err = lua_pcall(ws->state, 1, 1, 0);
+       if (err != 0) {
+               lua_cry(conn, err, ws->state, ws->script, "data handler");
+       } else {
+               if (lua_isboolean(ws->state, -1)) {
+                       ok = lua_toboolean(ws->state, -1);
+               }
+               lua_pop(ws->state, 1);
+       }
+       (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+       return ok;
+}
+
+
+static int
+lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
+{
+       struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+       int err, ok = 0;
+
+       assert(ws != NULL);
+       assert(ws->state != NULL);
+
+       (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+       lua_getglobal(ws->state, "ready");
+       lua_newtable(ws->state);
+       lua_pushstring(ws->state, "client");
+       lua_pushlightuserdata(ws->state, (void *)conn);
+       lua_rawset(ws->state, -3);
+       err = lua_pcall(ws->state, 1, 1, 0);
+       if (err != 0) {
+               lua_cry(conn, err, ws->state, ws->script, "ready handler");
+       } else {
+               if (lua_isboolean(ws->state, -1)) {
+                       ok = lua_toboolean(ws->state, -1);
+               }
+               lua_pop(ws->state, 1);
+       }
+
+       (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+       return ok;
+}
+
+
+static void
+lua_websocket_close(struct mg_connection *conn, void *ws_arg)
+{
+       struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+       struct mg_shared_lua_websocket_list **shared_websock_list =
+           &(conn->ctx->shared_lua_websockets);
+       int err = 0;
+       unsigned i;
+
+       assert(ws != NULL);
+       assert(ws->state != NULL);
+
+       (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+       lua_getglobal(ws->state, "close");
+       lua_newtable(ws->state);
+       lua_pushstring(ws->state, "client");
+       lua_pushlightuserdata(ws->state, (void *)conn);
+       lua_rawset(ws->state, -3);
+
+       err = lua_pcall(ws->state, 1, 0, 0);
+       if (err != 0) {
+               lua_cry(conn, err, ws->state, ws->script, "close handler");
+       }
+       for (i = 0; i < ws->references; i++) {
+               if (ws->conn[i] == conn) {
+                       ws->references--;
+                       ws->conn[i] = ws->conn[ws->references];
+               }
+       }
+       /* TODO: Delete lua_websock_data and remove it from the websocket list.
+          This must only be done, when all connections are closed, and all
+          asynchronous operations and timers are completed/expired. */
+       (void)shared_websock_list; /* shared_websock_list unused (see open 
TODO) */
+
+       (void)pthread_mutex_unlock(&(ws->ws_mutex));
+}
+#endif
+
+
+lua_State *
+mg_prepare_lua_context_script(const char *file_name,
+                              struct mg_context *ctx,
+                              char *ebuf,
+                              size_t ebuf_len)
+{
+       struct lua_State *L;
+       int lua_ret;
+       const char *lua_err_txt;
+
+       L = luaL_newstate();
+       if (L == NULL) {
+               mg_snprintf(NULL,
+                           NULL, /* No truncation check for ebuf */
+                           ebuf,
+                           ebuf_len,
+                           "Error: %s",
+                           "Cannot create Lua state");
+               return 0;
+       }
+       civetweb_open_lua_libs(L);
+
+       lua_ret = luaL_loadfile(L, file_name);
+       if (lua_ret != LUA_OK) {
+               /* Error when loading the file (e.g. file not found, out of 
memory, ...)
+                */
+               lua_err_txt = lua_tostring(L, -1);
+               mg_snprintf(NULL,
+                           NULL, /* No truncation check for ebuf */
+                           ebuf,
+                           ebuf_len,
+                           "Error loading file %s: %s\n",
+                           file_name,
+                           lua_err_txt);
+               return 0;
+       }
+
+       /* The script file is loaded, now call it */
+       lua_ret = lua_pcall(L,
+                           /* no arguments */ 0,
+                           /* zero or one return value */ 1,
+                           /* errors as strint return value */ 0);
+
+       if (lua_ret != LUA_OK) {
+               /* Error when executing the script */
+               lua_err_txt = lua_tostring(L, -1);
+               mg_snprintf(NULL,
+                           NULL, /* No truncation check for ebuf */
+                           ebuf,
+                           ebuf_len,
+                           "Error running file %s: %s\n",
+                           file_name,
+                           lua_err_txt);
+               return 0;
+       }
+       /*      lua_close(L); must be done somewhere else */
+
+       return L;
+}
+
+
+int
+run_lua(const char *file_name)
+{
+       int func_ret = EXIT_FAILURE;
+       char ebuf[512] = {0};
+       lua_State *L =
+           mg_prepare_lua_context_script(file_name, NULL, ebuf, sizeof(ebuf));
+       if (L) {
+               /* Script executed */
+               if (lua_type(L, -1) == LUA_TNUMBER) {
+                       func_ret = (int)lua_tonumber(L, -1);
+               } else {
+                       func_ret = EXIT_SUCCESS;
+               }
+               lua_close(L);
+       } else {
+               fprintf(stderr, "%s\n", ebuf);
+       }
+       return func_ret;
+}
+
+
+static void *lib_handle_uuid = NULL;
+
+static void
+lua_init_optional_libraries(void)
+{
+#if !defined(_WIN32)
+       lib_handle_uuid = dlopen("libuuid.so", RTLD_LAZY);
+       pf_uuid_generate.p = dlsym(lib_handle_uuid, "uuid_generate");
+#else
+       pf_uuid_generate.p = 0;
+#endif
+}
+
+
+static void
+lua_exit_optional_libraries(void)
+{
+#if !defined(_WIN32)
+       dlclose(lib_handle_uuid);
+#endif
+       pf_uuid_generate.p = 0;
+       lib_handle_uuid = NULL;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/sha1.inl
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.9.1/src/sha1.inl 
b/thirdparty/civetweb-1.9.1/src/sha1.inl
new file mode 100644
index 0000000..a629c2f
--- /dev/null
+++ b/thirdparty/civetweb-1.9.1/src/sha1.inl
@@ -0,0 +1,323 @@
+/*
+SHA-1 in C
+By Steve Reid <[email protected]>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <[email protected]>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+    void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+    void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <[email protected]>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from [email protected] to [email protected]
+
+-----------------
+Modified 4/01
+By Saul Kravitz <[email protected]>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 07/2002
+By Ralph Giles <[email protected]>
+Still 100% public domain
+modified for use with stdint types, autoconf
+code cleanup, removed attribution comments
+switched SHA1Final() argument order for consistency
+use SHA1_ prefix for public api
+move public api to sha1.h
+*/
+
+/*
+11/2016 adapted for CivetWeb:
+  include sha1.h in sha1.c,
+  rename to sha1.inl
+  remove unused #ifdef sections
+  make endian independent
+  align buffer to 4 bytes
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include <string.h>
+#include <stdint.h>
+
+typedef struct {
+       uint32_t state[5];
+       uint32_t count[2];
+       uint8_t buffer[64];
+} SHA1_CTX;
+
+#define SHA1_DIGEST_SIZE 20
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+
+
+typedef union {
+       uint8_t c[64];
+       uint32_t l[16];
+} CHAR64LONG16;
+
+
+static uint32_t
+blk0(CHAR64LONG16 *block, int i)
+{
+       static const uint32_t n = 1u;
+       if ((*((uint8_t *)(&n))) == 1) {
+               /* little endian / intel byte order */
+               block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
+                             | (rol(block->l[i], 8) & 0x00FF00FF);
+       }
+       return block->l[i];
+}
+
+#define blk(block, i)                                                          
\
+       (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 
15]   \
+                                   ^ block->l[(i + 2) & 15] ^ block->l[i & 
15],   \
+                               1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v, w, x, y, z, i)                                                   
\
+       z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5);     
   \
+       w = rol(w, 30);
+#define R1(v, w, x, y, z, i)                                                   
\
+       z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5);      
   \
+       w = rol(w, 30);
+#define R2(v, w, x, y, z, i)                                                   
\
+       z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5);              
   \
+       w = rol(w, 30);
+#define R3(v, w, x, y, z, i)                                                   
\
+       z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 
5);   \
+       w = rol(w, 30);
+#define R4(v, w, x, y, z, i)                                                   
\
+       z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5);              
   \
+       w = rol(w, 30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+static void
+SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
+{
+       uint32_t a, b, c, d, e;
+
+       /* Must use an aligned, read/write buffer */
+       CHAR64LONG16 block[1];
+       memcpy(block, buffer, sizeof(block));
+
+       /* Copy context->state[] to working vars */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+
+       /* 4 rounds of 20 operations each. Loop unrolled. */
+       R0(a, b, c, d, e, 0);
+       R0(e, a, b, c, d, 1);
+       R0(d, e, a, b, c, 2);
+       R0(c, d, e, a, b, 3);
+       R0(b, c, d, e, a, 4);
+       R0(a, b, c, d, e, 5);
+       R0(e, a, b, c, d, 6);
+       R0(d, e, a, b, c, 7);
+       R0(c, d, e, a, b, 8);
+       R0(b, c, d, e, a, 9);
+       R0(a, b, c, d, e, 10);
+       R0(e, a, b, c, d, 11);
+       R0(d, e, a, b, c, 12);
+       R0(c, d, e, a, b, 13);
+       R0(b, c, d, e, a, 14);
+       R0(a, b, c, d, e, 15);
+       R1(e, a, b, c, d, 16);
+       R1(d, e, a, b, c, 17);
+       R1(c, d, e, a, b, 18);
+       R1(b, c, d, e, a, 19);
+       R2(a, b, c, d, e, 20);
+       R2(e, a, b, c, d, 21);
+       R2(d, e, a, b, c, 22);
+       R2(c, d, e, a, b, 23);
+       R2(b, c, d, e, a, 24);
+       R2(a, b, c, d, e, 25);
+       R2(e, a, b, c, d, 26);
+       R2(d, e, a, b, c, 27);
+       R2(c, d, e, a, b, 28);
+       R2(b, c, d, e, a, 29);
+       R2(a, b, c, d, e, 30);
+       R2(e, a, b, c, d, 31);
+       R2(d, e, a, b, c, 32);
+       R2(c, d, e, a, b, 33);
+       R2(b, c, d, e, a, 34);
+       R2(a, b, c, d, e, 35);
+       R2(e, a, b, c, d, 36);
+       R2(d, e, a, b, c, 37);
+       R2(c, d, e, a, b, 38);
+       R2(b, c, d, e, a, 39);
+       R3(a, b, c, d, e, 40);
+       R3(e, a, b, c, d, 41);
+       R3(d, e, a, b, c, 42);
+       R3(c, d, e, a, b, 43);
+       R3(b, c, d, e, a, 44);
+       R3(a, b, c, d, e, 45);
+       R3(e, a, b, c, d, 46);
+       R3(d, e, a, b, c, 47);
+       R3(c, d, e, a, b, 48);
+       R3(b, c, d, e, a, 49);
+       R3(a, b, c, d, e, 50);
+       R3(e, a, b, c, d, 51);
+       R3(d, e, a, b, c, 52);
+       R3(c, d, e, a, b, 53);
+       R3(b, c, d, e, a, 54);
+       R3(a, b, c, d, e, 55);
+       R3(e, a, b, c, d, 56);
+       R3(d, e, a, b, c, 57);
+       R3(c, d, e, a, b, 58);
+       R3(b, c, d, e, a, 59);
+       R4(a, b, c, d, e, 60);
+       R4(e, a, b, c, d, 61);
+       R4(d, e, a, b, c, 62);
+       R4(c, d, e, a, b, 63);
+       R4(b, c, d, e, a, 64);
+       R4(a, b, c, d, e, 65);
+       R4(e, a, b, c, d, 66);
+       R4(d, e, a, b, c, 67);
+       R4(c, d, e, a, b, 68);
+       R4(b, c, d, e, a, 69);
+       R4(a, b, c, d, e, 70);
+       R4(e, a, b, c, d, 71);
+       R4(d, e, a, b, c, 72);
+       R4(c, d, e, a, b, 73);
+       R4(b, c, d, e, a, 74);
+       R4(a, b, c, d, e, 75);
+       R4(e, a, b, c, d, 76);
+       R4(d, e, a, b, c, 77);
+       R4(c, d, e, a, b, 78);
+       R4(b, c, d, e, a, 79);
+
+       /* Add the working vars back into context.state[] */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+
+       /* Wipe variables */
+       a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+SHA_API void
+SHA1_Init(SHA1_CTX *context)
+{
+       /* SHA1 initialization constants */
+       context->state[0] = 0x67452301;
+       context->state[1] = 0xEFCDAB89;
+       context->state[2] = 0x98BADCFE;
+       context->state[3] = 0x10325476;
+       context->state[4] = 0xC3D2E1F0;
+       context->count[0] = context->count[1] = 0;
+}
+
+
+SHA_API void
+SHA1_Update(SHA1_CTX *context, const uint8_t *data, const uint32_t len)
+{
+       uint32_t i, j;
+
+       j = context->count[0];
+       if ((context->count[0] += (len << 3)) < j) {
+               context->count[1]++;
+       }
+       context->count[1] += (len >> 29);
+       j = (j >> 3) & 63;
+       if ((j + len) > 63) {
+               i = 64 - j;
+               memcpy(&context->buffer[j], data, i);
+               SHA1_Transform(context->state, context->buffer);
+               for (; i + 63 < len; i += 64) {
+                       SHA1_Transform(context->state, &data[i]);
+               }
+               j = 0;
+       } else {
+               i = 0;
+       }
+       memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+SHA_API void
+SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE])
+{
+       uint32_t i;
+       uint8_t finalcount[8];
+
+       for (i = 0; i < 8; i++) {
+               finalcount[i] =
+                   (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 
3)) * 8))
+                             & 255); /* Endian independent */
+       }
+       SHA1_Update(context, (uint8_t *)"\x80", 1);
+       while ((context->count[0] & 504) != 448) {
+               SHA1_Update(context, (uint8_t *)"\x00", 1);
+       }
+       SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() 
*/
+       for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+               digest[i] =
+                   (uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 
255);
+       }
+
+       /* Wipe variables */
+       i = 0;
+       memset(context, '\0', sizeof(*context));
+       memset(&finalcount, '\0', sizeof(finalcount));
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua 
b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua
new file mode 100644
index 0000000..357be7e
--- /dev/null
+++ b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua
@@ -0,0 +1,116 @@
+local base = _G
+
+-- symbolic name for tag index, this allows accessing the tag by var[xml.TAG]
+xml.TAG = 0
+
+-- sets or returns tag of a LuaXML object
+function xml.tag(var,tag)
+       if base.type(var)~="table" then return end
+       if base.type(tag)=="nil" then 
+               return var[xml.TAG]
+       end
+       var[xml.TAG] = tag
+end
+
+-- creates a new LuaXML object either by setting the metatable of an existing 
Lua table or by setting its tag
+function xml.new(arg)
+       if base.type(arg)=="table" then 
+               base.setmetatable(arg,{__index=xml, __tostring=xml.str})
+               return arg
+       end
+       local var={}
+       base.setmetatable(var,{__index=xml, __tostring=xml.str})
+       if base.type(arg)=="string" then var[xml.TAG]=arg end
+       return var
+end
+
+-- appends a new subordinate LuaXML object to an existing one, optionally sets 
tag
+function xml.append(var,tag)
+       if base.type(var)~="table" then return end
+       local newVar = xml.new(tag)
+       var[#var+1] = newVar
+       return newVar
+end
+
+-- converts any Lua var into an XML string
+function xml.str(var,indent,tagValue)
+       if base.type(var)=="nil" then return end
+       local indent = indent or 0
+       local indentStr=""
+       for i = 1,indent do indentStr=indentStr.."      " end
+       local tableStr=""
+
+       if base.type(var)=="table" then
+               local tag = var[0] or tagValue or base.type(var)
+               local s = indentStr.."<"..tag
+               for k,v in base.pairs(var) do -- attributes 
+                       if base.type(k)=="string" then
+                               if base.type(v)=="table" and k~="_M" then -- 
otherwise recursiveness imminent
+                                       tableStr = 
tableStr..xml.str(v,indent+1,k)
+                               else
+                                       s = s.." 
"..k.."=\""..xml.encode(base.tostring(v)).."\""
+                               end
+                       end
+               end
+               if #var==0 and #tableStr==0 then
+                       s = s.." />\n"
+               elseif #var==1 and base.type(var[1])~="table" and #tableStr==0 
then -- single element
+                       s = 
s..">"..xml.encode(base.tostring(var[1])).."</"..tag..">\n"
+               else
+                       s = s..">\n"
+                       for k,v in base.ipairs(var) do -- elements
+                               if base.type(v)=="string" then
+                                       s = s..indentStr.."     
"..xml.encode(v).." \n"
+                               else
+                                       s = s..xml.str(v,indent+1)
+                               end
+                       end
+                       s=s..tableStr..indentStr.."</"..tag..">\n"
+               end
+               return s
+       else
+               local tag = base.type(var)
+               return indentStr.."<"..tag.."> 
"..xml.encode(base.tostring(var)).." </"..tag..">\n"
+       end
+end
+
+
+-- saves a Lua var as xml file
+function xml.save(var,filename)
+       if not var then return end
+       if not filename or #filename==0 then return end
+       local file = base.io.open(filename,"w")
+       file:write("<?xml version=\"1.0\"?>\n<!-- file \"",filename, "\", 
generated by LuaXML -->\n\n")
+       file:write(xml.str(var))
+       base.io.close(file)
+end
+
+
+-- recursively parses a Lua table for a substatement fitting to the provided 
tag and attribute
+function xml.find(var, tag, attributeKey,attributeValue)
+       -- check input:
+       if base.type(var)~="table" then return end
+       if base.type(tag)=="string" and #tag==0 then tag=nil end
+       if base.type(attributeKey)~="string" or #attributeKey==0 then 
attributeKey=nil end
+       if base.type(attributeValue)=="string" and #attributeValue==0 then 
attributeValue=nil end
+       -- compare this table:
+       if tag~=nil then
+               if var[0]==tag and ( attributeValue == nil or 
var[attributeKey]==attributeValue ) then
+                       base.setmetatable(var,{__index=xml, __tostring=xml.str})
+                       return var
+               end
+       else
+               if attributeValue == nil or var[attributeKey]==attributeValue 
then
+                       base.setmetatable(var,{__index=xml, __tostring=xml.str})
+                       return var
+               end
+       end
+       -- recursively parse subtags:
+       for k,v in base.ipairs(var) do
+               if base.type(v)=="table" then
+                       local ret = xml.find(v, tag, 
attributeKey,attributeValue)
+                       if ret ~= nil then return ret end
+               end
+       end
+end
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c 
b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c
new file mode 100644
index 0000000..9ac7f9f
--- /dev/null
+++ b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c
@@ -0,0 +1,476 @@
+/**
+LuaXML License
+
+LuaXml is licensed under the terms of the MIT license reproduced below,
+the same as Lua itself. This means that LuaXml is free software and can be
+used for both academic and commercial purposes at absolutely no cost.
+
+Copyright (C) 2007-2013 Gerald Franz, eludi.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#if defined __WIN32__ || defined WIN32
+# include <windows.h>
+# define _EXPORT __declspec(dllexport)
+#else
+# define _EXPORT
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "civetweb_lua.h"
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+static const char ESC=27;
+static const char OPN=28;
+static const char CLS=29;
+
+//--- auxliary functions -------------------------------------------
+
+static const char* char2code(unsigned char ch, char buf[8]) {
+    unsigned char i=0;
+    buf[i++]='&';
+    buf[i++]='#';
+    if(ch>99) buf[i++]=ch/100+48;
+    if(ch>9) buf[i++]=(ch%100)/10+48;
+    buf[i++]=ch%10+48;
+    buf[i++]=';';
+    buf[i]=0;
+    return buf;
+}
+
+static size_t find(const char* s, const char* pattern, size_t start) {
+    const char* found =strstr(s+start, pattern);
+    return found ? found-s : strlen(s);
+}
+
+//--- internal tokenizer -------------------------------------------
+
+typedef struct Tokenizer_s  {
+    /// stores string to be tokenized
+    const char* s;
+    /// stores size of string to be tokenized
+    size_t s_size;
+    /// stores current read position
+    size_t i;
+    /// stores current read context
+    int tagMode;
+    /// stores next token, if already determined
+    const char* m_next;
+    /// size of next token
+    size_t m_next_size;
+    /// pointer to current token
+    char* m_token;
+    /// size of current token
+    size_t m_token_size;
+    /// capacity of current token
+    size_t m_token_capacity;
+} Tokenizer;
+
+Tokenizer* Tokenizer_new(const char* str, size_t str_size) {
+    Tokenizer *tok = (Tokenizer*)malloc(sizeof(Tokenizer));
+    memset(tok, 0, sizeof(Tokenizer));
+    tok->s_size = str_size;
+    tok->s = str;
+    return tok;
+}
+
+void Tokenizer_delete(Tokenizer* tok) {
+    free(tok->m_token);
+    free(tok);
+}
+
+//void Tokenizer_print(Tokenizer* tok) { printf("  @%u %s\n", tok->i, 
!tok->m_token ? "(null)" : (tok->m_token[0]==ESC)?"(esc)" : 
(tok->m_token[0]==OPN)?"(open)": (tok->m_token[0]==CLS)?"(close)" : 
tok->m_token); fflush(stdout); }
+
+static const char* Tokenizer_set(Tokenizer* tok, const char* s, size_t size) {
+    if(!size||!s) return 0;
+    free(tok->m_token);
+    tok->m_token = (char*)malloc(size+1);
+    strncpy(tok->m_token,s, size);
+    tok->m_token[size] = 0;
+    tok->m_token_size = tok->m_token_capacity = size;
+    //Tokenizer_print(tok);
+    return tok->m_token;
+}
+
+static void Tokenizer_append(Tokenizer* tok, char ch) {
+    if(tok->m_token_size+1>=tok->m_token_capacity) {
+        tok->m_token_capacity = (tok->m_token_capacity==0) ? 16 : 
tok->m_token_capacity*2;
+        tok->m_token = (char*)realloc(tok->m_token, tok->m_token_capacity);
+    }
+    tok->m_token[tok->m_token_size]=ch;
+    tok->m_token[++tok->m_token_size]=0;
+}
+
+const char* Tokenizer_next(Tokenizer* tok) {
+    const char* ESC_str = "\033";
+    const char* OPEN_str = "\034";
+    const char* CLOSE_str = "\035";
+    int quotMode=0;
+    int tokenComplete = 0;
+
+    if(tok->m_token) {
+        free(tok->m_token);
+        tok->m_token = 0;
+        tok->m_token_size=tok->m_token_capacity = 0;
+    }
+
+    while(tok->m_next_size || (tok->i < tok->s_size)) {
+
+        if(tok->m_next_size) {
+            Tokenizer_set(tok, tok->m_next, tok->m_next_size);
+            tok->m_next=0;
+            tok->m_next_size=0;
+            return tok->m_token;
+        }
+
+        switch(tok->s[tok->i]) {
+            case '"':
+            case '\'':
+            if(tok->tagMode) {
+                if(!quotMode) quotMode=tok->s[tok->i];
+                else if(quotMode==tok->s[tok->i]) quotMode=0;
+            }
+            Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+            case '<':
+            
if(!quotMode&&(tok->i+4<tok->s_size)&&(strncmp(tok->s+tok->i,"<!--",4)==0)) // 
strip comments
+                tok->i=find(tok->s, "-->", tok->i+4)+2;
+            else 
if(!quotMode&&(tok->i+9<tok->s_size)&&(strncmp(tok->s+tok->i,"<![CDATA[",9)==0))
 { // interpet CDATA
+                size_t b=tok->i+9;
+                tok->i=find(tok->s, "]]>",b)+3;
+                if(!tok->m_token_size) return Tokenizer_set(tok, tok->s+b, 
tok->i-b-3);
+                tokenComplete = 1;
+                tok->m_next = tok->s+b;
+                tok->m_next_size = tok->i-b-3;
+                --tok->i;
+            }
+            else 
if(!quotMode&&(tok->i+1<tok->s_size)&&((tok->s[tok->i+1]=='?')||(tok->s[tok->i+1]=='!')))
 // strip meta information
+                tok->i=find(tok->s, ">", tok->i+2);
+            else if(!quotMode&&!tok->tagMode) {
+                if((tok->i+1<tok->s_size)&&(tok->s[tok->i+1]=='/')) {
+                    tok->m_next=ESC_str;
+                    tok->m_next_size = 1;
+                    tok->i=find(tok->s, ">", tok->i+2);
+                }
+                else {
+                    tok->m_next = OPEN_str;
+                    tok->m_next_size = 1;
+                    tok->tagMode=1;
+                }
+                tokenComplete = 1;
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+            case '/':
+            if(tok->tagMode&&!quotMode) {
+                tokenComplete = 1;
+                if((tok->i+1 < tok->s_size) && (tok->s[tok->i+1]=='>')) {
+                    tok->tagMode=0;
+                    tok->m_next=ESC_str;
+                    tok->m_next_size = 1;
+                    ++tok->i;
+                }
+                else Tokenizer_append(tok, tok->s[tok->i]);
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+            case '>':
+            if(!quotMode&&tok->tagMode) {
+                tok->tagMode=0;
+                tokenComplete = 1;
+                tok->m_next = CLOSE_str;
+                tok->m_next_size = 1;
+            }
+            else Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+            case ' ':
+            case '\r':
+            case '\n':
+            case '\t':
+            if(tok->tagMode&&!quotMode) {
+                if(tok->m_token_size) tokenComplete=1;
+            }
+            else if(tok->m_token_size) Tokenizer_append(tok, tok->s[tok->i]);
+            break;
+            default: Tokenizer_append(tok, tok->s[tok->i]);
+        }
+        ++tok->i;
+        if((tok->i>=tok->s_size)||(tokenComplete&&tok->m_token_size)) {
+            tokenComplete=0;
+            
while(tok->m_token_size&&isspace(tok->m_token[tok->m_token_size-1])) // trim 
whitespace
+                tok->m_token[--tok->m_token_size]=0;
+            if(tok->m_token_size) break;
+        }
+    }
+    //Tokenizer_print(tok);
+    return tok->m_token;
+}
+
+//--- local variables ----------------------------------------------
+
+/// stores number of special character codes
+static size_t sv_code_size=0;
+/// stores currently allocated capacity for special character codes
+static size_t sv_code_capacity=16;
+/// stores code table for special characters
+static char** sv_code=0;
+
+//--- public methods -----------------------------------------------
+
+static void Xml_pushDecode(lua_State* L, const char* s, size_t s_size) {
+
+    luaL_Buffer b;
+    const char* found = strstr(s, "&#");
+    size_t start=0, pos, i;
+
+    if(!s_size)
+        s_size=strlen(s);
+
+    luaL_buffinit(L, &b);
+    found = strstr(s, "&#");
+    pos = found ? found-s : s_size;
+
+    while(found) {
+        char ch = 0;
+        size_t i=0;
+        for(found += 2; i<3; ++i, ++found)
+            if(isdigit(*found))
+                ch = ch * 10 + (*found - 48);
+            else break;
+        if(*found == ';') {
+            if(pos>start)
+                luaL_addlstring(&b, s+start, pos-start);
+            luaL_addchar(&b, ch);
+            start = pos + 3 + i;
+        }
+        found = strstr(found+1, "&#");
+        pos = found ? found-s : s_size;
+    }
+    if(pos>start)
+        luaL_addlstring(&b,s+start, pos-start);
+    luaL_pushresult(&b);
+
+    for(i=sv_code_size-1; i<sv_code_size; i-=2) {
+        luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i-1]);
+        lua_remove(L,-2);
+    }
+}
+
+int Xml_eval(lua_State *L) {
+    char* str = 0;
+    size_t str_size=0;
+    Tokenizer* tok;
+    const char* token=0;
+    int firstStatement = 1;
+
+    if(lua_isuserdata(L,1))
+        str = (char*)lua_touserdata(L,1);
+    else {
+        const char * sTmp = luaL_checklstring(L,1,&str_size);
+        str = (char*)malloc(str_size+1);
+        memcpy(str, sTmp, str_size);
+        str[str_size]=0;
+    }
+    tok = Tokenizer_new(str, str_size ? str_size : strlen(str));
+    lua_settop(L,0);
+
+    while((token=Tokenizer_next(tok))!=0) if(token[0]==OPN) { // new tag found
+        if(lua_gettop(L)) {
+            size_t newIndex=lua_rawlen(L,-1)+1;
+            lua_pushnumber(L, (lua_Number)newIndex);
+            lua_newtable(L);
+            lua_settable(L, -3);
+            lua_pushnumber(L, (lua_Number)newIndex);
+            lua_gettable(L,-2);
+        }
+        else {
+            if (firstStatement) {
+                lua_newtable(L);
+                firstStatement = 0;
+            }
+            else return lua_gettop(L);
+        }
+        // set metatable:
+        lua_newtable(L);
+        lua_pushliteral(L, "__index");
+        lua_getglobal(L, "xml");
+        lua_settable(L, -3);
+
+        lua_pushliteral(L, "__tostring"); // set __tostring metamethod
+        lua_getglobal(L, "xml");
+        lua_pushliteral(L,"str");
+        lua_gettable(L, -2);
+        lua_remove(L, -2);
+        lua_settable(L, -3);
+        lua_setmetatable(L, -2);
+
+        // parse tag and content:
+        lua_pushnumber(L,0); // use index 0 for storing the tag
+        lua_pushstring(L, Tokenizer_next(tok));
+        lua_settable(L, -3);
+
+        while(((token = 
Tokenizer_next(tok))!=0)&&(token[0]!=CLS)&&(token[0]!=ESC)) { // parse tag 
header
+            size_t sepPos=find(token, "=", 0);
+            if(token[sepPos]) { // regular attribute
+                const char* aVal =token+sepPos+2;
+                size_t lenVal;
+
+                lua_pushlstring(L, token, sepPos);
+                lenVal = strlen(aVal)-1;
+                if(!lenVal) Xml_pushDecode(L, "", 0);
+                else Xml_pushDecode(L, aVal, lenVal);
+                lua_settable(L, -3);
+            }
+        }
+        if(!token||(token[0]==ESC)) {
+            if(lua_gettop(L)>1) lua_settop(L,-2); // this tag has no content, 
only attributes
+            else break;
+        }
+    }
+    else if(token[0]==ESC) { // previous tag is over
+        if(lua_gettop(L)>1) lua_settop(L,-2); // pop current table
+        else break;
+    }
+    else { // read elements
+        lua_pushnumber(L,(lua_Number)lua_rawlen(L,-1)+1);
+        Xml_pushDecode(L, token, 0);
+        lua_settable(L, -3);
+    }
+    Tokenizer_delete(tok);
+    free(str);
+    return lua_gettop(L);
+}
+
+int Xml_load (lua_State *L) {
+    const char * filename = luaL_checkstring(L,1);
+    FILE * file=fopen(filename,"r");
+    char* buffer;
+    size_t sz;
+
+    if(!file)
+        return luaL_error(L,"LuaXml ERROR: \"%s\" file error or file not 
found!",filename);
+
+    fseek (file , 0 , SEEK_END);
+    sz = ftell (file);
+    rewind (file);
+    buffer = (char*)malloc(sz+1);
+    sz = fread (buffer,1,sz,file);
+    fclose(file);
+    buffer[sz]=0;
+    lua_pushlightuserdata(L,buffer);
+    lua_replace(L,1);
+    return Xml_eval(L);
+};
+
+int Xml_registerCode(lua_State *L) {
+    const char * decoded = luaL_checkstring(L,1);
+    const char * encoded = luaL_checkstring(L,2);
+
+    size_t i;
+    for(i=0; i<sv_code_size; i+=2)
+        if(strcmp(sv_code[i],decoded)==0)
+            return luaL_error(L,"LuaXml ERROR: code already exists.");
+    if(sv_code_size+2>sv_code_capacity) {
+        sv_code_capacity*=2;
+        sv_code = (char**)realloc(sv_code, sv_code_capacity*sizeof(char*));
+    }
+    sv_code[sv_code_size]=(char*)malloc(strlen(decoded)+1);
+    strcpy(sv_code[sv_code_size++], decoded);
+    sv_code[sv_code_size]=(char*)malloc(strlen(encoded)+1);
+    strcpy(sv_code[sv_code_size++],encoded);
+    return 0;
+}
+
+int Xml_encode(lua_State *L) {
+
+    char buf[8];
+    size_t start, pos;
+    luaL_Buffer b;
+    const char* s;
+    size_t i;
+
+    if(lua_gettop(L)!=1)
+        return 0;
+    luaL_checkstring(L,-1);
+
+    for(i=0; i<sv_code_size; i+=2) {
+        luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i+1]);
+        lua_remove(L,-2);
+    }
+    s=lua_tostring(L,1);
+    luaL_buffinit(L, &b);
+    for(start=pos=0; s[pos]!=0; ++pos) if(s[pos]<0) {
+        if(pos>start) luaL_addlstring(&b,s+start, pos-start);
+        luaL_addstring(&b,char2code((unsigned char)(s[pos]),buf));
+        start=pos+1;
+    }
+    if(pos>start)
+        luaL_addlstring(&b,s+start, pos-start);
+    luaL_pushresult(&b);
+    lua_remove(L,-2);
+    return 1;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int _EXPORT luaopen_LuaXML_lib (lua_State* L) {
+    static const struct luaL_Reg funcs[] = {
+        {"load", Xml_load},
+        {"eval", Xml_eval},
+        {"encode", Xml_encode},
+        {"registerCode", Xml_registerCode},
+        {NULL, NULL}
+    };
+
+    luaL_newlibtable(L, funcs);
+    luaL_setfuncs(L, funcs, 0);
+    lua_setglobal(L, "xml");
+
+    // register default codes:
+    if(!sv_code) {
+        sv_code=(char**)malloc(sv_code_capacity*sizeof(char*));
+        sv_code[sv_code_size++]="&";
+        sv_code[sv_code_size++]="&amp;";
+        sv_code[sv_code_size++]="<";
+        sv_code[sv_code_size++]="&lt;";
+        sv_code[sv_code_size++]=">";
+        sv_code[sv_code_size++]="&gt;";
+        sv_code[sv_code_size++]="\"";
+        sv_code[sv_code_size++]="&quot;";
+        sv_code[sv_code_size++]="'";
+        sv_code[sv_code_size++]="&apos;";
+    }
+    return 1;
+}
+#ifdef __cplusplus
+} // extern "C"
+#endif

Reply via email to