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