]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/mod_lua.inl
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / mod_lua.inl
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)
15 static void *
16 mmap(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
39 static void
40 munmap(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
54 static const char *const LUASOCKET = "luasocket";
55 static const char lua_regkey_ctx = 1;
56 static const char lua_regkey_connlist = 2;
57 static const char lua_regkey_lsp_include_history = 3;
58 static const char lua_regkey_environment_type = 4;
59 static const char lua_regkey_dtor = 5;
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 */
71 static int handle_lsp_request(struct mg_connection *,
72 const char *,
73 struct mg_file *,
74 struct lua_State *);
75
76
77 static void
78 reg_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
91 static void
92 reg_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
110 static void
111 reg_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
121 static void
122 reg_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
138 static void
139 reg_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
149 static void
150 reg_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
160 static void
161 reg_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
175 static void
176 reg_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
186 static void
187 lua_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
244 static int
245 lsp_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
266 static int
267 lsp_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
294 static int
295 lsp_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
326 static int
327 lsp_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 */
351 static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
352 {"send", lsp_sock_send},
353 {"recv", lsp_sock_recv},
354 {"__gc", lsp_sock_gc},
355 {NULL, NULL}};
356
357
358 static int
359 lsp_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
394 static int
395 lsp_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. */
407 static void
408 lsp_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
421 struct 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 */
431 static const char *
432 lsp_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
469 static const char *
470 lsp_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
616 static int
617 run_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
671 static int
672 run_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 */
810 static int
811 lsp_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) */
836 static int
837 lsp_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 */
853 static int
854 lsp_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 */
878 struct 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 */
885 static int
886 lsp_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. */
993 static int
994 lsp_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). */
1012 static int
1013 lsp_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 */
1033 static int
1034 lsp_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 */
1052 static int
1053 lsp_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 */
1074 static int
1075 lsp_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 */
1100 static int
1101 lsp_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 */
1147 static int
1148 lsp_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 */
1185 static int
1186 lsp_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 */
1201 static int
1202 lsp_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 */
1246 static int
1247 lsp_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 */
1311 static int
1312 lsp_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 */
1344 static int
1345 lsp_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 */
1393 static int
1394 lsp_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 */
1423 static int
1424 lsp_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 */
1462 static int
1463 lsp_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 */
1503 static int
1504 lsp_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 */
1539 static int
1540 lsp_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 */
1586 static int
1587 lsp_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 */
1614 static int
1615 lsp_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 */
1637 static int
1638 lsp_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 */
1764 static int
1765 lsp_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
1821 static int s_lua_traceLevel = 1;
1822 static FILE *s_lua_traceFile = NULL;
1823 static pthread_mutex_t s_lua_traceMutex;
1824
1825
1826 /* mg.trace */
1827 static int
1828 lsp_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 */
1884 union {
1885 void *p;
1886 void (*f)(unsigned char uuid[16]);
1887 } pf_uuid_generate;
1888
1889
1890 /* mg.uuid */
1891 static int
1892 lsp_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)
1939 struct 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 */
1950 static int
1951 lwebsock_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
2053 struct laction_string_arg {
2054 lua_State *L;
2055 const char *script;
2056 pthread_mutex_t *pmutex;
2057 char txt[1];
2058 };
2059
2060 struct laction_funcref_arg {
2061 lua_State *L;
2062 const char *script;
2063 pthread_mutex_t *pmutex;
2064 int funcref;
2065 };
2066
2067
2068 static int
2069 lua_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
2110 static int
2111 lua_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
2146 static void
2147 lua_action_string_cancel(struct laction_string_arg *arg)
2148 {
2149 mg_free(arg);
2150 }
2151
2152
2153 static void
2154 lua_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
2161 static int
2162 lwebsocket_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 */
2304 static int
2305 lwebsocket_set_timeout(lua_State *L)
2306 {
2307 return lwebsocket_set_timer(L, 0);
2308 }
2309
2310
2311 /* mg.set_interval for websockets */
2312 static int
2313 lwebsocket_set_interval(lua_State *L)
2314 {
2315 return lwebsocket_set_timer(L, 1);
2316 }
2317
2318
2319 /* mg.response.send() */
2320 static int
2321 lsp_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 */
2401 static void
2402 lua_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 */
2479 enum {
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
2487 static void
2488 push_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
2526 static void
2527 prepare_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
2604 static void
2605 prepare_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
2616 static void
2617 prepare_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
2642 static void *
2643 lua_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
2661 static void
2662 civetweb_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 */
2695 static int
2696 lsp_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
2721 static void
2722 reg_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
2751 static int
2752 lua_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
2775 static void
2776 prepare_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
3000 static void
3001 mg_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
3050 static int
3051 handle_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
3202 cleanup_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)
3215 struct mg_shared_lua_websocket_list {
3216 struct lua_websock_data ws;
3217 struct mg_shared_lua_websocket_list *next;
3218 };
3219
3220
3221 static void *
3222 lua_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
3322 static int
3323 lua_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
3367 static int
3368 lua_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
3399 static void
3400 lua_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
3460 static lua_State *
3461 mg_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
3511 static lua_State *
3512 mg_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
3565 static void
3566 lua_ctx_init(struct mg_context *ctx)
3567 {
3568 #if defined(USE_WEBSOCKET)
3569 ctx->dd.shared_lua_websockets = NULL;
3570 #endif
3571 }
3572
3573
3574 static void
3575 lua_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 */
3598 int
3599 run_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
3625 static void *lib_handle_uuid = NULL;
3626
3627 static void
3628 lua_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
3647 static void
3648 lua_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 */