1/* This file is part of the CivetWeb web server.
2 * See https://github.com/civetweb/civetweb/
3 */
4
5#if !defined(_WIN32)
6#include <dlfcn.h>
7#include <sys/mman.h>
8#endif
9
10#include "civetweb_lua.h"
11#include "civetweb_private_lua.h"
12
13
14#if defined(_WIN32)
15static void *
16mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
17{
18	/* TODO (low): This is an incomplete implementation of mmap for windows.
19	 * Currently it is sufficient, but there are a lot of unused parameters.
20	 * Better use a function "mg_map" which only has the required parameters,
21	 * and implement it using mmap in Linux and CreateFileMapping in Windows.
22	 * No one should expect a full mmap for Windows here.
23	 */
24	HANDLE fh = (HANDLE)_get_osfhandle(fd);
25	HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
26	void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
27	CloseHandle(mh);
28
29	/* unused parameters */
30	(void)addr;
31	(void)prot;
32	(void)flags;
33	(void)offset;
34
35	return p;
36}
37
38
39static void
40munmap(void *addr, int64_t length)
41{
42	/* unused parameters */
43	(void)length;
44
45	UnmapViewOfFile(addr);
46}
47
48
49#define MAP_PRIVATE (0)
50#define PROT_READ (0)
51#endif
52
53
54static const char *const LUASOCKET = "luasocket";
55static const char lua_regkey_ctx = 1;
56static const char lua_regkey_connlist = 2;
57static const char lua_regkey_lsp_include_history = 3;
58static const char lua_regkey_environment_type = 4;
59static const char lua_regkey_dtor = 5;
60
61
62/* Limit nesting depth of mg.include.
63 * This takes a lot of stack (~10 kB per recursion),
64 * so do not use a too high limit. */
65#if !defined(LSP_INCLUDE_MAX_DEPTH)
66#define LSP_INCLUDE_MAX_DEPTH (10)
67#endif
68
69
70/* Forward declarations */
71static int handle_lsp_request(struct mg_connection *,
72                              const char *,
73                              struct mg_file *,
74                              struct lua_State *);
75
76
77static void
78reg_lstring(struct lua_State *L,
79            const char *name,
80            const void *buffer,
81            size_t buflen)
82{
83	if (name != NULL && buffer != NULL) {
84		lua_pushstring(L, name);
85		lua_pushlstring(L, (const char *)buffer, buflen);
86		lua_rawset(L, -3);
87	}
88}
89
90
91static void
92reg_llstring(struct lua_State *L,
93             const void *buffer1,
94             size_t buflen1,
95             const void *buffer2,
96             size_t buflen2)
97{
98	if (buffer1 != NULL && buffer2 != NULL) {
99		lua_pushlstring(L, (const char *)buffer1, buflen1);
100		lua_pushlstring(L, (const char *)buffer2, buflen2);
101		lua_rawset(L, -3);
102	}
103}
104
105
106#define reg_string(L, name, val)                                               \
107	reg_lstring(L, name, val, (val != NULL) ? strlen(val) : 0)
108
109
110static void
111reg_int(struct lua_State *L, const char *name, int val)
112{
113	if (name != NULL) {
114		lua_pushstring(L, name);
115		lua_pushinteger(L, val);
116		lua_rawset(L, -3);
117	}
118}
119
120
121static void
122reg_i64(struct lua_State *L, const char *name, int64_t val)
123{
124	if (name == NULL) {
125		return;
126	}
127	lua_pushstring(L, name);
128	if (sizeof(lua_Integer) >= sizeof(val)) {
129		lua_pushinteger(L, (lua_Integer)val);
130	} else {
131		double d = (double)val;
132		lua_pushnumber(L, d);
133	}
134	lua_rawset(L, -3);
135}
136
137
138static void
139reg_double(struct lua_State *L, const char *name, double val)
140{
141	if (name != NULL) {
142		lua_pushstring(L, name);
143		lua_pushnumber(L, val);
144		lua_rawset(L, -3);
145	}
146}
147
148
149static void
150reg_boolean(struct lua_State *L, const char *name, int val)
151{
152	if (name != NULL) {
153		lua_pushstring(L, name);
154		lua_pushboolean(L, val != 0);
155		lua_rawset(L, -3);
156	}
157}
158
159
160static void
161reg_conn_function(struct lua_State *L,
162                  const char *name,
163                  lua_CFunction func,
164                  struct mg_connection *conn)
165{
166	if (name != NULL && func != NULL && conn != NULL) {
167		lua_pushstring(L, name);
168		lua_pushlightuserdata(L, conn);
169		lua_pushcclosure(L, func, 1);
170		lua_rawset(L, -3);
171	}
172}
173
174
175static void
176reg_function(struct lua_State *L, const char *name, lua_CFunction func)
177{
178	if (name != NULL && func != NULL) {
179		lua_pushstring(L, name);
180		lua_pushcclosure(L, func, 0);
181		lua_rawset(L, -3);
182	}
183}
184
185
186static void
187lua_cry(const struct mg_connection *conn,
188        int err,
189        lua_State *L,
190        const char *lua_title,
191        const char *lua_operation)
192{
193	DEBUG_TRACE("lua_cry (err=%i): %s: %s", err, lua_title, lua_operation);
194
195	switch (err) {
196	case LUA_OK:
197	case LUA_YIELD:
198		break;
199	case LUA_ERRRUN:
200		mg_cry_internal(conn,
201		                "%s: %s failed: runtime error: %s",
202		                lua_title,
203		                lua_operation,
204		                lua_tostring(L, -1));
205		break;
206	case LUA_ERRSYNTAX:
207		mg_cry_internal(conn,
208		                "%s: %s failed: syntax error: %s",
209		                lua_title,
210		                lua_operation,
211		                lua_tostring(L, -1));
212		break;
213	case LUA_ERRMEM:
214		mg_cry_internal(conn,
215		                "%s: %s failed: out of memory",
216		                lua_title,
217		                lua_operation);
218		break;
219#if LUA_VERSION_NUM < 504
220	/* LUA_ERRGCMM has been removed in Lua 5.4.
221	 * See https://www.lua.org/manual/5.4/manual.html#8.3 */
222	case LUA_ERRGCMM:
223		mg_cry_internal(conn,
224		                "%s: %s failed: error during garbage collection",
225		                lua_title,
226		                lua_operation);
227		break;
228#endif
229	case LUA_ERRERR:
230		mg_cry_internal(conn,
231		                "%s: %s failed: error in error handling: %s",
232		                lua_title,
233		                lua_operation,
234		                lua_tostring(L, -1));
235		break;
236	default:
237		mg_cry_internal(
238		    conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
239		break;
240	}
241}
242
243
244static int
245lsp_sock_close(lua_State *L)
246{
247	int num_args = lua_gettop(L);
248	size_t s;
249	SOCKET *psock;
250
251	if ((num_args == 1) && lua_istable(L, 1)) {
252		lua_getfield(L, -1, "sock");
253		psock = (SOCKET *)lua_tolstring(L, -1, &s);
254		if (s != sizeof(SOCKET)) {
255			return luaL_error(L, "invalid internal state in :close() call");
256		}
257		/* Do not closesocket(*psock); here, close it in __gc */
258		(void)psock;
259	} else {
260		return luaL_error(L, "invalid :close() call");
261	}
262	return 0;
263}
264
265
266static int
267lsp_sock_recv(lua_State *L)
268{
269	int num_args = lua_gettop(L);
270	char buf[2000];
271	int n;
272	size_t s;
273	SOCKET *psock;
274
275	if ((num_args == 1) && lua_istable(L, 1)) {
276		lua_getfield(L, -1, "sock");
277		psock = (SOCKET *)lua_tolstring(L, -1, &s);
278		if (s != sizeof(SOCKET)) {
279			return luaL_error(L, "invalid internal state in :recv() call");
280		}
281		n = recv(*psock, buf, sizeof(buf), 0);
282		if (n <= 0) {
283			lua_pushnil(L);
284		} else {
285			lua_pushlstring(L, buf, n);
286		}
287	} else {
288		return luaL_error(L, "invalid :recv() call");
289	}
290	return 1;
291}
292
293
294static int
295lsp_sock_send(lua_State *L)
296{
297	int num_args = lua_gettop(L);
298	const char *buf;
299	size_t len, sent = 0;
300	int n = 0;
301	size_t s;
302	SOCKET *psock;
303
304	if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
305		buf = lua_tolstring(L, -1, &len);
306		lua_getfield(L, -2, "sock");
307		psock = (SOCKET *)lua_tolstring(L, -1, &s);
308		if (s != sizeof(SOCKET)) {
309			return luaL_error(L, "invalid internal state in :close() call");
310		}
311
312		while (sent < len) {
313			if ((n = send(*psock, buf + sent, (int)(len - sent), 0)) <= 0) {
314				break;
315			}
316			sent += n;
317		}
318		lua_pushnumber(L, n);
319	} else {
320		return luaL_error(L, "invalid :close() call");
321	}
322	return 1;
323}
324
325
326static int
327lsp_sock_gc(lua_State *L)
328{
329	int num_args = lua_gettop(L);
330	size_t s;
331	SOCKET *psock;
332
333	if ((num_args == 1) && lua_istable(L, 1)) {
334		lua_getfield(L, -1, "sock");
335		psock = (SOCKET *)lua_tolstring(L, 1, &s);
336		if (s != sizeof(SOCKET)) {
337			return luaL_error(
338			    L,
339			    "invalid internal state in __gc for object created by connect");
340		}
341		closesocket(*psock);
342	} else {
343		return luaL_error(L, "__gc for object created by connect failed");
344	}
345	return 0;
346}
347
348
349/* Methods and meta-methods supported by the object returned by connect.
350 * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
351static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
352                                                    {"send", lsp_sock_send},
353                                                    {"recv", lsp_sock_recv},
354                                                    {"__gc", lsp_sock_gc},
355                                                    {NULL, NULL}};
356
357
358static int
359lsp_connect(lua_State *L)
360{
361	int num_args = lua_gettop(L);
362	char ebuf[100];
363	SOCKET sock;
364	union usa sa;
365	int ok;
366
367	if ((num_args == 3) && lua_isstring(L, 1) && lua_isnumber(L, 2)
368	    && lua_isnumber(L, 3)) {
369
370		const char *host = lua_tostring(L, 1);
371		const int port = lua_tointeger(L, 2);
372		const int is_ssl = lua_tointeger(L, 3);
373
374		ok = connect_socket(
375		    NULL, host, port, is_ssl, ebuf, sizeof(ebuf), &sock, &sa);
376		if (!ok) {
377			return luaL_error(L, ebuf);
378		} else {
379			set_blocking_mode(sock);
380			lua_newtable(L);
381			reg_lstring(L, "sock", (const char *)&sock, sizeof(SOCKET));
382			reg_string(L, "host", lua_tostring(L, -4));
383			luaL_getmetatable(L, LUASOCKET);
384			lua_setmetatable(L, -2);
385		}
386	} else {
387		return luaL_error(
388		    L, "connect(host,port,is_ssl): invalid parameter given.");
389	}
390	return 1;
391}
392
393
394static int
395lsp_error(lua_State *L)
396{
397	DEBUG_TRACE("%s", "lsp_error");
398	lua_getglobal(L, "mg");
399	lua_getfield(L, -1, "onerror");
400	lua_pushvalue(L, -3);
401	lua_pcall(L, 1, 0, 0);
402	return 0;
403}
404
405
406/* Silently stop processing chunks. */
407static void
408lsp_abort(lua_State *L)
409{
410	int top = lua_gettop(L);
411	DEBUG_TRACE("%s", "lsp_abort");
412	lua_getglobal(L, "mg");
413	lua_pushnil(L);
414	lua_setfield(L, -2, "onerror");
415	lua_settop(L, top);
416	lua_pushstring(L, "aborting");
417	lua_error(L);
418}
419
420
421struct lsp_var_reader_data {
422	int64_t len;
423	int64_t consumed;
424	const char *begin;
425	unsigned char state;
426	char tag;
427};
428
429
430/* Helper function to read the content of variable values */
431static const char *
432lsp_var_reader(lua_State *L, void *ud, size_t *sz)
433{
434	struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
435	const char *ret;
436	(void)(L); /* unused */
437
438	/* This reader is called multiple times, to fetch the full Lua script */
439	switch (reader->state) {
440	case 0:
441		/* First call: what function to call */
442		reader->consumed = 0;
443		ret = "mg.write(";
444		*sz = strlen(ret);
445		break;
446	case 1:
447		/* Second call: forward variable name */
448		ret = reader->begin;
449		*sz = (size_t)reader->len;
450		reader->consumed += reader->len;
451		break;
452	case 2:
453		/* Third call: close function call */
454		ret = ")";
455		*sz = strlen(ret);
456		break;
457	default:
458		/* Forth/Final call: tell Lua we got the entire script */
459		ret = 0;
460		*sz = 0;
461	}
462
463	/* Step to the next state for the next call */
464	reader->state++;
465	return ret;
466}
467
468
469static const char *
470lsp_kepler_reader(lua_State *L, void *ud, size_t *sz)
471{
472	struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
473	const char *ret;
474	int64_t i;
475	int64_t left;
476
477	(void)(L); /* unused */
478
479	/* This reader is called multiple times, to fetch the full Lua script */
480
481	if (reader->state == 0) {
482		/* First call: Send opening tag - what function to call */
483		ret = "mg.write([=======[";
484		*sz = strlen(ret);
485		reader->state = 1;
486		reader->consumed = 0;
487		return ret;
488	}
489
490	if (reader->state == 4) {
491		/* Final call: Tell Lua reader, we reached the end */
492		*sz = 0;
493		return 0;
494	}
495
496	left = reader->len - reader->consumed;
497	if (left == 0) {
498		/* We reached the end of the file/available data. */
499		/* Send closing tag. */
500		ret = "]=======]);\n";
501		*sz = strlen(ret);
502		reader->state = 4; /* Next will be the final call */
503		return ret;
504	}
505	if (left > MG_BUF_LEN / 100) {
506		left = MG_BUF_LEN / 100; /* TODO XXX */
507	}
508	i = 0;
509
510	if (reader->state == 1) {
511		/* State 1: plain text - put inside mg.write(...) */
512		for (;;) {
513			/* Find next tag */
514			while ((i < left) && (reader->begin[i + reader->consumed] != '<')) {
515				i++;
516			}
517			if (i > 0) {
518				/* Forward all data until the next tag */
519				int64_t j = reader->consumed;
520				reader->consumed += i;
521				*sz = (size_t)i; /* cast is ok, i is limited to MG_BUF_LEN */
522				return reader->begin + j;
523			}
524
525			/* assert (reader->begin[reader->state] == '<') */
526			/* assert (i == 0) */
527			if (0 == memcmp(reader->begin + reader->consumed, "<?lua", 5)) {
528				/* kepler <?lua syntax */
529				i = 5;
530				reader->tag = '?';
531				break;
532			} else if (0 == memcmp(reader->begin + reader->consumed, "<%", 2)) {
533				/* kepler <% syntax */
534				i = 2;
535				reader->tag = '%';
536				break;
537			} else if (0 == memcmp(reader->begin + reader->consumed, "<?", 2)) {
538				/* civetweb <? syntax */
539				i = 2;
540				reader->tag = '?';
541				break;
542			} else {
543				i = 1;
544			}
545		}
546		/* We found an opening or closing tag, or we reached the end of the
547		 * file/data block */
548		if (reader->begin[reader->consumed + i] == '=') {
549			/* Lua= tag - Lua expression to print */
550			ret = "]=======]);\nmg.write(";
551			reader->state = 3;
552			i++;
553		} else {
554			/* Normal Lua tag - Lua chunk */
555			ret = "]=======]);\n";
556			reader->state = 2;
557		}
558		*sz = strlen(ret);
559		reader->consumed += i; /* length of <?lua or <% tag */
560		return ret;
561	}
562
563	if ((reader->state == 2) || (reader->state == 3)) {
564		/* State 2: Lua chunkg - keep outside mg.write(...) */
565		/* State 3: Lua expression - inside mg.write(...) */
566
567		for (;;) {
568			int close_tag_found = 0;
569
570			/* Find end tag */
571			while ((i < left)
572			       && (reader->begin[i + reader->consumed] != reader->tag)) {
573				i++;
574			}
575			if (i > 0) {
576				/* Forward all data inside the Lua script tag */
577				int64_t j = reader->consumed;
578				reader->consumed += i;
579				*sz = (size_t)i; /* cast is ok, i is limited to MG_BUF_LEN */
580
581				return reader->begin + j;
582			}
583
584			/* Is this the closing tag we are looking for? */
585			close_tag_found =
586			    ((i + 1 < left)
587			     && (reader->begin[i + 1 + reader->consumed] == '>'));
588
589			if (close_tag_found) {
590				/* Drop close tag */
591				reader->consumed += 2;
592
593				if (reader->state == 2) {
594					/* Send a new opening tag to Lua */
595					ret = ";\nmg.write([=======[";
596				} else {
597					ret = ");\nmg.write([=======[";
598				}
599				*sz = strlen(ret);
600				reader->state = 1;
601				return ret;
602			} else {
603				/* Not a close tag, continue searching */
604				i++;
605			}
606		}
607	}
608
609
610	/* Must never be reached */
611	*sz = 0;
612	return 0;
613}
614
615
616static int
617run_lsp_kepler(struct mg_connection *conn,
618               const char *path,
619               const char *p,
620               int64_t len,
621               lua_State *L,
622               int depth)
623{
624
625	int lua_ok;
626	struct lsp_var_reader_data data;
627	char date[64];
628	time_t curtime = time(NULL);
629
630	gmt_time_string(date, sizeof(date), &curtime);
631
632	if (depth == 1) {
633		/* Top level page assumes keep_alive is disabled.
634		 * Do not overwrite this setting for included pages. */
635		conn->must_close = 1;
636
637		/* Only send a HTML header, if this is the top level page.
638		 * If this page is included by some mg.include calls, do not add a
639		 * header. */
640		mg_printf(conn, "HTTP/1.1 200 OK\r\n");
641		send_no_cache_header(conn);
642		send_additional_header(conn);
643		mg_printf(conn,
644		          "Date: %s\r\n"
645		          "Connection: close\r\n"
646		          "Content-Type: text/html; charset=utf-8\r\n\r\n",
647		          date);
648	}
649
650	data.begin = p;
651	data.len = len;
652	data.state = 0;
653	data.consumed = 0;
654	data.tag = 0;
655	lua_ok = mg_lua_load(L, lsp_kepler_reader, &data, path, NULL);
656
657	if (lua_ok) {
658		/* Syntax error or OOM.
659		 * Error message is pushed on stack. */
660		lua_pcall(L, 1, 0, 0);
661		lua_cry(conn, lua_ok, L, "LSP", "execute"); /* XXX TODO: everywhere ! */
662
663	} else {
664		/* Success loading chunk. Call it. */
665		lua_pcall(L, 0, 0, 1);
666	}
667	return 0;
668}
669
670
671static int
672run_lsp_civetweb(struct mg_connection *conn,
673                 const char *path,
674                 const char *p,
675                 int64_t len,
676                 lua_State *L,
677                 int depth)
678{
679	int i, j, s, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
680	char chunkname[MG_BUF_LEN];
681	struct lsp_var_reader_data data;
682	const char lsp_mark1 = '?'; /* Use <? code ?> */
683	const char lsp_mark2 = '%'; /* Use <% code %> */
684
685	if (depth == 1) {
686		/* Assume the script does not support keep_alive. The script may change
687		 * this by calling mg.keep_alive(true). */
688		conn->must_close = 1;
689	}
690
691	for (i = 0; i < len; i++) {
692		if (p[i] == '\n') {
693			lines++;
694		}
695
696		/* Lua pages are normal text, unless there is a "<?" or "<%" tag. */
697		if (((i + 1) < len) && (p[i] == '<')
698		    && ((p[i + 1] == lsp_mark1) || (p[i + 1] == lsp_mark2))) {
699
700			/* Opening tag way "<?" or "<%", closing tag must be the same. */
701			char lsp_mark_used = p[i + 1];
702
703			/* <?= var ?> or <%= var %> means a variable is enclosed and its
704			 * value should be printed */
705			if (0 == memcmp("lua", p + i + 2, 3)) {
706				/* Syntax: <?lua code ?> or <?lua= var ?> */
707				/* This is added for compatibility to other LSP syntax
708				 * definitions. */
709				/* Skip 3 letters ("lua"). */
710				s = 3;
711			} else {
712				/* no additional letters to skip, only "<?" */
713				s = 0;
714			}
715
716			/* Check for '=' in "<?= ..." or "<%= ..." or "<?lua= ..." */
717			is_var = (((i + s + 2) < len) && (p[i + s + 2] == '='));
718			if (is_var) {
719				/* use variable value (print it later) */
720				j = i + 2;
721			} else {
722				/* execute script code */
723				j = i + 1;
724			}
725
726			while (j < len) {
727
728				if (p[j] == '\n') {
729					/* Add line (for line number offset) */
730					lualines++;
731				}
732
733				/* Check for closing tag. */
734				if (((j + 1) < len) && (p[j] == lsp_mark_used)
735				    && (p[j + 1] == '>')) {
736					/* We found the closing tag of the Lua tag. */
737
738					/* Print everything before the Lua opening tag. */
739					mg_write(conn, p + pos, i - pos);
740
741					/* Set a name for debugging purposes */
742					mg_snprintf(conn,
743					            NULL, /* ignore truncation for debugging */
744					            chunkname,
745					            sizeof(chunkname),
746					            "@%s+%i",
747					            path,
748					            lines);
749
750					/* Prepare data for Lua C functions */
751					lua_pushlightuserdata(L, conn);
752					lua_pushcclosure(L, lsp_error, 1);
753
754					/* Distinguish between <? script ?> (is_var == 0)
755					 * and <?= expression ?> (is_var != 0). */
756					if (is_var) {
757						/* For variables: Print the value */
758						/* Note: <?= expression ?> is equivalent to
759						 * <? mg.write( expression ) ?> */
760						data.begin = p + (i + 3 + s);
761						data.len = j - (i + 3 + s);
762						data.state = 0;
763						data.consumed = 0;
764						data.tag = 0;
765						lua_ok = mg_lua_load(
766						    L, lsp_var_reader, &data, chunkname, NULL);
767					} else {
768						/* For scripts: Execute them */
769						lua_ok = luaL_loadbuffer(L,
770						                         p + (i + 2 + s),
771						                         j - (i + 2 + s),
772						                         chunkname);
773					}
774
775					if (lua_ok) {
776						/* Syntax error or OOM.
777						 * Error message is pushed on stack. */
778						lua_pcall(L, 1, 0, 0);
779					} else {
780						/* Success loading chunk. Call it. */
781						lua_pcall(L, 0, 0, 1);
782					}
783
784					/* Progress until after the Lua closing tag. */
785					pos = j + 2;
786					i = pos - 1;
787					break;
788				}
789				j++;
790			}
791
792			/* Line number for debugging/error logging. */
793			if (lualines > 0) {
794				lines += lualines;
795				lualines = 0;
796			}
797		}
798	}
799
800	/* Print everything after the last Lua closing tag. */
801	if (i > pos) {
802		mg_write(conn, p + pos, i - pos);
803	}
804
805	return 0;
806}
807
808
809/* mg.write: Send data to the client */
810static int
811lsp_write(lua_State *L)
812{
813	struct mg_connection *conn =
814	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
815	int num_args = lua_gettop(L);
816	const char *str;
817	size_t size;
818	int i;
819	int rv = 1;
820
821	for (i = 1; i <= num_args; i++) {
822		if (lua_isstring(L, i)) {
823			str = lua_tolstring(L, i, &size);
824			if (mg_write(conn, str, size) != (int)size) {
825				rv = 0;
826			}
827		}
828	}
829	lua_pushboolean(L, rv);
830
831	return 1;
832}
833
834
835/* mg.read: Read data from the client (e.g., from a POST request) */
836static int
837lsp_read(lua_State *L)
838{
839	struct mg_connection *conn =
840	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
841	char buf[1024];
842	int len = mg_read(conn, buf, sizeof(buf));
843
844	if (len <= 0)
845		return 0;
846	lua_pushlstring(L, buf, len);
847
848	return 1;
849}
850
851
852/* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
853static int
854lsp_keep_alive(lua_State *L)
855{
856	struct mg_connection *conn =
857	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
858	int num_args = lua_gettop(L);
859
860	/* This function may be called with one parameter (boolean) to set the
861	keep_alive state.
862	Or without a parameter to just query the current keep_alive state. */
863	if ((num_args == 1) && lua_isboolean(L, 1)) {
864		conn->must_close = !lua_toboolean(L, 1);
865	} else if (num_args != 0) {
866		/* Syntax error */
867		return luaL_error(L, "invalid keep_alive() call");
868	}
869
870	/* Return the current "keep_alive" state. This may be false, even it
871	 * keep_alive(true) has been called. */
872	lua_pushboolean(L, should_keep_alive(conn));
873	return 1;
874}
875
876
877/* Stack of includes */
878struct lsp_include_history {
879	int depth;
880	const char *script[LSP_INCLUDE_MAX_DEPTH + 1];
881};
882
883
884/* mg.include: Include another .lp file */
885static int
886lsp_include(lua_State *L)
887{
888	struct mg_connection *conn =
889	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
890	int num_args = lua_gettop(L);
891	struct mg_file file = STRUCT_FILE_INITIALIZER;
892	const char *file_name = (num_args >= 1) ? lua_tostring(L, 1) : NULL;
893	const char *path_type = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
894	struct lsp_include_history *include_history;
895
896	if (path_type == NULL) {
897		/* default to "absolute" */
898		path_type = "a";
899	}
900
901	if ((file_name != NULL) && (num_args <= 2)) {
902
903		lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
904		lua_gettable(L, LUA_REGISTRYINDEX);
905		include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
906
907		if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
908			mg_cry_internal(
909			    conn,
910			    "lsp max include depth of %i reached while including %s",
911			    (int)(LSP_INCLUDE_MAX_DEPTH),
912			    file_name);
913		} else {
914			char file_name_path[512];
915			char *p;
916			size_t len;
917			int truncated = 0;
918
919			file_name_path[511] = 0;
920
921			if (*path_type == 'v') {
922				/* "virtual" = relative to document root. */
923				(void)mg_snprintf(conn,
924				                  &truncated,
925				                  file_name_path,
926				                  sizeof(file_name_path),
927				                  "%s/%s",
928				                  conn->dom_ctx->config[DOCUMENT_ROOT],
929				                  file_name);
930
931			} else if (*path_type == 'a') {
932				/* "absolute" = file name is relative to the
933				 * webserver working directory
934				 * or it is absolute system path. */
935				/* path_type==NULL is the legacy use case with 1 argument */
936				(void)mg_snprintf(conn,
937				                  &truncated,
938				                  file_name_path,
939				                  sizeof(file_name_path),
940				                  "%s",
941				                  file_name);
942
943			} else if ((*path_type == 'r') || (*path_type == 'f')) {
944				/* "relative" = file name is relative to the
945				 * currect document */
946				(void)mg_snprintf(
947				    conn,
948				    &truncated,
949				    file_name_path,
950				    sizeof(file_name_path),
951				    "%s",
952				    include_history->script[include_history->depth]);
953
954				if (!truncated) {
955					if ((p = strrchr(file_name_path, '/')) != NULL) {
956						p[1] = '\0';
957					}
958					len = strlen(file_name_path);
959					(void)mg_snprintf(conn,
960					                  &truncated,
961					                  file_name_path + len,
962					                  sizeof(file_name_path) - len,
963					                  "%s",
964					                  file_name);
965				}
966
967			} else {
968				return luaL_error(
969				    L,
970				    "invalid path_type in include(file_name, path_type) call");
971			}
972
973			if (handle_lsp_request(conn, file_name_path, &file, L)) {
974				/* handle_lsp_request returned an error code, meaning an error
975				 * occurred in the included page and mg.onerror returned
976				 * non-zero.
977				 * Stop processing.
978				 */
979
980				lsp_abort(L);
981			}
982		}
983
984	} else {
985		/* Syntax error */
986		return luaL_error(L, "invalid include() call");
987	}
988	return 0;
989}
990
991
992/* mg.cry: Log an error. Default value for mg.onerror. */
993static int
994lsp_cry(lua_State *L)
995{
996	struct mg_connection *conn =
997	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
998	int num_args = lua_gettop(L);
999	const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
1000
1001	if (text) {
1002		mg_cry_internal(conn, "%s", lua_tostring(L, -1));
1003	} else {
1004		/* Syntax error */
1005		return luaL_error(L, "invalid cry() call");
1006	}
1007	return 0;
1008}
1009
1010
1011/* mg.redirect: Redirect the request (internally). */
1012static int
1013lsp_redirect(lua_State *L)
1014{
1015	struct mg_connection *conn =
1016	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1017	int num_args = lua_gettop(L);
1018	const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
1019
1020	if (target) {
1021		conn->request_info.local_uri = target;
1022		handle_request(conn);
1023		lsp_abort(L);
1024	} else {
1025		/* Syntax error */
1026		return luaL_error(L, "invalid redirect() call");
1027	}
1028	return 0;
1029}
1030
1031
1032/* mg.send_file */
1033static int
1034lsp_send_file(lua_State *L)
1035{
1036	struct mg_connection *conn =
1037	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1038	int num_args = lua_gettop(L);
1039	const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
1040
1041	if (filename) {
1042		mg_send_file(conn, filename);
1043	} else {
1044		/* Syntax error */
1045		return luaL_error(L, "invalid send_file() call");
1046	}
1047	return 0;
1048}
1049
1050
1051/* mg.mg_send_file_body */
1052static int
1053lsp_send_file_body(lua_State *L)
1054{
1055	struct mg_connection *conn =
1056	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1057	int num_args = lua_gettop(L);
1058	const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
1059	int ret;
1060
1061	if (filename) {
1062		ret = mg_send_file_body(conn, filename);
1063	} else {
1064		/* Syntax error */
1065		return luaL_error(L, "invalid send_file_body() call");
1066	}
1067
1068	lua_pushboolean(L, ret >= 0);
1069	return 1;
1070}
1071
1072
1073/* mg.send_http_error */
1074static int
1075lsp_send_http_error(lua_State *L)
1076{
1077	struct mg_connection *conn =
1078	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1079	int num_args = lua_gettop(L);
1080	int status = (num_args >= 1) ? (int)lua_tonumber(L, 1) : -1;
1081	const char *auxText = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
1082	int ret;
1083
1084	if ((status >= 100) && (status <= 999)) {
1085		ret = mg_send_http_error(conn,
1086		                         status,
1087		                         "%s",
1088		                         (auxText != NULL) ? auxText : "");
1089	} else {
1090		/* Syntax error */
1091		return luaL_error(L, "invalid send_http_error() call");
1092	}
1093
1094	lua_pushnumber(L, ret);
1095	return 1;
1096}
1097
1098
1099/* mg.send_http_ok */
1100static int
1101lsp_send_http_ok(lua_State *L)
1102{
1103	struct mg_connection *conn =
1104	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1105	int num_args = lua_gettop(L);
1106	int type1, type2;
1107	const char *content_type = NULL;
1108	const char *content = NULL;
1109	int64_t content_len = 0;
1110	int ret;
1111
1112	if (num_args < 2) {
1113		/* Syntax error */
1114		return luaL_error(L, "invalid send_http_ok() call");
1115	}
1116	type1 = lua_type(L, 1);
1117	type2 = lua_type(L, 2);
1118	if (type1 == LUA_TSTRING) {
1119		content_type = lua_tostring(L, 1);
1120	} else if (type1 != LUA_TNIL) {
1121		/* Syntax error */
1122		return luaL_error(L, "invalid send_http_ok() call");
1123	}
1124	if (type2 == LUA_TSTRING) {
1125		size_t len;
1126		content = lua_tolstring(L, 2, &len);
1127		content_len = (int64_t)len;
1128	} else if (type2 == LUA_TNUMBER) {
1129		content_len = (int64_t)lua_tonumber(L, 2);
1130	} else {
1131		/* Syntax error */
1132		return luaL_error(L, "invalid send_http_ok() call");
1133	}
1134
1135	ret = mg_send_http_ok(conn, content_type, content_len);
1136
1137	if ((ret == 0) && (content != NULL) && (content_len > 0)) {
1138		mg_write(conn, content, (size_t)content_len);
1139	}
1140
1141	lua_pushnumber(L, ret);
1142	return 1;
1143}
1144
1145
1146/* mg.mg_send_http_redirect */
1147static int
1148lsp_send_http_redirect(lua_State *L)
1149{
1150	struct mg_connection *conn =
1151	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1152	int num_args = lua_gettop(L);
1153	int type1, type2;
1154	const char *target_url = NULL;
1155	int redirect_code = 300;
1156	int ret;
1157
1158	if (num_args < 2) {
1159		/* Syntax error */
1160		return luaL_error(L, "invalid send_http_redirect() call");
1161	}
1162	type1 = lua_type(L, 1);
1163	type2 = lua_type(L, 2);
1164	if (type1 == LUA_TSTRING) {
1165		target_url = lua_tostring(L, 1);
1166	} else if (type1 != LUA_TNIL) {
1167		/* Syntax error */
1168		return luaL_error(L, "invalid send_http_redirect() call");
1169	}
1170	if (type2 == LUA_TNUMBER) {
1171		redirect_code = (int)lua_tonumber(L, 2);
1172	} else {
1173		/* Syntax error */
1174		return luaL_error(L, "invalid send_http_redirect() call");
1175	}
1176
1177	ret = mg_send_http_redirect(conn, target_url, redirect_code);
1178
1179	lua_pushnumber(L, ret);
1180	return 1;
1181}
1182
1183
1184/* mg.get_time */
1185static int
1186lsp_get_time(lua_State *L)
1187{
1188	int num_args = lua_gettop(L);
1189	int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
1190	struct timespec ts;
1191	double d;
1192
1193	clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
1194	d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
1195	lua_pushnumber(L, d);
1196	return 1;
1197}
1198
1199
1200/* mg.get_var */
1201static int
1202lsp_get_var(lua_State *L)
1203{
1204	int num_args = lua_gettop(L);
1205	const char *data, *var_name;
1206	size_t data_len, occurrence;
1207	int ret;
1208	struct mg_context *ctx;
1209
1210	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1211	lua_gettable(L, LUA_REGISTRYINDEX);
1212	ctx = (struct mg_context *)lua_touserdata(L, -1);
1213
1214	if ((num_args >= 2) && (num_args <= 3)) {
1215		char *dst;
1216		data = lua_tolstring(L, 1, &data_len);
1217		var_name = lua_tostring(L, 2);
1218		occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
1219
1220		/* Allocate dynamically, so there is no internal limit for get_var */
1221		dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
1222		if (!dst) {
1223			return luaL_error(L, "out of memory in get_var() call");
1224		}
1225
1226		ret = mg_get_var2(data, data_len, var_name, dst, data_len, occurrence);
1227		if (ret >= 0) {
1228			/* Variable found: return value to Lua */
1229			lua_pushstring(L, dst);
1230		} else {
1231			/* Variable not found */
1232			lua_pushnil(L);
1233		}
1234		mg_free(dst);
1235	} else {
1236		/* Syntax error */
1237		return luaL_error(L, "invalid get_var() call");
1238	}
1239	return 1;
1240}
1241
1242
1243#define MG_MAX_FORM_FIELDS (64)
1244
1245/* mg.split_form_data */
1246static int
1247lsp_split_form_urlencoded(lua_State *L)
1248{
1249	int num_args = lua_gettop(L);
1250	const char *in;
1251	size_t len;
1252	char *buf;
1253	struct mg_context *ctx;
1254
1255	struct mg_header form_fields[MG_MAX_FORM_FIELDS] = {0};
1256	int ret, i;
1257
1258	if (num_args != 1) {
1259		return luaL_error(L, "invalid split_form_data() call");
1260	}
1261
1262	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1263	lua_gettable(L, LUA_REGISTRYINDEX);
1264	ctx = (struct mg_context *)lua_touserdata(L, -1);
1265
1266	/* Get input (const string) */
1267	in = lua_tolstring(L, 1, &len);
1268
1269	/* Create a modifyable copy */
1270	buf = (char *)mg_malloc_ctx(len + 1, ctx);
1271	if (buf == NULL) {
1272		return luaL_error(L, "out of memory in invalid split_form_data() call");
1273	}
1274	memcpy(buf, in, len + 1);
1275
1276	/* mg_split_form_urlencoded does the real work */
1277	ret = mg_split_form_urlencoded(buf, form_fields, MG_MAX_FORM_FIELDS);
1278
1279	if (ret < 0) {
1280		return luaL_error(L, "error in invalid split_form_data() call");
1281	}
1282
1283	/* return a table */
1284	lua_newtable(L);
1285	for (i = 0; i < ret; i++) {
1286
1287		lua_newtable(L);
1288		if (form_fields[i].name) {
1289			lua_pushstring(L, form_fields[i].name);
1290		} else {
1291			lua_pushnil(L);
1292		}
1293		lua_setfield(L, -2, "name");
1294		if (form_fields[i].value) {
1295			lua_pushstring(L, form_fields[i].value);
1296		} else {
1297			lua_pushnil(L);
1298		}
1299		lua_setfield(L, -2, "value");
1300
1301		lua_rawseti(L, -2, i + 1);
1302	}
1303
1304	mg_free(buf);
1305
1306	return 1;
1307}
1308
1309
1310/* mg.get_mime_type */
1311static int
1312lsp_get_mime_type(lua_State *L)
1313{
1314	int num_args = lua_gettop(L);
1315	struct vec mime_type = {0, 0};
1316	const char *text;
1317
1318	struct mg_connection *conn =
1319	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1320
1321	if (num_args == 1) {
1322		text = lua_tostring(L, 1);
1323		if (text) {
1324			if (conn) {
1325				get_mime_type(conn, text, &mime_type);
1326				lua_pushlstring(L, mime_type.ptr, mime_type.len);
1327			} else {
1328				text = mg_get_builtin_mime_type(text);
1329				lua_pushstring(L, text);
1330			}
1331		} else {
1332			/* Syntax error */
1333			return luaL_error(L, "invalid argument for get_mime_type() call");
1334		}
1335	} else {
1336		/* Syntax error */
1337		return luaL_error(L, "invalid get_mime_type() call");
1338	}
1339	return 1;
1340}
1341
1342
1343/* mg.get_cookie */
1344static int
1345lsp_get_cookie(lua_State *L)
1346{
1347	int num_args = lua_gettop(L);
1348	const char *cookie;
1349	const char *var_name;
1350	int ret;
1351	struct mg_context *ctx;
1352
1353	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1354	lua_gettable(L, LUA_REGISTRYINDEX);
1355	ctx = (struct mg_context *)lua_touserdata(L, -1);
1356
1357	if (num_args == 2) {
1358		/* Correct number of arguments */
1359		size_t data_len;
1360		char *dst;
1361
1362		cookie = lua_tolstring(L, 1, &data_len);
1363		var_name = lua_tostring(L, 2);
1364
1365		if (cookie == NULL || var_name == NULL) {
1366			/* Syntax error */
1367			return luaL_error(L, "invalid get_cookie() call");
1368		}
1369
1370		dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
1371		if (!dst) {
1372			return luaL_error(L, "out of memory in get_cookie() call");
1373		}
1374
1375		ret = mg_get_cookie(cookie, var_name, dst, data_len);
1376
1377		if (ret >= 0) {
1378			lua_pushlstring(L, dst, ret);
1379		} else {
1380			lua_pushnil(L);
1381		}
1382		mg_free(dst);
1383
1384	} else {
1385		/* Syntax error */
1386		return luaL_error(L, "invalid get_cookie() call");
1387	}
1388	return 1;
1389}
1390
1391
1392/* mg.md5 */
1393static int
1394lsp_md5(lua_State *L)
1395{
1396	int num_args = lua_gettop(L);
1397	const char *text;
1398	md5_byte_t hash[16];
1399	md5_state_t ctx;
1400	size_t text_len;
1401	char buf[40];
1402
1403	if (num_args == 1) {
1404		text = lua_tolstring(L, 1, &text_len);
1405		if (text) {
1406			md5_init(&ctx);
1407			md5_append(&ctx, (const md5_byte_t *)text, text_len);
1408			md5_finish(&ctx, hash);
1409			bin2str(buf, hash, sizeof(hash));
1410			lua_pushstring(L, buf);
1411		} else {
1412			lua_pushnil(L);
1413		}
1414	} else {
1415		/* Syntax error */
1416		return luaL_error(L, "invalid md5() call");
1417	}
1418	return 1;
1419}
1420
1421
1422/* mg.url_encode */
1423static int
1424lsp_url_encode(lua_State *L)
1425{
1426	int num_args = lua_gettop(L);
1427	const char *text;
1428	size_t text_len;
1429	char *dst;
1430	int dst_len;
1431	struct mg_context *ctx;
1432
1433	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1434	lua_gettable(L, LUA_REGISTRYINDEX);
1435	ctx = (struct mg_context *)lua_touserdata(L, -1);
1436
1437	if (num_args == 1) {
1438		text = lua_tolstring(L, 1, &text_len);
1439		if (text) {
1440			dst_len = 3 * (int)text_len + 1;
1441			dst = ((text_len < 0x2AAAAAAA) ? (char *)mg_malloc_ctx(dst_len, ctx)
1442			                               : (char *)NULL);
1443			if (dst) {
1444				mg_url_encode(text, dst, dst_len);
1445				lua_pushstring(L, dst);
1446				mg_free(dst);
1447			} else {
1448				return luaL_error(L, "out of memory in url_encode() call");
1449			}
1450		} else {
1451			lua_pushnil(L);
1452		}
1453	} else {
1454		/* Syntax error */
1455		return luaL_error(L, "invalid url_encode() call");
1456	}
1457	return 1;
1458}
1459
1460
1461/* mg.url_decode */
1462static int
1463lsp_url_decode(lua_State *L)
1464{
1465	int num_args = lua_gettop(L);
1466	const char *text;
1467	size_t text_len;
1468	int is_form;
1469	char *dst;
1470	int dst_len;
1471	struct mg_context *ctx;
1472
1473	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1474	lua_gettable(L, LUA_REGISTRYINDEX);
1475	ctx = (struct mg_context *)lua_touserdata(L, -1);
1476
1477	if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
1478		text = lua_tolstring(L, 1, &text_len);
1479		is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
1480		if (text) {
1481			dst_len = (int)text_len + 1;
1482			dst = ((text_len < 0x7FFFFFFF) ? (char *)mg_malloc_ctx(dst_len, ctx)
1483			                               : (char *)NULL);
1484			if (dst) {
1485				mg_url_decode(text, (int)text_len, dst, dst_len, is_form);
1486				lua_pushstring(L, dst);
1487				mg_free(dst);
1488			} else {
1489				return luaL_error(L, "out of memory in url_decode() call");
1490			}
1491		} else {
1492			lua_pushnil(L);
1493		}
1494	} else {
1495		/* Syntax error */
1496		return luaL_error(L, "invalid url_decode() call");
1497	}
1498	return 1;
1499}
1500
1501
1502/* mg.base64_encode */
1503static int
1504lsp_base64_encode(lua_State *L)
1505{
1506	int num_args = lua_gettop(L);
1507	const char *text;
1508	size_t text_len;
1509	char *dst;
1510	struct mg_context *ctx;
1511
1512	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1513	lua_gettable(L, LUA_REGISTRYINDEX);
1514	ctx = (struct mg_context *)lua_touserdata(L, -1);
1515
1516	if (num_args == 1) {
1517		text = lua_tolstring(L, 1, &text_len);
1518		if (text) {
1519			dst = (char *)mg_malloc_ctx(text_len * 8 / 6 + 4, ctx);
1520			if (dst) {
1521				base64_encode((const unsigned char *)text, (int)text_len, dst);
1522				lua_pushstring(L, dst);
1523				mg_free(dst);
1524			} else {
1525				return luaL_error(L, "out of memory in base64_encode() call");
1526			}
1527		} else {
1528			lua_pushnil(L);
1529		}
1530	} else {
1531		/* Syntax error */
1532		return luaL_error(L, "invalid base64_encode() call");
1533	}
1534	return 1;
1535}
1536
1537
1538/* mg.base64_encode */
1539static int
1540lsp_base64_decode(lua_State *L)
1541{
1542	int num_args = lua_gettop(L);
1543	const char *text;
1544	size_t text_len, dst_len;
1545	int ret;
1546	char *dst;
1547	struct mg_context *ctx;
1548
1549	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1550	lua_gettable(L, LUA_REGISTRYINDEX);
1551	ctx = (struct mg_context *)lua_touserdata(L, -1);
1552
1553	if (num_args == 1) {
1554		text = lua_tolstring(L, 1, &text_len);
1555		if (text) {
1556			dst = (char *)mg_malloc_ctx(text_len, ctx);
1557			if (dst) {
1558				ret = base64_decode((const unsigned char *)text,
1559				                    (int)text_len,
1560				                    dst,
1561				                    &dst_len);
1562				if (ret != -1) {
1563					mg_free(dst);
1564					return luaL_error(
1565					    L, "illegal character in lsp_base64_decode() call");
1566				} else {
1567					lua_pushlstring(L, dst, dst_len);
1568					mg_free(dst);
1569				}
1570			} else {
1571				return luaL_error(L,
1572				                  "out of memory in lsp_base64_decode() call");
1573			}
1574		} else {
1575			lua_pushnil(L);
1576		}
1577	} else {
1578		/* Syntax error */
1579		return luaL_error(L, "invalid lsp_base64_decode() call");
1580	}
1581	return 1;
1582}
1583
1584
1585/* mg.get_response_code_text */
1586static int
1587lsp_get_response_code_text(lua_State *L)
1588{
1589	int num_args = lua_gettop(L);
1590	int type1;
1591	double code;
1592	const char *text;
1593
1594	if (num_args == 1) {
1595		type1 = lua_type(L, 1);
1596		if (type1 == LUA_TNUMBER) {
1597			/* If the first argument is a number,
1598			   convert it to the corresponding text. */
1599			code = lua_tonumber(L, 1);
1600			text = mg_get_response_code_text(NULL, (int)code);
1601			if (text) { /* <-- should be always true */
1602				lua_pushstring(L, text);
1603			}
1604			return text ? 1 : 0;
1605		}
1606	}
1607
1608	/* Syntax error */
1609	return luaL_error(L, "invalid get_response_code_text() call");
1610}
1611
1612
1613/* mg.random - might be better than math.random on some systems */
1614static int
1615lsp_random(lua_State *L)
1616{
1617	int num_args = lua_gettop(L);
1618	if (num_args == 0) {
1619		/* The civetweb internal random number generator will generate
1620		 * a 64 bit random number. */
1621		uint64_t r = get_random();
1622		/* Lua "number" is a IEEE 754 double precission float:
1623		 * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
1624		 * Thus, mask with 2^53-1 to get an integer with the maximum
1625		 * precission available. */
1626		r &= ((((uint64_t)1) << 53) - 1);
1627		lua_pushnumber(L, (double)r);
1628		return 1;
1629	}
1630
1631	/* Syntax error */
1632	return luaL_error(L, "invalid random() call");
1633}
1634
1635
1636/* mg.get_info */
1637static int
1638lsp_get_info(lua_State *L)
1639{
1640	int num_args = lua_gettop(L);
1641	int type1, type2;
1642	const char *arg1;
1643	double arg2;
1644	int len;
1645	char *buf;
1646
1647	if (num_args == 1) {
1648		type1 = lua_type(L, 1);
1649		if (type1 == LUA_TSTRING) {
1650			arg1 = lua_tostring(L, 1);
1651			/* Get info according to argument */
1652			if (!mg_strcasecmp(arg1, "system")) {
1653				/* Get system info */
1654				len = mg_get_system_info(NULL, 0);
1655				if (len > 0) {
1656					buf = (char *)mg_malloc(len + 64);
1657					if (!buf) {
1658						return luaL_error(L, "OOM in get_info() call");
1659					}
1660					len = mg_get_system_info(buf, len + 63);
1661					lua_pushlstring(L, buf, len);
1662					mg_free(buf);
1663				} else {
1664					lua_pushstring(L, "");
1665				}
1666				return 1;
1667			}
1668			if (!mg_strcasecmp(arg1, "context")) {
1669				/* Get context */
1670				struct mg_context *ctx;
1671				lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1672				lua_gettable(L, LUA_REGISTRYINDEX);
1673				ctx = (struct mg_context *)lua_touserdata(L, -1);
1674
1675				/* Get context info for server context */
1676				len = mg_get_context_info(ctx, NULL, 0);
1677				if (len > 0) {
1678					buf = (char *)mg_malloc(len + 64);
1679					if (!buf) {
1680						return luaL_error(L, "OOM in get_info() call");
1681					}
1682					len = mg_get_context_info(ctx, buf, len + 63);
1683					lua_pushlstring(L, buf, len);
1684					mg_free(buf);
1685				} else {
1686					lua_pushstring(L, "");
1687				}
1688				return 1;
1689			}
1690			if (!mg_strcasecmp(arg1, "common")) {
1691				/* Get context info for NULL context */
1692				len = mg_get_context_info(NULL, NULL, 0);
1693				if (len > 0) {
1694					buf = (char *)mg_malloc(len + 64);
1695					if (!buf) {
1696						return luaL_error(L, "OOM in get_info() call");
1697					}
1698					len = mg_get_context_info(NULL, buf, len + 63);
1699					lua_pushlstring(L, buf, len);
1700					mg_free(buf);
1701				} else {
1702					lua_pushstring(L, "");
1703				}
1704				return 1;
1705			}
1706			return 0;
1707		}
1708	}
1709
1710	if (num_args == 2) {
1711		type1 = lua_type(L, 1);
1712		type2 = lua_type(L, 2);
1713		if ((type1 == LUA_TSTRING) && (type2 == LUA_TNUMBER)) {
1714			arg1 = lua_tostring(L, 1);
1715			arg2 = lua_tonumber(L, 2);
1716
1717			/* Get info according to argument */
1718			if (!mg_strcasecmp(arg1, "connection")) {
1719				int idx;
1720
1721				/* Get context */
1722				struct mg_context *ctx;
1723				lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1724				lua_gettable(L, LUA_REGISTRYINDEX);
1725				ctx = (struct mg_context *)lua_touserdata(L, -1);
1726
1727				/* Get connection info for connection idx */
1728				idx = (int)(arg2 + 0.5);
1729
1730				/* Lua uses 1 based index, C uses 0 based index */
1731				idx--;
1732
1733#if defined(MG_EXPERIMENTAL_INTERFACES)
1734				len = mg_get_connection_info(ctx, idx, NULL, 0);
1735				if (len > 0) {
1736					buf = (char *)mg_malloc(len + 64);
1737					if (!buf) {
1738						return luaL_error(L, "OOM in get_info() call");
1739					}
1740					len = mg_get_connection_info(ctx, idx, buf, len + 63);
1741					lua_pushlstring(L, buf, len);
1742					mg_free(buf);
1743				} else {
1744					lua_pushstring(L, "");
1745				}
1746#else
1747				(void)ctx;
1748				(void)idx;
1749				lua_pushstring(L, "");
1750#endif
1751
1752				return 1;
1753			}
1754			return 0;
1755		}
1756	}
1757
1758	/* Syntax error */
1759	return luaL_error(L, "invalid get_info() call");
1760}
1761
1762
1763/* mg.get_option */
1764static int
1765lsp_get_option(lua_State *L)
1766{
1767	int num_args = lua_gettop(L);
1768	int type1;
1769	const char *arg1;
1770	const char *data;
1771	int optidx;
1772
1773	/* Get connection */
1774	struct mg_connection *conn =
1775	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1776
1777	if (num_args == 0) {
1778		const struct mg_option *opts = mg_get_valid_options();
1779
1780		if (!opts) { /* <-- should be always false */
1781			return 0;
1782		}
1783
1784		lua_newtable(L);
1785		while (opts->name) {
1786			optidx = get_option_index(opts->name);
1787			if (optidx >= 0) {
1788				data = conn->dom_ctx->config[optidx];
1789				if (data) {
1790					reg_string(L, opts->name, data);
1791				}
1792			}
1793			opts++;
1794		}
1795
1796		return 1;
1797	}
1798
1799	if (num_args == 1) {
1800		type1 = lua_type(L, 1);
1801		if (type1 == LUA_TSTRING) {
1802			arg1 = lua_tostring(L, 1);
1803			/* Get option according to argument */
1804			optidx = get_option_index(arg1);
1805			if (optidx >= 0) {
1806				data = conn->dom_ctx->config[optidx];
1807				if (data) {
1808					lua_pushstring(L, data);
1809					return 1;
1810				}
1811			}
1812			return 0;
1813		}
1814	}
1815
1816	/* Syntax error */
1817	return luaL_error(L, "invalid get_option() call");
1818}
1819
1820
1821static int s_lua_traceLevel = 1;
1822static FILE *s_lua_traceFile = NULL;
1823static pthread_mutex_t s_lua_traceMutex;
1824
1825
1826/* mg.trace */
1827static int
1828lsp_trace(lua_State *L)
1829{
1830	int num_args = lua_gettop(L);
1831	int arg_type[8];
1832	int trace_level = 0;
1833	int firstarg = 1;
1834	int i;
1835
1836	for (i = 0; i < 8; i++) {
1837		if (num_args >= (i + 1)) {
1838			arg_type[i] = lua_type(L, (i + 1));
1839		} else {
1840			arg_type[i] = LUA_TNIL;
1841		}
1842	}
1843
1844	if (arg_type[0] == LUA_TNUMBER) {
1845		trace_level = (int)lua_tointeger(L, 1);
1846		if (num_args == 1) {
1847			/* Set a new trace level, return the current one. */
1848			lua_pushinteger(L, s_lua_traceLevel);
1849			s_lua_traceLevel = trace_level;
1850			if (s_lua_traceFile) {
1851				pthread_mutex_lock(&s_lua_traceMutex);
1852				fflush(s_lua_traceFile);
1853				pthread_mutex_unlock(&s_lua_traceMutex);
1854			}
1855			return 1;
1856		}
1857		firstarg = 2;
1858	}
1859
1860	if (trace_level > s_lua_traceLevel) {
1861		/* If this trace request has a higher trace level than the global trace
1862		 * level, do not trace. */
1863		lua_pushboolean(L, 0);
1864		return 1;
1865	}
1866
1867	/* Print to file */
1868	if (s_lua_traceFile) {
1869		pthread_mutex_lock(&s_lua_traceMutex);
1870		for (i = firstarg; i <= num_args; i++) {
1871			if (arg_type[i - 1] == LUA_TSTRING) {
1872				const char *arg = lua_tostring(L, i);
1873				fprintf(s_lua_traceFile, "%s\n", arg);
1874			}
1875		}
1876		pthread_mutex_unlock(&s_lua_traceMutex);
1877	}
1878	lua_pushboolean(L, 1);
1879	return 1;
1880}
1881
1882
1883/* UUID library and function pointer */
1884union {
1885	void *p;
1886	void (*f)(unsigned char uuid[16]);
1887} pf_uuid_generate;
1888
1889
1890/* mg.uuid */
1891static int
1892lsp_uuid(lua_State *L)
1893{
1894	union {
1895		unsigned char uuid_array[16];
1896		struct uuid_struct_type {
1897			uint32_t data1;
1898			uint16_t data2;
1899			uint16_t data3;
1900			uint8_t data4[8];
1901		} uuid_struct;
1902	} uuid;
1903
1904	char uuid_str[40];
1905	int num_args = lua_gettop(L);
1906
1907	memset(&uuid, 0, sizeof(uuid));
1908	memset(uuid_str, 0, sizeof(uuid_str));
1909
1910	if (num_args == 0) {
1911
1912		pf_uuid_generate.f(uuid.uuid_array);
1913
1914		sprintf(uuid_str,
1915		        "{%08lX-%04X-%04X-%02X%02X-"
1916		        "%02X%02X%02X%02X%02X%02X}",
1917		        (unsigned long)uuid.uuid_struct.data1,
1918		        (unsigned)uuid.uuid_struct.data2,
1919		        (unsigned)uuid.uuid_struct.data3,
1920		        (unsigned)uuid.uuid_struct.data4[0],
1921		        (unsigned)uuid.uuid_struct.data4[1],
1922		        (unsigned)uuid.uuid_struct.data4[2],
1923		        (unsigned)uuid.uuid_struct.data4[3],
1924		        (unsigned)uuid.uuid_struct.data4[4],
1925		        (unsigned)uuid.uuid_struct.data4[5],
1926		        (unsigned)uuid.uuid_struct.data4[6],
1927		        (unsigned)uuid.uuid_struct.data4[7]);
1928
1929		lua_pushstring(L, uuid_str);
1930		return 1;
1931	}
1932
1933	/* Syntax error */
1934	return luaL_error(L, "invalid uuid() call");
1935}
1936
1937
1938#if defined(USE_WEBSOCKET)
1939struct lua_websock_data {
1940	lua_State *state;
1941	char *script;
1942	unsigned references;
1943	struct mg_connection *conn[MAX_WORKER_THREADS];
1944	pthread_mutex_t ws_mutex;
1945};
1946#endif
1947
1948
1949/* mg.write for websockets */
1950static int
1951lwebsock_write(lua_State *L)
1952{
1953#if defined(USE_WEBSOCKET)
1954	int num_args = lua_gettop(L);
1955	struct lua_websock_data *ws;
1956	const char *str;
1957	size_t size;
1958	int opcode = -1;
1959	unsigned i;
1960	struct mg_connection *client = NULL;
1961
1962	lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1963	lua_gettable(L, LUA_REGISTRYINDEX);
1964	ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1965
1966	(void)pthread_mutex_lock(&(ws->ws_mutex));
1967
1968	if (num_args == 1) {
1969		/* just one text: send it to all client */
1970		if (lua_isstring(L, 1)) {
1971			opcode = MG_WEBSOCKET_OPCODE_TEXT;
1972		}
1973	} else if (num_args == 2) {
1974		if (lua_isnumber(L, 1)) {
1975			/* opcode number and message text */
1976			opcode = (int)lua_tointeger(L, 1);
1977		} else if (lua_isstring(L, 1)) {
1978			/* opcode string and message text */
1979			str = lua_tostring(L, 1);
1980			if (!mg_strncasecmp(str, "text", 4))
1981				opcode = MG_WEBSOCKET_OPCODE_TEXT;
1982			else if (!mg_strncasecmp(str, "bin", 3))
1983				opcode = MG_WEBSOCKET_OPCODE_BINARY;
1984			else if (!mg_strncasecmp(str, "close", 5))
1985				opcode = MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE;
1986			else if (!mg_strncasecmp(str, "ping", 4))
1987				opcode = MG_WEBSOCKET_OPCODE_PING;
1988			else if (!mg_strncasecmp(str, "pong", 4))
1989				opcode = MG_WEBSOCKET_OPCODE_PONG;
1990			else if (!mg_strncasecmp(str, "cont", 4))
1991				opcode = MG_WEBSOCKET_OPCODE_CONTINUATION;
1992		} else if (lua_isuserdata(L, 1)) {
1993			/* client id and message text */
1994			client = (struct mg_connection *)lua_touserdata(L, 1);
1995			opcode = MG_WEBSOCKET_OPCODE_TEXT;
1996		}
1997	} else if (num_args == 3) {
1998		if (lua_isuserdata(L, 1)) {
1999			client = (struct mg_connection *)lua_touserdata(L, 1);
2000			if (lua_isnumber(L, 2)) {
2001				/* client id, opcode number and message text */
2002				opcode = (int)lua_tointeger(L, 2);
2003			} else if (lua_isstring(L, 2)) {
2004				/* client id, opcode string and message text */
2005				str = lua_tostring(L, 2);
2006				if (!mg_strncasecmp(str, "text", 4))
2007					opcode = MG_WEBSOCKET_OPCODE_TEXT;
2008				else if (!mg_strncasecmp(str, "bin", 3))
2009					opcode = MG_WEBSOCKET_OPCODE_BINARY;
2010				else if (!mg_strncasecmp(str, "close", 5))
2011					opcode = MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE;
2012				else if (!mg_strncasecmp(str, "ping", 4))
2013					opcode = MG_WEBSOCKET_OPCODE_PING;
2014				else if (!mg_strncasecmp(str, "pong", 4))
2015					opcode = MG_WEBSOCKET_OPCODE_PONG;
2016				else if (!mg_strncasecmp(str, "cont", 4))
2017					opcode = MG_WEBSOCKET_OPCODE_CONTINUATION;
2018			}
2019		}
2020	}
2021
2022	if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
2023		str = lua_tolstring(L, num_args, &size);
2024		if (client) {
2025			for (i = 0; i < ws->references; i++) {
2026				if (client == ws->conn[i]) {
2027					mg_lock_connection(ws->conn[i]);
2028					mg_websocket_write(ws->conn[i], opcode, str, size);
2029					mg_unlock_connection(ws->conn[i]);
2030				}
2031			}
2032		} else {
2033			for (i = 0; i < ws->references; i++) {
2034				mg_lock_connection(ws->conn[i]);
2035				mg_websocket_write(ws->conn[i], opcode, str, size);
2036				mg_unlock_connection(ws->conn[i]);
2037			}
2038		}
2039	} else {
2040		(void)pthread_mutex_unlock(&(ws->ws_mutex));
2041		return luaL_error(L, "invalid websocket write() call");
2042	}
2043
2044	(void)pthread_mutex_unlock(&(ws->ws_mutex));
2045
2046#else
2047	(void)(L);           /* unused */
2048#endif
2049	return 0;
2050}
2051
2052
2053struct laction_string_arg {
2054	lua_State *L;
2055	const char *script;
2056	pthread_mutex_t *pmutex;
2057	char txt[1];
2058};
2059
2060struct laction_funcref_arg {
2061	lua_State *L;
2062	const char *script;
2063	pthread_mutex_t *pmutex;
2064	int funcref;
2065};
2066
2067
2068static int
2069lua_action_string(struct laction_string_arg *arg)
2070{
2071	int err, ok;
2072	struct mg_context *ctx;
2073
2074	(void)pthread_mutex_lock(arg->pmutex);
2075
2076	lua_pushlightuserdata(arg->L, (void *)&lua_regkey_ctx);
2077	lua_gettable(arg->L, LUA_REGISTRYINDEX);
2078	ctx = (struct mg_context *)lua_touserdata(arg->L, -1);
2079	lua_pop(arg->L, 1);
2080
2081	err = luaL_loadstring(arg->L, arg->txt);
2082	if (err != 0) {
2083		struct mg_connection fc;
2084		lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
2085		(void)pthread_mutex_unlock(arg->pmutex);
2086		return 0;
2087	}
2088	err = lua_pcall(arg->L, 0, 1, 0);
2089	if (err != 0) {
2090		struct mg_connection fc;
2091		lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
2092		(void)pthread_mutex_unlock(arg->pmutex);
2093		return 0;
2094	}
2095
2096	ok = lua_type(arg->L, -1);
2097	if (lua_isboolean(arg->L, -1)) {
2098		ok = lua_toboolean(arg->L, -1);
2099	} else {
2100		ok = 0;
2101	}
2102	lua_pop(arg->L, 1);
2103
2104	(void)pthread_mutex_unlock(arg->pmutex);
2105
2106	return ok;
2107}
2108
2109
2110static int
2111lua_action_funcref(struct laction_funcref_arg *arg)
2112{
2113	int err, ok;
2114	struct mg_context *ctx;
2115
2116	(void)pthread_mutex_lock(arg->pmutex);
2117
2118	lua_pushlightuserdata(arg->L, (void *)&lua_regkey_ctx);
2119	lua_gettable(arg->L, LUA_REGISTRYINDEX);
2120	ctx = (struct mg_context *)lua_touserdata(arg->L, -1);
2121	lua_pop(arg->L, 1);
2122
2123	lua_rawgeti(arg->L, LUA_REGISTRYINDEX, arg->funcref);
2124	err = lua_pcall(arg->L, 0, 1, 0);
2125	if (err != 0) {
2126		struct mg_connection fc;
2127		lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
2128		(void)pthread_mutex_unlock(arg->pmutex);
2129		return 0;
2130	}
2131
2132	ok = lua_type(arg->L, -1);
2133	if (lua_isboolean(arg->L, -1)) {
2134		ok = lua_toboolean(arg->L, -1);
2135	} else {
2136		ok = 0;
2137	}
2138	lua_pop(arg->L, 1);
2139
2140	(void)pthread_mutex_unlock(arg->pmutex);
2141
2142	return ok;
2143}
2144
2145
2146static void
2147lua_action_string_cancel(struct laction_string_arg *arg)
2148{
2149	mg_free(arg);
2150}
2151
2152
2153static void
2154lua_action_funcref_cancel(struct laction_funcref_arg *arg)
2155{
2156	luaL_unref(arg->L, LUA_REGISTRYINDEX, arg->funcref);
2157	mg_free(arg);
2158}
2159
2160
2161static int
2162lwebsocket_set_timer(lua_State *L, int is_periodic)
2163{
2164#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
2165	int num_args = lua_gettop(L);
2166	struct lua_websock_data *ws;
2167	int type1, type2, type3, ok = 0;
2168	double delay, interval;
2169	struct mg_context *ctx;
2170
2171	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2172	lua_gettable(L, LUA_REGISTRYINDEX);
2173	ctx = (struct mg_context *)lua_touserdata(L, -1);
2174
2175	lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
2176	lua_gettable(L, LUA_REGISTRYINDEX);
2177	ws = (struct lua_websock_data *)lua_touserdata(L, -1);
2178
2179	if (num_args < 2) {
2180		return luaL_error(L,
2181		                  "not enough arguments for set_timer/interval() call");
2182	}
2183
2184	type1 = lua_type(L, 1);
2185	type2 = lua_type(L, 2);
2186	type3 = lua_type(L, 3);
2187
2188	/* Must have at least two arguments, ant the first one has to be some text
2189	 */
2190	if ((num_args < 2) || (num_args > 3)) {
2191		return luaL_error(L, "invalid arguments for set_timer/interval() call");
2192	}
2193
2194	/* Second argument is the delay (and interval) */
2195	if (type2 != LUA_TNUMBER) {
2196		return luaL_error(L, "invalid arguments for set_timer/interval() call");
2197	}
2198	delay = (double)lua_tonumber(L, 2);
2199	interval = (is_periodic ? delay : 0.0);
2200
2201	/* Third argument (optional) could be an interval */
2202	if (num_args > 2) {
2203		if (is_periodic || (type3 != LUA_TNUMBER)) {
2204			return luaL_error(
2205			    L, "invalid arguments for set_timer/interval() call");
2206		}
2207		interval = (double)lua_tonumber(L, 3);
2208	}
2209
2210	/* Check numbers */
2211	if ((delay < 0.0) || (interval < 0.0)) {
2212		return luaL_error(L, "invalid arguments for set_timer/interval() call");
2213	}
2214
2215	/* First value specifies the action */
2216	if (type1 == LUA_TSTRING) {
2217
2218		/* Action could be passed as a string value */
2219		struct laction_string_arg *arg;
2220		const char *action_txt;
2221		size_t action_txt_len;
2222
2223		action_txt = lua_tostring(L, 1);
2224		if ((action_txt == NULL) || (action_txt[0] == 0)) {
2225			return luaL_error(
2226			    L, "invalid arguments for set_timer/interval() call");
2227		}
2228		action_txt_len = strlen(action_txt);
2229
2230		/* Create timer data structure and schedule timer */
2231		arg = (struct laction_string_arg *)mg_malloc_ctx(
2232		    sizeof(struct laction_string_arg) + action_txt_len + 10, ctx);
2233		if (!arg) {
2234			return luaL_error(L, "out of memory");
2235		}
2236
2237		/* Argument for timer */
2238		arg->L = L;
2239		arg->script = (ws ? ws->script : NULL);
2240		arg->pmutex = (ws ? &(ws->ws_mutex) : &(ctx->lua_bg_mutex));
2241		memcpy(arg->txt, "return(", 7);
2242		memcpy(arg->txt + 7, action_txt, action_txt_len);
2243		arg->txt[action_txt_len + 7] = ')';
2244		arg->txt[action_txt_len + 8] = 0;
2245		if (0
2246		    == timer_add(ctx,
2247		                 delay,
2248		                 interval,
2249		                 1,
2250		                 (taction)lua_action_string,
2251		                 (void *)arg,
2252		                 (tcancelaction)lua_action_string_cancel)) {
2253			/* Timer added successfully */
2254			ok = 1;
2255		}
2256	} else if (type1 == LUA_TFUNCTION) {
2257
2258		/* Action could be passed as a function */
2259		int funcref;
2260		struct laction_funcref_arg *arg;
2261
2262		lua_pushvalue(L, 1);
2263		funcref = luaL_ref(L, LUA_REGISTRYINDEX);
2264
2265		/* Create timer data structure and schedule timer */
2266		arg = (struct laction_funcref_arg *)
2267		    mg_malloc_ctx(sizeof(struct laction_funcref_arg), ctx);
2268		if (!arg) {
2269			return luaL_error(L, "out of memory");
2270		}
2271
2272		/* Argument for timer */
2273		arg->L = L;
2274		arg->script = (ws ? ws->script : NULL);
2275		arg->pmutex = (ws ? &(ws->ws_mutex) : &(ctx->lua_bg_mutex));
2276		arg->funcref = funcref;
2277		if (0
2278		    == timer_add(ctx,
2279		                 delay,
2280		                 interval,
2281		                 1,
2282		                 (taction)lua_action_funcref,
2283		                 (void *)arg,
2284		                 (tcancelaction)lua_action_funcref_cancel)) {
2285			/* Timer added successfully */
2286			ok = 1;
2287		}
2288	} else {
2289		return luaL_error(L, "invalid arguments for set_timer/interval() call");
2290	}
2291
2292	lua_pushboolean(L, ok);
2293	return 1;
2294
2295#else
2296	(void)(L);           /* unused */
2297	(void)(is_periodic); /* unused */
2298	return 0;
2299#endif
2300}
2301
2302
2303/* mg.set_timeout for websockets */
2304static int
2305lwebsocket_set_timeout(lua_State *L)
2306{
2307	return lwebsocket_set_timer(L, 0);
2308}
2309
2310
2311/* mg.set_interval for websockets */
2312static int
2313lwebsocket_set_interval(lua_State *L)
2314{
2315	return lwebsocket_set_timer(L, 1);
2316}
2317
2318
2319/* mg.response.send() */
2320static int
2321lsp_response_send(lua_State *L)
2322{
2323	int http_status;
2324	int ret1, ret2, ret3;
2325
2326	struct mg_connection *conn =
2327	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
2328
2329	/* Get mg.response - table */
2330	lua_getglobal(L, "mg");
2331	if (!lua_istable(L, -1)) {
2332		return luaL_error(L, "table mg not available");
2333	}
2334	lua_pushstring(L, "response");
2335	lua_rawget(L, -2); /* rawget: no metatable */
2336	if (!lua_istable(L, -1)) {
2337		return luaL_error(L, "table mg.response not available");
2338	}
2339
2340	/* Get element: status code  */
2341	lua_pushstring(L, "status");
2342	lua_gettable(L, -2); /* get .. could use metatable */
2343	if (!lua_isnumber(L, -1)) {
2344		return luaL_error(L, "number mg.response.status not available");
2345	}
2346	http_status = (int)lua_tonumber(L, -1);
2347	lua_pop(L, 1); /* remove number "status" */
2348
2349	/* Get element: table of http response headers */
2350	lua_pushstring(L, "http_headers");
2351	lua_gettable(L, -2); /* get .. could use metatable */
2352	if (!lua_istable(L, -1)) {
2353		return luaL_error(L, "table mg.response.http_headers not available");
2354	}
2355
2356	/* Parameter checks passed, initiate response */
2357	ret1 = mg_response_header_start(conn, http_status);
2358	if (ret1 != 0) {
2359		lua_pushboolean(L, 0); /* false */
2360		lua_pushinteger(L, ret1);
2361		return 2;
2362	}
2363
2364	/* Iterate table of http response headers */
2365	ret2 = 0;
2366	lua_pushnil(L);
2367	while (lua_next(L, -2)) {
2368		int retadd = 0;
2369		int key_type = lua_type(L, -2);
2370		int value_type = lua_type(L, -1);
2371		if ((key_type == LUA_TSTRING) && (value_type == LUA_TSTRING)) {
2372			size_t key_len = 0, value_len = 0;
2373			const char *key = lua_tolstring(L, -2, &key_len);
2374			const char *value = lua_tolstring(L, -1, &value_len);
2375			retadd = mg_response_header_add(conn, key, value, (int)value_len);
2376		} else if ((key_type == LUA_TNUMBER) && (value_type == LUA_TSTRING)) {
2377			const char *value = lua_tostring(L, -1);
2378			retadd = mg_response_header_add_lines(conn, value);
2379		}
2380		if ((retadd != 0) && (ret2 == 0)) {
2381			/* Store first error */
2382			ret2 = retadd;
2383		}
2384		lua_pop(L, 1);
2385	}
2386
2387	/* Finalize */
2388	ret3 = mg_response_header_send(conn);
2389	if (ret3 == 0) {
2390		lua_pushboolean(L, 1);    /* TRUE */
2391		lua_pushinteger(L, ret2); /* Error/Warning from header_add */
2392	} else {
2393		lua_pushboolean(L, 0);    /* FALSE */
2394		lua_pushinteger(L, ret3); /* Error from header_send */
2395	}
2396	return 2;
2397}
2398
2399
2400/* Debug hook */
2401static void
2402lua_debug_hook(lua_State *L, lua_Debug *ar)
2403{
2404	int i;
2405	int stack_len = lua_gettop(L);
2406
2407	lua_getinfo(L, "nSlu", ar);
2408
2409	if (ar->event == LUA_HOOKCALL) {
2410		printf("call\n");
2411	} else if (ar->event == LUA_HOOKRET) {
2412		printf("ret\n");
2413#if defined(LUA_HOOKTAILRET)
2414	} else if (ar->event == LUA_HOOKTAILRET) {
2415		printf("tail ret\n");
2416#endif
2417#if defined(LUA_HOOKTAILCALL)
2418	} else if (ar->event == LUA_HOOKTAILCALL) {
2419		printf("tail call\n");
2420#endif
2421	} else if (ar->event == LUA_HOOKLINE) {
2422		printf("line\n");
2423	} else if (ar->event == LUA_HOOKCOUNT) {
2424		printf("count\n");
2425	} else {
2426		printf("unknown (%i)\n", ar->event);
2427	}
2428
2429	if (ar->currentline >= 0) {
2430		printf("%s:%i\n", ar->source, ar->currentline);
2431	}
2432
2433	printf("%s (%s)\n", ar->name, ar->namewhat);
2434
2435
2436	for (i = 1; i <= stack_len; i++) { /* repeat for each level */
2437		int val_type = lua_type(L, i);
2438		const char *s;
2439		size_t n;
2440
2441		switch (val_type) {
2442
2443		case LUA_TNIL:
2444			/* nil value  on the stack */
2445			printf("nil\n");
2446			break;
2447
2448		case LUA_TBOOLEAN:
2449			/* boolean (true / false) */
2450			printf("boolean: %s\n", lua_toboolean(L, i) ? "true" : "false");
2451			break;
2452
2453		case LUA_TNUMBER:
2454			/* number */
2455			printf("number: %g\n", lua_tonumber(L, i));
2456			break;
2457
2458		case LUA_TSTRING:
2459			/* string with limited length */
2460			s = lua_tolstring(L, i, &n);
2461			printf("string: '%.*s%s\n",
2462			       ((n > 30) ? 28 : (int)n),
2463			       s,
2464			       ((n > 30) ? ".." : "'"));
2465			break;
2466
2467		default:
2468			/* other values */
2469			printf("%s\n", lua_typename(L, val_type));
2470			break;
2471		}
2472	}
2473
2474	printf("\n");
2475}
2476
2477
2478/* Lua Environment */
2479enum {
2480	LUA_ENV_TYPE_LUA_SERVER_PAGE = 0, /* page.lp */
2481	LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,  /* script.lua */
2482	LUA_ENV_TYPE_LUA_WEBSOCKET = 2,   /* websock.lua */
2483	LUA_ENV_TYPE_BACKGROUND = 9 /* Lua backgrond script or exec from cmdline */
2484};
2485
2486
2487static void
2488push_lua_response_log_data(const struct mg_connection *conn, lua_State *L)
2489{
2490	int i;
2491	const char *s;
2492
2493	lua_newtable(L);
2494
2495	/* request status */
2496	reg_int(L, "status", conn->status_code);
2497
2498	/* protocol (http, https, ws, wss) */
2499	s = get_proto_name(conn);
2500	reg_string(L, "protocol", s);
2501
2502	/* request counter */
2503	reg_int(L, "handled_requests", conn->handled_requests);
2504
2505	/* data read and written */
2506	reg_i64(L, "read", conn->consumed_content);
2507	reg_i64(L, "written", conn->num_bytes_sent);
2508
2509#if !defined(NO_RESPONSE_BUFFERING)
2510	lua_pushstring(L, "http_headers");
2511	lua_newtable(L);
2512	for (i = 0; i < conn->response_info.num_headers; i++) {
2513		reg_string(L,
2514		           conn->response_info.http_headers[i].name,
2515		           conn->response_info.http_headers[i].value);
2516	}
2517	lua_rawset(L, -3);
2518#endif
2519
2520#if defined(USE_SERVER_STATS)
2521	reg_double(L, "processing_time", conn->processing_time);
2522#endif
2523}
2524
2525
2526static void
2527prepare_lua_request_info_inner(const struct mg_connection *conn, lua_State *L)
2528{
2529	const char *s;
2530	int i;
2531
2532	lua_newtable(L);
2533	reg_string(L, "request_method", conn->request_info.request_method);
2534	reg_string(L, "request_uri", conn->request_info.request_uri);
2535	reg_string(L, "uri", conn->request_info.local_uri);
2536	reg_string(L, "uri_raw", conn->request_info.local_uri_raw);
2537	reg_string(L, "http_version", conn->request_info.http_version);
2538	reg_string(L, "query_string", conn->request_info.query_string);
2539	reg_string(L, "remote_addr", conn->request_info.remote_addr);
2540	/* TODO (high): ip version */
2541	reg_int(L, "remote_port", conn->request_info.remote_port);
2542	reg_int(L, "server_port", conn->request_info.server_port);
2543	reg_int(L, "num_headers", conn->request_info.num_headers);
2544
2545	if (conn->path_info != NULL) {
2546		reg_string(L, "path_info", conn->path_info);
2547	}
2548
2549	{
2550		char buf[2048];
2551		if (0 == mg_get_request_link(conn, buf, sizeof(buf))) {
2552			reg_string(L, "request_link", buf);
2553		}
2554	}
2555
2556	if (conn->request_info.content_length >= 0) {
2557		/* reg_int64: content_length */
2558		lua_pushstring(L, "content_length");
2559		lua_pushnumber(
2560		    L,
2561		    (lua_Number)conn->request_info
2562		        .content_length); /* lua_Number may be used as 52 bit integer */
2563		lua_rawset(L, -3);
2564	}
2565	if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
2566		reg_string(L, "content_type", s);
2567	}
2568
2569	if (conn->request_info.remote_user != NULL) {
2570		reg_string(L, "remote_user", conn->request_info.remote_user);
2571		reg_string(L, "auth_type", "Digest");
2572	}
2573
2574	reg_boolean(L, "https", conn->ssl != NULL);
2575
2576	if (conn->status_code > 0) {
2577		/* Lua error handler should show the status code */
2578		reg_int(L, "status", conn->status_code);
2579	}
2580
2581	/* Table "HTTP headers" */
2582	lua_pushstring(L, "http_headers");
2583	lua_newtable(L);
2584	for (i = 0; i < conn->request_info.num_headers; i++) {
2585		reg_string(L,
2586		           conn->request_info.http_headers[i].name,
2587		           conn->request_info.http_headers[i].value);
2588	}
2589	lua_rawset(L, -3);
2590
2591	/* Table "Client Certificate" */
2592	if (conn->request_info.client_cert) {
2593		lua_pushstring(L, "client_cert");
2594		lua_newtable(L);
2595		reg_string(L, "subject", conn->request_info.client_cert->subject);
2596		reg_string(L, "issuer", conn->request_info.client_cert->issuer);
2597		reg_string(L, "serial", conn->request_info.client_cert->serial);
2598		reg_string(L, "finger", conn->request_info.client_cert->finger);
2599		lua_rawset(L, -3);
2600	}
2601}
2602
2603
2604static void
2605prepare_lua_request_info(const struct mg_connection *conn, lua_State *L)
2606{
2607	/* Export mg.request_info */
2608	lua_pushstring(L, "request_info");
2609	prepare_lua_request_info_inner(conn, L);
2610
2611	/* End of request_info */
2612	lua_rawset(L, -3);
2613}
2614
2615
2616static void
2617prepare_lua_response_table(struct mg_connection *conn, lua_State *L)
2618{
2619	/* Export mg.request_info */
2620	lua_pushstring(L, "response");
2621	lua_newtable(L);
2622
2623	/* Add table elements */
2624
2625	/* HTTP status code (default to 200 OK) */
2626	reg_int(L, "status", 200);
2627
2628	/* Table "HTTP headers" */
2629	lua_pushstring(L, "http_headers");
2630	lua_newtable(L);
2631	/* Initially empty */
2632	lua_rawset(L, -3);
2633
2634	/* mg_response_header_send wrapper */
2635	reg_conn_function(L, "send", lsp_response_send, conn);
2636
2637	/* End of response table */
2638	lua_rawset(L, -3);
2639}
2640
2641
2642static void *
2643lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
2644{
2645	(void)osize; /* not used */
2646
2647	if (nsize == 0) {
2648		mg_free(ptr);
2649		return NULL;
2650	}
2651
2652	return mg_realloc_ctx(ptr, nsize, (struct mg_context *)ud);
2653}
2654
2655
2656/* In CivetWeb, Lua-Shared is used as *.inl file */
2657#define LUA_SHARED_INTERFACE static
2658#include "mod_lua_shared.inl"
2659
2660
2661static void
2662civetweb_open_lua_libs(lua_State *L)
2663{
2664	{
2665		extern void luaL_openlibs(lua_State *);
2666		luaL_openlibs(L);
2667	}
2668
2669#if defined(USE_LUA_SQLITE3)
2670	{
2671		extern int luaopen_lsqlite3(lua_State *);
2672		luaopen_lsqlite3(L);
2673	}
2674#endif
2675#if defined(USE_LUA_LUAXML)
2676	{
2677		extern int luaopen_LuaXML_lib(lua_State *);
2678		luaopen_LuaXML_lib(L);
2679		// lua_pushvalue(L, -1); to copy value
2680		lua_setglobal(L, "xml");
2681	}
2682#endif
2683#if defined(USE_LUA_FILE_SYSTEM)
2684	{
2685		extern int luaopen_lfs(lua_State *);
2686		luaopen_lfs(L);
2687	}
2688#endif
2689}
2690
2691
2692/* garbage collect "mg"
2693 * this indicates when a Lua state is closed
2694 */
2695static int
2696lsp_mg_gc(lua_State *L)
2697{
2698	int context_flags;
2699	struct mg_context *ctx;
2700	struct mg_connection *conn =
2701	    (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
2702
2703	lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2704	lua_gettable(L, LUA_REGISTRYINDEX);
2705	ctx = (struct mg_context *)lua_touserdata(L, -1);
2706
2707	lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
2708	lua_gettable(L, LUA_REGISTRYINDEX);
2709	context_flags = lua_tointeger(L, -1);
2710
2711	if (ctx != NULL) {
2712		if (ctx->callbacks.exit_lua != NULL) {
2713			ctx->callbacks.exit_lua(conn, L, (unsigned)context_flags);
2714		}
2715	}
2716
2717	return 0;
2718}
2719
2720
2721static void
2722reg_gc(lua_State *L, void *conn)
2723{
2724	/* Key element */
2725	lua_pushlightuserdata(L, (void *)&lua_regkey_dtor);
2726
2727	/* Value element */
2728	lua_newuserdata(L, 0);
2729
2730	/* Prepare metatable for value element */
2731	lua_newtable(L);
2732
2733	/* Add garbage collector key to metatable */
2734	lua_pushliteral(L, "__gc");
2735
2736	/* Add garbage collector function with one upvalue (conn) */
2737	lua_pushlightuserdata(L, conn);
2738	lua_pushcclosure(L, lsp_mg_gc, 1);
2739
2740	/* Set __gc = function lsp_mg_gc in metatable */
2741	lua_rawset(L, -3);
2742
2743	/* Set metatable for "value element" */
2744	lua_setmetatable(L, -2);
2745
2746	/* Add key (lightuserdata) = value (userdata with metatable) */
2747	lua_settable(L, LUA_REGISTRYINDEX);
2748}
2749
2750
2751static int
2752lua_error_handler(lua_State *L)
2753{
2754	const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
2755
2756	lua_getglobal(L, "mg");
2757	if (!lua_isnil(L, -1)) {
2758		lua_getfield(L, -1, "write"); /* call mg.write() */
2759		lua_pushstring(L, error_msg);
2760		lua_pushliteral(L, "\n");
2761		lua_call(L, 2, 0);
2762		IGNORE_UNUSED_RESULT(
2763		    luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
2764	} else {
2765		printf("Lua error: [%s]\n", error_msg);
2766		IGNORE_UNUSED_RESULT(
2767		    luaL_dostring(L, "print(debug.traceback(), '\\n')"));
2768	}
2769	/* TODO(lsm, low): leave the stack balanced */
2770
2771	return 0;
2772}
2773
2774
2775static void
2776prepare_lua_environment(struct mg_context *ctx,
2777                        struct mg_connection *conn,
2778                        struct lua_websock_data *ws_conn_list,
2779                        lua_State *L,
2780                        const char *script_name,
2781                        int lua_env_type)
2782{
2783	const char *preload_file_name = NULL;
2784	const char *debug_params = NULL;
2785
2786	int lua_context_flags = lua_env_type;
2787
2788	civetweb_open_lua_libs(L);
2789
2790#if defined(MG_EXPERIMENTAL_INTERFACES)
2791	/* Check if debugging should be enabled */
2792	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
2793		debug_params = conn->dom_ctx->config[LUA_DEBUG_PARAMS];
2794	}
2795#endif
2796
2797#if LUA_VERSION_NUM == 502
2798	/* Keep the "connect" method for compatibility,
2799	 * but do not backport it to Lua 5.1.
2800	 * TODO: Redesign the interface.
2801	 */
2802	luaL_newmetatable(L, LUASOCKET);
2803	/* self.__index = self */
2804	lua_pushvalue(L, -1);
2805	lua_setfield(L, -2, "__index");
2806	luaL_setfuncs(L, luasocket_methods, 0);
2807	lua_pop(L, 1);
2808	lua_register(L, "connect", lsp_connect);
2809#endif
2810
2811	/* Store context in the registry */
2812	if (ctx != NULL) {
2813		lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2814		lua_pushlightuserdata(L, (void *)ctx);
2815		lua_settable(L, LUA_REGISTRYINDEX);
2816	}
2817	if (ws_conn_list != NULL) {
2818		lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
2819		lua_pushlightuserdata(L, (void *)ws_conn_list);
2820		lua_settable(L, LUA_REGISTRYINDEX);
2821	}
2822	lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
2823	lua_pushinteger(L, lua_context_flags);
2824	lua_settable(L, LUA_REGISTRYINDEX);
2825
2826	/* State close function */
2827	reg_gc(L, conn);
2828
2829	/* Lua server pages store the depth of mg.include, in order
2830	 * to detect recursions and prevent stack overflows. */
2831	if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
2832		struct lsp_include_history *h;
2833		lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
2834		h = (struct lsp_include_history *)
2835		    lua_newuserdata(L, sizeof(struct lsp_include_history));
2836		lua_settable(L, LUA_REGISTRYINDEX);
2837		memset(h, 0, sizeof(struct lsp_include_history));
2838	}
2839
2840	/* Register mg module */
2841	lua_newtable(L);
2842
2843	switch (lua_env_type) {
2844	case LUA_ENV_TYPE_LUA_SERVER_PAGE:
2845		reg_string(L, "lua_type", "page");
2846		break;
2847	case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
2848		reg_string(L, "lua_type", "script");
2849		break;
2850	case LUA_ENV_TYPE_LUA_WEBSOCKET:
2851		reg_string(L, "lua_type", "websocket");
2852		break;
2853	case LUA_ENV_TYPE_BACKGROUND:
2854		reg_string(L, "lua_type", "background");
2855		break;
2856	}
2857
2858	if ((lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE)
2859	    || (lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE)) {
2860		reg_conn_function(L, "cry", lsp_cry, conn);
2861		reg_conn_function(L, "read", lsp_read, conn);
2862		reg_conn_function(L, "write", lsp_write, conn);
2863		reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
2864		reg_conn_function(L, "send_file", lsp_send_file, conn);
2865		reg_conn_function(L, "send_file_body", lsp_send_file_body, conn);
2866		reg_conn_function(L, "send_http_error", lsp_send_http_error, conn);
2867		reg_conn_function(L, "send_http_ok", lsp_send_http_ok, conn);
2868		reg_conn_function(L,
2869		                  "send_http_redirect",
2870		                  lsp_send_http_redirect,
2871		                  conn);
2872		reg_conn_function(L, "redirect", lsp_redirect, conn);
2873	}
2874
2875	if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
2876		reg_conn_function(L, "include", lsp_include, conn);
2877	}
2878
2879	if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
2880		reg_function(L, "write", lwebsock_write);
2881	}
2882
2883#if defined(USE_TIMERS)
2884	if ((lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET)
2885	    || (lua_env_type == LUA_ENV_TYPE_BACKGROUND)) {
2886		reg_function(L, "set_timeout", lwebsocket_set_timeout);
2887		reg_function(L, "set_interval", lwebsocket_set_interval);
2888#endif
2889	}
2890
2891	reg_conn_function(L, "get_mime_type", lsp_get_mime_type, conn);
2892	reg_conn_function(L, "get_option", lsp_get_option, conn);
2893
2894	reg_function(L, "time", lsp_get_time);
2895	reg_function(L, "get_var", lsp_get_var);
2896	reg_function(L, "split_form_data", lsp_split_form_urlencoded);
2897	reg_function(L, "get_cookie", lsp_get_cookie);
2898	reg_function(L, "md5", lsp_md5);
2899	reg_function(L, "url_encode", lsp_url_encode);
2900	reg_function(L, "url_decode", lsp_url_decode);
2901	reg_function(L, "base64_encode", lsp_base64_encode);
2902	reg_function(L, "base64_decode", lsp_base64_decode);
2903	reg_function(L, "get_response_code_text", lsp_get_response_code_text);
2904	reg_function(L, "random", lsp_random);
2905	reg_function(L, "get_info", lsp_get_info);
2906	reg_function(L, "trace", lsp_trace);
2907
2908	if (pf_uuid_generate.f) {
2909		reg_function(L, "uuid", lsp_uuid);
2910	}
2911
2912	reg_string(L, "version", CIVETWEB_VERSION);
2913
2914	reg_string(L, "script_name", script_name);
2915
2916	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
2917		reg_string(L, "document_root", conn->dom_ctx->config[DOCUMENT_ROOT]);
2918		reg_string(L,
2919		           "auth_domain",
2920		           conn->dom_ctx->config[AUTHENTICATION_DOMAIN]);
2921#if defined(USE_WEBSOCKET)
2922		if (conn->dom_ctx->config[WEBSOCKET_ROOT]) {
2923			reg_string(L,
2924			           "websocket_root",
2925			           conn->dom_ctx->config[WEBSOCKET_ROOT]);
2926		} else {
2927			reg_string(L,
2928			           "websocket_root",
2929			           conn->dom_ctx->config[DOCUMENT_ROOT]);
2930		}
2931#endif
2932
2933		if ((ctx != NULL) && (ctx->systemName != NULL)) {
2934			reg_string(L, "system", ctx->systemName);
2935		}
2936	}
2937
2938	/* Export connection specific info */
2939	if (conn != NULL) {
2940		/* mg.request_info.* available for all environments */
2941		prepare_lua_request_info(conn, L);
2942
2943		if (lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
2944			/* mg.response.* available only for *.lua scripts */
2945			prepare_lua_response_table(conn, L);
2946		}
2947	}
2948
2949	/* Store as global table "mg" */
2950	lua_setglobal(L, "mg");
2951
2952	/* Register "shared" table */
2953	lua_shared_register(L);
2954
2955	/* Register default mg.onerror function */
2956	IGNORE_UNUSED_RESULT(
2957	    luaL_dostring(L,
2958	                  "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
2959	                  "debug.traceback(e, 1)) end"));
2960
2961	/* Check if a preload file is available */
2962	if ((conn != NULL) && (conn->dom_ctx != NULL)) {
2963		preload_file_name = conn->dom_ctx->config[LUA_PRELOAD_FILE];
2964	}
2965
2966	/* Call user init function */
2967	if (ctx != NULL) {
2968		if (ctx->callbacks.init_lua != NULL) {
2969			ctx->callbacks.init_lua(conn, L, lua_context_flags);
2970		}
2971	}
2972
2973	/* Preload file into new Lua environment */
2974	if (preload_file_name) {
2975		int ret = luaL_loadfile(L, preload_file_name);
2976		if (ret != 0) {
2977			lua_error_handler(L);
2978		} else {
2979			ret = lua_pcall(L, 0, 1, 0);
2980		}
2981	}
2982
2983	/* If debugging is enabled, add a hook */
2984	if (debug_params) {
2985		int mask = 0;
2986		if (0 != strchr(debug_params, 'c')) {
2987			mask |= LUA_MASKCALL;
2988		}
2989		if (0 != strchr(debug_params, 'r')) {
2990			mask |= LUA_MASKRET;
2991		}
2992		if (0 != strchr(debug_params, 'l')) {
2993			mask |= LUA_MASKLINE;
2994		}
2995		lua_sethook(L, lua_debug_hook, mask, 0);
2996	}
2997}
2998
2999
3000static void
3001mg_exec_lua_script(struct mg_connection *conn,
3002                   const char *path,
3003                   const void **exports)
3004{
3005	int i;
3006	lua_State *L;
3007
3008	/* Assume the script does not support keep_alive. The script may change this
3009	 * by calling mg.keep_alive(true). */
3010	conn->must_close = 1;
3011
3012	/* Execute a plain Lua script. */
3013	if (path != NULL
3014	    && (L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx)))
3015	           != NULL) {
3016		prepare_lua_environment(
3017		    conn->phys_ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
3018		lua_pushcclosure(L, &lua_error_handler, 0);
3019
3020		if (exports != NULL) {
3021#if LUA_VERSION_NUM > 501
3022			lua_pushglobaltable(L);
3023			for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
3024				lua_CFunction func;
3025				lua_pushstring(L, (const char *)(exports[i]));
3026				*(const void **)(&func) = exports[i + 1];
3027				lua_pushcclosure(L, func, 0);
3028				lua_rawset(L, -3);
3029			}
3030#else
3031			for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
3032				lua_CFunction func;
3033				const char *name = (const char *)(exports[i]);
3034				*(const void **)(&func) = exports[i + 1];
3035				lua_register(L, name, func);
3036			}
3037#endif
3038		}
3039
3040		if (luaL_loadfile(L, path) != 0) {
3041			lua_error_handler(L);
3042		} else {
3043			lua_pcall(L, 0, 0, -2);
3044		}
3045		lua_close(L);
3046	}
3047}
3048
3049
3050static int
3051handle_lsp_request(struct mg_connection *conn,
3052                   const char *path,
3053                   struct mg_file *filep,
3054                   struct lua_State *ls)
3055{
3056	void *p = NULL;
3057	lua_State *L = NULL;
3058	struct lsp_include_history *include_history;
3059	int error = 1;
3060	int (*run_lsp)(struct mg_connection *,
3061	               const char *,
3062	               const char *,
3063	               int64_t,
3064	               lua_State *,
3065	               int);
3066	const char *addr;
3067
3068	/* mg_fopen opens the file and sets the size accordingly */
3069	if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
3070
3071		/* File not found or not accessible */
3072		if (ls == NULL) {
3073			mg_send_http_error(conn,
3074			                   500,
3075			                   "Error: Cannot open script file %s",
3076			                   path);
3077		} else {
3078			luaL_error(ls, "Cannot include [%s]: not found", path);
3079		}
3080
3081		goto cleanup_handle_lsp_request;
3082	}
3083
3084	/* Map file in memory (size is known). */
3085	if ((p = mmap(NULL,
3086	              (size_t)filep->stat.size,
3087	              PROT_READ,
3088	              MAP_PRIVATE,
3089	              fileno(filep->access.fp),
3090	              0))
3091	    == NULL) {
3092
3093		/* File was not already in memory, and mmap failed now.
3094		 * Since wi have no data, show an error. */
3095		if (ls == NULL) {
3096			/* No open Lua state - use generic error function */
3097			mg_send_http_error(
3098			    conn,
3099			    500,
3100			    "Error: Cannot open script\nFile %s can not be mapped",
3101			    path);
3102		} else {
3103			/* Lua state exists - use Lua error function */
3104			luaL_error(ls,
3105			           "mmap(%s, %zu, %d): %s",
3106			           path,
3107			           (size_t)filep->stat.size,
3108			           fileno(filep->access.fp),
3109			           strerror(errno));
3110		}
3111
3112		goto cleanup_handle_lsp_request;
3113	}
3114
3115	/* File content is now memory mapped. Get mapping address. */
3116	addr = (const char *)p;
3117
3118	/* Get a Lua state */
3119	if (ls != NULL) {
3120		/* We got a Lua state as argument. Use it! */
3121		L = ls;
3122	} else {
3123		/* We need to create a Lua state. */
3124		L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx));
3125		if (L == NULL) {
3126			/* We neither got a Lua state from the command line,
3127			 * nor did we succeed in creating our own state.
3128			 * Show an error, and stop further processing of this request. */
3129			mg_send_http_error(
3130			    conn,
3131			    500,
3132			    "%s",
3133			    "Error: Cannot execute script\nlua_newstate failed");
3134
3135			goto cleanup_handle_lsp_request;
3136		}
3137
3138		/* New Lua state needs CivetWeb functions (e.g., the "mg" library). */
3139		prepare_lua_environment(
3140		    conn->phys_ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
3141	}
3142
3143	/* Get LSP include history table */
3144	lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
3145	lua_gettable(L, LUA_REGISTRYINDEX);
3146	include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
3147
3148	/* Store script name and increment depth */
3149	include_history->depth++;
3150	include_history->script[include_history->depth] = path;
3151
3152	/* Lua state is ready to use now. */
3153	/* Currently we have two different syntax options:
3154	 * Either "classic" CivetWeb syntax:
3155	 *    <? code ?>
3156	 *    <?= expression ?>
3157	 * Or "Kepler Syntax"
3158	 * https://keplerproject.github.io/cgilua/manual.html#templates
3159	 *    <?lua chunk ?>
3160	 *    <?lua= expression ?>
3161	 *    <% chunk %>
3162	 *    <%= expression %>
3163	 *
3164	 * Two important differences are:
3165	 * - In the "classic" CivetWeb syntax, the Lua Page had to send the HTTP
3166	 *   response headers itself. So the first lines are usually something like
3167	 *   HTTP/1.0 200 OK
3168	 *   Content-Type: text/html
3169	 *   followed by additional headers and an empty line, before the actual
3170	 *   Lua page in HTML syntax with <? code ?> tags.
3171	 *   The "Kepler"Syntax" does not send any HTTP header from the Lua Server
3172	 *   Page, but starts directly with <html> code - so it cannot influence
3173	 *   the HTTP response code, e.g., to send a 301 Moved Permanently.
3174	 *   Due to this difference, the same *.lp file cannot be used with the
3175	 *   same algorithm.
3176	 * - The "Kepler Syntax" used to allow mixtures of Lua and HTML inside an
3177	 *   incomplete Lua block, e.g.:
3178	 *   <lua? for i=1,10 do ?><li><%= key %></li><lua? end ?>
3179	 *   This was not provided in "classic" CivetWeb syntax, but you had to use
3180	 *   <? for i=1,10 do mg.write("<li>"..i.."</li>") end ?>
3181	 *   instead. The parsing algorithm for "Kepler syntax" is more complex
3182	 *   than for "classic" CivetWeb syntax - TODO: check timing/performance.
3183	 *
3184	 * CivetWeb now can use both parsing methods, but needs to know what
3185	 * parsing algorithm should be used.
3186	 * Idea: Files starting with '<' are HTML files in "Kepler Syntax", except
3187	 * "<?" which means "classic CivetWeb Syntax".
3188	 *
3189	 */
3190	run_lsp = run_lsp_civetweb;
3191	if ((addr[0] == '<') && (addr[1] != '?')) {
3192		run_lsp = run_lsp_kepler;
3193	}
3194
3195	/* We're not sending HTTP headers here, Lua page must do it. */
3196	error =
3197	    run_lsp(conn, path, addr, filep->stat.size, L, include_history->depth);
3198
3199	/* pop from stack */
3200	include_history->depth--;
3201
3202cleanup_handle_lsp_request:
3203
3204	if (L != NULL && ls == NULL)
3205		lua_close(L);
3206	if (p != NULL)
3207		munmap(p, filep->stat.size);
3208	(void)mg_fclose(&filep->access);
3209
3210	return error;
3211}
3212
3213
3214#if defined(USE_WEBSOCKET)
3215struct mg_shared_lua_websocket_list {
3216	struct lua_websock_data ws;
3217	struct mg_shared_lua_websocket_list *next;
3218};
3219
3220
3221static void *
3222lua_websocket_new(const char *script, struct mg_connection *conn)
3223{
3224	struct mg_shared_lua_websocket_list **shared_websock_list =
3225	    &(conn->dom_ctx->shared_lua_websockets);
3226	struct lua_websock_data *ws;
3227	int err, ok = 0;
3228
3229	DEBUG_ASSERT(conn->lua_websocket_state == NULL);
3230
3231	/* lock list (mg_context global) */
3232	mg_lock_context(conn->phys_ctx);
3233	while (*shared_websock_list) {
3234		/* check if ws already in list */
3235		if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
3236			break;
3237		}
3238		shared_websock_list = &((*shared_websock_list)->next);
3239	}
3240
3241	if (*shared_websock_list == NULL) {
3242		/* add ws to list */
3243		*shared_websock_list =
3244		    (struct mg_shared_lua_websocket_list *)mg_calloc_ctx(
3245		        sizeof(struct mg_shared_lua_websocket_list), 1, conn->phys_ctx);
3246		if (*shared_websock_list == NULL) {
3247			conn->must_close = 1;
3248			mg_unlock_context(conn->phys_ctx);
3249			mg_cry_internal(conn,
3250			                "%s",
3251			                "Cannot create shared websocket struct, OOM");
3252			return NULL;
3253		}
3254		/* init ws list element */
3255		ws = &(*shared_websock_list)->ws;
3256		ws->script = mg_strdup_ctx(script, conn->phys_ctx);
3257		if (!ws->script) {
3258			conn->must_close = 1;
3259			mg_unlock_context(conn->phys_ctx);
3260			mg_cry_internal(conn,
3261			                "%s",
3262			                "Cannot create shared websocket script, OOM");
3263			return NULL;
3264		}
3265		pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
3266		(void)pthread_mutex_lock(&(ws->ws_mutex));
3267		ws->state = lua_newstate(lua_allocator, (void *)(conn->phys_ctx));
3268		ws->conn[0] = conn;
3269		ws->references = 1;
3270		prepare_lua_environment(conn->phys_ctx,
3271		                        conn,
3272		                        ws,
3273		                        ws->state,
3274		                        script,
3275		                        LUA_ENV_TYPE_LUA_WEBSOCKET);
3276		err = luaL_loadfile(ws->state, script);
3277		if (err != 0) {
3278			lua_cry(conn, err, ws->state, script, "load");
3279		}
3280		err = lua_pcall(ws->state, 0, 0, 0);
3281		if (err != 0) {
3282			lua_cry(conn, err, ws->state, script, "init");
3283		}
3284	} else {
3285		/* inc ref count */
3286		ws = &(*shared_websock_list)->ws;
3287		(void)pthread_mutex_lock(&(ws->ws_mutex));
3288		(*shared_websock_list)->ws.conn[(ws->references)++] = conn;
3289	}
3290	mg_unlock_context(conn->phys_ctx);
3291
3292	/* call add */
3293	lua_getglobal(ws->state, "open");
3294	lua_newtable(ws->state);
3295	prepare_lua_request_info(conn, ws->state);
3296	lua_pushstring(ws->state, "client");
3297	lua_pushlightuserdata(ws->state, (void *)conn);
3298	lua_rawset(ws->state, -3);
3299
3300	err = lua_pcall(ws->state, 1, 1, 0);
3301	if (err != 0) {
3302		lua_cry(conn, err, ws->state, script, "open handler");
3303	} else {
3304		if (lua_isboolean(ws->state, -1)) {
3305			ok = lua_toboolean(ws->state, -1);
3306		}
3307		lua_pop(ws->state, 1);
3308	}
3309	if (!ok) {
3310		/* Remove from ws connection list. */
3311		/* TODO (mid): Check if list entry and Lua state needs to be deleted
3312		 * (see websocket_close). */
3313		(*shared_websock_list)->ws.conn[--(ws->references)] = 0;
3314	}
3315
3316	(void)pthread_mutex_unlock(&(ws->ws_mutex));
3317
3318	return ok ? (void *)ws : NULL;
3319}
3320
3321
3322static int
3323lua_websocket_data(struct mg_connection *conn,
3324                   int bits,
3325                   char *data,
3326                   size_t data_len,
3327                   void *ws_arg)
3328{
3329	struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
3330	int err, ok = 0;
3331
3332	DEBUG_ASSERT(ws != NULL);
3333	DEBUG_ASSERT(ws->state != NULL);
3334
3335	(void)pthread_mutex_lock(&(ws->ws_mutex));
3336
3337	lua_getglobal(ws->state, "data");
3338	lua_newtable(ws->state);
3339	lua_pushstring(ws->state, "client");
3340	lua_pushlightuserdata(ws->state, (void *)conn);
3341	lua_rawset(ws->state, -3);
3342	lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
3343	                                      a meaning according to
3344	                                      http://tools.ietf.org/html/rfc6455,
3345	                                      section 5.2 */
3346	lua_pushnumber(ws->state, bits);
3347	lua_rawset(ws->state, -3);
3348	lua_pushstring(ws->state, "data");
3349	lua_pushlstring(ws->state, data, data_len);
3350	lua_rawset(ws->state, -3);
3351
3352	err = lua_pcall(ws->state, 1, 1, 0);
3353	if (err != 0) {
3354		lua_cry(conn, err, ws->state, ws->script, "data handler");
3355	} else {
3356		if (lua_isboolean(ws->state, -1)) {
3357			ok = lua_toboolean(ws->state, -1);
3358		}
3359		lua_pop(ws->state, 1);
3360	}
3361	(void)pthread_mutex_unlock(&(ws->ws_mutex));
3362
3363	return ok;
3364}
3365
3366
3367static int
3368lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
3369{
3370	struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
3371	int err, ok = 0;
3372
3373	DEBUG_ASSERT(ws != NULL);
3374	DEBUG_ASSERT(ws->state != NULL);
3375
3376	(void)pthread_mutex_lock(&(ws->ws_mutex));
3377
3378	lua_getglobal(ws->state, "ready");
3379	lua_newtable(ws->state);
3380	lua_pushstring(ws->state, "client");
3381	lua_pushlightuserdata(ws->state, (void *)conn);
3382	lua_rawset(ws->state, -3);
3383	err = lua_pcall(ws->state, 1, 1, 0);
3384	if (err != 0) {
3385		lua_cry(conn, err, ws->state, ws->script, "ready handler");
3386	} else {
3387		if (lua_isboolean(ws->state, -1)) {
3388			ok = lua_toboolean(ws->state, -1);
3389		}
3390		lua_pop(ws->state, 1);
3391	}
3392
3393	(void)pthread_mutex_unlock(&(ws->ws_mutex));
3394
3395	return ok;
3396}
3397
3398
3399static void
3400lua_websocket_close(struct mg_connection *conn, void *ws_arg)
3401{
3402	struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
3403	struct mg_shared_lua_websocket_list **shared_websock_list =
3404	    &(conn->dom_ctx->shared_lua_websockets);
3405	int err = 0;
3406	unsigned i;
3407	int delete_state = 0;
3408
3409	DEBUG_ASSERT(ws != NULL);
3410	DEBUG_ASSERT(ws->state != NULL);
3411
3412	(void)pthread_mutex_lock(&(ws->ws_mutex));
3413
3414	lua_getglobal(ws->state, "close");
3415	lua_newtable(ws->state);
3416	lua_pushstring(ws->state, "client");
3417	lua_pushlightuserdata(ws->state, (void *)conn);
3418	lua_rawset(ws->state, -3);
3419
3420	err = lua_pcall(ws->state, 1, 0, 0);
3421	if (err != 0) {
3422		lua_cry(conn, err, ws->state, ws->script, "close handler");
3423	}
3424	for (i = 0; i < ws->references; i++) {
3425		if (ws->conn[i] == conn) {
3426			ws->references--;
3427			if (ws->references == 0) {
3428				delete_state = 1;
3429				break;
3430			}
3431			ws->conn[i] = ws->conn[ws->references];
3432		}
3433	}
3434	/* TODO: Delete lua_websock_data and remove it from the websocket list.
3435	   This must only be done, when all connections are closed, and all
3436	   asynchronous operations and timers are completed/expired. */
3437	if (delete_state) {
3438		/* lock list (mg_context global) */
3439		mg_lock_context(conn->phys_ctx);
3440		while (*shared_websock_list) {
3441			/* find ws in list */
3442			if (0 == strcmp(ws->script, (*shared_websock_list)->ws.script)) {
3443				break;
3444			}
3445			shared_websock_list = &((*shared_websock_list)->next);
3446		}
3447		if (*shared_websock_list != NULL) {
3448			/* TODO: If we close the state here, timers must be stopped first */
3449			/* lua_close(ws->state); <-- other thread will crash, if there are
3450			 * still active timers */
3451		}
3452		mg_unlock_context(conn->phys_ctx);
3453	}
3454
3455	(void)pthread_mutex_unlock(&(ws->ws_mutex));
3456}
3457#endif
3458
3459
3460static lua_State *
3461mg_lua_context_script_prepare(const char *file_name,
3462                              struct mg_context *ctx,
3463                              char *ebuf,
3464                              size_t ebuf_len)
3465{
3466	struct lua_State *L;
3467	int lua_ret;
3468	const char *lua_err_txt;
3469
3470	L = luaL_newstate();
3471	if (L == NULL) {
3472		mg_snprintf(NULL,
3473		            NULL, /* No truncation check for ebuf */
3474		            ebuf,
3475		            ebuf_len,
3476		            "Error: %s",
3477		            "Cannot create Lua state");
3478		return 0;
3479	}
3480
3481	/* Add all libraries */
3482	prepare_lua_environment(ctx,
3483	                        NULL /* conn */,
3484	                        NULL /* WS list*/,
3485	                        L,
3486	                        file_name,
3487	                        LUA_ENV_TYPE_BACKGROUND);
3488
3489	/* Load lua script file */
3490	lua_ret = luaL_loadfile(L, file_name);
3491	if (lua_ret != LUA_OK) {
3492		/* Error when loading the file (e.g. file not found,
3493		 * out of memory, ...)
3494		 */
3495		lua_err_txt = lua_tostring(L, -1);
3496		mg_snprintf(NULL,
3497		            NULL, /* No truncation check for ebuf */
3498		            ebuf,
3499		            ebuf_len,
3500		            "Error loading file %s: %s\n",
3501		            file_name,
3502		            lua_err_txt);
3503		lua_close(L);
3504		return 0;
3505	}
3506	/*	lua_close(L); must be done somewhere else */
3507	return L;
3508}
3509
3510
3511static lua_State *
3512mg_lua_context_script_run(lua_State *L,
3513                          const char *file_name,
3514                          struct mg_context *ctx,
3515                          char *ebuf,
3516                          size_t ebuf_len)
3517{
3518	int lua_ret;
3519	const char *lua_err_txt;
3520
3521	(void)ctx;
3522
3523	/* The script file is loaded, now call it */
3524	lua_ret = lua_pcall(L,
3525	                    /* no arguments */ 0,
3526	                    /* zero or one return value */ 1,
3527	                    /* errors as string return value */ 0);
3528
3529	if (lua_ret != LUA_OK) {
3530		/* Error when executing the script */
3531		lua_err_txt = lua_tostring(L, -1);
3532		mg_snprintf(NULL,
3533		            NULL, /* No truncation check for ebuf */
3534		            ebuf,
3535		            ebuf_len,
3536		            "Error running file %s: %s\n",
3537		            file_name,
3538		            lua_err_txt);
3539		lua_close(L);
3540		return 0;
3541	}
3542
3543	/* Check optional return value */
3544	if (lua_isboolean(L, -1)) {
3545		/* A boolean return value false indicates failure */
3546		int ret = lua_toboolean(L, -1);
3547		if (ret == 0) {
3548			/* Script returned false */
3549			mg_snprintf(NULL,
3550			            NULL, /* No truncation check for ebuf */
3551			            ebuf,
3552			            ebuf_len,
3553			            "Script %s returned false\n",
3554			            file_name);
3555			lua_close(L);
3556			return 0;
3557		}
3558	}
3559
3560	/*	lua_close(L); must be done somewhere else */
3561	return L;
3562}
3563
3564
3565static void
3566lua_ctx_init(struct mg_context *ctx)
3567{
3568#if defined(USE_WEBSOCKET)
3569	ctx->dd.shared_lua_websockets = NULL;
3570#endif
3571}
3572
3573
3574static void
3575lua_ctx_exit(struct mg_context *ctx)
3576{
3577#if defined(USE_WEBSOCKET)
3578	struct mg_shared_lua_websocket_list **shared_websock_list =
3579	    &(ctx->dd.shared_lua_websockets);
3580	struct mg_shared_lua_websocket_list *next;
3581
3582	mg_lock_context(ctx);
3583	while (*shared_websock_list) {
3584		lua_close((*shared_websock_list)->ws.state);
3585		mg_free((*shared_websock_list)->ws.script);
3586
3587		/* Save "next" pointer before freeing list element */
3588		next = ((*shared_websock_list)->next);
3589		mg_free(*shared_websock_list);
3590		shared_websock_list = &next;
3591	}
3592	mg_unlock_context(ctx);
3593#endif
3594}
3595
3596
3597/* Execute Lua script from main */
3598int
3599run_lua(const char *file_name)
3600{
3601	int func_ret = EXIT_FAILURE;
3602	char ebuf[512] = {0};
3603	lua_State *L =
3604	    mg_lua_context_script_prepare(file_name, NULL, ebuf, sizeof(ebuf));
3605
3606	if (L) {
3607		L = mg_lua_context_script_run(L, file_name, NULL, ebuf, sizeof(ebuf));
3608	}
3609
3610	if (L) {
3611		/* Script executed */
3612		if (lua_type(L, -1) == LUA_TNUMBER) {
3613			func_ret = (int)lua_tonumber(L, -1);
3614		} else {
3615			func_ret = EXIT_SUCCESS;
3616		}
3617		lua_close(L);
3618	} else {
3619		fprintf(stderr, "%s\n", ebuf);
3620	}
3621	return func_ret;
3622}
3623
3624
3625static void *lib_handle_uuid = NULL;
3626
3627static void
3628lua_init_optional_libraries(void)
3629{
3630	/* Create logging mutex */
3631	pthread_mutex_init(&s_lua_traceMutex, &pthread_mutex_attr);
3632
3633	/* shared Lua state */
3634	lua_shared_init();
3635
3636/* UUID library */
3637#if !defined(_WIN32)
3638	lib_handle_uuid = dlopen("libuuid.so", RTLD_LAZY);
3639	pf_uuid_generate.p =
3640	    (lib_handle_uuid ? dlsym(lib_handle_uuid, "uuid_generate") : 0);
3641#else
3642	pf_uuid_generate.p = 0;
3643#endif
3644}
3645
3646
3647static void
3648lua_exit_optional_libraries(void)
3649{
3650/* UUID library */
3651#if !defined(_WIN32)
3652	if (lib_handle_uuid) {
3653		dlclose(lib_handle_uuid);
3654	}
3655#endif
3656	pf_uuid_generate.p = 0;
3657	lib_handle_uuid = NULL;
3658
3659	/* shared Lua state */
3660	lua_shared_exit();
3661
3662	/* Delete logging mutex */
3663	pthread_mutex_destroy(&s_lua_traceMutex);
3664}
3665
3666
3667/* End of mod_lua.inl */
3668