1 /* This file is part of the CivetWeb web server.
2 * See https://github.com/civetweb/civetweb/
5 #include "civetweb_lua.h"
6 #include "civetweb_private_lua.h"
10 mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
12 /* TODO (low): This is an incomplete implementation of mmap for windows.
13 * Currently it is sufficient, but there are a lot of unused parameters.
14 * Better use a function "mg_map" which only has the required parameters,
15 * and implement it using mmap in Linux and CreateFileMapping in Windows.
16 * Noone should expect a full mmap for Windows here.
18 HANDLE fh = (HANDLE)_get_osfhandle(fd);
19 HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
20 void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
23 /* unused parameters */
33 munmap(void *addr, int64_t length)
35 /* unused parameters */
38 UnmapViewOfFile(addr);
41 #define MAP_FAILED (NULL)
42 #define MAP_PRIVATE (0)
48 static const char *LUASOCKET = "luasocket";
49 static const char lua_regkey_ctx = 1;
50 static const char lua_regkey_connlist = 2;
51 static const char lua_regkey_lsp_include_history = 3;
52 static const char *LUABACKGROUNDPARAMS = "mg";
54 #ifndef LSP_INCLUDE_MAX_DEPTH
55 #define LSP_INCLUDE_MAX_DEPTH (32)
59 /* Forward declarations */
60 static void handle_request(struct mg_connection *);
61 static int handle_lsp_request(struct mg_connection *,
67 reg_lstring(struct lua_State *L,
72 if (name != NULL && buffer != NULL) {
73 lua_pushstring(L, name);
74 lua_pushlstring(L, (const char *)buffer, buflen);
80 reg_llstring(struct lua_State *L,
86 if (buffer1 != NULL && buffer2 != NULL) {
87 lua_pushlstring(L, (const char *)buffer1, buflen1);
88 lua_pushlstring(L, (const char *)buffer2, buflen2);
93 #define reg_string(L, name, val) \
94 reg_lstring(L, name, val, val ? strlen(val) : 0)
97 reg_int(struct lua_State *L, const char *name, int val)
100 lua_pushstring(L, name);
101 lua_pushinteger(L, val);
107 reg_boolean(struct lua_State *L, const char *name, int val)
110 lua_pushstring(L, name);
111 lua_pushboolean(L, val != 0);
117 reg_conn_function(struct lua_State *L,
120 struct mg_connection *conn)
122 if (name != NULL && func != NULL && conn != NULL) {
123 lua_pushstring(L, name);
124 lua_pushlightuserdata(L, conn);
125 lua_pushcclosure(L, func, 1);
131 reg_function(struct lua_State *L, const char *name, lua_CFunction func)
133 if (name != NULL && func != NULL) {
134 lua_pushstring(L, name);
135 lua_pushcclosure(L, func, 0);
141 lua_cry(struct mg_connection *conn,
144 const char *lua_title,
145 const char *lua_operation)
153 "%s: %s failed: runtime error: %s",
156 lua_tostring(L, -1));
160 "%s: %s failed: syntax error: %s",
163 lua_tostring(L, -1));
166 mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
170 "%s: %s failed: error during garbage collection",
176 "%s: %s failed: error in error handling: %s",
179 lua_tostring(L, -1));
182 mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
188 lsp_sock_close(lua_State *L)
190 int num_args = lua_gettop(L);
194 if ((num_args == 1) && lua_istable(L, -1)) {
195 lua_getfield(L, -1, "sock");
196 psock = (SOCKET *)lua_tolstring(L, -1, &s);
197 if (s != sizeof(SOCKET)) {
198 return luaL_error(L, "invalid internal state in :close() call");
200 /* Do not closesocket(*psock); here, close it in __gc */
203 return luaL_error(L, "invalid :close() call");
209 lsp_sock_recv(lua_State *L)
211 int num_args = lua_gettop(L);
217 if ((num_args == 1) && lua_istable(L, -1)) {
218 lua_getfield(L, -1, "sock");
219 psock = (SOCKET *)lua_tolstring(L, -1, &s);
220 if (s != sizeof(SOCKET)) {
221 return luaL_error(L, "invalid internal state in :recv() call");
223 n = recv(*psock, buf, sizeof(buf), 0);
227 lua_pushlstring(L, buf, n);
230 return luaL_error(L, "invalid :recv() call");
236 lsp_sock_send(lua_State *L)
238 int num_args = lua_gettop(L);
240 size_t len, sent = 0;
245 if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
246 buf = lua_tolstring(L, -1, &len);
247 lua_getfield(L, -2, "sock");
248 psock = (SOCKET *)lua_tolstring(L, -1, &s);
249 if (s != sizeof(SOCKET)) {
250 return luaL_error(L, "invalid internal state in :close() call");
254 if ((n = send(*psock, buf + sent, (int)(len - sent), 0)) <= 0) {
259 lua_pushnumber(L, n);
261 return luaL_error(L, "invalid :close() call");
267 lsp_sock_gc(lua_State *L)
269 int num_args = lua_gettop(L);
273 if ((num_args == 1) && lua_istable(L, -1)) {
274 lua_getfield(L, -1, "sock");
275 psock = (SOCKET *)lua_tolstring(L, -1, &s);
276 if (s != sizeof(SOCKET)) {
279 "invalid internal state in __gc for object created by connect");
283 return luaL_error(L, "__gc for object created by connect failed");
288 /* Methods and meta-methods supported by the object returned by connect.
289 * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
290 static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
291 {"send", lsp_sock_send},
292 {"recv", lsp_sock_recv},
293 {"__gc", lsp_sock_gc},
297 lsp_connect(lua_State *L)
299 int num_args = lua_gettop(L);
305 if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
306 && lua_isnumber(L, -1)) {
307 ok = connect_socket(NULL,
309 (int)lua_tonumber(L, -2),
310 (int)lua_tonumber(L, -1),
316 return luaL_error(L, ebuf);
319 reg_lstring(L, "sock", (const char *)&sock, sizeof(SOCKET));
320 reg_string(L, "host", lua_tostring(L, -4));
321 luaL_getmetatable(L, LUASOCKET);
322 lua_setmetatable(L, -2);
326 L, "connect(host,port,is_ssl): invalid parameter given.");
332 lsp_error(lua_State *L)
334 lua_getglobal(L, "mg");
335 lua_getfield(L, -1, "onerror");
336 lua_pushvalue(L, -3);
337 lua_pcall(L, 1, 0, 0);
341 /* Silently stop processing chunks. */
343 lsp_abort(lua_State *L)
345 int top = lua_gettop(L);
346 lua_getglobal(L, "mg");
348 lua_setfield(L, -2, "onerror");
350 lua_pushstring(L, "aborting");
354 struct lsp_var_reader_data {
362 lsp_var_reader(lua_State *L, void *ud, size_t *sz)
364 struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
366 (void)(L); /* unused */
368 switch (reader->state) {
392 run_lsp(struct mg_connection *conn,
398 int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
399 char chunkname[MG_BUF_LEN];
400 struct lsp_var_reader_data data;
402 for (i = 0; i < len; i++) {
405 if (((i + 1) < len) && (p[i] == '<') && (p[i + 1] == '?')) {
407 /* <?= ?> means a variable is enclosed and its value should be
409 is_var = (((i + 2) < len) && (p[i + 2] == '='));
419 if (((j + 1) < len) && (p[j] == '?') && (p[j + 1] == '>')) {
420 mg_write(conn, p + pos, i - pos);
423 NULL, /* name only used for debugging */
429 lua_pushlightuserdata(L, conn);
430 lua_pushcclosure(L, lsp_error, 1);
433 data.begin = p + (i + 3);
434 data.len = j - (i + 3);
436 lua_ok = mg_lua_load(
437 L, lsp_var_reader, &data, chunkname, NULL);
439 lua_ok = luaL_loadbuffer(L,
446 /* Syntax error or OOM. Error message is pushed on
448 lua_pcall(L, 1, 0, 0);
450 /* Success loading chunk. Call it. */
451 lua_pcall(L, 0, 0, 1);
469 mg_write(conn, p + pos, i - pos);
476 /* mg.write: Send data to the client */
478 lsp_write(lua_State *L)
480 struct mg_connection *conn =
481 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
482 int num_args = lua_gettop(L);
488 for (i = 1; i <= num_args; i++) {
489 if (lua_isstring(L, i)) {
490 str = lua_tolstring(L, i, &size);
491 if (mg_write(conn, str, size) != (int)size) {
496 lua_pushboolean(L, rv);
502 /* mg.read: Read data from the client (e.g., from a POST request) */
504 lsp_read(lua_State *L)
506 struct mg_connection *conn =
507 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
509 int len = mg_read(conn, buf, sizeof(buf));
513 lua_pushlstring(L, buf, len);
519 /* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
521 lsp_keep_alive(lua_State *L)
523 struct mg_connection *conn =
524 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
525 int num_args = lua_gettop(L);
527 /* This function may be called with one parameter (boolean) to set the
529 Or without a parameter to just query the current keep_alive state. */
530 if ((num_args == 1) && lua_isboolean(L, 1)) {
531 conn->must_close = !lua_toboolean(L, 1);
532 } else if (num_args != 0) {
534 return luaL_error(L, "invalid keep_alive() call");
537 /* Return the current "keep_alive" state. This may be false, even it
538 * keep_alive(true) has been called. */
539 lua_pushboolean(L, should_keep_alive(conn));
544 /* Stack of includes */
545 struct lsp_include_history {
547 const char *script[LSP_INCLUDE_MAX_DEPTH + 1];
551 /* mg.include: Include another .lp file */
553 lsp_include(lua_State *L)
555 struct mg_connection *conn =
556 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
557 int num_args = lua_gettop(L);
558 struct mg_file file = STRUCT_FILE_INITIALIZER;
559 const char *file_name = (num_args >= 1) ? lua_tostring(L, 1) : NULL;
560 const char *path_type = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
561 struct lsp_include_history *include_history;
563 if ((file_name) && (num_args <= 2)) {
565 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
566 lua_gettable(L, LUA_REGISTRYINDEX);
567 include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
569 if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
571 "lsp max include depth of %i reached while including %s",
572 (int)(LSP_INCLUDE_MAX_DEPTH),
575 char file_name_path[512];
580 file_name_path[511] = 0;
582 if (path_type && (*path_type == 'v')) {
583 /* "virtual" = relative to document root. */
584 (void)mg_snprintf(conn,
587 sizeof(file_name_path),
589 conn->ctx->config[DOCUMENT_ROOT],
592 } else if ((path_type && (*path_type == 'a'))
593 || (path_type == NULL)) {
594 /* "absolute" = file name is relative to the
595 * webserver working directory
596 * or it is absolute system path. */
597 /* path_type==NULL is the legacy use case with 1 argument */
598 (void)mg_snprintf(conn,
601 sizeof(file_name_path),
605 } else if (path_type && (*path_type == 'r' || *path_type == 'f')) {
606 /* "relative" = file name is relative to the
607 * currect document */
612 sizeof(file_name_path),
614 include_history->script[include_history->depth]);
617 if ((p = strrchr(file_name_path, '/')) != NULL) {
620 len = strlen(file_name_path);
621 (void)mg_snprintf(conn,
623 file_name_path + len,
624 sizeof(file_name_path) - len,
632 "invalid path_type in include(file_name, path_type) call");
635 if (handle_lsp_request(conn, file_name_path, &file, L)) {
636 /* handle_lsp_request returned an error code, meaning an error
637 * occured in the included page and mg.onerror returned non-zero.
647 return luaL_error(L, "invalid include() call");
653 /* mg.cry: Log an error. Default value for mg.onerror. */
655 lsp_cry(lua_State *L)
657 struct mg_connection *conn =
658 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
659 int num_args = lua_gettop(L);
660 const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
663 mg_cry(conn, "%s", lua_tostring(L, -1));
666 return luaL_error(L, "invalid cry() call");
672 /* mg.redirect: Redirect the request (internally). */
674 lsp_redirect(lua_State *L)
676 struct mg_connection *conn =
677 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
678 int num_args = lua_gettop(L);
679 const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
682 conn->request_info.local_uri = target;
683 handle_request(conn);
687 return luaL_error(L, "invalid redirect() call");
695 lsp_send_file(lua_State *L)
697 struct mg_connection *conn =
698 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
699 int num_args = lua_gettop(L);
700 const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
703 mg_send_file(conn, filename);
706 return luaL_error(L, "invalid send_file() call");
714 lsp_get_time(lua_State *L)
716 int num_args = lua_gettop(L);
717 int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
721 clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
722 d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
723 lua_pushnumber(L, d);
730 lsp_get_var(lua_State *L)
732 int num_args = lua_gettop(L);
733 const char *data, *var_name;
734 size_t data_len, occurrence;
736 struct mg_context *ctx;
738 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
739 lua_gettable(L, LUA_REGISTRYINDEX);
740 ctx = (struct mg_context *)lua_touserdata(L, -1);
742 if (num_args >= 2 && num_args <= 3) {
744 data = lua_tolstring(L, 1, &data_len);
745 var_name = lua_tostring(L, 2);
746 occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
748 /* Allocate dynamically, so there is no internal limit for get_var */
749 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
751 return luaL_error(L, "out of memory in get_var() call");
754 ret = mg_get_var2(data, data_len, var_name, dst, data_len, occurrence);
756 /* Variable found: return value to Lua */
757 lua_pushstring(L, dst);
759 /* Variable not found (TODO (mid): may be string too long) */
765 return luaL_error(L, "invalid get_var() call");
771 /* mg.get_mime_type */
773 lsp_get_mime_type(lua_State *L)
775 int num_args = lua_gettop(L);
776 struct vec mime_type = {0, 0};
777 struct mg_context *ctx;
780 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
781 lua_gettable(L, LUA_REGISTRYINDEX);
782 ctx = (struct mg_context *)lua_touserdata(L, -1);
785 text = lua_tostring(L, 1);
788 get_mime_type(ctx, text, &mime_type);
789 lua_pushlstring(L, mime_type.ptr, mime_type.len);
791 text = mg_get_builtin_mime_type(text);
792 lua_pushstring(L, text);
796 return luaL_error(L, "invalid argument for get_mime_type() call");
800 return luaL_error(L, "invalid get_mime_type() call");
808 lsp_get_cookie(lua_State *L)
810 int num_args = lua_gettop(L);
812 const char *var_name;
814 struct mg_context *ctx;
816 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
817 lua_gettable(L, LUA_REGISTRYINDEX);
818 ctx = (struct mg_context *)lua_touserdata(L, -1);
821 /* Correct number of arguments */
825 cookie = lua_tolstring(L, 1, &data_len);
826 var_name = lua_tostring(L, 2);
828 if (cookie == NULL || var_name == NULL) {
830 return luaL_error(L, "invalid get_cookie() call");
833 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
835 return luaL_error(L, "out of memory in get_cookie() call");
838 ret = mg_get_cookie(cookie, var_name, dst, data_len);
841 lua_pushlstring(L, dst, ret);
849 return luaL_error(L, "invalid get_cookie() call");
857 lsp_md5(lua_State *L)
859 int num_args = lua_gettop(L);
867 text = lua_tolstring(L, 1, &text_len);
870 md5_append(&ctx, (const md5_byte_t *)text, text_len);
871 md5_finish(&ctx, hash);
872 bin2str(buf, hash, sizeof(hash));
873 lua_pushstring(L, buf);
879 return luaL_error(L, "invalid md5() call");
887 lsp_url_encode(lua_State *L)
889 int num_args = lua_gettop(L);
894 struct mg_context *ctx;
896 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
897 lua_gettable(L, LUA_REGISTRYINDEX);
898 ctx = (struct mg_context *)lua_touserdata(L, -1);
901 text = lua_tolstring(L, 1, &text_len);
903 dst_len = 3 * (int)text_len + 1;
904 dst = ((text_len < 0x2AAAAAAA) ? (char *)mg_malloc_ctx(dst_len, ctx)
907 mg_url_encode(text, dst, dst_len);
908 lua_pushstring(L, dst);
911 return luaL_error(L, "out of memory in url_decode() call");
918 return luaL_error(L, "invalid url_encode() call");
926 lsp_url_decode(lua_State *L)
928 int num_args = lua_gettop(L);
934 struct mg_context *ctx;
936 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
937 lua_gettable(L, LUA_REGISTRYINDEX);
938 ctx = (struct mg_context *)lua_touserdata(L, -1);
940 if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
941 text = lua_tolstring(L, 1, &text_len);
942 is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
944 dst_len = (int)text_len + 1;
945 dst = ((text_len < 0x7FFFFFFF) ? (char *)mg_malloc_ctx(dst_len, ctx)
948 mg_url_decode(text, (int)text_len, dst, dst_len, is_form);
949 lua_pushstring(L, dst);
952 return luaL_error(L, "out of memory in url_decode() call");
959 return luaL_error(L, "invalid url_decode() call");
965 /* mg.base64_encode */
967 lsp_base64_encode(lua_State *L)
969 int num_args = lua_gettop(L);
973 struct mg_context *ctx;
975 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
976 lua_gettable(L, LUA_REGISTRYINDEX);
977 ctx = (struct mg_context *)lua_touserdata(L, -1);
980 text = lua_tolstring(L, 1, &text_len);
982 dst = (char *)mg_malloc_ctx(text_len * 8 / 6 + 4, ctx);
984 base64_encode((const unsigned char *)text, (int)text_len, dst);
985 lua_pushstring(L, dst);
988 return luaL_error(L, "out of memory in base64_encode() call");
995 return luaL_error(L, "invalid base64_encode() call");
1001 /* mg.base64_encode */
1003 lsp_base64_decode(lua_State *L)
1005 int num_args = lua_gettop(L);
1007 size_t text_len, dst_len;
1010 struct mg_context *ctx;
1012 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1013 lua_gettable(L, LUA_REGISTRYINDEX);
1014 ctx = (struct mg_context *)lua_touserdata(L, -1);
1016 if (num_args == 1) {
1017 text = lua_tolstring(L, 1, &text_len);
1019 dst = (char *)mg_malloc_ctx(text_len, ctx);
1021 ret = base64_decode((const unsigned char *)text,
1028 L, "illegal character in lsp_base64_decode() call");
1030 lua_pushlstring(L, dst, dst_len);
1034 return luaL_error(L,
1035 "out of memory in lsp_base64_decode() call");
1042 return luaL_error(L, "invalid lsp_base64_decode() call");
1048 /* mg.get_response_code_text */
1050 lsp_get_response_code_text(lua_State *L)
1052 int num_args = lua_gettop(L);
1057 if (num_args == 1) {
1058 type1 = lua_type(L, 1);
1059 if (type1 == LUA_TNUMBER) {
1060 /* If the first argument is a number,
1061 convert it to the corresponding text. */
1062 code = lua_tonumber(L, 1);
1063 text = mg_get_response_code_text(NULL, (int)code);
1065 lua_pushstring(L, text);
1066 return text ? 1 : 0;
1071 return luaL_error(L, "invalid get_response_code_text() call");
1075 /* mg.random - might be better than math.random on some systems */
1077 lsp_random(lua_State *L)
1079 int num_args = lua_gettop(L);
1080 if (num_args == 0) {
1081 /* The civetweb internal random number generator will generate
1082 * a 64 bit random number. */
1083 uint64_t r = get_random();
1084 /* Lua "number" is a IEEE 754 double precission float:
1085 * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
1086 * Thus, mask with 2^53-1 to get an integer with the maximum
1087 * precission available. */
1088 r &= ((((uint64_t)1) << 53) - 1);
1089 lua_pushnumber(L, (double)r);
1094 return luaL_error(L, "invalid random() call");
1100 lsp_get_info(lua_State *L)
1102 int num_args = lua_gettop(L);
1109 if (num_args == 1) {
1110 type1 = lua_type(L, 1);
1111 if (type1 == LUA_TSTRING) {
1112 arg1 = lua_tostring(L, 1);
1113 /* Get info according to argument */
1114 if (!mg_strcasecmp(arg1, "system")) {
1115 /* Get system info */
1116 len = mg_get_system_info(NULL, 0);
1118 buf = mg_malloc(len + 64);
1120 return luaL_error(L, "OOM in get_info() call");
1122 len = mg_get_system_info(buf, len + 63);
1123 lua_pushlstring(L, buf, len);
1126 lua_pushstring(L, "");
1130 if (!mg_strcasecmp(arg1, "context")) {
1132 struct mg_context *ctx;
1133 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1134 lua_gettable(L, LUA_REGISTRYINDEX);
1135 ctx = (struct mg_context *)lua_touserdata(L, -1);
1137 /* Get context info for server context */
1138 len = mg_get_context_info(ctx, NULL, 0);
1140 buf = mg_malloc(len + 64);
1142 return luaL_error(L, "OOM in get_info() call");
1144 len = mg_get_context_info(ctx, buf, len + 63);
1145 lua_pushlstring(L, buf, len);
1148 lua_pushstring(L, "");
1152 if (!mg_strcasecmp(arg1, "common")) {
1153 /* Get context info for NULL context */
1154 len = mg_get_context_info(NULL, NULL, 0);
1156 buf = mg_malloc(len + 64);
1158 return luaL_error(L, "OOM in get_info() call");
1160 len = mg_get_context_info(NULL, buf, len + 63);
1161 lua_pushlstring(L, buf, len);
1164 lua_pushstring(L, "");
1172 if (num_args == 2) {
1173 type1 = lua_type(L, 1);
1174 type2 = lua_type(L, 2);
1175 if ((type1 == LUA_TSTRING) && (type2 == LUA_TNUMBER)) {
1176 arg1 = lua_tostring(L, 1);
1177 arg2 = lua_tonumber(L, 2);
1179 /* Get info according to argument */
1180 if (!mg_strcasecmp(arg1, "connection")) {
1183 struct mg_context *ctx;
1184 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1185 lua_gettable(L, LUA_REGISTRYINDEX);
1186 ctx = (struct mg_context *)lua_touserdata(L, -1);
1188 /* Get connection info for connection idx */
1189 int idx = (int)(arg2 + 0.5);
1191 /* Lua uses 1 based index, C uses 0 based index */
1194 #ifdef MG_EXPERIMENTAL_INTERFACES
1195 len = mg_get_connection_info(ctx, idx, NULL, 0);
1197 buf = mg_malloc(len + 64);
1199 return luaL_error(L, "OOM in get_info() call");
1201 len = mg_get_connection_info(ctx, idx, buf, len + 63);
1202 lua_pushlstring(L, buf, len);
1205 lua_pushstring(L, "");
1210 lua_pushstring(L, "");
1220 return luaL_error(L, "invalid get_info() call");
1226 lsp_get_option(lua_State *L)
1228 int num_args = lua_gettop(L);
1234 struct mg_context *ctx;
1235 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1236 lua_gettable(L, LUA_REGISTRYINDEX);
1237 ctx = (struct mg_context *)lua_touserdata(L, -1);
1239 if (num_args == 0) {
1240 const struct mg_option *opts = mg_get_valid_options();
1247 while (opts->name) {
1248 data = mg_get_option(ctx, opts->name);
1250 reg_string(L, opts->name, data);
1258 if (num_args == 1) {
1259 type1 = lua_type(L, 1);
1260 if (type1 == LUA_TSTRING) {
1261 arg1 = lua_tostring(L, 1);
1262 /* Get option according to argument */
1263 data = mg_get_option(ctx, arg1);
1265 lua_pushstring(L, data);
1273 return luaL_error(L, "invalid get_option() call");
1277 /* UUID library and function pointer */
1280 void (*f)(unsigned char uuid[16]);
1286 lsp_uuid(lua_State *L)
1289 unsigned char uuid_array[16];
1290 struct uuid_struct_type {
1299 int num_args = lua_gettop(L);
1301 memset(&uuid, 0, sizeof(uuid));
1302 memset(uuid_str, 0, sizeof(uuid_str));
1304 if (num_args == 0) {
1306 pf_uuid_generate.f(uuid.uuid_array);
1309 "{%08lX-%04X-%04X-%02X%02X-"
1310 "%02X%02X%02X%02X%02X%02X}",
1311 (unsigned long)uuid.uuid_struct.data1,
1312 (unsigned)uuid.uuid_struct.data2,
1313 (unsigned)uuid.uuid_struct.data3,
1314 (unsigned)uuid.uuid_struct.data4[0],
1315 (unsigned)uuid.uuid_struct.data4[1],
1316 (unsigned)uuid.uuid_struct.data4[2],
1317 (unsigned)uuid.uuid_struct.data4[3],
1318 (unsigned)uuid.uuid_struct.data4[4],
1319 (unsigned)uuid.uuid_struct.data4[5],
1320 (unsigned)uuid.uuid_struct.data4[6],
1321 (unsigned)uuid.uuid_struct.data4[7]);
1323 lua_pushstring(L, uuid_str);
1328 return luaL_error(L, "invalid random() call");
1332 #ifdef USE_WEBSOCKET
1333 struct lua_websock_data {
1336 unsigned references;
1337 struct mg_connection *conn[MAX_WORKER_THREADS];
1338 pthread_mutex_t ws_mutex;
1343 /* mg.write for websockets */
1345 lwebsock_write(lua_State *L)
1347 #ifdef USE_WEBSOCKET
1348 int num_args = lua_gettop(L);
1349 struct lua_websock_data *ws;
1354 struct mg_connection *client = NULL;
1356 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1357 lua_gettable(L, LUA_REGISTRYINDEX);
1358 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1360 (void)pthread_mutex_lock(&(ws->ws_mutex));
1362 if (num_args == 1) {
1363 /* just one text: send it to all client */
1364 if (lua_isstring(L, 1)) {
1365 opcode = WEBSOCKET_OPCODE_TEXT;
1367 } else if (num_args == 2) {
1368 if (lua_isnumber(L, 1)) {
1369 /* opcode number and message text */
1370 opcode = (int)lua_tointeger(L, 1);
1371 } else if (lua_isstring(L, 1)) {
1372 /* opcode string and message text */
1373 str = lua_tostring(L, 1);
1374 if (!mg_strncasecmp(str, "text", 4))
1375 opcode = WEBSOCKET_OPCODE_TEXT;
1376 else if (!mg_strncasecmp(str, "bin", 3))
1377 opcode = WEBSOCKET_OPCODE_BINARY;
1378 else if (!mg_strncasecmp(str, "close", 5))
1379 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
1380 else if (!mg_strncasecmp(str, "ping", 4))
1381 opcode = WEBSOCKET_OPCODE_PING;
1382 else if (!mg_strncasecmp(str, "pong", 4))
1383 opcode = WEBSOCKET_OPCODE_PONG;
1384 else if (!mg_strncasecmp(str, "cont", 4))
1385 opcode = WEBSOCKET_OPCODE_CONTINUATION;
1386 } else if (lua_isuserdata(L, 1)) {
1387 /* client id and message text */
1388 client = (struct mg_connection *)lua_touserdata(L, 1);
1389 opcode = WEBSOCKET_OPCODE_TEXT;
1391 } else if (num_args == 3) {
1392 if (lua_isuserdata(L, 1)) {
1393 client = (struct mg_connection *)lua_touserdata(L, 1);
1394 if (lua_isnumber(L, 2)) {
1395 /* client id, opcode number and message text */
1396 opcode = (int)lua_tointeger(L, 2);
1397 } else if (lua_isstring(L, 2)) {
1398 /* client id, opcode string and message text */
1399 str = lua_tostring(L, 2);
1400 if (!mg_strncasecmp(str, "text", 4))
1401 opcode = WEBSOCKET_OPCODE_TEXT;
1402 else if (!mg_strncasecmp(str, "bin", 3))
1403 opcode = WEBSOCKET_OPCODE_BINARY;
1404 else if (!mg_strncasecmp(str, "close", 5))
1405 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
1406 else if (!mg_strncasecmp(str, "ping", 4))
1407 opcode = WEBSOCKET_OPCODE_PING;
1408 else if (!mg_strncasecmp(str, "pong", 4))
1409 opcode = WEBSOCKET_OPCODE_PONG;
1410 else if (!mg_strncasecmp(str, "cont", 4))
1411 opcode = WEBSOCKET_OPCODE_CONTINUATION;
1416 if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
1417 str = lua_tolstring(L, num_args, &size);
1419 for (i = 0; i < ws->references; i++) {
1420 if (client == ws->conn[i]) {
1421 mg_lock_connection(ws->conn[i]);
1422 mg_websocket_write(ws->conn[i], opcode, str, size);
1423 mg_unlock_connection(ws->conn[i]);
1427 for (i = 0; i < ws->references; i++) {
1428 mg_lock_connection(ws->conn[i]);
1429 mg_websocket_write(ws->conn[i], opcode, str, size);
1430 mg_unlock_connection(ws->conn[i]);
1434 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1435 return luaL_error(L, "invalid websocket write() call");
1438 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1441 (void)(L); /* unused */
1447 struct laction_arg {
1450 pthread_mutex_t *pmutex;
1456 lua_action(struct laction_arg *arg)
1459 struct mg_context *ctx;
1461 (void)pthread_mutex_lock(arg->pmutex);
1463 lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
1464 lua_gettable(arg->state, LUA_REGISTRYINDEX);
1465 ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
1467 err = luaL_loadstring(arg->state, arg->txt);
1469 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1470 (void)pthread_mutex_unlock(arg->pmutex);
1474 err = lua_pcall(arg->state, 0, 1, 0);
1476 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1477 (void)pthread_mutex_unlock(arg->pmutex);
1482 ok = lua_type(arg->state, -1);
1483 if (lua_isboolean(arg->state, -1)) {
1484 ok = lua_toboolean(arg->state, -1);
1488 lua_pop(arg->state, 1);
1490 (void)pthread_mutex_unlock(arg->pmutex);
1500 lua_action_free(struct laction_arg *arg)
1502 if (lua_action(arg)) {
1510 lwebsocket_set_timer(lua_State *L, int is_periodic)
1512 #if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
1513 int num_args = lua_gettop(L);
1514 struct lua_websock_data *ws;
1515 int type1, type2, ok = 0;
1517 struct mg_context *ctx;
1518 struct laction_arg *arg;
1522 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1523 lua_gettable(L, LUA_REGISTRYINDEX);
1524 ctx = (struct mg_context *)lua_touserdata(L, -1);
1526 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1527 lua_gettable(L, LUA_REGISTRYINDEX);
1528 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1531 return luaL_error(L,
1532 "not enough arguments for set_timer/interval() call");
1535 type1 = lua_type(L, 1);
1536 type2 = lua_type(L, 2);
1538 if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
1539 timediff = (double)lua_tonumber(L, 2);
1540 txt = lua_tostring(L, 1);
1541 txt_len = strlen(txt);
1542 arg = (struct laction_arg *)mg_malloc_ctx(sizeof(struct laction_arg)
1546 arg->script = ws->script;
1547 arg->pmutex = &(ws->ws_mutex);
1548 memcpy(arg->txt, "return(", 7);
1549 memcpy(arg->txt + 7, txt, txt_len);
1550 arg->txt[txt_len + 7] = ')';
1551 arg->txt[txt_len + 8] = 0;
1558 (taction)(is_periodic ? lua_action : lua_action_free),
1560 } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
1561 /* TODO (mid): not implemented yet */
1562 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1564 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1567 lua_pushboolean(L, ok);
1571 (void)(L); /* unused */
1572 (void)(is_periodic); /* unused */
1578 /* mg.set_timeout for websockets */
1580 lwebsocket_set_timeout(lua_State *L)
1582 return lwebsocket_set_timer(L, 0);
1586 /* mg.set_interval for websockets */
1588 lwebsocket_set_interval(lua_State *L)
1590 return lwebsocket_set_timer(L, 1);
1594 LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
1595 LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
1596 LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
1601 prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
1606 /* Export mg.request_info */
1607 lua_pushstring(L, "request_info");
1609 reg_string(L, "request_method", conn->request_info.request_method);
1610 reg_string(L, "request_uri", conn->request_info.request_uri);
1611 reg_string(L, "uri", conn->request_info.local_uri);
1612 reg_string(L, "http_version", conn->request_info.http_version);
1613 reg_string(L, "query_string", conn->request_info.query_string);
1614 #if defined(MG_LEGACY_INTERFACE)
1615 reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
1620 reg_string(L, "remote_addr", conn->request_info.remote_addr);
1621 /* TODO (high): ip version */
1622 reg_int(L, "remote_port", conn->request_info.remote_port);
1623 reg_int(L, "num_headers", conn->request_info.num_headers);
1624 reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
1626 if (conn->path_info != NULL) {
1627 reg_string(L, "path_info", conn->path_info);
1630 if (conn->request_info.content_length >= 0) {
1631 /* reg_int64: content_length */
1632 lua_pushstring(L, "content_length");
1635 (lua_Number)conn->request_info
1636 .content_length); /* lua_Number may be used as 52 bit integer */
1639 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
1640 reg_string(L, "content_type", s);
1643 if (conn->request_info.remote_user != NULL) {
1644 reg_string(L, "remote_user", conn->request_info.remote_user);
1645 reg_string(L, "auth_type", "Digest");
1648 reg_boolean(L, "https", conn->ssl != NULL);
1650 if (conn->status_code > 0) {
1651 /* Lua error handler should show the status code */
1652 reg_int(L, "status", conn->status_code);
1655 lua_pushstring(L, "http_headers");
1657 for (i = 0; i < conn->request_info.num_headers; i++) {
1659 conn->request_info.http_headers[i].name,
1660 conn->request_info.http_headers[i].value);
1669 civetweb_open_lua_libs(lua_State *L)
1672 extern void luaL_openlibs(lua_State *);
1676 #ifdef USE_LUA_SQLITE3
1678 extern int luaopen_lsqlite3(lua_State *);
1679 luaopen_lsqlite3(L);
1682 #ifdef USE_LUA_LUAXML
1684 extern int luaopen_LuaXML_lib(lua_State *);
1685 luaopen_LuaXML_lib(L);
1688 #ifdef USE_LUA_FILE_SYSTEM
1690 extern int luaopen_lfs(lua_State *);
1694 #ifdef USE_LUA_BINARY
1696 /* TODO (low): Test if this could be used as a replacement for bit32.
1697 * Check again with Lua 5.3 later. */
1698 extern int luaopen_binary(lua_State *);
1700 luaL_requiref(L, "binary", luaopen_binary, 1);
1708 prepare_lua_environment(struct mg_context *ctx,
1709 struct mg_connection *conn,
1710 struct lua_websock_data *ws_conn_list,
1712 const char *script_name,
1715 civetweb_open_lua_libs(L);
1717 #if LUA_VERSION_NUM == 502
1718 /* Keep the "connect" method for compatibility,
1719 * but do not backport it to Lua 5.1.
1720 * TODO: Redesign the interface.
1722 luaL_newmetatable(L, LUASOCKET);
1723 lua_pushliteral(L, "__index");
1724 luaL_newlib(L, luasocket_methods);
1727 lua_register(L, "connect", lsp_connect);
1730 /* Store context in the registry */
1732 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1733 lua_pushlightuserdata(L, (void *)ctx);
1734 lua_settable(L, LUA_REGISTRYINDEX);
1736 if (ws_conn_list != NULL) {
1737 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1738 lua_pushlightuserdata(L, (void *)ws_conn_list);
1739 lua_settable(L, LUA_REGISTRYINDEX);
1742 /* Lua server pages store the depth of mg.include, in order
1743 * to detect recursions and prevent stack overflows. */
1744 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
1745 struct lsp_include_history *h;
1746 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
1747 h = (struct lsp_include_history *)
1748 lua_newuserdata(L, sizeof(struct lsp_include_history));
1749 lua_settable(L, LUA_REGISTRYINDEX);
1750 memset(h, 0, sizeof(struct lsp_include_history));
1753 /* Register mg module */
1756 switch (lua_env_type) {
1757 case LUA_ENV_TYPE_LUA_SERVER_PAGE:
1758 reg_string(L, "lua_type", "page");
1760 case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
1761 reg_string(L, "lua_type", "script");
1763 case LUA_ENV_TYPE_LUA_WEBSOCKET:
1764 reg_string(L, "lua_type", "websocket");
1768 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
1769 || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
1770 reg_conn_function(L, "cry", lsp_cry, conn);
1771 reg_conn_function(L, "read", lsp_read, conn);
1772 reg_conn_function(L, "write", lsp_write, conn);
1773 reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
1774 reg_conn_function(L, "send_file", lsp_send_file, conn);
1777 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
1778 reg_conn_function(L, "include", lsp_include, conn);
1779 reg_conn_function(L, "redirect", lsp_redirect, conn);
1782 if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
1783 reg_function(L, "write", lwebsock_write);
1785 reg_function(L, "set_timeout", lwebsocket_set_timeout);
1786 reg_function(L, "set_interval", lwebsocket_set_interval);
1788 /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
1791 reg_function(L, "time", lsp_get_time);
1792 reg_function(L, "get_var", lsp_get_var);
1793 reg_function(L, "get_mime_type", lsp_get_mime_type);
1794 reg_function(L, "get_cookie", lsp_get_cookie);
1795 reg_function(L, "md5", lsp_md5);
1796 reg_function(L, "url_encode", lsp_url_encode);
1797 reg_function(L, "url_decode", lsp_url_decode);
1798 reg_function(L, "base64_encode", lsp_base64_encode);
1799 reg_function(L, "base64_decode", lsp_base64_decode);
1800 reg_function(L, "get_response_code_text", lsp_get_response_code_text);
1801 reg_function(L, "random", lsp_random);
1802 reg_function(L, "get_info", lsp_get_info);
1803 reg_function(L, "get_option", lsp_get_option);
1805 if (pf_uuid_generate.f) {
1806 reg_function(L, "uuid", lsp_uuid);
1809 reg_string(L, "version", CIVETWEB_VERSION);
1811 reg_string(L, "script_name", script_name);
1814 reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
1815 reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
1816 #if defined(USE_WEBSOCKET)
1817 if (ctx->config[WEBSOCKET_ROOT]) {
1818 reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
1820 reg_string(L, "websocket_root", ctx->config[DOCUMENT_ROOT]);
1824 if (ctx->systemName != NULL) {
1825 reg_string(L, "system", ctx->systemName);
1829 /* Export connection specific info */
1831 prepare_lua_request_info(conn, L);
1834 lua_setglobal(L, "mg");
1836 /* Register default mg.onerror function */
1837 IGNORE_UNUSED_RESULT(
1839 "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
1840 "debug.traceback(e, 1)) end"));
1844 if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
1845 IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
1848 if (ctx->callbacks.init_lua != NULL) {
1849 ctx->callbacks.init_lua(conn, L);
1856 lua_error_handler(lua_State *L)
1858 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
1860 lua_getglobal(L, "mg");
1861 if (!lua_isnil(L, -1)) {
1862 lua_getfield(L, -1, "write"); /* call mg.write() */
1863 lua_pushstring(L, error_msg);
1864 lua_pushliteral(L, "\n");
1866 IGNORE_UNUSED_RESULT(
1867 luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
1869 printf("Lua error: [%s]\n", error_msg);
1870 IGNORE_UNUSED_RESULT(
1871 luaL_dostring(L, "print(debug.traceback(), '\\n')"));
1873 /* TODO(lsm, low): leave the stack balanced */
1880 lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
1882 (void)osize; /* not used */
1888 return mg_realloc_ctx(ptr, nsize, (struct mg_context *)ud);
1893 mg_exec_lua_script(struct mg_connection *conn,
1895 const void **exports)
1900 /* Assume the script does not support keep_alive. The script may change this
1901 * by calling mg.keep_alive(true). */
1902 conn->must_close = 1;
1904 /* Execute a plain Lua script. */
1906 && (L = lua_newstate(lua_allocator, (void *)(conn->ctx))) != NULL) {
1907 prepare_lua_environment(
1908 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
1909 lua_pushcclosure(L, &lua_error_handler, 0);
1911 if (exports != NULL) {
1912 #if LUA_VERSION_NUM > 501
1913 lua_pushglobaltable(L);
1914 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1916 lua_pushstring(L, (const char *)(exports[i]));
1917 *(const void **)(&func) = exports[i + 1];
1918 lua_pushcclosure(L, func, 0);
1922 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1924 const char *name = (const char *)(exports[i]);
1925 *(const void **)(&func) = exports[i + 1];
1926 lua_register(L, name, func);
1931 if (luaL_loadfile(L, path) != 0) {
1932 lua_error_handler(L);
1934 lua_pcall(L, 0, 0, -2);
1941 handle_lsp_request(struct mg_connection *conn,
1943 struct mg_file *filep,
1944 struct lua_State *ls)
1947 lua_State *L = NULL;
1948 struct lsp_include_history *include_history;
1951 /* Assume the script does not support keep_alive. The script may change this
1952 * by calling mg.keep_alive(true). */
1953 conn->must_close = 1;
1955 /* mg_fopen opens the file and sets the size accordingly */
1956 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
1958 /* File not found or not accessible */
1960 mg_send_http_error(conn,
1962 "Error: Cannot open script file %s",
1965 luaL_error(ls, "Cannot include [%s]: not found", path);
1968 goto cleanup_handle_lsp_request;
1971 /* Map file in memory (size is known). */
1972 if (filep->access.membuf == NULL
1974 (size_t)filep->stat.size,
1977 fileno(filep->access.fp),
1978 0)) == MAP_FAILED) {
1985 "Error: Cannot open script\nFile %s can not be mapped",
1989 "mmap(%s, %zu, %d): %s",
1991 (size_t)filep->stat.size,
1992 fileno(filep->access.fp),
1996 goto cleanup_handle_lsp_request;
2002 L = lua_newstate(lua_allocator, (void *)(conn->ctx));
2008 "Error: Cannot execute script\nlua_newstate failed");
2010 goto cleanup_handle_lsp_request;
2012 prepare_lua_environment(
2013 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
2016 /* Get LSP include history table */
2017 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
2018 lua_gettable(L, LUA_REGISTRYINDEX);
2019 include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
2021 /* Store script name and increment depth */
2022 include_history->depth++;
2023 include_history->script[include_history->depth] = path;
2025 /* Lua state is ready to use */
2026 /* We're not sending HTTP headers here, Lua page must do it. */
2027 error = run_lsp(conn,
2029 (filep->access.membuf == NULL)
2031 : (const char *)filep->access.membuf,
2035 cleanup_handle_lsp_request:
2037 if (L != NULL && ls == NULL)
2040 munmap(p, filep->stat.size);
2041 (void)mg_fclose(&filep->access);
2047 #ifdef USE_WEBSOCKET
2048 struct mg_shared_lua_websocket_list {
2049 struct lua_websock_data ws;
2050 struct mg_shared_lua_websocket_list *next;
2055 lua_websocket_new(const char *script, struct mg_connection *conn)
2057 struct mg_shared_lua_websocket_list **shared_websock_list =
2058 &(conn->ctx->shared_lua_websockets);
2059 struct lua_websock_data *ws;
2062 assert(conn->lua_websocket_state == NULL);
2064 /* lock list (mg_context global) */
2065 mg_lock_context(conn->ctx);
2066 while (*shared_websock_list) {
2067 /* check if ws already in list */
2068 if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
2071 shared_websock_list = &((*shared_websock_list)->next);
2074 if (*shared_websock_list == NULL) {
2075 /* add ws to list */
2076 *shared_websock_list =
2077 (struct mg_shared_lua_websocket_list *)mg_calloc_ctx(
2078 sizeof(struct mg_shared_lua_websocket_list), 1, conn->ctx);
2079 if (*shared_websock_list == NULL) {
2080 mg_unlock_context(conn->ctx);
2081 mg_cry(conn, "Cannot create shared websocket struct, OOM");
2084 /* init ws list element */
2085 ws = &(*shared_websock_list)->ws;
2086 ws->script = mg_strdup(script); /* TODO (low): handle OOM */
2087 pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
2088 (void)pthread_mutex_lock(&(ws->ws_mutex));
2089 ws->state = lua_newstate(lua_allocator, (void *)(conn->ctx));
2092 prepare_lua_environment(
2093 conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
2094 err = luaL_loadfile(ws->state, script);
2096 lua_cry(conn, err, ws->state, script, "load");
2098 err = lua_pcall(ws->state, 0, 0, 0);
2100 lua_cry(conn, err, ws->state, script, "init");
2104 ws = &(*shared_websock_list)->ws;
2105 (void)pthread_mutex_lock(&(ws->ws_mutex));
2106 (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
2108 mg_unlock_context(conn->ctx);
2111 lua_getglobal(ws->state, "open");
2112 lua_newtable(ws->state);
2113 prepare_lua_request_info(conn, ws->state);
2114 lua_pushstring(ws->state, "client");
2115 lua_pushlightuserdata(ws->state, (void *)conn);
2116 lua_rawset(ws->state, -3);
2118 err = lua_pcall(ws->state, 1, 1, 0);
2120 lua_cry(conn, err, ws->state, script, "open handler");
2122 if (lua_isboolean(ws->state, -1)) {
2123 ok = lua_toboolean(ws->state, -1);
2125 lua_pop(ws->state, 1);
2128 /* Remove from ws connection list. */
2129 /* TODO (mid): Check if list entry and Lua state needs to be deleted
2130 * (see websocket_close). */
2131 (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
2134 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2136 return ok ? (void *)ws : NULL;
2141 lua_websocket_data(struct mg_connection *conn,
2147 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2151 assert(ws->state != NULL);
2153 (void)pthread_mutex_lock(&(ws->ws_mutex));
2155 lua_getglobal(ws->state, "data");
2156 lua_newtable(ws->state);
2157 lua_pushstring(ws->state, "client");
2158 lua_pushlightuserdata(ws->state, (void *)conn);
2159 lua_rawset(ws->state, -3);
2160 lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
2161 a meaning according to
2162 http://tools.ietf.org/html/rfc6455,
2164 lua_pushnumber(ws->state, bits);
2165 lua_rawset(ws->state, -3);
2166 lua_pushstring(ws->state, "data");
2167 lua_pushlstring(ws->state, data, data_len);
2168 lua_rawset(ws->state, -3);
2170 err = lua_pcall(ws->state, 1, 1, 0);
2172 lua_cry(conn, err, ws->state, ws->script, "data handler");
2174 if (lua_isboolean(ws->state, -1)) {
2175 ok = lua_toboolean(ws->state, -1);
2177 lua_pop(ws->state, 1);
2179 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2186 lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
2188 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2192 assert(ws->state != NULL);
2194 (void)pthread_mutex_lock(&(ws->ws_mutex));
2196 lua_getglobal(ws->state, "ready");
2197 lua_newtable(ws->state);
2198 lua_pushstring(ws->state, "client");
2199 lua_pushlightuserdata(ws->state, (void *)conn);
2200 lua_rawset(ws->state, -3);
2201 err = lua_pcall(ws->state, 1, 1, 0);
2203 lua_cry(conn, err, ws->state, ws->script, "ready handler");
2205 if (lua_isboolean(ws->state, -1)) {
2206 ok = lua_toboolean(ws->state, -1);
2208 lua_pop(ws->state, 1);
2211 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2218 lua_websocket_close(struct mg_connection *conn, void *ws_arg)
2220 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2221 struct mg_shared_lua_websocket_list **shared_websock_list =
2222 &(conn->ctx->shared_lua_websockets);
2227 assert(ws->state != NULL);
2229 (void)pthread_mutex_lock(&(ws->ws_mutex));
2231 lua_getglobal(ws->state, "close");
2232 lua_newtable(ws->state);
2233 lua_pushstring(ws->state, "client");
2234 lua_pushlightuserdata(ws->state, (void *)conn);
2235 lua_rawset(ws->state, -3);
2237 err = lua_pcall(ws->state, 1, 0, 0);
2239 lua_cry(conn, err, ws->state, ws->script, "close handler");
2241 for (i = 0; i < ws->references; i++) {
2242 if (ws->conn[i] == conn) {
2244 ws->conn[i] = ws->conn[ws->references];
2247 /* TODO: Delete lua_websock_data and remove it from the websocket list.
2248 This must only be done, when all connections are closed, and all
2249 asynchronous operations and timers are completed/expired. */
2250 (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
2252 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2258 mg_prepare_lua_context_script(const char *file_name,
2259 struct mg_context *ctx,
2263 struct lua_State *L;
2265 const char *lua_err_txt;
2269 L = luaL_newstate();
2272 NULL, /* No truncation check for ebuf */
2276 "Cannot create Lua state");
2279 civetweb_open_lua_libs(L);
2281 lua_ret = luaL_loadfile(L, file_name);
2282 if (lua_ret != LUA_OK) {
2283 /* Error when loading the file (e.g. file not found,
2284 * out of memory, ...)
2286 lua_err_txt = lua_tostring(L, -1);
2288 NULL, /* No truncation check for ebuf */
2291 "Error loading file %s: %s\n",
2297 /* The script file is loaded, now call it */
2298 lua_ret = lua_pcall(L,
2299 /* no arguments */ 0,
2300 /* zero or one return value */ 1,
2301 /* errors as strint return value */ 0);
2303 if (lua_ret != LUA_OK) {
2304 /* Error when executing the script */
2305 lua_err_txt = lua_tostring(L, -1);
2307 NULL, /* No truncation check for ebuf */
2310 "Error running file %s: %s\n",
2315 /* lua_close(L); must be done somewhere else */
2322 run_lua(const char *file_name)
2324 int func_ret = EXIT_FAILURE;
2325 char ebuf[512] = {0};
2327 mg_prepare_lua_context_script(file_name, NULL, ebuf, sizeof(ebuf));
2329 /* Script executed */
2330 if (lua_type(L, -1) == LUA_TNUMBER) {
2331 func_ret = (int)lua_tonumber(L, -1);
2333 func_ret = EXIT_SUCCESS;
2337 fprintf(stderr, "%s\n", ebuf);
2343 static void *lib_handle_uuid = NULL;
2346 lua_init_optional_libraries(void)
2348 #if !defined(_WIN32)
2349 lib_handle_uuid = dlopen("libuuid.so", RTLD_LAZY);
2350 pf_uuid_generate.p =
2351 (lib_handle_uuid ? dlsym(lib_handle_uuid, "uuid_generate") : 0);
2353 pf_uuid_generate.p = 0;
2359 lua_exit_optional_libraries(void)
2361 #if !defined(_WIN32)
2362 if (lib_handle_uuid) {
2363 dlclose(lib_handle_uuid);
2366 pf_uuid_generate.p = 0;
2367 lib_handle_uuid = NULL;
2371 /* End of mod_lua.inl */