1 /* This file is part of the CivetWeb web server.
2 * See https://github.com/civetweb/civetweb/
10 #include "civetweb_lua.h"
11 #include "civetweb_private_lua.h"
16 mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
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.
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);
29 /* unused parameters */
40 munmap(void *addr, int64_t length)
42 /* unused parameters */
45 UnmapViewOfFile(addr);
49 #define MAP_PRIVATE (0)
54 static const char *const LUASOCKET = "luasocket";
55 static const char lua_regkey_ctx = 1;
56 static const char lua_regkey_connlist = 2;
57 static const char lua_regkey_lsp_include_history = 3;
58 static const char lua_regkey_environment_type = 4;
59 static const char lua_regkey_dtor = 5;
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)
70 /* Forward declarations */
71 static int handle_lsp_request(struct mg_connection *,
78 reg_lstring(struct lua_State *L,
83 if (name != NULL && buffer != NULL) {
84 lua_pushstring(L, name);
85 lua_pushlstring(L, (const char *)buffer, buflen);
92 reg_llstring(struct lua_State *L,
98 if (buffer1 != NULL && buffer2 != NULL) {
99 lua_pushlstring(L, (const char *)buffer1, buflen1);
100 lua_pushlstring(L, (const char *)buffer2, buflen2);
106 #define reg_string(L, name, val) \
107 reg_lstring(L, name, val, (val != NULL) ? strlen(val) : 0)
111 reg_int(struct lua_State *L, const char *name, int val)
114 lua_pushstring(L, name);
115 lua_pushinteger(L, val);
122 reg_i64(struct lua_State *L, const char *name, int64_t val)
127 lua_pushstring(L, name);
128 if (sizeof(lua_Integer) >= sizeof(val)) {
129 lua_pushinteger(L, (lua_Integer)val);
131 double d = (double)val;
132 lua_pushnumber(L, d);
139 reg_double(struct lua_State *L, const char *name, double val)
142 lua_pushstring(L, name);
143 lua_pushnumber(L, val);
150 reg_boolean(struct lua_State *L, const char *name, int val)
153 lua_pushstring(L, name);
154 lua_pushboolean(L, val != 0);
161 reg_conn_function(struct lua_State *L,
164 struct mg_connection *conn)
166 if (name != NULL && func != NULL && conn != NULL) {
167 lua_pushstring(L, name);
168 lua_pushlightuserdata(L, conn);
169 lua_pushcclosure(L, func, 1);
176 reg_function(struct lua_State *L, const char *name, lua_CFunction func)
178 if (name != NULL && func != NULL) {
179 lua_pushstring(L, name);
180 lua_pushcclosure(L, func, 0);
187 lua_cry(const struct mg_connection *conn,
190 const char *lua_title,
191 const char *lua_operation)
193 DEBUG_TRACE("lua_cry (err=%i): %s: %s", err, lua_title, lua_operation);
200 mg_cry_internal(conn,
201 "%s: %s failed: runtime error: %s",
204 lua_tostring(L, -1));
207 mg_cry_internal(conn,
208 "%s: %s failed: syntax error: %s",
211 lua_tostring(L, -1));
214 mg_cry_internal(conn,
215 "%s: %s failed: out of memory",
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 */
223 mg_cry_internal(conn,
224 "%s: %s failed: error during garbage collection",
230 mg_cry_internal(conn,
231 "%s: %s failed: error in error handling: %s",
234 lua_tostring(L, -1));
238 conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
245 lsp_sock_close(lua_State *L)
247 int num_args = lua_gettop(L);
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");
257 /* Do not closesocket(*psock); here, close it in __gc */
260 return luaL_error(L, "invalid :close() call");
267 lsp_sock_recv(lua_State *L)
269 int num_args = lua_gettop(L);
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");
281 n = recv(*psock, buf, sizeof(buf), 0);
285 lua_pushlstring(L, buf, n);
288 return luaL_error(L, "invalid :recv() call");
295 lsp_sock_send(lua_State *L)
297 int num_args = lua_gettop(L);
299 size_t len, sent = 0;
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");
313 if ((n = send(*psock, buf + sent, (int)(len - sent), 0)) <= 0) {
318 lua_pushnumber(L, n);
320 return luaL_error(L, "invalid :close() call");
327 lsp_sock_gc(lua_State *L)
329 int num_args = lua_gettop(L);
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)) {
339 "invalid internal state in __gc for object created by connect");
343 return luaL_error(L, "__gc for object created by connect failed");
349 /* Methods and meta-methods supported by the object returned by connect.
350 * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
351 static 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},
359 lsp_connect(lua_State *L)
361 int num_args = lua_gettop(L);
367 if ((num_args == 3) && lua_isstring(L, 1) && lua_isnumber(L, 2)
368 && lua_isnumber(L, 3)) {
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);
375 NULL, host, port, is_ssl, ebuf, sizeof(ebuf), &sock, &sa);
377 return luaL_error(L, ebuf);
379 set_blocking_mode(sock);
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);
388 L, "connect(host,port,is_ssl): invalid parameter given.");
395 lsp_error(lua_State *L)
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);
406 /* Silently stop processing chunks. */
408 lsp_abort(lua_State *L)
410 int top = lua_gettop(L);
411 DEBUG_TRACE("%s", "lsp_abort");
412 lua_getglobal(L, "mg");
414 lua_setfield(L, -2, "onerror");
416 lua_pushstring(L, "aborting");
421 struct lsp_var_reader_data {
430 /* Helper function to read the content of variable values */
432 lsp_var_reader(lua_State *L, void *ud, size_t *sz)
434 struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
436 (void)(L); /* unused */
438 /* This reader is called multiple times, to fetch the full Lua script */
439 switch (reader->state) {
441 /* First call: what function to call */
442 reader->consumed = 0;
447 /* Second call: forward variable name */
449 *sz = (size_t)reader->len;
450 reader->consumed += reader->len;
453 /* Third call: close function call */
458 /* Forth/Final call: tell Lua we got the entire script */
463 /* Step to the next state for the next call */
470 lsp_kepler_reader(lua_State *L, void *ud, size_t *sz)
472 struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
477 (void)(L); /* unused */
479 /* This reader is called multiple times, to fetch the full Lua script */
481 if (reader->state == 0) {
482 /* First call: Send opening tag - what function to call */
483 ret = "mg.write([=======[";
486 reader->consumed = 0;
490 if (reader->state == 4) {
491 /* Final call: Tell Lua reader, we reached the end */
496 left = reader->len - reader->consumed;
498 /* We reached the end of the file/available data. */
499 /* Send closing tag. */
500 ret = "]=======]);\n";
502 reader->state = 4; /* Next will be the final call */
505 if (left > MG_BUF_LEN / 100) {
506 left = MG_BUF_LEN / 100; /* TODO XXX */
510 if (reader->state == 1) {
511 /* State 1: plain text - put inside mg.write(...) */
514 while ((i < left) && (reader->begin[i + reader->consumed] != '<')) {
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;
525 /* assert (reader->begin[reader->state] == '<') */
526 /* assert (i == 0) */
527 if (0 == memcmp(reader->begin + reader->consumed, "<?lua", 5)) {
528 /* kepler <?lua syntax */
532 } else if (0 == memcmp(reader->begin + reader->consumed, "<%", 2)) {
533 /* kepler <% syntax */
537 } else if (0 == memcmp(reader->begin + reader->consumed, "<?", 2)) {
538 /* civetweb <? syntax */
546 /* We found an opening or closing tag, or we reached the end of the
548 if (reader->begin[reader->consumed + i] == '=') {
549 /* Lua= tag - Lua expression to print */
550 ret = "]=======]);\nmg.write(";
554 /* Normal Lua tag - Lua chunk */
555 ret = "]=======]);\n";
559 reader->consumed += i; /* length of <?lua or <% tag */
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(...) */
568 int close_tag_found = 0;
572 && (reader->begin[i + reader->consumed] != reader->tag)) {
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 */
581 return reader->begin + j;
584 /* Is this the closing tag we are looking for? */
587 && (reader->begin[i + 1 + reader->consumed] == '>'));
589 if (close_tag_found) {
591 reader->consumed += 2;
593 if (reader->state == 2) {
594 /* Send a new opening tag to Lua */
595 ret = ";\nmg.write([=======[";
597 ret = ");\nmg.write([=======[";
603 /* Not a close tag, continue searching */
610 /* Must never be reached */
617 run_lsp_kepler(struct mg_connection *conn,
626 struct lsp_var_reader_data data;
628 time_t curtime = time(NULL);
630 gmt_time_string(date, sizeof(date), &curtime);
633 /* Top level page assumes keep_alive is disabled.
634 * Do not overwrite this setting for included pages. */
635 conn->must_close = 1;
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
640 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
641 send_no_cache_header(conn);
642 send_additional_header(conn);
645 "Connection: close\r\n"
646 "Content-Type: text/html; charset=utf-8\r\n\r\n",
655 lua_ok = mg_lua_load(L, lsp_kepler_reader, &data, path, NULL);
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 ! */
664 /* Success loading chunk. Call it. */
665 lua_pcall(L, 0, 0, 1);
672 run_lsp_civetweb(struct mg_connection *conn,
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 %> */
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;
691 for (i = 0; i < len; i++) {
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))) {
700 /* Opening tag way "<?" or "<%", closing tag must be the same. */
701 char lsp_mark_used = p[i + 1];
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
709 /* Skip 3 letters ("lua"). */
712 /* no additional letters to skip, only "<?" */
716 /* Check for '=' in "<?= ..." or "<%= ..." or "<?lua= ..." */
717 is_var = (((i + s + 2) < len) && (p[i + s + 2] == '='));
719 /* use variable value (print it later) */
722 /* execute script code */
729 /* Add line (for line number offset) */
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. */
738 /* Print everything before the Lua opening tag. */
739 mg_write(conn, p + pos, i - pos);
741 /* Set a name for debugging purposes */
743 NULL, /* ignore truncation for debugging */
750 /* Prepare data for Lua C functions */
751 lua_pushlightuserdata(L, conn);
752 lua_pushcclosure(L, lsp_error, 1);
754 /* Distinguish between <? script ?> (is_var == 0)
755 * and <?= expression ?> (is_var != 0). */
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);
765 lua_ok = mg_lua_load(
766 L, lsp_var_reader, &data, chunkname, NULL);
768 /* For scripts: Execute them */
769 lua_ok = luaL_loadbuffer(L,
776 /* Syntax error or OOM.
777 * Error message is pushed on stack. */
778 lua_pcall(L, 1, 0, 0);
780 /* Success loading chunk. Call it. */
781 lua_pcall(L, 0, 0, 1);
784 /* Progress until after the Lua closing tag. */
792 /* Line number for debugging/error logging. */
800 /* Print everything after the last Lua closing tag. */
802 mg_write(conn, p + pos, i - pos);
809 /* mg.write: Send data to the client */
811 lsp_write(lua_State *L)
813 struct mg_connection *conn =
814 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
815 int num_args = lua_gettop(L);
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) {
829 lua_pushboolean(L, rv);
835 /* mg.read: Read data from the client (e.g., from a POST request) */
837 lsp_read(lua_State *L)
839 struct mg_connection *conn =
840 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
842 int len = mg_read(conn, buf, sizeof(buf));
846 lua_pushlstring(L, buf, len);
852 /* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
854 lsp_keep_alive(lua_State *L)
856 struct mg_connection *conn =
857 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
858 int num_args = lua_gettop(L);
860 /* This function may be called with one parameter (boolean) to set the
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) {
867 return luaL_error(L, "invalid keep_alive() call");
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));
877 /* Stack of includes */
878 struct lsp_include_history {
880 const char *script[LSP_INCLUDE_MAX_DEPTH + 1];
884 /* mg.include: Include another .lp file */
886 lsp_include(lua_State *L)
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;
896 if (path_type == NULL) {
897 /* default to "absolute" */
901 if ((file_name != NULL) && (num_args <= 2)) {
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);
907 if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
910 "lsp max include depth of %i reached while including %s",
911 (int)(LSP_INCLUDE_MAX_DEPTH),
914 char file_name_path[512];
919 file_name_path[511] = 0;
921 if (*path_type == 'v') {
922 /* "virtual" = relative to document root. */
923 (void)mg_snprintf(conn,
926 sizeof(file_name_path),
928 conn->dom_ctx->config[DOCUMENT_ROOT],
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,
939 sizeof(file_name_path),
943 } else if ((*path_type == 'r') || (*path_type == 'f')) {
944 /* "relative" = file name is relative to the
945 * currect document */
950 sizeof(file_name_path),
952 include_history->script[include_history->depth]);
955 if ((p = strrchr(file_name_path, '/')) != NULL) {
958 len = strlen(file_name_path);
959 (void)mg_snprintf(conn,
961 file_name_path + len,
962 sizeof(file_name_path) - len,
970 "invalid path_type in include(file_name, path_type) call");
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
986 return luaL_error(L, "invalid include() call");
992 /* mg.cry: Log an error. Default value for mg.onerror. */
994 lsp_cry(lua_State *L)
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;
1002 mg_cry_internal(conn, "%s", lua_tostring(L, -1));
1005 return luaL_error(L, "invalid cry() call");
1011 /* mg.redirect: Redirect the request (internally). */
1013 lsp_redirect(lua_State *L)
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;
1021 conn->request_info.local_uri = target;
1022 handle_request(conn);
1026 return luaL_error(L, "invalid redirect() call");
1034 lsp_send_file(lua_State *L)
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;
1042 mg_send_file(conn, filename);
1045 return luaL_error(L, "invalid send_file() call");
1051 /* mg.mg_send_file_body */
1053 lsp_send_file_body(lua_State *L)
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;
1062 ret = mg_send_file_body(conn, filename);
1065 return luaL_error(L, "invalid send_file_body() call");
1068 lua_pushboolean(L, ret >= 0);
1073 /* mg.send_http_error */
1075 lsp_send_http_error(lua_State *L)
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;
1084 if ((status >= 100) && (status <= 999)) {
1085 ret = mg_send_http_error(conn,
1088 (auxText != NULL) ? auxText : "");
1091 return luaL_error(L, "invalid send_http_error() call");
1094 lua_pushnumber(L, ret);
1099 /* mg.send_http_ok */
1101 lsp_send_http_ok(lua_State *L)
1103 struct mg_connection *conn =
1104 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1105 int num_args = lua_gettop(L);
1107 const char *content_type = NULL;
1108 const char *content = NULL;
1109 int64_t content_len = 0;
1114 return luaL_error(L, "invalid send_http_ok() call");
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) {
1122 return luaL_error(L, "invalid send_http_ok() call");
1124 if (type2 == LUA_TSTRING) {
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);
1132 return luaL_error(L, "invalid send_http_ok() call");
1135 ret = mg_send_http_ok(conn, content_type, content_len);
1137 if ((ret == 0) && (content != NULL) && (content_len > 0)) {
1138 mg_write(conn, content, (size_t)content_len);
1141 lua_pushnumber(L, ret);
1146 /* mg.mg_send_http_redirect */
1148 lsp_send_http_redirect(lua_State *L)
1150 struct mg_connection *conn =
1151 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1152 int num_args = lua_gettop(L);
1154 const char *target_url = NULL;
1155 int redirect_code = 300;
1160 return luaL_error(L, "invalid send_http_redirect() call");
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) {
1168 return luaL_error(L, "invalid send_http_redirect() call");
1170 if (type2 == LUA_TNUMBER) {
1171 redirect_code = (int)lua_tonumber(L, 2);
1174 return luaL_error(L, "invalid send_http_redirect() call");
1177 ret = mg_send_http_redirect(conn, target_url, redirect_code);
1179 lua_pushnumber(L, ret);
1186 lsp_get_time(lua_State *L)
1188 int num_args = lua_gettop(L);
1189 int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
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);
1202 lsp_get_var(lua_State *L)
1204 int num_args = lua_gettop(L);
1205 const char *data, *var_name;
1206 size_t data_len, occurrence;
1208 struct mg_context *ctx;
1210 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1211 lua_gettable(L, LUA_REGISTRYINDEX);
1212 ctx = (struct mg_context *)lua_touserdata(L, -1);
1214 if ((num_args >= 2) && (num_args <= 3)) {
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;
1220 /* Allocate dynamically, so there is no internal limit for get_var */
1221 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
1223 return luaL_error(L, "out of memory in get_var() call");
1226 ret = mg_get_var2(data, data_len, var_name, dst, data_len, occurrence);
1228 /* Variable found: return value to Lua */
1229 lua_pushstring(L, dst);
1231 /* Variable not found */
1237 return luaL_error(L, "invalid get_var() call");
1243 #define MG_MAX_FORM_FIELDS (64)
1245 /* mg.split_form_data */
1247 lsp_split_form_urlencoded(lua_State *L)
1249 int num_args = lua_gettop(L);
1253 struct mg_context *ctx;
1255 struct mg_header form_fields[MG_MAX_FORM_FIELDS] = {0};
1258 if (num_args != 1) {
1259 return luaL_error(L, "invalid split_form_data() call");
1262 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1263 lua_gettable(L, LUA_REGISTRYINDEX);
1264 ctx = (struct mg_context *)lua_touserdata(L, -1);
1266 /* Get input (const string) */
1267 in = lua_tolstring(L, 1, &len);
1269 /* Create a modifyable copy */
1270 buf = (char *)mg_malloc_ctx(len + 1, ctx);
1272 return luaL_error(L, "out of memory in invalid split_form_data() call");
1274 memcpy(buf, in, len + 1);
1276 /* mg_split_form_urlencoded does the real work */
1277 ret = mg_split_form_urlencoded(buf, form_fields, MG_MAX_FORM_FIELDS);
1280 return luaL_error(L, "error in invalid split_form_data() call");
1283 /* return a table */
1285 for (i = 0; i < ret; i++) {
1288 if (form_fields[i].name) {
1289 lua_pushstring(L, form_fields[i].name);
1293 lua_setfield(L, -2, "name");
1294 if (form_fields[i].value) {
1295 lua_pushstring(L, form_fields[i].value);
1299 lua_setfield(L, -2, "value");
1301 lua_rawseti(L, -2, i + 1);
1310 /* mg.get_mime_type */
1312 lsp_get_mime_type(lua_State *L)
1314 int num_args = lua_gettop(L);
1315 struct vec mime_type = {0, 0};
1318 struct mg_connection *conn =
1319 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1321 if (num_args == 1) {
1322 text = lua_tostring(L, 1);
1325 get_mime_type(conn, text, &mime_type);
1326 lua_pushlstring(L, mime_type.ptr, mime_type.len);
1328 text = mg_get_builtin_mime_type(text);
1329 lua_pushstring(L, text);
1333 return luaL_error(L, "invalid argument for get_mime_type() call");
1337 return luaL_error(L, "invalid get_mime_type() call");
1345 lsp_get_cookie(lua_State *L)
1347 int num_args = lua_gettop(L);
1349 const char *var_name;
1351 struct mg_context *ctx;
1353 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1354 lua_gettable(L, LUA_REGISTRYINDEX);
1355 ctx = (struct mg_context *)lua_touserdata(L, -1);
1357 if (num_args == 2) {
1358 /* Correct number of arguments */
1362 cookie = lua_tolstring(L, 1, &data_len);
1363 var_name = lua_tostring(L, 2);
1365 if (cookie == NULL || var_name == NULL) {
1367 return luaL_error(L, "invalid get_cookie() call");
1370 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
1372 return luaL_error(L, "out of memory in get_cookie() call");
1375 ret = mg_get_cookie(cookie, var_name, dst, data_len);
1378 lua_pushlstring(L, dst, ret);
1386 return luaL_error(L, "invalid get_cookie() call");
1394 lsp_md5(lua_State *L)
1396 int num_args = lua_gettop(L);
1398 md5_byte_t hash[16];
1403 if (num_args == 1) {
1404 text = lua_tolstring(L, 1, &text_len);
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);
1416 return luaL_error(L, "invalid md5() call");
1424 lsp_url_encode(lua_State *L)
1426 int num_args = lua_gettop(L);
1431 struct mg_context *ctx;
1433 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1434 lua_gettable(L, LUA_REGISTRYINDEX);
1435 ctx = (struct mg_context *)lua_touserdata(L, -1);
1437 if (num_args == 1) {
1438 text = lua_tolstring(L, 1, &text_len);
1440 dst_len = 3 * (int)text_len + 1;
1441 dst = ((text_len < 0x2AAAAAAA) ? (char *)mg_malloc_ctx(dst_len, ctx)
1444 mg_url_encode(text, dst, dst_len);
1445 lua_pushstring(L, dst);
1448 return luaL_error(L, "out of memory in url_encode() call");
1455 return luaL_error(L, "invalid url_encode() call");
1463 lsp_url_decode(lua_State *L)
1465 int num_args = lua_gettop(L);
1471 struct mg_context *ctx;
1473 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1474 lua_gettable(L, LUA_REGISTRYINDEX);
1475 ctx = (struct mg_context *)lua_touserdata(L, -1);
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;
1481 dst_len = (int)text_len + 1;
1482 dst = ((text_len < 0x7FFFFFFF) ? (char *)mg_malloc_ctx(dst_len, ctx)
1485 mg_url_decode(text, (int)text_len, dst, dst_len, is_form);
1486 lua_pushstring(L, dst);
1489 return luaL_error(L, "out of memory in url_decode() call");
1496 return luaL_error(L, "invalid url_decode() call");
1502 /* mg.base64_encode */
1504 lsp_base64_encode(lua_State *L)
1506 int num_args = lua_gettop(L);
1510 struct mg_context *ctx;
1512 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1513 lua_gettable(L, LUA_REGISTRYINDEX);
1514 ctx = (struct mg_context *)lua_touserdata(L, -1);
1516 if (num_args == 1) {
1517 text = lua_tolstring(L, 1, &text_len);
1519 dst = (char *)mg_malloc_ctx(text_len * 8 / 6 + 4, ctx);
1521 base64_encode((const unsigned char *)text, (int)text_len, dst);
1522 lua_pushstring(L, dst);
1525 return luaL_error(L, "out of memory in base64_encode() call");
1532 return luaL_error(L, "invalid base64_encode() call");
1538 /* mg.base64_encode */
1540 lsp_base64_decode(lua_State *L)
1542 int num_args = lua_gettop(L);
1544 size_t text_len, dst_len;
1547 struct mg_context *ctx;
1549 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1550 lua_gettable(L, LUA_REGISTRYINDEX);
1551 ctx = (struct mg_context *)lua_touserdata(L, -1);
1553 if (num_args == 1) {
1554 text = lua_tolstring(L, 1, &text_len);
1556 dst = (char *)mg_malloc_ctx(text_len, ctx);
1558 ret = base64_decode((const unsigned char *)text,
1565 L, "illegal character in lsp_base64_decode() call");
1567 lua_pushlstring(L, dst, dst_len);
1571 return luaL_error(L,
1572 "out of memory in lsp_base64_decode() call");
1579 return luaL_error(L, "invalid lsp_base64_decode() call");
1585 /* mg.get_response_code_text */
1587 lsp_get_response_code_text(lua_State *L)
1589 int num_args = lua_gettop(L);
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);
1604 return text ? 1 : 0;
1609 return luaL_error(L, "invalid get_response_code_text() call");
1613 /* mg.random - might be better than math.random on some systems */
1615 lsp_random(lua_State *L)
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);
1632 return luaL_error(L, "invalid random() call");
1638 lsp_get_info(lua_State *L)
1640 int num_args = lua_gettop(L);
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);
1656 buf = (char *)mg_malloc(len + 64);
1658 return luaL_error(L, "OOM in get_info() call");
1660 len = mg_get_system_info(buf, len + 63);
1661 lua_pushlstring(L, buf, len);
1664 lua_pushstring(L, "");
1668 if (!mg_strcasecmp(arg1, "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);
1675 /* Get context info for server context */
1676 len = mg_get_context_info(ctx, NULL, 0);
1678 buf = (char *)mg_malloc(len + 64);
1680 return luaL_error(L, "OOM in get_info() call");
1682 len = mg_get_context_info(ctx, buf, len + 63);
1683 lua_pushlstring(L, buf, len);
1686 lua_pushstring(L, "");
1690 if (!mg_strcasecmp(arg1, "common")) {
1691 /* Get context info for NULL context */
1692 len = mg_get_context_info(NULL, NULL, 0);
1694 buf = (char *)mg_malloc(len + 64);
1696 return luaL_error(L, "OOM in get_info() call");
1698 len = mg_get_context_info(NULL, buf, len + 63);
1699 lua_pushlstring(L, buf, len);
1702 lua_pushstring(L, "");
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);
1717 /* Get info according to argument */
1718 if (!mg_strcasecmp(arg1, "connection")) {
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);
1727 /* Get connection info for connection idx */
1728 idx = (int)(arg2 + 0.5);
1730 /* Lua uses 1 based index, C uses 0 based index */
1733 #if defined(MG_EXPERIMENTAL_INTERFACES)
1734 len = mg_get_connection_info(ctx, idx, NULL, 0);
1736 buf = (char *)mg_malloc(len + 64);
1738 return luaL_error(L, "OOM in get_info() call");
1740 len = mg_get_connection_info(ctx, idx, buf, len + 63);
1741 lua_pushlstring(L, buf, len);
1744 lua_pushstring(L, "");
1749 lua_pushstring(L, "");
1759 return luaL_error(L, "invalid get_info() call");
1765 lsp_get_option(lua_State *L)
1767 int num_args = lua_gettop(L);
1773 /* Get connection */
1774 struct mg_connection *conn =
1775 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
1777 if (num_args == 0) {
1778 const struct mg_option *opts = mg_get_valid_options();
1780 if (!opts) { /* <-- should be always false */
1785 while (opts->name) {
1786 optidx = get_option_index(opts->name);
1788 data = conn->dom_ctx->config[optidx];
1790 reg_string(L, opts->name, data);
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);
1806 data = conn->dom_ctx->config[optidx];
1808 lua_pushstring(L, data);
1817 return luaL_error(L, "invalid get_option() call");
1821 static int s_lua_traceLevel = 1;
1822 static FILE *s_lua_traceFile = NULL;
1823 static pthread_mutex_t s_lua_traceMutex;
1828 lsp_trace(lua_State *L)
1830 int num_args = lua_gettop(L);
1832 int trace_level = 0;
1836 for (i = 0; i < 8; i++) {
1837 if (num_args >= (i + 1)) {
1838 arg_type[i] = lua_type(L, (i + 1));
1840 arg_type[i] = LUA_TNIL;
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);
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);
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);
1876 pthread_mutex_unlock(&s_lua_traceMutex);
1878 lua_pushboolean(L, 1);
1883 /* UUID library and function pointer */
1886 void (*f)(unsigned char uuid[16]);
1892 lsp_uuid(lua_State *L)
1895 unsigned char uuid_array[16];
1896 struct uuid_struct_type {
1905 int num_args = lua_gettop(L);
1907 memset(&uuid, 0, sizeof(uuid));
1908 memset(uuid_str, 0, sizeof(uuid_str));
1910 if (num_args == 0) {
1912 pf_uuid_generate.f(uuid.uuid_array);
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]);
1929 lua_pushstring(L, uuid_str);
1934 return luaL_error(L, "invalid uuid() call");
1938 #if defined(USE_WEBSOCKET)
1939 struct lua_websock_data {
1942 unsigned references;
1943 struct mg_connection *conn[MAX_WORKER_THREADS];
1944 pthread_mutex_t ws_mutex;
1949 /* mg.write for websockets */
1951 lwebsock_write(lua_State *L)
1953 #if defined(USE_WEBSOCKET)
1954 int num_args = lua_gettop(L);
1955 struct lua_websock_data *ws;
1960 struct mg_connection *client = NULL;
1962 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1963 lua_gettable(L, LUA_REGISTRYINDEX);
1964 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1966 (void)pthread_mutex_lock(&(ws->ws_mutex));
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;
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;
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;
2022 if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
2023 str = lua_tolstring(L, num_args, &size);
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]);
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]);
2040 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2041 return luaL_error(L, "invalid websocket write() call");
2044 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2047 (void)(L); /* unused */
2053 struct laction_string_arg {
2056 pthread_mutex_t *pmutex;
2060 struct laction_funcref_arg {
2063 pthread_mutex_t *pmutex;
2069 lua_action_string(struct laction_string_arg *arg)
2072 struct mg_context *ctx;
2074 (void)pthread_mutex_lock(arg->pmutex);
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);
2081 err = luaL_loadstring(arg->L, arg->txt);
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);
2088 err = lua_pcall(arg->L, 0, 1, 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);
2096 ok = lua_type(arg->L, -1);
2097 if (lua_isboolean(arg->L, -1)) {
2098 ok = lua_toboolean(arg->L, -1);
2104 (void)pthread_mutex_unlock(arg->pmutex);
2111 lua_action_funcref(struct laction_funcref_arg *arg)
2114 struct mg_context *ctx;
2116 (void)pthread_mutex_lock(arg->pmutex);
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);
2123 lua_rawgeti(arg->L, LUA_REGISTRYINDEX, arg->funcref);
2124 err = lua_pcall(arg->L, 0, 1, 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);
2132 ok = lua_type(arg->L, -1);
2133 if (lua_isboolean(arg->L, -1)) {
2134 ok = lua_toboolean(arg->L, -1);
2140 (void)pthread_mutex_unlock(arg->pmutex);
2147 lua_action_string_cancel(struct laction_string_arg *arg)
2154 lua_action_funcref_cancel(struct laction_funcref_arg *arg)
2156 luaL_unref(arg->L, LUA_REGISTRYINDEX, arg->funcref);
2162 lwebsocket_set_timer(lua_State *L, int is_periodic)
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;
2171 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2172 lua_gettable(L, LUA_REGISTRYINDEX);
2173 ctx = (struct mg_context *)lua_touserdata(L, -1);
2175 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
2176 lua_gettable(L, LUA_REGISTRYINDEX);
2177 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
2180 return luaL_error(L,
2181 "not enough arguments for set_timer/interval() call");
2184 type1 = lua_type(L, 1);
2185 type2 = lua_type(L, 2);
2186 type3 = lua_type(L, 3);
2188 /* Must have at least two arguments, ant the first one has to be some text
2190 if ((num_args < 2) || (num_args > 3)) {
2191 return luaL_error(L, "invalid arguments for set_timer/interval() call");
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");
2198 delay = (double)lua_tonumber(L, 2);
2199 interval = (is_periodic ? delay : 0.0);
2201 /* Third argument (optional) could be an interval */
2203 if (is_periodic || (type3 != LUA_TNUMBER)) {
2205 L, "invalid arguments for set_timer/interval() call");
2207 interval = (double)lua_tonumber(L, 3);
2211 if ((delay < 0.0) || (interval < 0.0)) {
2212 return luaL_error(L, "invalid arguments for set_timer/interval() call");
2215 /* First value specifies the action */
2216 if (type1 == LUA_TSTRING) {
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;
2223 action_txt = lua_tostring(L, 1);
2224 if ((action_txt == NULL) || (action_txt[0] == 0)) {
2226 L, "invalid arguments for set_timer/interval() call");
2228 action_txt_len = strlen(action_txt);
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);
2234 return luaL_error(L, "out of memory");
2237 /* Argument for timer */
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;
2250 (taction)lua_action_string,
2252 (tcancelaction)lua_action_string_cancel)) {
2253 /* Timer added successfully */
2256 } else if (type1 == LUA_TFUNCTION) {
2258 /* Action could be passed as a function */
2260 struct laction_funcref_arg *arg;
2262 lua_pushvalue(L, 1);
2263 funcref = luaL_ref(L, LUA_REGISTRYINDEX);
2265 /* Create timer data structure and schedule timer */
2266 arg = (struct laction_funcref_arg *)
2267 mg_malloc_ctx(sizeof(struct laction_funcref_arg), ctx);
2269 return luaL_error(L, "out of memory");
2272 /* Argument for timer */
2274 arg->script = (ws ? ws->script : NULL);
2275 arg->pmutex = (ws ? &(ws->ws_mutex) : &(ctx->lua_bg_mutex));
2276 arg->funcref = funcref;
2282 (taction)lua_action_funcref,
2284 (tcancelaction)lua_action_funcref_cancel)) {
2285 /* Timer added successfully */
2289 return luaL_error(L, "invalid arguments for set_timer/interval() call");
2292 lua_pushboolean(L, ok);
2296 (void)(L); /* unused */
2297 (void)(is_periodic); /* unused */
2303 /* mg.set_timeout for websockets */
2305 lwebsocket_set_timeout(lua_State *L)
2307 return lwebsocket_set_timer(L, 0);
2311 /* mg.set_interval for websockets */
2313 lwebsocket_set_interval(lua_State *L)
2315 return lwebsocket_set_timer(L, 1);
2319 /* mg.response.send() */
2321 lsp_response_send(lua_State *L)
2324 int ret1, ret2, ret3;
2326 struct mg_connection *conn =
2327 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
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");
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");
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");
2346 http_status = (int)lua_tonumber(L, -1);
2347 lua_pop(L, 1); /* remove number "status" */
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");
2356 /* Parameter checks passed, initiate response */
2357 ret1 = mg_response_header_start(conn, http_status);
2359 lua_pushboolean(L, 0); /* false */
2360 lua_pushinteger(L, ret1);
2364 /* Iterate table of http response headers */
2367 while (lua_next(L, -2)) {
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);
2380 if ((retadd != 0) && (ret2 == 0)) {
2381 /* Store first error */
2388 ret3 = mg_response_header_send(conn);
2390 lua_pushboolean(L, 1); /* TRUE */
2391 lua_pushinteger(L, ret2); /* Error/Warning from header_add */
2393 lua_pushboolean(L, 0); /* FALSE */
2394 lua_pushinteger(L, ret3); /* Error from header_send */
2402 lua_debug_hook(lua_State *L, lua_Debug *ar)
2405 int stack_len = lua_gettop(L);
2407 lua_getinfo(L, "nSlu", ar);
2409 if (ar->event == LUA_HOOKCALL) {
2411 } else if (ar->event == LUA_HOOKRET) {
2413 #if defined(LUA_HOOKTAILRET)
2414 } else if (ar->event == LUA_HOOKTAILRET) {
2415 printf("tail ret\n");
2417 #if defined(LUA_HOOKTAILCALL)
2418 } else if (ar->event == LUA_HOOKTAILCALL) {
2419 printf("tail call\n");
2421 } else if (ar->event == LUA_HOOKLINE) {
2423 } else if (ar->event == LUA_HOOKCOUNT) {
2426 printf("unknown (%i)\n", ar->event);
2429 if (ar->currentline >= 0) {
2430 printf("%s:%i\n", ar->source, ar->currentline);
2433 printf("%s (%s)\n", ar->name, ar->namewhat);
2436 for (i = 1; i <= stack_len; i++) { /* repeat for each level */
2437 int val_type = lua_type(L, i);
2444 /* nil value on the stack */
2449 /* boolean (true / false) */
2450 printf("boolean: %s\n", lua_toboolean(L, i) ? "true" : "false");
2455 printf("number: %g\n", lua_tonumber(L, i));
2459 /* string with limited length */
2460 s = lua_tolstring(L, i, &n);
2461 printf("string: '%.*s%s\n",
2462 ((n > 30) ? 28 : (int)n),
2464 ((n > 30) ? ".." : "'"));
2469 printf("%s\n", lua_typename(L, val_type));
2478 /* Lua Environment */
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 */
2488 push_lua_response_log_data(const struct mg_connection *conn, lua_State *L)
2495 /* request status */
2496 reg_int(L, "status", conn->status_code);
2498 /* protocol (http, https, ws, wss) */
2499 s = get_proto_name(conn);
2500 reg_string(L, "protocol", s);
2502 /* request counter */
2503 reg_int(L, "handled_requests", conn->handled_requests);
2505 /* data read and written */
2506 reg_i64(L, "read", conn->consumed_content);
2507 reg_i64(L, "written", conn->num_bytes_sent);
2509 #if !defined(NO_RESPONSE_BUFFERING)
2510 lua_pushstring(L, "http_headers");
2512 for (i = 0; i < conn->response_info.num_headers; i++) {
2514 conn->response_info.http_headers[i].name,
2515 conn->response_info.http_headers[i].value);
2520 #if defined(USE_SERVER_STATS)
2521 reg_double(L, "processing_time", conn->processing_time);
2527 prepare_lua_request_info_inner(const struct mg_connection *conn, lua_State *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);
2545 if (conn->path_info != NULL) {
2546 reg_string(L, "path_info", conn->path_info);
2551 if (0 == mg_get_request_link(conn, buf, sizeof(buf))) {
2552 reg_string(L, "request_link", buf);
2556 if (conn->request_info.content_length >= 0) {
2557 /* reg_int64: content_length */
2558 lua_pushstring(L, "content_length");
2561 (lua_Number)conn->request_info
2562 .content_length); /* lua_Number may be used as 52 bit integer */
2565 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
2566 reg_string(L, "content_type", s);
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");
2574 reg_boolean(L, "https", conn->ssl != NULL);
2576 if (conn->status_code > 0) {
2577 /* Lua error handler should show the status code */
2578 reg_int(L, "status", conn->status_code);
2581 /* Table "HTTP headers" */
2582 lua_pushstring(L, "http_headers");
2584 for (i = 0; i < conn->request_info.num_headers; i++) {
2586 conn->request_info.http_headers[i].name,
2587 conn->request_info.http_headers[i].value);
2591 /* Table "Client Certificate" */
2592 if (conn->request_info.client_cert) {
2593 lua_pushstring(L, "client_cert");
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);
2605 prepare_lua_request_info(const struct mg_connection *conn, lua_State *L)
2607 /* Export mg.request_info */
2608 lua_pushstring(L, "request_info");
2609 prepare_lua_request_info_inner(conn, L);
2611 /* End of request_info */
2617 prepare_lua_response_table(struct mg_connection *conn, lua_State *L)
2619 /* Export mg.request_info */
2620 lua_pushstring(L, "response");
2623 /* Add table elements */
2625 /* HTTP status code (default to 200 OK) */
2626 reg_int(L, "status", 200);
2628 /* Table "HTTP headers" */
2629 lua_pushstring(L, "http_headers");
2631 /* Initially empty */
2634 /* mg_response_header_send wrapper */
2635 reg_conn_function(L, "send", lsp_response_send, conn);
2637 /* End of response table */
2643 lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
2645 (void)osize; /* not used */
2652 return mg_realloc_ctx(ptr, nsize, (struct mg_context *)ud);
2656 /* In CivetWeb, Lua-Shared is used as *.inl file */
2657 #define LUA_SHARED_INTERFACE static
2658 #include "mod_lua_shared.inl"
2662 civetweb_open_lua_libs(lua_State *L)
2665 extern void luaL_openlibs(lua_State *);
2669 #if defined(USE_LUA_SQLITE3)
2671 extern int luaopen_lsqlite3(lua_State *);
2672 luaopen_lsqlite3(L);
2675 #if defined(USE_LUA_LUAXML)
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");
2683 #if defined(USE_LUA_FILE_SYSTEM)
2685 extern int luaopen_lfs(lua_State *);
2692 /* garbage collect "mg"
2693 * this indicates when a Lua state is closed
2696 lsp_mg_gc(lua_State *L)
2699 struct mg_context *ctx;
2700 struct mg_connection *conn =
2701 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
2703 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2704 lua_gettable(L, LUA_REGISTRYINDEX);
2705 ctx = (struct mg_context *)lua_touserdata(L, -1);
2707 lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
2708 lua_gettable(L, LUA_REGISTRYINDEX);
2709 context_flags = lua_tointeger(L, -1);
2712 if (ctx->callbacks.exit_lua != NULL) {
2713 ctx->callbacks.exit_lua(conn, L, (unsigned)context_flags);
2722 reg_gc(lua_State *L, void *conn)
2725 lua_pushlightuserdata(L, (void *)&lua_regkey_dtor);
2728 lua_newuserdata(L, 0);
2730 /* Prepare metatable for value element */
2733 /* Add garbage collector key to metatable */
2734 lua_pushliteral(L, "__gc");
2736 /* Add garbage collector function with one upvalue (conn) */
2737 lua_pushlightuserdata(L, conn);
2738 lua_pushcclosure(L, lsp_mg_gc, 1);
2740 /* Set __gc = function lsp_mg_gc in metatable */
2743 /* Set metatable for "value element" */
2744 lua_setmetatable(L, -2);
2746 /* Add key (lightuserdata) = value (userdata with metatable) */
2747 lua_settable(L, LUA_REGISTRYINDEX);
2752 lua_error_handler(lua_State *L)
2754 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
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");
2762 IGNORE_UNUSED_RESULT(
2763 luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
2765 printf("Lua error: [%s]\n", error_msg);
2766 IGNORE_UNUSED_RESULT(
2767 luaL_dostring(L, "print(debug.traceback(), '\\n')"));
2769 /* TODO(lsm, low): leave the stack balanced */
2776 prepare_lua_environment(struct mg_context *ctx,
2777 struct mg_connection *conn,
2778 struct lua_websock_data *ws_conn_list,
2780 const char *script_name,
2783 const char *preload_file_name = NULL;
2784 const char *debug_params = NULL;
2786 int lua_context_flags = lua_env_type;
2788 civetweb_open_lua_libs(L);
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];
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.
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);
2808 lua_register(L, "connect", lsp_connect);
2811 /* Store context in the registry */
2813 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
2814 lua_pushlightuserdata(L, (void *)ctx);
2815 lua_settable(L, LUA_REGISTRYINDEX);
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);
2822 lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
2823 lua_pushinteger(L, lua_context_flags);
2824 lua_settable(L, LUA_REGISTRYINDEX);
2826 /* State close function */
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));
2840 /* Register mg module */
2843 switch (lua_env_type) {
2844 case LUA_ENV_TYPE_LUA_SERVER_PAGE:
2845 reg_string(L, "lua_type", "page");
2847 case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
2848 reg_string(L, "lua_type", "script");
2850 case LUA_ENV_TYPE_LUA_WEBSOCKET:
2851 reg_string(L, "lua_type", "websocket");
2853 case LUA_ENV_TYPE_BACKGROUND:
2854 reg_string(L, "lua_type", "background");
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,
2872 reg_conn_function(L, "redirect", lsp_redirect, conn);
2875 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
2876 reg_conn_function(L, "include", lsp_include, conn);
2879 if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
2880 reg_function(L, "write", lwebsock_write);
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);
2891 reg_conn_function(L, "get_mime_type", lsp_get_mime_type, conn);
2892 reg_conn_function(L, "get_option", lsp_get_option, conn);
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);
2908 if (pf_uuid_generate.f) {
2909 reg_function(L, "uuid", lsp_uuid);
2912 reg_string(L, "version", CIVETWEB_VERSION);
2914 reg_string(L, "script_name", script_name);
2916 if ((conn != NULL) && (conn->dom_ctx != NULL)) {
2917 reg_string(L, "document_root", conn->dom_ctx->config[DOCUMENT_ROOT]);
2920 conn->dom_ctx->config[AUTHENTICATION_DOMAIN]);
2921 #if defined(USE_WEBSOCKET)
2922 if (conn->dom_ctx->config[WEBSOCKET_ROOT]) {
2925 conn->dom_ctx->config[WEBSOCKET_ROOT]);
2929 conn->dom_ctx->config[DOCUMENT_ROOT]);
2933 if ((ctx != NULL) && (ctx->systemName != NULL)) {
2934 reg_string(L, "system", ctx->systemName);
2938 /* Export connection specific info */
2940 /* mg.request_info.* available for all environments */
2941 prepare_lua_request_info(conn, L);
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);
2949 /* Store as global table "mg" */
2950 lua_setglobal(L, "mg");
2952 /* Register "shared" table */
2953 lua_shared_register(L);
2955 /* Register default mg.onerror function */
2956 IGNORE_UNUSED_RESULT(
2958 "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
2959 "debug.traceback(e, 1)) end"));
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];
2966 /* Call user init function */
2968 if (ctx->callbacks.init_lua != NULL) {
2969 ctx->callbacks.init_lua(conn, L, lua_context_flags);
2973 /* Preload file into new Lua environment */
2974 if (preload_file_name) {
2975 int ret = luaL_loadfile(L, preload_file_name);
2977 lua_error_handler(L);
2979 ret = lua_pcall(L, 0, 1, 0);
2983 /* If debugging is enabled, add a hook */
2986 if (0 != strchr(debug_params, 'c')) {
2987 mask |= LUA_MASKCALL;
2989 if (0 != strchr(debug_params, 'r')) {
2990 mask |= LUA_MASKRET;
2992 if (0 != strchr(debug_params, 'l')) {
2993 mask |= LUA_MASKLINE;
2995 lua_sethook(L, lua_debug_hook, mask, 0);
3001 mg_exec_lua_script(struct mg_connection *conn,
3003 const void **exports)
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;
3012 /* Execute a plain Lua script. */
3014 && (L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx)))
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);
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) {
3025 lua_pushstring(L, (const char *)(exports[i]));
3026 *(const void **)(&func) = exports[i + 1];
3027 lua_pushcclosure(L, func, 0);
3031 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
3033 const char *name = (const char *)(exports[i]);
3034 *(const void **)(&func) = exports[i + 1];
3035 lua_register(L, name, func);
3040 if (luaL_loadfile(L, path) != 0) {
3041 lua_error_handler(L);
3043 lua_pcall(L, 0, 0, -2);
3051 handle_lsp_request(struct mg_connection *conn,
3053 struct mg_file *filep,
3054 struct lua_State *ls)
3057 lua_State *L = NULL;
3058 struct lsp_include_history *include_history;
3060 int (*run_lsp)(struct mg_connection *,
3068 /* mg_fopen opens the file and sets the size accordingly */
3069 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
3071 /* File not found or not accessible */
3073 mg_send_http_error(conn,
3075 "Error: Cannot open script file %s",
3078 luaL_error(ls, "Cannot include [%s]: not found", path);
3081 goto cleanup_handle_lsp_request;
3084 /* Map file in memory (size is known). */
3086 (size_t)filep->stat.size,
3089 fileno(filep->access.fp),
3093 /* File was not already in memory, and mmap failed now.
3094 * Since wi have no data, show an error. */
3096 /* No open Lua state - use generic error function */
3100 "Error: Cannot open script\nFile %s can not be mapped",
3103 /* Lua state exists - use Lua error function */
3105 "mmap(%s, %zu, %d): %s",
3107 (size_t)filep->stat.size,
3108 fileno(filep->access.fp),
3112 goto cleanup_handle_lsp_request;
3115 /* File content is now memory mapped. Get mapping address. */
3116 addr = (const char *)p;
3118 /* Get a Lua state */
3120 /* We got a Lua state as argument. Use it! */
3123 /* We need to create a Lua state. */
3124 L = lua_newstate(lua_allocator, (void *)(conn->phys_ctx));
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. */
3133 "Error: Cannot execute script\nlua_newstate failed");
3135 goto cleanup_handle_lsp_request;
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);
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);
3148 /* Store script name and increment depth */
3149 include_history->depth++;
3150 include_history->script[include_history->depth] = path;
3152 /* Lua state is ready to use now. */
3153 /* Currently we have two different syntax options:
3154 * Either "classic" CivetWeb syntax:
3157 * Or "Kepler Syntax"
3158 * https://keplerproject.github.io/cgilua/manual.html#templates
3160 * <?lua= expression ?>
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
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
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.
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".
3190 run_lsp = run_lsp_civetweb;
3191 if ((addr[0] == '<') && (addr[1] != '?')) {
3192 run_lsp = run_lsp_kepler;
3195 /* We're not sending HTTP headers here, Lua page must do it. */
3197 run_lsp(conn, path, addr, filep->stat.size, L, include_history->depth);
3199 /* pop from stack */
3200 include_history->depth--;
3202 cleanup_handle_lsp_request:
3204 if (L != NULL && ls == NULL)
3207 munmap(p, filep->stat.size);
3208 (void)mg_fclose(&filep->access);
3214 #if defined(USE_WEBSOCKET)
3215 struct mg_shared_lua_websocket_list {
3216 struct lua_websock_data ws;
3217 struct mg_shared_lua_websocket_list *next;
3222 lua_websocket_new(const char *script, struct mg_connection *conn)
3224 struct mg_shared_lua_websocket_list **shared_websock_list =
3225 &(conn->dom_ctx->shared_lua_websockets);
3226 struct lua_websock_data *ws;
3229 DEBUG_ASSERT(conn->lua_websocket_state == NULL);
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)) {
3238 shared_websock_list = &((*shared_websock_list)->next);
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,
3251 "Cannot create shared websocket struct, OOM");
3254 /* init ws list element */
3255 ws = &(*shared_websock_list)->ws;
3256 ws->script = mg_strdup_ctx(script, conn->phys_ctx);
3258 conn->must_close = 1;
3259 mg_unlock_context(conn->phys_ctx);
3260 mg_cry_internal(conn,
3262 "Cannot create shared websocket script, OOM");
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));
3270 prepare_lua_environment(conn->phys_ctx,
3275 LUA_ENV_TYPE_LUA_WEBSOCKET);
3276 err = luaL_loadfile(ws->state, script);
3278 lua_cry(conn, err, ws->state, script, "load");
3280 err = lua_pcall(ws->state, 0, 0, 0);
3282 lua_cry(conn, err, ws->state, script, "init");
3286 ws = &(*shared_websock_list)->ws;
3287 (void)pthread_mutex_lock(&(ws->ws_mutex));
3288 (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
3290 mg_unlock_context(conn->phys_ctx);
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);
3300 err = lua_pcall(ws->state, 1, 1, 0);
3302 lua_cry(conn, err, ws->state, script, "open handler");
3304 if (lua_isboolean(ws->state, -1)) {
3305 ok = lua_toboolean(ws->state, -1);
3307 lua_pop(ws->state, 1);
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;
3316 (void)pthread_mutex_unlock(&(ws->ws_mutex));
3318 return ok ? (void *)ws : NULL;
3323 lua_websocket_data(struct mg_connection *conn,
3329 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
3332 DEBUG_ASSERT(ws != NULL);
3333 DEBUG_ASSERT(ws->state != NULL);
3335 (void)pthread_mutex_lock(&(ws->ws_mutex));
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,
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);
3352 err = lua_pcall(ws->state, 1, 1, 0);
3354 lua_cry(conn, err, ws->state, ws->script, "data handler");
3356 if (lua_isboolean(ws->state, -1)) {
3357 ok = lua_toboolean(ws->state, -1);
3359 lua_pop(ws->state, 1);
3361 (void)pthread_mutex_unlock(&(ws->ws_mutex));
3368 lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
3370 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
3373 DEBUG_ASSERT(ws != NULL);
3374 DEBUG_ASSERT(ws->state != NULL);
3376 (void)pthread_mutex_lock(&(ws->ws_mutex));
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);
3385 lua_cry(conn, err, ws->state, ws->script, "ready handler");
3387 if (lua_isboolean(ws->state, -1)) {
3388 ok = lua_toboolean(ws->state, -1);
3390 lua_pop(ws->state, 1);
3393 (void)pthread_mutex_unlock(&(ws->ws_mutex));
3400 lua_websocket_close(struct mg_connection *conn, void *ws_arg)
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);
3407 int delete_state = 0;
3409 DEBUG_ASSERT(ws != NULL);
3410 DEBUG_ASSERT(ws->state != NULL);
3412 (void)pthread_mutex_lock(&(ws->ws_mutex));
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);
3420 err = lua_pcall(ws->state, 1, 0, 0);
3422 lua_cry(conn, err, ws->state, ws->script, "close handler");
3424 for (i = 0; i < ws->references; i++) {
3425 if (ws->conn[i] == conn) {
3427 if (ws->references == 0) {
3431 ws->conn[i] = ws->conn[ws->references];
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. */
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)) {
3445 shared_websock_list = &((*shared_websock_list)->next);
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 */
3452 mg_unlock_context(conn->phys_ctx);
3455 (void)pthread_mutex_unlock(&(ws->ws_mutex));
3461 mg_lua_context_script_prepare(const char *file_name,
3462 struct mg_context *ctx,
3466 struct lua_State *L;
3468 const char *lua_err_txt;
3470 L = luaL_newstate();
3473 NULL, /* No truncation check for ebuf */
3477 "Cannot create Lua state");
3481 /* Add all libraries */
3482 prepare_lua_environment(ctx,
3487 LUA_ENV_TYPE_BACKGROUND);
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, ...)
3495 lua_err_txt = lua_tostring(L, -1);
3497 NULL, /* No truncation check for ebuf */
3500 "Error loading file %s: %s\n",
3506 /* lua_close(L); must be done somewhere else */
3512 mg_lua_context_script_run(lua_State *L,
3513 const char *file_name,
3514 struct mg_context *ctx,
3519 const char *lua_err_txt;
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);
3529 if (lua_ret != LUA_OK) {
3530 /* Error when executing the script */
3531 lua_err_txt = lua_tostring(L, -1);
3533 NULL, /* No truncation check for ebuf */
3536 "Error running file %s: %s\n",
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);
3548 /* Script returned false */
3550 NULL, /* No truncation check for ebuf */
3553 "Script %s returned false\n",
3560 /* lua_close(L); must be done somewhere else */
3566 lua_ctx_init(struct mg_context *ctx)
3568 #if defined(USE_WEBSOCKET)
3569 ctx->dd.shared_lua_websockets = NULL;
3575 lua_ctx_exit(struct mg_context *ctx)
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;
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);
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;
3592 mg_unlock_context(ctx);
3597 /* Execute Lua script from main */
3599 run_lua(const char *file_name)
3601 int func_ret = EXIT_FAILURE;
3602 char ebuf[512] = {0};
3604 mg_lua_context_script_prepare(file_name, NULL, ebuf, sizeof(ebuf));
3607 L = mg_lua_context_script_run(L, file_name, NULL, ebuf, sizeof(ebuf));
3611 /* Script executed */
3612 if (lua_type(L, -1) == LUA_TNUMBER) {
3613 func_ret = (int)lua_tonumber(L, -1);
3615 func_ret = EXIT_SUCCESS;
3619 fprintf(stderr, "%s\n", ebuf);
3625 static void *lib_handle_uuid = NULL;
3628 lua_init_optional_libraries(void)
3630 /* Create logging mutex */
3631 pthread_mutex_init(&s_lua_traceMutex, &pthread_mutex_attr);
3633 /* shared Lua state */
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);
3642 pf_uuid_generate.p = 0;
3648 lua_exit_optional_libraries(void)
3651 #if !defined(_WIN32)
3652 if (lib_handle_uuid) {
3653 dlclose(lib_handle_uuid);
3656 pf_uuid_generate.p = 0;
3657 lib_handle_uuid = NULL;
3659 /* shared Lua state */
3662 /* Delete logging mutex */
3663 pthread_mutex_destroy(&s_lua_traceMutex);
3667 /* End of mod_lua.inl */