]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/mod_lua.inl
buildsys: switch source download to quincy
[ceph.git] / ceph / src / 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 #include "civetweb_lua.h"
6 #include "civetweb_private_lua.h"
7
8 #ifdef _WIN32
9 static void *
10 mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
11 {
12 /* TODO (low): This is an incomplete implementation of mmap for windows.
13 * Currently it is sufficient, but there are a lot of unused parameters.
14 * Better use a function "mg_map" which only has the required parameters,
15 * and implement it using mmap in Linux and CreateFileMapping in Windows.
16 * Noone should expect a full mmap for Windows here.
17 */
18 HANDLE fh = (HANDLE)_get_osfhandle(fd);
19 HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
20 void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
21 CloseHandle(mh);
22
23 /* unused parameters */
24 (void)addr;
25 (void)prot;
26 (void)flags;
27 (void)offset;
28
29 return p;
30 }
31
32 static void
33 munmap(void *addr, int64_t length)
34 {
35 /* unused parameters */
36 (void)length;
37
38 UnmapViewOfFile(addr);
39 }
40
41 #define MAP_FAILED (NULL)
42 #define MAP_PRIVATE (0)
43 #define PROT_READ (0)
44 #else
45 #include <sys/mman.h>
46 #endif
47
48 static const char *LUASOCKET = "luasocket";
49 static const char lua_regkey_ctx = 1;
50 static const char lua_regkey_connlist = 2;
51 static const char lua_regkey_lsp_include_history = 3;
52 static const char *LUABACKGROUNDPARAMS = "mg";
53
54 #ifndef LSP_INCLUDE_MAX_DEPTH
55 #define LSP_INCLUDE_MAX_DEPTH (32)
56 #endif
57
58
59 /* Forward declarations */
60 static void handle_request(struct mg_connection *);
61 static int handle_lsp_request(struct mg_connection *,
62 const char *,
63 struct mg_file *,
64 struct lua_State *);
65
66 static void
67 reg_lstring(struct lua_State *L,
68 const char *name,
69 const void *buffer,
70 size_t buflen)
71 {
72 if (name != NULL && buffer != NULL) {
73 lua_pushstring(L, name);
74 lua_pushlstring(L, (const char *)buffer, buflen);
75 lua_rawset(L, -3);
76 }
77 }
78
79 static void
80 reg_llstring(struct lua_State *L,
81 const void *buffer1,
82 size_t buflen1,
83 const void *buffer2,
84 size_t buflen2)
85 {
86 if (buffer1 != NULL && buffer2 != NULL) {
87 lua_pushlstring(L, (const char *)buffer1, buflen1);
88 lua_pushlstring(L, (const char *)buffer2, buflen2);
89 lua_rawset(L, -3);
90 }
91 }
92
93 #define reg_string(L, name, val) \
94 reg_lstring(L, name, val, val ? strlen(val) : 0)
95
96 static void
97 reg_int(struct lua_State *L, const char *name, int val)
98 {
99 if (name != NULL) {
100 lua_pushstring(L, name);
101 lua_pushinteger(L, val);
102 lua_rawset(L, -3);
103 }
104 }
105
106 static void
107 reg_boolean(struct lua_State *L, const char *name, int val)
108 {
109 if (name != NULL) {
110 lua_pushstring(L, name);
111 lua_pushboolean(L, val != 0);
112 lua_rawset(L, -3);
113 }
114 }
115
116 static void
117 reg_conn_function(struct lua_State *L,
118 const char *name,
119 lua_CFunction func,
120 struct mg_connection *conn)
121 {
122 if (name != NULL && func != NULL && conn != NULL) {
123 lua_pushstring(L, name);
124 lua_pushlightuserdata(L, conn);
125 lua_pushcclosure(L, func, 1);
126 lua_rawset(L, -3);
127 }
128 }
129
130 static void
131 reg_function(struct lua_State *L, const char *name, lua_CFunction func)
132 {
133 if (name != NULL && func != NULL) {
134 lua_pushstring(L, name);
135 lua_pushcclosure(L, func, 0);
136 lua_rawset(L, -3);
137 }
138 }
139
140 static void
141 lua_cry(struct mg_connection *conn,
142 int err,
143 lua_State *L,
144 const char *lua_title,
145 const char *lua_operation)
146 {
147 switch (err) {
148 case LUA_OK:
149 case LUA_YIELD:
150 break;
151 case LUA_ERRRUN:
152 mg_cry(conn,
153 "%s: %s failed: runtime error: %s",
154 lua_title,
155 lua_operation,
156 lua_tostring(L, -1));
157 break;
158 case LUA_ERRSYNTAX:
159 mg_cry(conn,
160 "%s: %s failed: syntax error: %s",
161 lua_title,
162 lua_operation,
163 lua_tostring(L, -1));
164 break;
165 case LUA_ERRMEM:
166 mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
167 break;
168 case LUA_ERRGCMM:
169 mg_cry(conn,
170 "%s: %s failed: error during garbage collection",
171 lua_title,
172 lua_operation);
173 break;
174 case LUA_ERRERR:
175 mg_cry(conn,
176 "%s: %s failed: error in error handling: %s",
177 lua_title,
178 lua_operation,
179 lua_tostring(L, -1));
180 break;
181 default:
182 mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
183 break;
184 }
185 }
186
187 static int
188 lsp_sock_close(lua_State *L)
189 {
190 int num_args = lua_gettop(L);
191 size_t s;
192 SOCKET *psock;
193
194 if ((num_args == 1) && lua_istable(L, -1)) {
195 lua_getfield(L, -1, "sock");
196 psock = (SOCKET *)lua_tolstring(L, -1, &s);
197 if (s != sizeof(SOCKET)) {
198 return luaL_error(L, "invalid internal state in :close() call");
199 }
200 /* Do not closesocket(*psock); here, close it in __gc */
201 (void)psock;
202 } else {
203 return luaL_error(L, "invalid :close() call");
204 }
205 return 0;
206 }
207
208 static int
209 lsp_sock_recv(lua_State *L)
210 {
211 int num_args = lua_gettop(L);
212 char buf[2000];
213 int n;
214 size_t s;
215 SOCKET *psock;
216
217 if ((num_args == 1) && lua_istable(L, -1)) {
218 lua_getfield(L, -1, "sock");
219 psock = (SOCKET *)lua_tolstring(L, -1, &s);
220 if (s != sizeof(SOCKET)) {
221 return luaL_error(L, "invalid internal state in :recv() call");
222 }
223 n = recv(*psock, buf, sizeof(buf), 0);
224 if (n <= 0) {
225 lua_pushnil(L);
226 } else {
227 lua_pushlstring(L, buf, n);
228 }
229 } else {
230 return luaL_error(L, "invalid :recv() call");
231 }
232 return 1;
233 }
234
235 static int
236 lsp_sock_send(lua_State *L)
237 {
238 int num_args = lua_gettop(L);
239 const char *buf;
240 size_t len, sent = 0;
241 int n = 0;
242 size_t s;
243 SOCKET *psock;
244
245 if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
246 buf = lua_tolstring(L, -1, &len);
247 lua_getfield(L, -2, "sock");
248 psock = (SOCKET *)lua_tolstring(L, -1, &s);
249 if (s != sizeof(SOCKET)) {
250 return luaL_error(L, "invalid internal state in :close() call");
251 }
252
253 while (sent < len) {
254 if ((n = send(*psock, buf + sent, (int)(len - sent), 0)) <= 0) {
255 break;
256 }
257 sent += n;
258 }
259 lua_pushnumber(L, n);
260 } else {
261 return luaL_error(L, "invalid :close() call");
262 }
263 return 1;
264 }
265
266 static int
267 lsp_sock_gc(lua_State *L)
268 {
269 int num_args = lua_gettop(L);
270 size_t s;
271 SOCKET *psock;
272
273 if ((num_args == 1) && lua_istable(L, -1)) {
274 lua_getfield(L, -1, "sock");
275 psock = (SOCKET *)lua_tolstring(L, -1, &s);
276 if (s != sizeof(SOCKET)) {
277 return luaL_error(
278 L,
279 "invalid internal state in __gc for object created by connect");
280 }
281 closesocket(*psock);
282 } else {
283 return luaL_error(L, "__gc for object created by connect failed");
284 }
285 return 0;
286 }
287
288 /* Methods and meta-methods supported by the object returned by connect.
289 * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
290 static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
291 {"send", lsp_sock_send},
292 {"recv", lsp_sock_recv},
293 {"__gc", lsp_sock_gc},
294 {NULL, NULL}};
295
296 static int
297 lsp_connect(lua_State *L)
298 {
299 int num_args = lua_gettop(L);
300 char ebuf[100];
301 SOCKET sock;
302 union usa sa;
303 int ok;
304
305 if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
306 && lua_isnumber(L, -1)) {
307 ok = connect_socket(NULL,
308 lua_tostring(L, -3),
309 (int)lua_tonumber(L, -2),
310 (int)lua_tonumber(L, -1),
311 ebuf,
312 sizeof(ebuf),
313 &sock,
314 &sa);
315 if (!ok) {
316 return luaL_error(L, ebuf);
317 } else {
318 lua_newtable(L);
319 reg_lstring(L, "sock", (const char *)&sock, sizeof(SOCKET));
320 reg_string(L, "host", lua_tostring(L, -4));
321 luaL_getmetatable(L, LUASOCKET);
322 lua_setmetatable(L, -2);
323 }
324 } else {
325 return luaL_error(
326 L, "connect(host,port,is_ssl): invalid parameter given.");
327 }
328 return 1;
329 }
330
331 static int
332 lsp_error(lua_State *L)
333 {
334 lua_getglobal(L, "mg");
335 lua_getfield(L, -1, "onerror");
336 lua_pushvalue(L, -3);
337 lua_pcall(L, 1, 0, 0);
338 return 0;
339 }
340
341 /* Silently stop processing chunks. */
342 static void
343 lsp_abort(lua_State *L)
344 {
345 int top = lua_gettop(L);
346 lua_getglobal(L, "mg");
347 lua_pushnil(L);
348 lua_setfield(L, -2, "onerror");
349 lua_settop(L, top);
350 lua_pushstring(L, "aborting");
351 lua_error(L);
352 }
353
354 struct lsp_var_reader_data {
355 const char *begin;
356 unsigned len;
357 unsigned state;
358 };
359
360
361 static const char *
362 lsp_var_reader(lua_State *L, void *ud, size_t *sz)
363 {
364 struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
365 const char *ret;
366 (void)(L); /* unused */
367
368 switch (reader->state) {
369 case 0:
370 ret = "mg.write(";
371 *sz = strlen(ret);
372 break;
373 case 1:
374 ret = reader->begin;
375 *sz = reader->len;
376 break;
377 case 2:
378 ret = ")";
379 *sz = strlen(ret);
380 break;
381 default:
382 ret = 0;
383 *sz = 0;
384 }
385
386 reader->state++;
387 return ret;
388 }
389
390
391 static int
392 run_lsp(struct mg_connection *conn,
393 const char *path,
394 const char *p,
395 int64_t len,
396 lua_State *L)
397 {
398 int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
399 char chunkname[MG_BUF_LEN];
400 struct lsp_var_reader_data data;
401
402 for (i = 0; i < len; i++) {
403 if (p[i] == '\n')
404 lines++;
405 if (((i + 1) < len) && (p[i] == '<') && (p[i + 1] == '?')) {
406
407 /* <?= ?> means a variable is enclosed and its value should be
408 * printed */
409 is_var = (((i + 2) < len) && (p[i + 2] == '='));
410
411 if (is_var)
412 j = i + 2;
413 else
414 j = i + 1;
415
416 while (j < len) {
417 if (p[j] == '\n')
418 lualines++;
419 if (((j + 1) < len) && (p[j] == '?') && (p[j + 1] == '>')) {
420 mg_write(conn, p + pos, i - pos);
421
422 mg_snprintf(conn,
423 NULL, /* name only used for debugging */
424 chunkname,
425 sizeof(chunkname),
426 "@%s+%i",
427 path,
428 lines);
429 lua_pushlightuserdata(L, conn);
430 lua_pushcclosure(L, lsp_error, 1);
431
432 if (is_var) {
433 data.begin = p + (i + 3);
434 data.len = j - (i + 3);
435 data.state = 0;
436 lua_ok = mg_lua_load(
437 L, lsp_var_reader, &data, chunkname, NULL);
438 } else {
439 lua_ok = luaL_loadbuffer(L,
440 p + (i + 2),
441 j - (i + 2),
442 chunkname);
443 }
444
445 if (lua_ok) {
446 /* Syntax error or OOM. Error message is pushed on
447 * stack. */
448 lua_pcall(L, 1, 0, 0);
449 } else {
450 /* Success loading chunk. Call it. */
451 lua_pcall(L, 0, 0, 1);
452 }
453
454 pos = j + 2;
455 i = pos - 1;
456 break;
457 }
458 j++;
459 }
460
461 if (lualines > 0) {
462 lines += lualines;
463 lualines = 0;
464 }
465 }
466 }
467
468 if (i > pos) {
469 mg_write(conn, p + pos, i - pos);
470 }
471
472 return 0;
473 }
474
475
476 /* mg.write: Send data to the client */
477 static int
478 lsp_write(lua_State *L)
479 {
480 struct mg_connection *conn =
481 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
482 int num_args = lua_gettop(L);
483 const char *str;
484 size_t size;
485 int i;
486 int rv = 1;
487
488 for (i = 1; i <= num_args; i++) {
489 if (lua_isstring(L, i)) {
490 str = lua_tolstring(L, i, &size);
491 if (mg_write(conn, str, size) != (int)size) {
492 rv = 0;
493 }
494 }
495 }
496 lua_pushboolean(L, rv);
497
498 return 1;
499 }
500
501
502 /* mg.read: Read data from the client (e.g., from a POST request) */
503 static int
504 lsp_read(lua_State *L)
505 {
506 struct mg_connection *conn =
507 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
508 char buf[1024];
509 int len = mg_read(conn, buf, sizeof(buf));
510
511 if (len <= 0)
512 return 0;
513 lua_pushlstring(L, buf, len);
514
515 return 1;
516 }
517
518
519 /* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
520 static int
521 lsp_keep_alive(lua_State *L)
522 {
523 struct mg_connection *conn =
524 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
525 int num_args = lua_gettop(L);
526
527 /* This function may be called with one parameter (boolean) to set the
528 keep_alive state.
529 Or without a parameter to just query the current keep_alive state. */
530 if ((num_args == 1) && lua_isboolean(L, 1)) {
531 conn->must_close = !lua_toboolean(L, 1);
532 } else if (num_args != 0) {
533 /* Syntax error */
534 return luaL_error(L, "invalid keep_alive() call");
535 }
536
537 /* Return the current "keep_alive" state. This may be false, even it
538 * keep_alive(true) has been called. */
539 lua_pushboolean(L, should_keep_alive(conn));
540 return 1;
541 }
542
543
544 /* Stack of includes */
545 struct lsp_include_history {
546 int depth;
547 const char *script[LSP_INCLUDE_MAX_DEPTH + 1];
548 };
549
550
551 /* mg.include: Include another .lp file */
552 static int
553 lsp_include(lua_State *L)
554 {
555 struct mg_connection *conn =
556 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
557 int num_args = lua_gettop(L);
558 struct mg_file file = STRUCT_FILE_INITIALIZER;
559 const char *file_name = (num_args >= 1) ? lua_tostring(L, 1) : NULL;
560 const char *path_type = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
561 struct lsp_include_history *include_history;
562
563 if ((file_name) && (num_args <= 2)) {
564
565 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
566 lua_gettable(L, LUA_REGISTRYINDEX);
567 include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
568
569 if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
570 mg_cry(conn,
571 "lsp max include depth of %i reached while including %s",
572 (int)(LSP_INCLUDE_MAX_DEPTH),
573 file_name);
574 } else {
575 char file_name_path[512];
576 char *p;
577 size_t len;
578 int truncated = 0;
579
580 file_name_path[511] = 0;
581
582 if (path_type && (*path_type == 'v')) {
583 /* "virtual" = relative to document root. */
584 (void)mg_snprintf(conn,
585 &truncated,
586 file_name_path,
587 sizeof(file_name_path),
588 "%s/%s",
589 conn->ctx->config[DOCUMENT_ROOT],
590 file_name);
591
592 } else if ((path_type && (*path_type == 'a'))
593 || (path_type == NULL)) {
594 /* "absolute" = file name is relative to the
595 * webserver working directory
596 * or it is absolute system path. */
597 /* path_type==NULL is the legacy use case with 1 argument */
598 (void)mg_snprintf(conn,
599 &truncated,
600 file_name_path,
601 sizeof(file_name_path),
602 "%s",
603 file_name);
604
605 } else if (path_type && (*path_type == 'r' || *path_type == 'f')) {
606 /* "relative" = file name is relative to the
607 * currect document */
608 (void)mg_snprintf(
609 conn,
610 &truncated,
611 file_name_path,
612 sizeof(file_name_path),
613 "%s",
614 include_history->script[include_history->depth]);
615
616 if (!truncated) {
617 if ((p = strrchr(file_name_path, '/')) != NULL) {
618 p[1] = '\0';
619 }
620 len = strlen(file_name_path);
621 (void)mg_snprintf(conn,
622 &truncated,
623 file_name_path + len,
624 sizeof(file_name_path) - len,
625 "%s",
626 file_name);
627 }
628
629 } else {
630 return luaL_error(
631 L,
632 "invalid path_type in include(file_name, path_type) call");
633 }
634
635 if (handle_lsp_request(conn, file_name_path, &file, L)) {
636 /* handle_lsp_request returned an error code, meaning an error
637 * occured in the included page and mg.onerror returned non-zero.
638 * Stop processing.
639 */
640
641 lsp_abort(L);
642 }
643 }
644
645 } else {
646 /* Syntax error */
647 return luaL_error(L, "invalid include() call");
648 }
649 return 0;
650 }
651
652
653 /* mg.cry: Log an error. Default value for mg.onerror. */
654 static int
655 lsp_cry(lua_State *L)
656 {
657 struct mg_connection *conn =
658 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
659 int num_args = lua_gettop(L);
660 const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
661
662 if (text) {
663 mg_cry(conn, "%s", lua_tostring(L, -1));
664 } else {
665 /* Syntax error */
666 return luaL_error(L, "invalid cry() call");
667 }
668 return 0;
669 }
670
671
672 /* mg.redirect: Redirect the request (internally). */
673 static int
674 lsp_redirect(lua_State *L)
675 {
676 struct mg_connection *conn =
677 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
678 int num_args = lua_gettop(L);
679 const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
680
681 if (target) {
682 conn->request_info.local_uri = target;
683 handle_request(conn);
684 lsp_abort(L);
685 } else {
686 /* Syntax error */
687 return luaL_error(L, "invalid redirect() call");
688 }
689 return 0;
690 }
691
692
693 /* mg.send_file */
694 static int
695 lsp_send_file(lua_State *L)
696 {
697 struct mg_connection *conn =
698 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
699 int num_args = lua_gettop(L);
700 const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
701
702 if (filename) {
703 mg_send_file(conn, filename);
704 } else {
705 /* Syntax error */
706 return luaL_error(L, "invalid send_file() call");
707 }
708 return 0;
709 }
710
711
712 /* mg.get_time */
713 static int
714 lsp_get_time(lua_State *L)
715 {
716 int num_args = lua_gettop(L);
717 int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
718 struct timespec ts;
719 double d;
720
721 clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
722 d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
723 lua_pushnumber(L, d);
724 return 1;
725 }
726
727
728 /* mg.get_var */
729 static int
730 lsp_get_var(lua_State *L)
731 {
732 int num_args = lua_gettop(L);
733 const char *data, *var_name;
734 size_t data_len, occurrence;
735 int ret;
736 struct mg_context *ctx;
737
738 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
739 lua_gettable(L, LUA_REGISTRYINDEX);
740 ctx = (struct mg_context *)lua_touserdata(L, -1);
741
742 if (num_args >= 2 && num_args <= 3) {
743 char *dst;
744 data = lua_tolstring(L, 1, &data_len);
745 var_name = lua_tostring(L, 2);
746 occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
747
748 /* Allocate dynamically, so there is no internal limit for get_var */
749 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
750 if (!dst) {
751 return luaL_error(L, "out of memory in get_var() call");
752 }
753
754 ret = mg_get_var2(data, data_len, var_name, dst, data_len, occurrence);
755 if (ret >= 0) {
756 /* Variable found: return value to Lua */
757 lua_pushstring(L, dst);
758 } else {
759 /* Variable not found (TODO (mid): may be string too long) */
760 lua_pushnil(L);
761 }
762 mg_free(dst);
763 } else {
764 /* Syntax error */
765 return luaL_error(L, "invalid get_var() call");
766 }
767 return 1;
768 }
769
770
771 /* mg.get_mime_type */
772 static int
773 lsp_get_mime_type(lua_State *L)
774 {
775 int num_args = lua_gettop(L);
776 struct vec mime_type = {0, 0};
777 struct mg_context *ctx;
778 const char *text;
779
780 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
781 lua_gettable(L, LUA_REGISTRYINDEX);
782 ctx = (struct mg_context *)lua_touserdata(L, -1);
783
784 if (num_args == 1) {
785 text = lua_tostring(L, 1);
786 if (text) {
787 if (ctx) {
788 get_mime_type(ctx, text, &mime_type);
789 lua_pushlstring(L, mime_type.ptr, mime_type.len);
790 } else {
791 text = mg_get_builtin_mime_type(text);
792 lua_pushstring(L, text);
793 }
794 } else {
795 /* Syntax error */
796 return luaL_error(L, "invalid argument for get_mime_type() call");
797 }
798 } else {
799 /* Syntax error */
800 return luaL_error(L, "invalid get_mime_type() call");
801 }
802 return 1;
803 }
804
805
806 /* mg.get_cookie */
807 static int
808 lsp_get_cookie(lua_State *L)
809 {
810 int num_args = lua_gettop(L);
811 const char *cookie;
812 const char *var_name;
813 int ret;
814 struct mg_context *ctx;
815
816 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
817 lua_gettable(L, LUA_REGISTRYINDEX);
818 ctx = (struct mg_context *)lua_touserdata(L, -1);
819
820 if (num_args == 2) {
821 /* Correct number of arguments */
822 size_t data_len;
823 char *dst;
824
825 cookie = lua_tolstring(L, 1, &data_len);
826 var_name = lua_tostring(L, 2);
827
828 if (cookie == NULL || var_name == NULL) {
829 /* Syntax error */
830 return luaL_error(L, "invalid get_cookie() call");
831 }
832
833 dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
834 if (!dst) {
835 return luaL_error(L, "out of memory in get_cookie() call");
836 }
837
838 ret = mg_get_cookie(cookie, var_name, dst, data_len);
839
840 if (ret >= 0) {
841 lua_pushlstring(L, dst, ret);
842 } else {
843 lua_pushnil(L);
844 }
845 mg_free(dst);
846
847 } else {
848 /* Syntax error */
849 return luaL_error(L, "invalid get_cookie() call");
850 }
851 return 1;
852 }
853
854
855 /* mg.md5 */
856 static int
857 lsp_md5(lua_State *L)
858 {
859 int num_args = lua_gettop(L);
860 const char *text;
861 md5_byte_t hash[16];
862 md5_state_t ctx;
863 size_t text_len;
864 char buf[40];
865
866 if (num_args == 1) {
867 text = lua_tolstring(L, 1, &text_len);
868 if (text) {
869 md5_init(&ctx);
870 md5_append(&ctx, (const md5_byte_t *)text, text_len);
871 md5_finish(&ctx, hash);
872 bin2str(buf, hash, sizeof(hash));
873 lua_pushstring(L, buf);
874 } else {
875 lua_pushnil(L);
876 }
877 } else {
878 /* Syntax error */
879 return luaL_error(L, "invalid md5() call");
880 }
881 return 1;
882 }
883
884
885 /* mg.url_encode */
886 static int
887 lsp_url_encode(lua_State *L)
888 {
889 int num_args = lua_gettop(L);
890 const char *text;
891 size_t text_len;
892 char *dst;
893 int dst_len;
894 struct mg_context *ctx;
895
896 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
897 lua_gettable(L, LUA_REGISTRYINDEX);
898 ctx = (struct mg_context *)lua_touserdata(L, -1);
899
900 if (num_args == 1) {
901 text = lua_tolstring(L, 1, &text_len);
902 if (text) {
903 dst_len = 3 * (int)text_len + 1;
904 dst = ((text_len < 0x2AAAAAAA) ? (char *)mg_malloc_ctx(dst_len, ctx)
905 : (char *)NULL);
906 if (dst) {
907 mg_url_encode(text, dst, dst_len);
908 lua_pushstring(L, dst);
909 mg_free(dst);
910 } else {
911 return luaL_error(L, "out of memory in url_decode() call");
912 }
913 } else {
914 lua_pushnil(L);
915 }
916 } else {
917 /* Syntax error */
918 return luaL_error(L, "invalid url_encode() call");
919 }
920 return 1;
921 }
922
923
924 /* mg.url_decode */
925 static int
926 lsp_url_decode(lua_State *L)
927 {
928 int num_args = lua_gettop(L);
929 const char *text;
930 size_t text_len;
931 int is_form;
932 char *dst;
933 int dst_len;
934 struct mg_context *ctx;
935
936 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
937 lua_gettable(L, LUA_REGISTRYINDEX);
938 ctx = (struct mg_context *)lua_touserdata(L, -1);
939
940 if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
941 text = lua_tolstring(L, 1, &text_len);
942 is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
943 if (text) {
944 dst_len = (int)text_len + 1;
945 dst = ((text_len < 0x7FFFFFFF) ? (char *)mg_malloc_ctx(dst_len, ctx)
946 : (char *)NULL);
947 if (dst) {
948 mg_url_decode(text, (int)text_len, dst, dst_len, is_form);
949 lua_pushstring(L, dst);
950 mg_free(dst);
951 } else {
952 return luaL_error(L, "out of memory in url_decode() call");
953 }
954 } else {
955 lua_pushnil(L);
956 }
957 } else {
958 /* Syntax error */
959 return luaL_error(L, "invalid url_decode() call");
960 }
961 return 1;
962 }
963
964
965 /* mg.base64_encode */
966 static int
967 lsp_base64_encode(lua_State *L)
968 {
969 int num_args = lua_gettop(L);
970 const char *text;
971 size_t text_len;
972 char *dst;
973 struct mg_context *ctx;
974
975 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
976 lua_gettable(L, LUA_REGISTRYINDEX);
977 ctx = (struct mg_context *)lua_touserdata(L, -1);
978
979 if (num_args == 1) {
980 text = lua_tolstring(L, 1, &text_len);
981 if (text) {
982 dst = (char *)mg_malloc_ctx(text_len * 8 / 6 + 4, ctx);
983 if (dst) {
984 base64_encode((const unsigned char *)text, (int)text_len, dst);
985 lua_pushstring(L, dst);
986 mg_free(dst);
987 } else {
988 return luaL_error(L, "out of memory in base64_encode() call");
989 }
990 } else {
991 lua_pushnil(L);
992 }
993 } else {
994 /* Syntax error */
995 return luaL_error(L, "invalid base64_encode() call");
996 }
997 return 1;
998 }
999
1000
1001 /* mg.base64_encode */
1002 static int
1003 lsp_base64_decode(lua_State *L)
1004 {
1005 int num_args = lua_gettop(L);
1006 const char *text;
1007 size_t text_len, dst_len;
1008 int ret;
1009 char *dst;
1010 struct mg_context *ctx;
1011
1012 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1013 lua_gettable(L, LUA_REGISTRYINDEX);
1014 ctx = (struct mg_context *)lua_touserdata(L, -1);
1015
1016 if (num_args == 1) {
1017 text = lua_tolstring(L, 1, &text_len);
1018 if (text) {
1019 dst = (char *)mg_malloc_ctx(text_len, ctx);
1020 if (dst) {
1021 ret = base64_decode((const unsigned char *)text,
1022 (int)text_len,
1023 dst,
1024 &dst_len);
1025 if (ret != -1) {
1026 mg_free(dst);
1027 return luaL_error(
1028 L, "illegal character in lsp_base64_decode() call");
1029 } else {
1030 lua_pushlstring(L, dst, dst_len);
1031 mg_free(dst);
1032 }
1033 } else {
1034 return luaL_error(L,
1035 "out of memory in lsp_base64_decode() call");
1036 }
1037 } else {
1038 lua_pushnil(L);
1039 }
1040 } else {
1041 /* Syntax error */
1042 return luaL_error(L, "invalid lsp_base64_decode() call");
1043 }
1044 return 1;
1045 }
1046
1047
1048 /* mg.get_response_code_text */
1049 static int
1050 lsp_get_response_code_text(lua_State *L)
1051 {
1052 int num_args = lua_gettop(L);
1053 int type1;
1054 double code;
1055 const char *text;
1056
1057 if (num_args == 1) {
1058 type1 = lua_type(L, 1);
1059 if (type1 == LUA_TNUMBER) {
1060 /* If the first argument is a number,
1061 convert it to the corresponding text. */
1062 code = lua_tonumber(L, 1);
1063 text = mg_get_response_code_text(NULL, (int)code);
1064 if (text)
1065 lua_pushstring(L, text);
1066 return text ? 1 : 0;
1067 }
1068 }
1069
1070 /* Syntax error */
1071 return luaL_error(L, "invalid get_response_code_text() call");
1072 }
1073
1074
1075 /* mg.random - might be better than math.random on some systems */
1076 static int
1077 lsp_random(lua_State *L)
1078 {
1079 int num_args = lua_gettop(L);
1080 if (num_args == 0) {
1081 /* The civetweb internal random number generator will generate
1082 * a 64 bit random number. */
1083 uint64_t r = get_random();
1084 /* Lua "number" is a IEEE 754 double precission float:
1085 * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
1086 * Thus, mask with 2^53-1 to get an integer with the maximum
1087 * precission available. */
1088 r &= ((((uint64_t)1) << 53) - 1);
1089 lua_pushnumber(L, (double)r);
1090 return 1;
1091 }
1092
1093 /* Syntax error */
1094 return luaL_error(L, "invalid random() call");
1095 }
1096
1097
1098 /* mg.get_info */
1099 static int
1100 lsp_get_info(lua_State *L)
1101 {
1102 int num_args = lua_gettop(L);
1103 int type1, type2;
1104 const char *arg1;
1105 double arg2;
1106 int len;
1107 char *buf;
1108
1109 if (num_args == 1) {
1110 type1 = lua_type(L, 1);
1111 if (type1 == LUA_TSTRING) {
1112 arg1 = lua_tostring(L, 1);
1113 /* Get info according to argument */
1114 if (!mg_strcasecmp(arg1, "system")) {
1115 /* Get system info */
1116 len = mg_get_system_info(NULL, 0);
1117 if (len > 0) {
1118 buf = mg_malloc(len + 64);
1119 if (!buf) {
1120 return luaL_error(L, "OOM in get_info() call");
1121 }
1122 len = mg_get_system_info(buf, len + 63);
1123 lua_pushlstring(L, buf, len);
1124 mg_free(buf);
1125 } else {
1126 lua_pushstring(L, "");
1127 }
1128 return 1;
1129 }
1130 if (!mg_strcasecmp(arg1, "context")) {
1131 /* Get context */
1132 struct mg_context *ctx;
1133 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1134 lua_gettable(L, LUA_REGISTRYINDEX);
1135 ctx = (struct mg_context *)lua_touserdata(L, -1);
1136
1137 /* Get context info for server context */
1138 len = mg_get_context_info(ctx, NULL, 0);
1139 if (len > 0) {
1140 buf = mg_malloc(len + 64);
1141 if (!buf) {
1142 return luaL_error(L, "OOM in get_info() call");
1143 }
1144 len = mg_get_context_info(ctx, buf, len + 63);
1145 lua_pushlstring(L, buf, len);
1146 mg_free(buf);
1147 } else {
1148 lua_pushstring(L, "");
1149 }
1150 return 1;
1151 }
1152 if (!mg_strcasecmp(arg1, "common")) {
1153 /* Get context info for NULL context */
1154 len = mg_get_context_info(NULL, NULL, 0);
1155 if (len > 0) {
1156 buf = mg_malloc(len + 64);
1157 if (!buf) {
1158 return luaL_error(L, "OOM in get_info() call");
1159 }
1160 len = mg_get_context_info(NULL, buf, len + 63);
1161 lua_pushlstring(L, buf, len);
1162 mg_free(buf);
1163 } else {
1164 lua_pushstring(L, "");
1165 }
1166 return 1;
1167 }
1168 return 0;
1169 }
1170 }
1171
1172 if (num_args == 2) {
1173 type1 = lua_type(L, 1);
1174 type2 = lua_type(L, 2);
1175 if ((type1 == LUA_TSTRING) && (type2 == LUA_TNUMBER)) {
1176 arg1 = lua_tostring(L, 1);
1177 arg2 = lua_tonumber(L, 2);
1178
1179 /* Get info according to argument */
1180 if (!mg_strcasecmp(arg1, "connection")) {
1181
1182 /* Get context */
1183 struct mg_context *ctx;
1184 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1185 lua_gettable(L, LUA_REGISTRYINDEX);
1186 ctx = (struct mg_context *)lua_touserdata(L, -1);
1187
1188 /* Get connection info for connection idx */
1189 int idx = (int)(arg2 + 0.5);
1190
1191 /* Lua uses 1 based index, C uses 0 based index */
1192 idx--;
1193
1194 #ifdef MG_EXPERIMENTAL_INTERFACES
1195 len = mg_get_connection_info(ctx, idx, NULL, 0);
1196 if (len > 0) {
1197 buf = mg_malloc(len + 64);
1198 if (!buf) {
1199 return luaL_error(L, "OOM in get_info() call");
1200 }
1201 len = mg_get_connection_info(ctx, idx, buf, len + 63);
1202 lua_pushlstring(L, buf, len);
1203 mg_free(buf);
1204 } else {
1205 lua_pushstring(L, "");
1206 }
1207 #else
1208 (void)ctx;
1209 (void)idx;
1210 lua_pushstring(L, "");
1211 #endif
1212
1213 return 1;
1214 }
1215 return 0;
1216 }
1217 }
1218
1219 /* Syntax error */
1220 return luaL_error(L, "invalid get_info() call");
1221 }
1222
1223
1224 /* mg.get_option */
1225 static int
1226 lsp_get_option(lua_State *L)
1227 {
1228 int num_args = lua_gettop(L);
1229 int type1;
1230 const char *arg1;
1231 const char *data;
1232
1233 /* Get context */
1234 struct mg_context *ctx;
1235 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1236 lua_gettable(L, LUA_REGISTRYINDEX);
1237 ctx = (struct mg_context *)lua_touserdata(L, -1);
1238
1239 if (num_args == 0) {
1240 const struct mg_option *opts = mg_get_valid_options();
1241
1242 if (!opts) {
1243 return 0;
1244 }
1245
1246 lua_newtable(L);
1247 while (opts->name) {
1248 data = mg_get_option(ctx, opts->name);
1249 if (data) {
1250 reg_string(L, opts->name, data);
1251 }
1252 opts++;
1253 }
1254
1255 return 1;
1256 }
1257
1258 if (num_args == 1) {
1259 type1 = lua_type(L, 1);
1260 if (type1 == LUA_TSTRING) {
1261 arg1 = lua_tostring(L, 1);
1262 /* Get option according to argument */
1263 data = mg_get_option(ctx, arg1);
1264 if (data) {
1265 lua_pushstring(L, data);
1266 return 1;
1267 }
1268 return 0;
1269 }
1270 }
1271
1272 /* Syntax error */
1273 return luaL_error(L, "invalid get_option() call");
1274 }
1275
1276
1277 /* UUID library and function pointer */
1278 union {
1279 void *p;
1280 void (*f)(unsigned char uuid[16]);
1281 } pf_uuid_generate;
1282
1283
1284 /* mg.uuid */
1285 static int
1286 lsp_uuid(lua_State *L)
1287 {
1288 union {
1289 unsigned char uuid_array[16];
1290 struct uuid_struct_type {
1291 uint32_t data1;
1292 uint16_t data2;
1293 uint16_t data3;
1294 uint8_t data4[8];
1295 } uuid_struct;
1296 } uuid;
1297
1298 char uuid_str[40];
1299 int num_args = lua_gettop(L);
1300
1301 memset(&uuid, 0, sizeof(uuid));
1302 memset(uuid_str, 0, sizeof(uuid_str));
1303
1304 if (num_args == 0) {
1305
1306 pf_uuid_generate.f(uuid.uuid_array);
1307
1308 sprintf(uuid_str,
1309 "{%08lX-%04X-%04X-%02X%02X-"
1310 "%02X%02X%02X%02X%02X%02X}",
1311 (unsigned long)uuid.uuid_struct.data1,
1312 (unsigned)uuid.uuid_struct.data2,
1313 (unsigned)uuid.uuid_struct.data3,
1314 (unsigned)uuid.uuid_struct.data4[0],
1315 (unsigned)uuid.uuid_struct.data4[1],
1316 (unsigned)uuid.uuid_struct.data4[2],
1317 (unsigned)uuid.uuid_struct.data4[3],
1318 (unsigned)uuid.uuid_struct.data4[4],
1319 (unsigned)uuid.uuid_struct.data4[5],
1320 (unsigned)uuid.uuid_struct.data4[6],
1321 (unsigned)uuid.uuid_struct.data4[7]);
1322
1323 lua_pushstring(L, uuid_str);
1324 return 1;
1325 }
1326
1327 /* Syntax error */
1328 return luaL_error(L, "invalid random() call");
1329 }
1330
1331
1332 #ifdef USE_WEBSOCKET
1333 struct lua_websock_data {
1334 lua_State *state;
1335 char *script;
1336 unsigned references;
1337 struct mg_connection *conn[MAX_WORKER_THREADS];
1338 pthread_mutex_t ws_mutex;
1339 };
1340 #endif
1341
1342
1343 /* mg.write for websockets */
1344 static int
1345 lwebsock_write(lua_State *L)
1346 {
1347 #ifdef USE_WEBSOCKET
1348 int num_args = lua_gettop(L);
1349 struct lua_websock_data *ws;
1350 const char *str;
1351 size_t size;
1352 int opcode = -1;
1353 unsigned i;
1354 struct mg_connection *client = NULL;
1355
1356 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1357 lua_gettable(L, LUA_REGISTRYINDEX);
1358 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1359
1360 (void)pthread_mutex_lock(&(ws->ws_mutex));
1361
1362 if (num_args == 1) {
1363 /* just one text: send it to all client */
1364 if (lua_isstring(L, 1)) {
1365 opcode = WEBSOCKET_OPCODE_TEXT;
1366 }
1367 } else if (num_args == 2) {
1368 if (lua_isnumber(L, 1)) {
1369 /* opcode number and message text */
1370 opcode = (int)lua_tointeger(L, 1);
1371 } else if (lua_isstring(L, 1)) {
1372 /* opcode string and message text */
1373 str = lua_tostring(L, 1);
1374 if (!mg_strncasecmp(str, "text", 4))
1375 opcode = WEBSOCKET_OPCODE_TEXT;
1376 else if (!mg_strncasecmp(str, "bin", 3))
1377 opcode = WEBSOCKET_OPCODE_BINARY;
1378 else if (!mg_strncasecmp(str, "close", 5))
1379 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
1380 else if (!mg_strncasecmp(str, "ping", 4))
1381 opcode = WEBSOCKET_OPCODE_PING;
1382 else if (!mg_strncasecmp(str, "pong", 4))
1383 opcode = WEBSOCKET_OPCODE_PONG;
1384 else if (!mg_strncasecmp(str, "cont", 4))
1385 opcode = WEBSOCKET_OPCODE_CONTINUATION;
1386 } else if (lua_isuserdata(L, 1)) {
1387 /* client id and message text */
1388 client = (struct mg_connection *)lua_touserdata(L, 1);
1389 opcode = WEBSOCKET_OPCODE_TEXT;
1390 }
1391 } else if (num_args == 3) {
1392 if (lua_isuserdata(L, 1)) {
1393 client = (struct mg_connection *)lua_touserdata(L, 1);
1394 if (lua_isnumber(L, 2)) {
1395 /* client id, opcode number and message text */
1396 opcode = (int)lua_tointeger(L, 2);
1397 } else if (lua_isstring(L, 2)) {
1398 /* client id, opcode string and message text */
1399 str = lua_tostring(L, 2);
1400 if (!mg_strncasecmp(str, "text", 4))
1401 opcode = WEBSOCKET_OPCODE_TEXT;
1402 else if (!mg_strncasecmp(str, "bin", 3))
1403 opcode = WEBSOCKET_OPCODE_BINARY;
1404 else if (!mg_strncasecmp(str, "close", 5))
1405 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
1406 else if (!mg_strncasecmp(str, "ping", 4))
1407 opcode = WEBSOCKET_OPCODE_PING;
1408 else if (!mg_strncasecmp(str, "pong", 4))
1409 opcode = WEBSOCKET_OPCODE_PONG;
1410 else if (!mg_strncasecmp(str, "cont", 4))
1411 opcode = WEBSOCKET_OPCODE_CONTINUATION;
1412 }
1413 }
1414 }
1415
1416 if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
1417 str = lua_tolstring(L, num_args, &size);
1418 if (client) {
1419 for (i = 0; i < ws->references; i++) {
1420 if (client == ws->conn[i]) {
1421 mg_lock_connection(ws->conn[i]);
1422 mg_websocket_write(ws->conn[i], opcode, str, size);
1423 mg_unlock_connection(ws->conn[i]);
1424 }
1425 }
1426 } else {
1427 for (i = 0; i < ws->references; i++) {
1428 mg_lock_connection(ws->conn[i]);
1429 mg_websocket_write(ws->conn[i], opcode, str, size);
1430 mg_unlock_connection(ws->conn[i]);
1431 }
1432 }
1433 } else {
1434 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1435 return luaL_error(L, "invalid websocket write() call");
1436 }
1437
1438 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1439
1440 #else
1441 (void)(L); /* unused */
1442 #endif
1443 return 0;
1444 }
1445
1446
1447 struct laction_arg {
1448 lua_State *state;
1449 const char *script;
1450 pthread_mutex_t *pmutex;
1451 char txt[1];
1452 };
1453
1454
1455 static int
1456 lua_action(struct laction_arg *arg)
1457 {
1458 int err, ok;
1459 struct mg_context *ctx;
1460
1461 (void)pthread_mutex_lock(arg->pmutex);
1462
1463 lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
1464 lua_gettable(arg->state, LUA_REGISTRYINDEX);
1465 ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
1466
1467 err = luaL_loadstring(arg->state, arg->txt);
1468 if (err != 0) {
1469 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1470 (void)pthread_mutex_unlock(arg->pmutex);
1471 mg_free(arg);
1472 return 0;
1473 }
1474 err = lua_pcall(arg->state, 0, 1, 0);
1475 if (err != 0) {
1476 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1477 (void)pthread_mutex_unlock(arg->pmutex);
1478 mg_free(arg);
1479 return 0;
1480 }
1481
1482 ok = lua_type(arg->state, -1);
1483 if (lua_isboolean(arg->state, -1)) {
1484 ok = lua_toboolean(arg->state, -1);
1485 } else {
1486 ok = 0;
1487 }
1488 lua_pop(arg->state, 1);
1489
1490 (void)pthread_mutex_unlock(arg->pmutex);
1491
1492 if (!ok) {
1493 mg_free(arg);
1494 }
1495 return ok;
1496 }
1497
1498
1499 static int
1500 lua_action_free(struct laction_arg *arg)
1501 {
1502 if (lua_action(arg)) {
1503 mg_free(arg);
1504 }
1505 return 0;
1506 }
1507
1508
1509 static int
1510 lwebsocket_set_timer(lua_State *L, int is_periodic)
1511 {
1512 #if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
1513 int num_args = lua_gettop(L);
1514 struct lua_websock_data *ws;
1515 int type1, type2, ok = 0;
1516 double timediff;
1517 struct mg_context *ctx;
1518 struct laction_arg *arg;
1519 const char *txt;
1520 size_t txt_len;
1521
1522 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1523 lua_gettable(L, LUA_REGISTRYINDEX);
1524 ctx = (struct mg_context *)lua_touserdata(L, -1);
1525
1526 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1527 lua_gettable(L, LUA_REGISTRYINDEX);
1528 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1529
1530 if (num_args < 2) {
1531 return luaL_error(L,
1532 "not enough arguments for set_timer/interval() call");
1533 }
1534
1535 type1 = lua_type(L, 1);
1536 type2 = lua_type(L, 2);
1537
1538 if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
1539 timediff = (double)lua_tonumber(L, 2);
1540 txt = lua_tostring(L, 1);
1541 txt_len = strlen(txt);
1542 arg = (struct laction_arg *)mg_malloc_ctx(sizeof(struct laction_arg)
1543 + txt_len + 10,
1544 ctx);
1545 arg->state = L;
1546 arg->script = ws->script;
1547 arg->pmutex = &(ws->ws_mutex);
1548 memcpy(arg->txt, "return(", 7);
1549 memcpy(arg->txt + 7, txt, txt_len);
1550 arg->txt[txt_len + 7] = ')';
1551 arg->txt[txt_len + 8] = 0;
1552 ok =
1553 (0
1554 == timer_add(ctx,
1555 timediff,
1556 is_periodic,
1557 1,
1558 (taction)(is_periodic ? lua_action : lua_action_free),
1559 (void *)arg));
1560 } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
1561 /* TODO (mid): not implemented yet */
1562 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1563 } else {
1564 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1565 }
1566
1567 lua_pushboolean(L, ok);
1568 return 1;
1569
1570 #else
1571 (void)(L); /* unused */
1572 (void)(is_periodic); /* unused */
1573 return 0;
1574 #endif
1575 }
1576
1577
1578 /* mg.set_timeout for websockets */
1579 static int
1580 lwebsocket_set_timeout(lua_State *L)
1581 {
1582 return lwebsocket_set_timer(L, 0);
1583 }
1584
1585
1586 /* mg.set_interval for websockets */
1587 static int
1588 lwebsocket_set_interval(lua_State *L)
1589 {
1590 return lwebsocket_set_timer(L, 1);
1591 }
1592
1593 enum {
1594 LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
1595 LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
1596 LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
1597 };
1598
1599
1600 static void
1601 prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
1602 {
1603 const char *s;
1604 int i;
1605
1606 /* Export mg.request_info */
1607 lua_pushstring(L, "request_info");
1608 lua_newtable(L);
1609 reg_string(L, "request_method", conn->request_info.request_method);
1610 reg_string(L, "request_uri", conn->request_info.request_uri);
1611 reg_string(L, "uri", conn->request_info.local_uri);
1612 reg_string(L, "http_version", conn->request_info.http_version);
1613 reg_string(L, "query_string", conn->request_info.query_string);
1614 #if defined(MG_LEGACY_INTERFACE)
1615 reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
1616 deprecated, use
1617 remote_addr
1618 instead */
1619 #endif
1620 reg_string(L, "remote_addr", conn->request_info.remote_addr);
1621 /* TODO (high): ip version */
1622 reg_int(L, "remote_port", conn->request_info.remote_port);
1623 reg_int(L, "num_headers", conn->request_info.num_headers);
1624 reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
1625
1626 if (conn->path_info != NULL) {
1627 reg_string(L, "path_info", conn->path_info);
1628 }
1629
1630 if (conn->request_info.content_length >= 0) {
1631 /* reg_int64: content_length */
1632 lua_pushstring(L, "content_length");
1633 lua_pushnumber(
1634 L,
1635 (lua_Number)conn->request_info
1636 .content_length); /* lua_Number may be used as 52 bit integer */
1637 lua_rawset(L, -3);
1638 }
1639 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
1640 reg_string(L, "content_type", s);
1641 }
1642
1643 if (conn->request_info.remote_user != NULL) {
1644 reg_string(L, "remote_user", conn->request_info.remote_user);
1645 reg_string(L, "auth_type", "Digest");
1646 }
1647
1648 reg_boolean(L, "https", conn->ssl != NULL);
1649
1650 if (conn->status_code > 0) {
1651 /* Lua error handler should show the status code */
1652 reg_int(L, "status", conn->status_code);
1653 }
1654
1655 lua_pushstring(L, "http_headers");
1656 lua_newtable(L);
1657 for (i = 0; i < conn->request_info.num_headers; i++) {
1658 reg_string(L,
1659 conn->request_info.http_headers[i].name,
1660 conn->request_info.http_headers[i].value);
1661 }
1662 lua_rawset(L, -3);
1663
1664 lua_rawset(L, -3);
1665 }
1666
1667
1668 static void
1669 civetweb_open_lua_libs(lua_State *L)
1670 {
1671 {
1672 extern void luaL_openlibs(lua_State *);
1673 luaL_openlibs(L);
1674 }
1675
1676 #ifdef USE_LUA_SQLITE3
1677 {
1678 extern int luaopen_lsqlite3(lua_State *);
1679 luaopen_lsqlite3(L);
1680 }
1681 #endif
1682 #ifdef USE_LUA_LUAXML
1683 {
1684 extern int luaopen_LuaXML_lib(lua_State *);
1685 luaopen_LuaXML_lib(L);
1686 }
1687 #endif
1688 #ifdef USE_LUA_FILE_SYSTEM
1689 {
1690 extern int luaopen_lfs(lua_State *);
1691 luaopen_lfs(L);
1692 }
1693 #endif
1694 #ifdef USE_LUA_BINARY
1695 {
1696 /* TODO (low): Test if this could be used as a replacement for bit32.
1697 * Check again with Lua 5.3 later. */
1698 extern int luaopen_binary(lua_State *);
1699
1700 luaL_requiref(L, "binary", luaopen_binary, 1);
1701 lua_pop(L, 1);
1702 }
1703 #endif
1704 }
1705
1706
1707 static void
1708 prepare_lua_environment(struct mg_context *ctx,
1709 struct mg_connection *conn,
1710 struct lua_websock_data *ws_conn_list,
1711 lua_State *L,
1712 const char *script_name,
1713 int lua_env_type)
1714 {
1715 civetweb_open_lua_libs(L);
1716
1717 #if LUA_VERSION_NUM == 502
1718 /* Keep the "connect" method for compatibility,
1719 * but do not backport it to Lua 5.1.
1720 * TODO: Redesign the interface.
1721 */
1722 luaL_newmetatable(L, LUASOCKET);
1723 lua_pushliteral(L, "__index");
1724 luaL_newlib(L, luasocket_methods);
1725 lua_rawset(L, -3);
1726 lua_pop(L, 1);
1727 lua_register(L, "connect", lsp_connect);
1728 #endif
1729
1730 /* Store context in the registry */
1731 if (ctx != NULL) {
1732 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1733 lua_pushlightuserdata(L, (void *)ctx);
1734 lua_settable(L, LUA_REGISTRYINDEX);
1735 }
1736 if (ws_conn_list != NULL) {
1737 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1738 lua_pushlightuserdata(L, (void *)ws_conn_list);
1739 lua_settable(L, LUA_REGISTRYINDEX);
1740 }
1741
1742 /* Lua server pages store the depth of mg.include, in order
1743 * to detect recursions and prevent stack overflows. */
1744 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
1745 struct lsp_include_history *h;
1746 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
1747 h = (struct lsp_include_history *)
1748 lua_newuserdata(L, sizeof(struct lsp_include_history));
1749 lua_settable(L, LUA_REGISTRYINDEX);
1750 memset(h, 0, sizeof(struct lsp_include_history));
1751 }
1752
1753 /* Register mg module */
1754 lua_newtable(L);
1755
1756 switch (lua_env_type) {
1757 case LUA_ENV_TYPE_LUA_SERVER_PAGE:
1758 reg_string(L, "lua_type", "page");
1759 break;
1760 case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
1761 reg_string(L, "lua_type", "script");
1762 break;
1763 case LUA_ENV_TYPE_LUA_WEBSOCKET:
1764 reg_string(L, "lua_type", "websocket");
1765 break;
1766 }
1767
1768 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
1769 || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
1770 reg_conn_function(L, "cry", lsp_cry, conn);
1771 reg_conn_function(L, "read", lsp_read, conn);
1772 reg_conn_function(L, "write", lsp_write, conn);
1773 reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
1774 reg_conn_function(L, "send_file", lsp_send_file, conn);
1775 }
1776
1777 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
1778 reg_conn_function(L, "include", lsp_include, conn);
1779 reg_conn_function(L, "redirect", lsp_redirect, conn);
1780 }
1781
1782 if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
1783 reg_function(L, "write", lwebsock_write);
1784 #ifdef USE_TIMERS
1785 reg_function(L, "set_timeout", lwebsocket_set_timeout);
1786 reg_function(L, "set_interval", lwebsocket_set_interval);
1787 #endif
1788 /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
1789 }
1790
1791 reg_function(L, "time", lsp_get_time);
1792 reg_function(L, "get_var", lsp_get_var);
1793 reg_function(L, "get_mime_type", lsp_get_mime_type);
1794 reg_function(L, "get_cookie", lsp_get_cookie);
1795 reg_function(L, "md5", lsp_md5);
1796 reg_function(L, "url_encode", lsp_url_encode);
1797 reg_function(L, "url_decode", lsp_url_decode);
1798 reg_function(L, "base64_encode", lsp_base64_encode);
1799 reg_function(L, "base64_decode", lsp_base64_decode);
1800 reg_function(L, "get_response_code_text", lsp_get_response_code_text);
1801 reg_function(L, "random", lsp_random);
1802 reg_function(L, "get_info", lsp_get_info);
1803 reg_function(L, "get_option", lsp_get_option);
1804
1805 if (pf_uuid_generate.f) {
1806 reg_function(L, "uuid", lsp_uuid);
1807 }
1808
1809 reg_string(L, "version", CIVETWEB_VERSION);
1810
1811 reg_string(L, "script_name", script_name);
1812
1813 if (ctx != NULL) {
1814 reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
1815 reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
1816 #if defined(USE_WEBSOCKET)
1817 if (ctx->config[WEBSOCKET_ROOT]) {
1818 reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
1819 } else {
1820 reg_string(L, "websocket_root", ctx->config[DOCUMENT_ROOT]);
1821 }
1822 #endif
1823
1824 if (ctx->systemName != NULL) {
1825 reg_string(L, "system", ctx->systemName);
1826 }
1827 }
1828
1829 /* Export connection specific info */
1830 if (conn != NULL) {
1831 prepare_lua_request_info(conn, L);
1832 }
1833
1834 lua_setglobal(L, "mg");
1835
1836 /* Register default mg.onerror function */
1837 IGNORE_UNUSED_RESULT(
1838 luaL_dostring(L,
1839 "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
1840 "debug.traceback(e, 1)) end"));
1841
1842 if (ctx != NULL) {
1843 /* Preload */
1844 if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
1845 IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
1846 }
1847
1848 if (ctx->callbacks.init_lua != NULL) {
1849 ctx->callbacks.init_lua(conn, L);
1850 }
1851 }
1852 }
1853
1854
1855 static int
1856 lua_error_handler(lua_State *L)
1857 {
1858 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
1859
1860 lua_getglobal(L, "mg");
1861 if (!lua_isnil(L, -1)) {
1862 lua_getfield(L, -1, "write"); /* call mg.write() */
1863 lua_pushstring(L, error_msg);
1864 lua_pushliteral(L, "\n");
1865 lua_call(L, 2, 0);
1866 IGNORE_UNUSED_RESULT(
1867 luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
1868 } else {
1869 printf("Lua error: [%s]\n", error_msg);
1870 IGNORE_UNUSED_RESULT(
1871 luaL_dostring(L, "print(debug.traceback(), '\\n')"));
1872 }
1873 /* TODO(lsm, low): leave the stack balanced */
1874
1875 return 0;
1876 }
1877
1878
1879 static void *
1880 lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
1881 {
1882 (void)osize; /* not used */
1883
1884 if (nsize == 0) {
1885 mg_free(ptr);
1886 return NULL;
1887 }
1888 return mg_realloc_ctx(ptr, nsize, (struct mg_context *)ud);
1889 }
1890
1891
1892 static void
1893 mg_exec_lua_script(struct mg_connection *conn,
1894 const char *path,
1895 const void **exports)
1896 {
1897 int i;
1898 lua_State *L;
1899
1900 /* Assume the script does not support keep_alive. The script may change this
1901 * by calling mg.keep_alive(true). */
1902 conn->must_close = 1;
1903
1904 /* Execute a plain Lua script. */
1905 if (path != NULL
1906 && (L = lua_newstate(lua_allocator, (void *)(conn->ctx))) != NULL) {
1907 prepare_lua_environment(
1908 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
1909 lua_pushcclosure(L, &lua_error_handler, 0);
1910
1911 if (exports != NULL) {
1912 #if LUA_VERSION_NUM > 501
1913 lua_pushglobaltable(L);
1914 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1915 lua_CFunction func;
1916 lua_pushstring(L, (const char *)(exports[i]));
1917 *(const void **)(&func) = exports[i + 1];
1918 lua_pushcclosure(L, func, 0);
1919 lua_rawset(L, -3);
1920 }
1921 #else
1922 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1923 lua_CFunction func;
1924 const char *name = (const char *)(exports[i]);
1925 *(const void **)(&func) = exports[i + 1];
1926 lua_register(L, name, func);
1927 }
1928 #endif
1929 }
1930
1931 if (luaL_loadfile(L, path) != 0) {
1932 lua_error_handler(L);
1933 }
1934 lua_pcall(L, 0, 0, -2);
1935 lua_close(L);
1936 }
1937 }
1938
1939
1940 static int
1941 handle_lsp_request(struct mg_connection *conn,
1942 const char *path,
1943 struct mg_file *filep,
1944 struct lua_State *ls)
1945 {
1946 void *p = NULL;
1947 lua_State *L = NULL;
1948 struct lsp_include_history *include_history;
1949 int error = 1;
1950
1951 /* Assume the script does not support keep_alive. The script may change this
1952 * by calling mg.keep_alive(true). */
1953 conn->must_close = 1;
1954
1955 /* mg_fopen opens the file and sets the size accordingly */
1956 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
1957
1958 /* File not found or not accessible */
1959 if (ls == NULL) {
1960 mg_send_http_error(conn,
1961 500,
1962 "Error: Cannot open script file %s",
1963 path);
1964 } else {
1965 luaL_error(ls, "Cannot include [%s]: not found", path);
1966 }
1967
1968 goto cleanup_handle_lsp_request;
1969 }
1970
1971 /* Map file in memory (size is known). */
1972 if (filep->access.membuf == NULL
1973 && (p = mmap(NULL,
1974 (size_t)filep->stat.size,
1975 PROT_READ,
1976 MAP_PRIVATE,
1977 fileno(filep->access.fp),
1978 0)) == MAP_FAILED) {
1979
1980 /* mmap failed */
1981 if (ls == NULL) {
1982 mg_send_http_error(
1983 conn,
1984 500,
1985 "Error: Cannot open script\nFile %s can not be mapped",
1986 path);
1987 } else {
1988 luaL_error(ls,
1989 "mmap(%s, %zu, %d): %s",
1990 path,
1991 (size_t)filep->stat.size,
1992 fileno(filep->access.fp),
1993 strerror(errno));
1994 }
1995
1996 goto cleanup_handle_lsp_request;
1997 }
1998
1999 if (ls != NULL) {
2000 L = ls;
2001 } else {
2002 L = lua_newstate(lua_allocator, (void *)(conn->ctx));
2003 if (L == NULL) {
2004 mg_send_http_error(
2005 conn,
2006 500,
2007 "%s",
2008 "Error: Cannot execute script\nlua_newstate failed");
2009
2010 goto cleanup_handle_lsp_request;
2011 }
2012 prepare_lua_environment(
2013 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
2014 }
2015
2016 /* Get LSP include history table */
2017 lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
2018 lua_gettable(L, LUA_REGISTRYINDEX);
2019 include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
2020
2021 /* Store script name and increment depth */
2022 include_history->depth++;
2023 include_history->script[include_history->depth] = path;
2024
2025 /* Lua state is ready to use */
2026 /* We're not sending HTTP headers here, Lua page must do it. */
2027 error = run_lsp(conn,
2028 path,
2029 (filep->access.membuf == NULL)
2030 ? (const char *)p
2031 : (const char *)filep->access.membuf,
2032 filep->stat.size,
2033 L);
2034
2035 cleanup_handle_lsp_request:
2036
2037 if (L != NULL && ls == NULL)
2038 lua_close(L);
2039 if (p != NULL)
2040 munmap(p, filep->stat.size);
2041 (void)mg_fclose(&filep->access);
2042
2043 return error;
2044 }
2045
2046
2047 #ifdef USE_WEBSOCKET
2048 struct mg_shared_lua_websocket_list {
2049 struct lua_websock_data ws;
2050 struct mg_shared_lua_websocket_list *next;
2051 };
2052
2053
2054 static void *
2055 lua_websocket_new(const char *script, struct mg_connection *conn)
2056 {
2057 struct mg_shared_lua_websocket_list **shared_websock_list =
2058 &(conn->ctx->shared_lua_websockets);
2059 struct lua_websock_data *ws;
2060 int err, ok = 0;
2061
2062 assert(conn->lua_websocket_state == NULL);
2063
2064 /* lock list (mg_context global) */
2065 mg_lock_context(conn->ctx);
2066 while (*shared_websock_list) {
2067 /* check if ws already in list */
2068 if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
2069 break;
2070 }
2071 shared_websock_list = &((*shared_websock_list)->next);
2072 }
2073
2074 if (*shared_websock_list == NULL) {
2075 /* add ws to list */
2076 *shared_websock_list =
2077 (struct mg_shared_lua_websocket_list *)mg_calloc_ctx(
2078 sizeof(struct mg_shared_lua_websocket_list), 1, conn->ctx);
2079 if (*shared_websock_list == NULL) {
2080 mg_unlock_context(conn->ctx);
2081 mg_cry(conn, "Cannot create shared websocket struct, OOM");
2082 return NULL;
2083 }
2084 /* init ws list element */
2085 ws = &(*shared_websock_list)->ws;
2086 ws->script = mg_strdup(script); /* TODO (low): handle OOM */
2087 pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
2088 (void)pthread_mutex_lock(&(ws->ws_mutex));
2089 ws->state = lua_newstate(lua_allocator, (void *)(conn->ctx));
2090 ws->conn[0] = conn;
2091 ws->references = 1;
2092 prepare_lua_environment(
2093 conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
2094 err = luaL_loadfile(ws->state, script);
2095 if (err != 0) {
2096 lua_cry(conn, err, ws->state, script, "load");
2097 }
2098 err = lua_pcall(ws->state, 0, 0, 0);
2099 if (err != 0) {
2100 lua_cry(conn, err, ws->state, script, "init");
2101 }
2102 } else {
2103 /* inc ref count */
2104 ws = &(*shared_websock_list)->ws;
2105 (void)pthread_mutex_lock(&(ws->ws_mutex));
2106 (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
2107 }
2108 mg_unlock_context(conn->ctx);
2109
2110 /* call add */
2111 lua_getglobal(ws->state, "open");
2112 lua_newtable(ws->state);
2113 prepare_lua_request_info(conn, ws->state);
2114 lua_pushstring(ws->state, "client");
2115 lua_pushlightuserdata(ws->state, (void *)conn);
2116 lua_rawset(ws->state, -3);
2117
2118 err = lua_pcall(ws->state, 1, 1, 0);
2119 if (err != 0) {
2120 lua_cry(conn, err, ws->state, script, "open handler");
2121 } else {
2122 if (lua_isboolean(ws->state, -1)) {
2123 ok = lua_toboolean(ws->state, -1);
2124 }
2125 lua_pop(ws->state, 1);
2126 }
2127 if (!ok) {
2128 /* Remove from ws connection list. */
2129 /* TODO (mid): Check if list entry and Lua state needs to be deleted
2130 * (see websocket_close). */
2131 (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
2132 }
2133
2134 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2135
2136 return ok ? (void *)ws : NULL;
2137 }
2138
2139
2140 static int
2141 lua_websocket_data(struct mg_connection *conn,
2142 int bits,
2143 char *data,
2144 size_t data_len,
2145 void *ws_arg)
2146 {
2147 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2148 int err, ok = 0;
2149
2150 assert(ws != NULL);
2151 assert(ws->state != NULL);
2152
2153 (void)pthread_mutex_lock(&(ws->ws_mutex));
2154
2155 lua_getglobal(ws->state, "data");
2156 lua_newtable(ws->state);
2157 lua_pushstring(ws->state, "client");
2158 lua_pushlightuserdata(ws->state, (void *)conn);
2159 lua_rawset(ws->state, -3);
2160 lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
2161 a meaning according to
2162 http://tools.ietf.org/html/rfc6455,
2163 section 5.2 */
2164 lua_pushnumber(ws->state, bits);
2165 lua_rawset(ws->state, -3);
2166 lua_pushstring(ws->state, "data");
2167 lua_pushlstring(ws->state, data, data_len);
2168 lua_rawset(ws->state, -3);
2169
2170 err = lua_pcall(ws->state, 1, 1, 0);
2171 if (err != 0) {
2172 lua_cry(conn, err, ws->state, ws->script, "data handler");
2173 } else {
2174 if (lua_isboolean(ws->state, -1)) {
2175 ok = lua_toboolean(ws->state, -1);
2176 }
2177 lua_pop(ws->state, 1);
2178 }
2179 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2180
2181 return ok;
2182 }
2183
2184
2185 static int
2186 lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
2187 {
2188 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2189 int err, ok = 0;
2190
2191 assert(ws != NULL);
2192 assert(ws->state != NULL);
2193
2194 (void)pthread_mutex_lock(&(ws->ws_mutex));
2195
2196 lua_getglobal(ws->state, "ready");
2197 lua_newtable(ws->state);
2198 lua_pushstring(ws->state, "client");
2199 lua_pushlightuserdata(ws->state, (void *)conn);
2200 lua_rawset(ws->state, -3);
2201 err = lua_pcall(ws->state, 1, 1, 0);
2202 if (err != 0) {
2203 lua_cry(conn, err, ws->state, ws->script, "ready handler");
2204 } else {
2205 if (lua_isboolean(ws->state, -1)) {
2206 ok = lua_toboolean(ws->state, -1);
2207 }
2208 lua_pop(ws->state, 1);
2209 }
2210
2211 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2212
2213 return ok;
2214 }
2215
2216
2217 static void
2218 lua_websocket_close(struct mg_connection *conn, void *ws_arg)
2219 {
2220 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
2221 struct mg_shared_lua_websocket_list **shared_websock_list =
2222 &(conn->ctx->shared_lua_websockets);
2223 int err = 0;
2224 unsigned i;
2225
2226 assert(ws != NULL);
2227 assert(ws->state != NULL);
2228
2229 (void)pthread_mutex_lock(&(ws->ws_mutex));
2230
2231 lua_getglobal(ws->state, "close");
2232 lua_newtable(ws->state);
2233 lua_pushstring(ws->state, "client");
2234 lua_pushlightuserdata(ws->state, (void *)conn);
2235 lua_rawset(ws->state, -3);
2236
2237 err = lua_pcall(ws->state, 1, 0, 0);
2238 if (err != 0) {
2239 lua_cry(conn, err, ws->state, ws->script, "close handler");
2240 }
2241 for (i = 0; i < ws->references; i++) {
2242 if (ws->conn[i] == conn) {
2243 ws->references--;
2244 ws->conn[i] = ws->conn[ws->references];
2245 }
2246 }
2247 /* TODO: Delete lua_websock_data and remove it from the websocket list.
2248 This must only be done, when all connections are closed, and all
2249 asynchronous operations and timers are completed/expired. */
2250 (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
2251
2252 (void)pthread_mutex_unlock(&(ws->ws_mutex));
2253 }
2254 #endif
2255
2256
2257 static lua_State *
2258 mg_prepare_lua_context_script(const char *file_name,
2259 struct mg_context *ctx,
2260 char *ebuf,
2261 size_t ebuf_len)
2262 {
2263 struct lua_State *L;
2264 int lua_ret;
2265 const char *lua_err_txt;
2266
2267 (void)ctx;
2268
2269 L = luaL_newstate();
2270 if (L == NULL) {
2271 mg_snprintf(NULL,
2272 NULL, /* No truncation check for ebuf */
2273 ebuf,
2274 ebuf_len,
2275 "Error: %s",
2276 "Cannot create Lua state");
2277 return 0;
2278 }
2279 civetweb_open_lua_libs(L);
2280
2281 lua_ret = luaL_loadfile(L, file_name);
2282 if (lua_ret != LUA_OK) {
2283 /* Error when loading the file (e.g. file not found,
2284 * out of memory, ...)
2285 */
2286 lua_err_txt = lua_tostring(L, -1);
2287 mg_snprintf(NULL,
2288 NULL, /* No truncation check for ebuf */
2289 ebuf,
2290 ebuf_len,
2291 "Error loading file %s: %s\n",
2292 file_name,
2293 lua_err_txt);
2294 return 0;
2295 }
2296
2297 /* The script file is loaded, now call it */
2298 lua_ret = lua_pcall(L,
2299 /* no arguments */ 0,
2300 /* zero or one return value */ 1,
2301 /* errors as strint return value */ 0);
2302
2303 if (lua_ret != LUA_OK) {
2304 /* Error when executing the script */
2305 lua_err_txt = lua_tostring(L, -1);
2306 mg_snprintf(NULL,
2307 NULL, /* No truncation check for ebuf */
2308 ebuf,
2309 ebuf_len,
2310 "Error running file %s: %s\n",
2311 file_name,
2312 lua_err_txt);
2313 return 0;
2314 }
2315 /* lua_close(L); must be done somewhere else */
2316
2317 return L;
2318 }
2319
2320
2321 int
2322 run_lua(const char *file_name)
2323 {
2324 int func_ret = EXIT_FAILURE;
2325 char ebuf[512] = {0};
2326 lua_State *L =
2327 mg_prepare_lua_context_script(file_name, NULL, ebuf, sizeof(ebuf));
2328 if (L) {
2329 /* Script executed */
2330 if (lua_type(L, -1) == LUA_TNUMBER) {
2331 func_ret = (int)lua_tonumber(L, -1);
2332 } else {
2333 func_ret = EXIT_SUCCESS;
2334 }
2335 lua_close(L);
2336 } else {
2337 fprintf(stderr, "%s\n", ebuf);
2338 }
2339 return func_ret;
2340 }
2341
2342
2343 static void *lib_handle_uuid = NULL;
2344
2345 static void
2346 lua_init_optional_libraries(void)
2347 {
2348 #if !defined(_WIN32)
2349 lib_handle_uuid = dlopen("libuuid.so", RTLD_LAZY);
2350 pf_uuid_generate.p =
2351 (lib_handle_uuid ? dlsym(lib_handle_uuid, "uuid_generate") : 0);
2352 #else
2353 pf_uuid_generate.p = 0;
2354 #endif
2355 }
2356
2357
2358 static void
2359 lua_exit_optional_libraries(void)
2360 {
2361 #if !defined(_WIN32)
2362 if (lib_handle_uuid) {
2363 dlclose(lib_handle_uuid);
2364 }
2365 #endif
2366 pf_uuid_generate.p = 0;
2367 lib_handle_uuid = NULL;
2368 }
2369
2370
2371 /* End of mod_lua.inl */