]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/Lib/libhttp/include/mod_lua.inl
Fix the boot issue for pfSense 2.7.x (#2775)
[Ventoy.git] / Plugson / src / Lib / libhttp / include / mod_lua.inl
1 #include "civetweb_lua.h"
2 #include "civetweb_private_lua.h"
3
4 #ifdef _WIN32
5 static void *
6 mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
7 {
8 /* TODO (low): This is an incomplete implementation of mmap for windows.
9 * Currently it is sufficient, but there are a lot of unused parameters.
10 * Better use a function "mg_map" which only has the required parameters,
11 * and implement it using mmap in Linux and CreateFileMapping in Windows.
12 * Noone should expect a full mmap for Windows here.
13 */
14 HANDLE fh = (HANDLE)_get_osfhandle(fd);
15 HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
16 void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
17 CloseHandle(mh);
18
19 /* unused parameters */
20 (void)addr;
21 (void)prot;
22 (void)flags;
23 (void)offset;
24
25 return p;
26 }
27
28 static void
29 munmap(void *addr, int64_t length)
30 {
31 /* unused parameters */
32 (void)length;
33
34 UnmapViewOfFile(addr);
35 }
36
37 #define MAP_FAILED (NULL)
38 #define MAP_PRIVATE (0)
39 #define PROT_READ (0)
40 #else
41 #include <sys/mman.h>
42 #endif
43
44 static const char *LUASOCKET = "luasocket";
45 static const char lua_regkey_ctx = 1;
46 static const char lua_regkey_connlist = 2;
47
48 /* Forward declarations */
49 static void handle_request(struct mg_connection *);
50 static int handle_lsp_request(struct mg_connection *,
51 const char *,
52 struct file *,
53 struct lua_State *);
54
55 static void
56 reg_string(struct lua_State *L, const char *name, const char *val)
57 {
58 if (name != NULL && val != NULL) {
59 lua_pushstring(L, name);
60 lua_pushstring(L, val);
61 lua_rawset(L, -3);
62 }
63 }
64
65 static void
66 reg_int(struct lua_State *L, const char *name, int val)
67 {
68 if (name != NULL) {
69 lua_pushstring(L, name);
70 lua_pushinteger(L, val);
71 lua_rawset(L, -3);
72 }
73 }
74
75 static void
76 reg_boolean(struct lua_State *L, const char *name, int val)
77 {
78 if (name != NULL) {
79 lua_pushstring(L, name);
80 lua_pushboolean(L, val != 0);
81 lua_rawset(L, -3);
82 }
83 }
84
85 static void
86 reg_conn_function(struct lua_State *L,
87 const char *name,
88 lua_CFunction func,
89 struct mg_connection *conn)
90 {
91 if (name != NULL && func != NULL && conn != NULL) {
92 lua_pushstring(L, name);
93 lua_pushlightuserdata(L, conn);
94 lua_pushcclosure(L, func, 1);
95 lua_rawset(L, -3);
96 }
97 }
98
99 static void
100 reg_function(struct lua_State *L, const char *name, lua_CFunction func)
101 {
102 if (name != NULL && func != NULL) {
103 lua_pushstring(L, name);
104 lua_pushcclosure(L, func, 0);
105 lua_rawset(L, -3);
106 }
107 }
108
109 static void
110 lua_cry(struct mg_connection *conn,
111 int err,
112 lua_State *L,
113 const char *lua_title,
114 const char *lua_operation)
115 {
116 switch (err) {
117 case LUA_OK:
118 case LUA_YIELD:
119 break;
120 case LUA_ERRRUN:
121 mg_cry(conn,
122 "%s: %s failed: runtime error: %s",
123 lua_title,
124 lua_operation,
125 lua_tostring(L, -1));
126 break;
127 case LUA_ERRSYNTAX:
128 mg_cry(conn,
129 "%s: %s failed: syntax error: %s",
130 lua_title,
131 lua_operation,
132 lua_tostring(L, -1));
133 break;
134 case LUA_ERRMEM:
135 mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
136 break;
137 case LUA_ERRGCMM:
138 mg_cry(conn,
139 "%s: %s failed: error during garbage collection",
140 lua_title,
141 lua_operation);
142 break;
143 case LUA_ERRERR:
144 mg_cry(conn,
145 "%s: %s failed: error in error handling: %s",
146 lua_title,
147 lua_operation,
148 lua_tostring(L, -1));
149 break;
150 default:
151 mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
152 break;
153 }
154 }
155
156 static int
157 lsp_sock_close(lua_State *L)
158 {
159 int num_args = lua_gettop(L);
160 if ((num_args == 1) && lua_istable(L, -1)) {
161 lua_getfield(L, -1, "sock");
162 closesocket((SOCKET)lua_tonumber(L, -1));
163 } else {
164 return luaL_error(L, "invalid :close() call");
165 }
166 return 1;
167 }
168
169 static int
170 lsp_sock_recv(lua_State *L)
171 {
172 int num_args = lua_gettop(L);
173 char buf[2000];
174 int n;
175
176 if ((num_args == 1) && lua_istable(L, -1)) {
177 lua_getfield(L, -1, "sock");
178 n = recv((SOCKET)lua_tonumber(L, -1), buf, sizeof(buf), 0);
179 if (n <= 0) {
180 lua_pushnil(L);
181 } else {
182 lua_pushlstring(L, buf, n);
183 }
184 } else {
185 return luaL_error(L, "invalid :close() call");
186 }
187 return 1;
188 }
189
190 static int
191 lsp_sock_send(lua_State *L)
192 {
193 int num_args = lua_gettop(L);
194 const char *buf;
195 size_t len, sent = 0;
196 int n = 0, sock;
197
198 if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
199 buf = lua_tolstring(L, -1, &len);
200 lua_getfield(L, -2, "sock");
201 sock = (int)lua_tonumber(L, -1);
202 while (sent < len) {
203 if ((n = send(sock, buf + sent, (int)(len - sent), 0)) <= 0) {
204 break;
205 }
206 sent += n;
207 }
208 lua_pushnumber(L, n);
209 } else {
210 return luaL_error(L, "invalid :close() call");
211 }
212 return 1;
213 }
214
215 static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
216 {"send", lsp_sock_send},
217 {"recv", lsp_sock_recv},
218 {NULL, NULL}};
219
220 static int
221 lsp_connect(lua_State *L)
222 {
223 int num_args = lua_gettop(L);
224 char ebuf[100];
225 SOCKET sock;
226 union usa sa;
227 int ok;
228
229 if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
230 && lua_isnumber(L, -1)) {
231 ok = connect_socket(NULL,
232 lua_tostring(L, -3),
233 (int)lua_tonumber(L, -2),
234 (int)lua_tonumber(L, -1),
235 ebuf,
236 sizeof(ebuf),
237 &sock,
238 &sa);
239 if (!ok) {
240 return luaL_error(L, ebuf);
241 } else {
242 lua_newtable(L);
243 reg_int(L, "sock", (int)sock);
244 reg_string(L, "host", lua_tostring(L, -4));
245 luaL_getmetatable(L, LUASOCKET);
246 lua_setmetatable(L, -2);
247 /* TODO (high): The metatable misses a _gc method to free the
248 * sock object -> currently lsp_connect is a resource leak. */
249 }
250 } else {
251 return luaL_error(
252 L, "connect(host,port,is_ssl): invalid parameter given.");
253 }
254 return 1;
255 }
256
257 static int
258 lsp_error(lua_State *L)
259 {
260 lua_getglobal(L, "mg");
261 lua_getfield(L, -1, "onerror");
262 lua_pushvalue(L, -3);
263 lua_pcall(L, 1, 0, 0);
264 return 0;
265 }
266
267 /* Silently stop processing chunks. */
268 static void
269 lsp_abort(lua_State *L)
270 {
271 int top = lua_gettop(L);
272 lua_getglobal(L, "mg");
273 lua_pushnil(L);
274 lua_setfield(L, -2, "onerror");
275 lua_settop(L, top);
276 lua_pushstring(L, "aborting");
277 lua_error(L);
278 }
279
280 struct lsp_var_reader_data {
281 const char *begin;
282 unsigned len;
283 unsigned state;
284 };
285
286
287 static const char *
288 lsp_var_reader(lua_State *L, void *ud, size_t *sz)
289 {
290 struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
291 const char *ret;
292 (void)(L); /* unused */
293
294 switch (reader->state) {
295 case 0:
296 ret = "mg.write(";
297 *sz = strlen(ret);
298 break;
299 case 1:
300 ret = reader->begin;
301 *sz = reader->len;
302 break;
303 case 2:
304 ret = ")";
305 *sz = strlen(ret);
306 break;
307 default:
308 ret = 0;
309 *sz = 0;
310 }
311
312 reader->state++;
313 return ret;
314 }
315
316
317 static int
318 lsp(struct mg_connection *conn,
319 const char *path,
320 const char *p,
321 int64_t len,
322 lua_State *L)
323 {
324 int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
325 char chunkname[MG_BUF_LEN];
326 struct lsp_var_reader_data data;
327
328 for (i = 0; i < len; i++) {
329 if (p[i] == '\n')
330 lines++;
331 if ((i + 1) < len && p[i] == '<' && p[i + 1] == '?') {
332
333 /* <?= ?> means a variable is enclosed and its value should be
334 * printed */
335 is_var = ((i + 2) < len && p[i + 2] == '=');
336
337 if (is_var)
338 j = i + 2;
339 else
340 j = i + 1;
341
342 while (j < len) {
343 if (p[j] == '\n')
344 lualines++;
345 if ((j + 1) < len && p[j] == '?' && p[j + 1] == '>') {
346 mg_write(conn, p + pos, i - pos);
347
348 mg_snprintf(conn,
349 NULL, /* name only used for debugging */
350 chunkname,
351 sizeof(chunkname),
352 "@%s+%i",
353 path,
354 lines);
355 lua_pushlightuserdata(L, conn);
356 lua_pushcclosure(L, lsp_error, 1);
357
358 if (is_var) {
359 data.begin = p + (i + 3);
360 data.len = j - (i + 3);
361 data.state = 0;
362 lua_ok = mg_lua_load(
363 L, lsp_var_reader, &data, chunkname, NULL);
364 } else {
365 lua_ok = luaL_loadbuffer(L,
366 p + (i + 2),
367 j - (i + 2),
368 chunkname);
369 }
370
371 if (lua_ok) {
372 /* Syntax error or OOM. Error message is pushed on
373 * stack. */
374 lua_pcall(L, 1, 0, 0);
375 } else {
376 /* Success loading chunk. Call it. */
377 lua_pcall(L, 0, 0, 1);
378 }
379
380 pos = j + 2;
381 i = pos - 1;
382 break;
383 }
384 j++;
385 }
386
387 if (lualines > 0) {
388 lines += lualines;
389 lualines = 0;
390 }
391 }
392 }
393
394 if (i > pos) {
395 mg_write(conn, p + pos, i - pos);
396 }
397
398 return 0;
399 }
400
401
402 /* mg.write: Send data to the client */
403 static int
404 lsp_write(lua_State *L)
405 {
406 struct mg_connection *conn =
407 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
408 int num_args = lua_gettop(L);
409 const char *str;
410 size_t size;
411 int i;
412
413 for (i = 1; i <= num_args; i++) {
414 if (lua_isstring(L, i)) {
415 str = lua_tolstring(L, i, &size);
416 mg_write(conn, str, size);
417 }
418 }
419
420 return 0;
421 }
422
423
424 /* mg.read: Read data from the client (e.g., from a POST request) */
425 static int
426 lsp_read(lua_State *L)
427 {
428 struct mg_connection *conn =
429 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
430 char buf[1024];
431 int len = mg_read(conn, buf, sizeof(buf));
432
433 if (len <= 0)
434 return 0;
435 lua_pushlstring(L, buf, len);
436
437 return 1;
438 }
439
440
441 /* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
442 static int
443 lsp_keep_alive(lua_State *L)
444 {
445 struct mg_connection *conn =
446 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
447 int num_args = lua_gettop(L);
448
449 /* This function may be called with one parameter (boolean) to set the
450 keep_alive state.
451 Or without a parameter to just query the current keep_alive state. */
452 if ((num_args == 1) && lua_isboolean(L, 1)) {
453 conn->must_close = !lua_toboolean(L, 1);
454 } else if (num_args != 0) {
455 /* Syntax error */
456 return luaL_error(L, "invalid keep_alive() call");
457 }
458
459 /* Return the current "keep_alive" state. This may be false, even it
460 * keep_alive(true) has been called. */
461 lua_pushboolean(L, should_keep_alive(conn));
462 return 1;
463 }
464
465
466 /* mg.include: Include another .lp file */
467 static int
468 lsp_include(lua_State *L)
469 {
470 struct mg_connection *conn =
471 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
472 int num_args = lua_gettop(L);
473 struct file file = STRUCT_FILE_INITIALIZER;
474 const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
475
476 if (filename) {
477 if (handle_lsp_request(conn, filename, &file, L)) {
478 /* handle_lsp_request returned an error code, meaning an error
479 occured in
480 the included page and mg.onerror returned non-zero. Stop processing.
481 */
482 lsp_abort(L);
483 }
484 } else {
485 /* Syntax error */
486 return luaL_error(L, "invalid include() call");
487 }
488 return 0;
489 }
490
491
492 /* mg.cry: Log an error. Default value for mg.onerror. */
493 static int
494 lsp_cry(lua_State *L)
495 {
496 struct mg_connection *conn =
497 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
498 int num_args = lua_gettop(L);
499 const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
500
501 if (text) {
502 mg_cry(conn, "%s", lua_tostring(L, -1));
503 } else {
504 /* Syntax error */
505 return luaL_error(L, "invalid cry() call");
506 }
507 return 0;
508 }
509
510
511 /* mg.redirect: Redirect the request (internally). */
512 static int
513 lsp_redirect(lua_State *L)
514 {
515 struct mg_connection *conn =
516 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
517 int num_args = lua_gettop(L);
518 const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
519
520 if (target) {
521 conn->request_info.local_uri = target;
522 handle_request(conn);
523 lsp_abort(L);
524 } else {
525 /* Syntax error */
526 return luaL_error(L, "invalid redirect() call");
527 }
528 return 0;
529 }
530
531
532 /* mg.send_file */
533 static int
534 lsp_send_file(lua_State *L)
535 {
536 struct mg_connection *conn =
537 (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
538 int num_args = lua_gettop(L);
539 const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
540
541 if (filename) {
542 mg_send_file(conn, filename);
543 } else {
544 /* Syntax error */
545 return luaL_error(L, "invalid send_file() call");
546 }
547 return 0;
548 }
549
550
551 /* mg.get_time */
552 static int
553 lsp_get_time(lua_State *L)
554 {
555 int num_args = lua_gettop(L);
556 int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
557 struct timespec ts;
558 double d;
559
560 clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
561 d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
562 lua_pushnumber(L, d);
563 return 1;
564 }
565
566
567 /* mg.get_var */
568 static int
569 lsp_get_var(lua_State *L)
570 {
571 int num_args = lua_gettop(L);
572 const char *data, *var_name;
573 size_t data_len, occurrence;
574 int ret;
575 char dst[512];
576
577 if (num_args >= 2 && num_args <= 3) {
578 data = lua_tolstring(L, 1, &data_len);
579 var_name = lua_tostring(L, 2);
580 occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
581
582 ret =
583 mg_get_var2(data, data_len, var_name, dst, sizeof(dst), occurrence);
584 if (ret >= 0) {
585 /* Variable found: return value to Lua */
586 lua_pushstring(L, dst);
587 } else {
588 /* Variable not found (TODO (mid): may be string too long) */
589 lua_pushnil(L);
590 }
591 } else {
592 /* Syntax error */
593 return luaL_error(L, "invalid get_var() call");
594 }
595 return 1;
596 }
597
598
599 /* mg.get_mime_type */
600 static int
601 lsp_get_mime_type(lua_State *L)
602 {
603 int num_args = lua_gettop(L);
604 struct vec mime_type = {0, 0};
605 struct mg_context *ctx;
606 const char *text;
607
608 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
609 lua_gettable(L, LUA_REGISTRYINDEX);
610 ctx = (struct mg_context *)lua_touserdata(L, -1);
611
612 if (num_args == 1) {
613 text = lua_tostring(L, 1);
614 if (text) {
615 if (ctx) {
616 get_mime_type(ctx, text, &mime_type);
617 lua_pushlstring(L, mime_type.ptr, mime_type.len);
618 } else {
619 text = mg_get_builtin_mime_type(text);
620 lua_pushstring(L, text);
621 }
622 } else {
623 /* Syntax error */
624 return luaL_error(L, "invalid argument for get_mime_type() call");
625 }
626 } else {
627 /* Syntax error */
628 return luaL_error(L, "invalid get_mime_type() call");
629 }
630 return 1;
631 }
632
633
634 /* mg.get_cookie */
635 static int
636 lsp_get_cookie(lua_State *L)
637 {
638 int num_args = lua_gettop(L);
639 const char *cookie;
640 const char *var_name;
641 int ret;
642 char dst[512];
643
644 if (num_args == 2) {
645 cookie = lua_tostring(L, 1);
646 var_name = lua_tostring(L, 2);
647 if (cookie != NULL && var_name != NULL) {
648 ret = mg_get_cookie(cookie, var_name, dst, sizeof(dst));
649 } else {
650 ret = -1;
651 }
652
653 if (ret >= 0) {
654 lua_pushlstring(L, dst, ret);
655 } else {
656 lua_pushnil(L);
657 }
658 } else {
659 /* Syntax error */
660 return luaL_error(L, "invalid get_cookie() call");
661 }
662 return 1;
663 }
664
665
666 /* mg.md5 */
667 static int
668 lsp_md5(lua_State *L)
669 {
670 int num_args = lua_gettop(L);
671 const char *text;
672 md5_byte_t hash[16];
673 md5_state_t ctx;
674 size_t text_len;
675 char buf[40];
676
677 if (num_args == 1) {
678 text = lua_tolstring(L, 1, &text_len);
679 if (text) {
680 md5_init(&ctx);
681 md5_append(&ctx, (const md5_byte_t *)text, text_len);
682 md5_finish(&ctx, hash);
683 bin2str(buf, hash, sizeof(hash));
684 lua_pushstring(L, buf);
685 } else {
686 lua_pushnil(L);
687 }
688 } else {
689 /* Syntax error */
690 return luaL_error(L, "invalid md5() call");
691 }
692 return 1;
693 }
694
695
696 /* mg.url_encode */
697 static int
698 lsp_url_encode(lua_State *L)
699 {
700 int num_args = lua_gettop(L);
701 const char *text;
702 size_t text_len;
703 char dst[512];
704
705 if (num_args == 1) {
706 text = lua_tolstring(L, 1, &text_len);
707 if (text) {
708 mg_url_encode(text, dst, sizeof(dst));
709 lua_pushstring(L, dst);
710 } else {
711 lua_pushnil(L);
712 }
713 } else {
714 /* Syntax error */
715 return luaL_error(L, "invalid url_encode() call");
716 }
717 return 1;
718 }
719
720
721 /* mg.url_decode */
722 static int
723 lsp_url_decode(lua_State *L)
724 {
725 int num_args = lua_gettop(L);
726 const char *text;
727 size_t text_len;
728 int is_form;
729 char dst[512];
730
731 if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
732 text = lua_tolstring(L, 1, &text_len);
733 is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
734 if (text) {
735 mg_url_decode(text, text_len, dst, (int)sizeof(dst), is_form);
736 lua_pushstring(L, dst);
737 } else {
738 lua_pushnil(L);
739 }
740 } else {
741 /* Syntax error */
742 return luaL_error(L, "invalid url_decode() call");
743 }
744 return 1;
745 }
746
747
748 /* mg.base64_encode */
749 static int
750 lsp_base64_encode(lua_State *L)
751 {
752 int num_args = lua_gettop(L);
753 const char *text;
754 size_t text_len;
755 char *dst;
756
757 if (num_args == 1) {
758 text = lua_tolstring(L, 1, &text_len);
759 if (text) {
760 dst = (char *)mg_malloc(text_len * 8 / 6 + 4);
761 if (dst) {
762 base64_encode((const unsigned char *)text, (int)text_len, dst);
763 lua_pushstring(L, dst);
764 mg_free(dst);
765 } else {
766 return luaL_error(L, "out of memory in base64_encode() call");
767 }
768 } else {
769 lua_pushnil(L);
770 }
771 } else {
772 /* Syntax error */
773 return luaL_error(L, "invalid base64_encode() call");
774 }
775 return 1;
776 }
777
778
779 /* mg.base64_encode */
780 static int
781 lsp_base64_decode(lua_State *L)
782 {
783 int num_args = lua_gettop(L);
784 const char *text;
785 size_t text_len, dst_len;
786 int ret;
787 char *dst;
788
789 if (num_args == 1) {
790 text = lua_tolstring(L, 1, &text_len);
791 if (text) {
792 dst = (char *)mg_malloc(text_len);
793 if (dst) {
794 ret = base64_decode((const unsigned char *)text,
795 (int)text_len,
796 dst,
797 &dst_len);
798 if (ret != -1) {
799 mg_free(dst);
800 return luaL_error(
801 L, "illegal character in lsp_base64_decode() call");
802 } else {
803 lua_pushlstring(L, dst, dst_len);
804 mg_free(dst);
805 }
806 } else {
807 return luaL_error(L,
808 "out of memory in lsp_base64_decode() call");
809 }
810 } else {
811 lua_pushnil(L);
812 }
813 } else {
814 /* Syntax error */
815 return luaL_error(L, "invalid lsp_base64_decode() call");
816 }
817 return 1;
818 }
819
820
821 /* mg.get_response_code_text */
822 static int
823 lsp_get_response_code_text(lua_State *L)
824 {
825 int num_args = lua_gettop(L);
826 int type1;
827 double code;
828 const char *text;
829
830 if (num_args == 1) {
831 type1 = lua_type(L, 1);
832 if (type1 == LUA_TNUMBER) {
833 /* If the first argument is a number,
834 convert it to the corresponding text. */
835 code = lua_tonumber(L, 1);
836 text = mg_get_response_code_text(NULL, (int)code);
837 if (text)
838 lua_pushstring(L, text);
839 return text ? 1 : 0;
840 }
841 }
842
843 /* Syntax error */
844 return luaL_error(L, "invalid get_response_code_text() call");
845 }
846
847
848 /* mg.random - might be better than math.random on some systems */
849 static int
850 lsp_random(lua_State *L)
851 {
852 int num_args = lua_gettop(L);
853 if (num_args == 0) {
854 /* The civetweb internal random number generator will generate
855 * a 64 bit random number. */
856 uint64_t r = get_random();
857 /* Lua "number" is a IEEE 754 double precission float:
858 * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
859 * Thus, mask with 2^53-1 to get an integer with the maximum
860 * precission available. */
861 r &= ((((uint64_t)1) << 53) - 1);
862 lua_pushnumber(L, (double)r);
863 return 1;
864 }
865
866 /* Syntax error */
867 return luaL_error(L, "invalid random() call");
868 }
869
870
871 union {
872 void *p;
873 void (*f)(unsigned char uuid[16]);
874 } pf_uuid_generate;
875
876
877 /* mg.uuid */
878 static int
879 lsp_uuid(lua_State *L)
880 {
881 union {
882 unsigned char uuid_array[16];
883 struct uuid_struct_type {
884 uint32_t data1;
885 uint16_t data2;
886 uint16_t data3;
887 uint8_t data4[8];
888 } uuid_struct;
889 } uuid;
890
891 char uuid_str[40];
892 int num_args = lua_gettop(L);
893
894 memset(&uuid, 0, sizeof(uuid));
895 memset(uuid_str, 0, sizeof(uuid_str));
896
897 if (num_args == 0) {
898
899 pf_uuid_generate.f(uuid.uuid_array);
900
901 sprintf(uuid_str,
902 "{%08lX-%04X-%04X-%02X%02X-"
903 "%02X%02X%02X%02X%02X%02X}",
904 (unsigned long)uuid.uuid_struct.data1,
905 (unsigned)uuid.uuid_struct.data2,
906 (unsigned)uuid.uuid_struct.data3,
907 (unsigned)uuid.uuid_struct.data4[0],
908 (unsigned)uuid.uuid_struct.data4[1],
909 (unsigned)uuid.uuid_struct.data4[2],
910 (unsigned)uuid.uuid_struct.data4[3],
911 (unsigned)uuid.uuid_struct.data4[4],
912 (unsigned)uuid.uuid_struct.data4[5],
913 (unsigned)uuid.uuid_struct.data4[6],
914 (unsigned)uuid.uuid_struct.data4[7]);
915
916 lua_pushstring(L, uuid_str);
917 return 1;
918 }
919
920 /* Syntax error */
921 return luaL_error(L, "invalid random() call");
922 }
923
924
925 #ifdef USE_WEBSOCKET
926 struct lua_websock_data {
927 lua_State *state;
928 char *script;
929 unsigned references;
930 struct mg_connection *conn[MAX_WORKER_THREADS];
931 pthread_mutex_t ws_mutex;
932 };
933 #endif
934
935
936 /* mg.write for websockets */
937 static int
938 lwebsock_write(lua_State *L)
939 {
940 #ifdef USE_WEBSOCKET
941 int num_args = lua_gettop(L);
942 struct lua_websock_data *ws;
943 const char *str;
944 size_t size;
945 int opcode = -1;
946 unsigned i;
947 struct mg_connection *client = NULL;
948
949 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
950 lua_gettable(L, LUA_REGISTRYINDEX);
951 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
952
953 (void)pthread_mutex_lock(&(ws->ws_mutex));
954
955 if (num_args == 1) {
956 /* just one text: send it to all client */
957 if (lua_isstring(L, 1)) {
958 opcode = WEBSOCKET_OPCODE_TEXT;
959 }
960 } else if (num_args == 2) {
961 if (lua_isnumber(L, 1)) {
962 /* opcode number and message text */
963 opcode = (int)lua_tointeger(L, 1);
964 } else if (lua_isstring(L, 1)) {
965 /* opcode string and message text */
966 str = lua_tostring(L, 1);
967 if (!mg_strncasecmp(str, "text", 4))
968 opcode = WEBSOCKET_OPCODE_TEXT;
969 else if (!mg_strncasecmp(str, "bin", 3))
970 opcode = WEBSOCKET_OPCODE_BINARY;
971 else if (!mg_strncasecmp(str, "close", 5))
972 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
973 else if (!mg_strncasecmp(str, "ping", 4))
974 opcode = WEBSOCKET_OPCODE_PING;
975 else if (!mg_strncasecmp(str, "pong", 4))
976 opcode = WEBSOCKET_OPCODE_PONG;
977 else if (!mg_strncasecmp(str, "cont", 4))
978 opcode = WEBSOCKET_OPCODE_CONTINUATION;
979 } else if (lua_isuserdata(L, 1)) {
980 /* client id and message text */
981 client = (struct mg_connection *)lua_touserdata(L, 1);
982 opcode = WEBSOCKET_OPCODE_TEXT;
983 }
984 } else if (num_args == 3) {
985 if (lua_isuserdata(L, 1)) {
986 client = (struct mg_connection *)lua_touserdata(L, 1);
987 if (lua_isnumber(L, 2)) {
988 /* client id, opcode number and message text */
989 opcode = (int)lua_tointeger(L, 2);
990 } else if (lua_isstring(L, 2)) {
991 /* client id, opcode string and message text */
992 str = lua_tostring(L, 2);
993 if (!mg_strncasecmp(str, "text", 4))
994 opcode = WEBSOCKET_OPCODE_TEXT;
995 else if (!mg_strncasecmp(str, "bin", 3))
996 opcode = WEBSOCKET_OPCODE_BINARY;
997 else if (!mg_strncasecmp(str, "close", 5))
998 opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
999 else if (!mg_strncasecmp(str, "ping", 4))
1000 opcode = WEBSOCKET_OPCODE_PING;
1001 else if (!mg_strncasecmp(str, "pong", 4))
1002 opcode = WEBSOCKET_OPCODE_PONG;
1003 else if (!mg_strncasecmp(str, "cont", 4))
1004 opcode = WEBSOCKET_OPCODE_CONTINUATION;
1005 }
1006 }
1007 }
1008
1009 if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
1010 str = lua_tolstring(L, num_args, &size);
1011 if (client) {
1012 for (i = 0; i < ws->references; i++) {
1013 if (client == ws->conn[i]) {
1014 mg_websocket_write(ws->conn[i], opcode, str, size);
1015 }
1016 }
1017 } else {
1018 for (i = 0; i < ws->references; i++) {
1019 mg_websocket_write(ws->conn[i], opcode, str, size);
1020 }
1021 }
1022 } else {
1023 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1024 return luaL_error(L, "invalid websocket write() call");
1025 }
1026
1027 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1028
1029 #else
1030 (void)(L); /* unused */
1031 #endif
1032 return 0;
1033 }
1034
1035
1036 struct laction_arg {
1037 lua_State *state;
1038 const char *script;
1039 pthread_mutex_t *pmutex;
1040 char txt[1];
1041 };
1042
1043
1044 static int
1045 lua_action(struct laction_arg *arg)
1046 {
1047 int err, ok;
1048 struct mg_context *ctx;
1049
1050 (void)pthread_mutex_lock(arg->pmutex);
1051
1052 lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
1053 lua_gettable(arg->state, LUA_REGISTRYINDEX);
1054 ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
1055
1056 err = luaL_loadstring(arg->state, arg->txt);
1057 if (err != 0) {
1058 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1059 (void)pthread_mutex_unlock(arg->pmutex);
1060 mg_free(arg);
1061 return 0;
1062 }
1063 err = lua_pcall(arg->state, 0, 1, 0);
1064 if (err != 0) {
1065 lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
1066 (void)pthread_mutex_unlock(arg->pmutex);
1067 mg_free(arg);
1068 return 0;
1069 }
1070
1071 ok = lua_type(arg->state, -1);
1072 if (lua_isboolean(arg->state, -1)) {
1073 ok = lua_toboolean(arg->state, -1);
1074 } else {
1075 ok = 0;
1076 }
1077 lua_pop(arg->state, 1);
1078
1079 (void)pthread_mutex_unlock(arg->pmutex);
1080
1081 if (!ok) {
1082 mg_free(arg);
1083 }
1084 return ok;
1085 }
1086
1087
1088 static int
1089 lua_action_free(struct laction_arg *arg)
1090 {
1091 if (lua_action(arg)) {
1092 mg_free(arg);
1093 }
1094 return 0;
1095 }
1096
1097
1098 static int
1099 lwebsocket_set_timer(lua_State *L, int is_periodic)
1100 {
1101 #if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
1102 int num_args = lua_gettop(L);
1103 struct lua_websock_data *ws;
1104 int type1, type2, ok = 0;
1105 double timediff;
1106 struct mg_context *ctx;
1107 struct laction_arg *arg;
1108 const char *txt;
1109 size_t txt_len;
1110
1111 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1112 lua_gettable(L, LUA_REGISTRYINDEX);
1113 ctx = (struct mg_context *)lua_touserdata(L, -1);
1114
1115 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1116 lua_gettable(L, LUA_REGISTRYINDEX);
1117 ws = (struct lua_websock_data *)lua_touserdata(L, -1);
1118
1119 if (num_args < 2) {
1120 return luaL_error(L,
1121 "not enough arguments for set_timer/interval() call");
1122 }
1123
1124 type1 = lua_type(L, 1);
1125 type2 = lua_type(L, 2);
1126
1127 if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
1128 timediff = (double)lua_tonumber(L, 2);
1129 txt = lua_tostring(L, 1);
1130 txt_len = strlen(txt);
1131 arg = (struct laction_arg *)mg_malloc(sizeof(struct laction_arg)
1132 + txt_len + 10);
1133 arg->state = L;
1134 arg->script = ws->script;
1135 arg->pmutex = &(ws->ws_mutex);
1136 memcpy(arg->txt, "return(", 7);
1137 memcpy(arg->txt + 7, txt, txt_len);
1138 arg->txt[txt_len + 7] = ')';
1139 arg->txt[txt_len + 8] = 0;
1140 ok =
1141 (0
1142 == timer_add(ctx,
1143 timediff,
1144 is_periodic,
1145 1,
1146 (taction)(is_periodic ? lua_action : lua_action_free),
1147 (void *)arg));
1148 } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
1149 /* TODO (mid): not implemented yet */
1150 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1151 } else {
1152 return luaL_error(L, "invalid arguments for set_timer/interval() call");
1153 }
1154
1155 lua_pushboolean(L, ok);
1156 return 1;
1157
1158 #else
1159 (void)(L); /* unused */
1160 (void)(is_periodic); /* unused */
1161 return 0;
1162 #endif
1163 }
1164
1165
1166 /* mg.set_timeout for websockets */
1167 static int
1168 lwebsocket_set_timeout(lua_State *L)
1169 {
1170 return lwebsocket_set_timer(L, 0);
1171 }
1172
1173
1174 /* mg.set_interval for websockets */
1175 static int
1176 lwebsocket_set_interval(lua_State *L)
1177 {
1178 return lwebsocket_set_timer(L, 1);
1179 }
1180
1181 enum {
1182 LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
1183 LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
1184 LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
1185 };
1186
1187
1188 static void
1189 prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
1190 {
1191 const char *s;
1192 int i;
1193
1194 /* Export mg.request_info */
1195 lua_pushstring(L, "request_info");
1196 lua_newtable(L);
1197 reg_string(L, "request_method", conn->request_info.request_method);
1198 reg_string(L, "request_uri", conn->request_info.request_uri);
1199 reg_string(L, "uri", conn->request_info.local_uri);
1200 reg_string(L, "http_version", conn->request_info.http_version);
1201 reg_string(L, "query_string", conn->request_info.query_string);
1202 #if defined(MG_LEGACY_INTERFACE)
1203 reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
1204 deprecated, use
1205 remote_addr
1206 instead */
1207 #endif
1208 reg_string(L, "remote_addr", conn->request_info.remote_addr);
1209 /* TODO (high): ip version */
1210 reg_int(L, "remote_port", conn->request_info.remote_port);
1211 reg_int(L, "num_headers", conn->request_info.num_headers);
1212 reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
1213
1214 if (conn->request_info.content_length >= 0) {
1215 /* reg_int64: content_length */
1216 lua_pushstring(L, "content_length");
1217 lua_pushnumber(
1218 L,
1219 (lua_Number)conn->request_info
1220 .content_length); /* lua_Number may be used as 52 bit integer */
1221 lua_rawset(L, -3);
1222 }
1223 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
1224 reg_string(L, "content_type", s);
1225 }
1226
1227 if (conn->request_info.remote_user != NULL) {
1228 reg_string(L, "remote_user", conn->request_info.remote_user);
1229 reg_string(L, "auth_type", "Digest");
1230 }
1231
1232 reg_boolean(L, "https", conn->ssl != NULL);
1233
1234 if (conn->status_code > 0) {
1235 /* Lua error handler should show the status code */
1236 reg_int(L, "status", conn->status_code);
1237 }
1238
1239 lua_pushstring(L, "http_headers");
1240 lua_newtable(L);
1241 for (i = 0; i < conn->request_info.num_headers; i++) {
1242 reg_string(L,
1243 conn->request_info.http_headers[i].name,
1244 conn->request_info.http_headers[i].value);
1245 }
1246 lua_rawset(L, -3);
1247
1248 lua_rawset(L, -3);
1249 }
1250
1251
1252 void
1253 civetweb_open_lua_libs(lua_State *L)
1254 {
1255 {
1256 extern void luaL_openlibs(lua_State *);
1257 luaL_openlibs(L);
1258 }
1259
1260 #ifdef USE_LUA_SQLITE3
1261 {
1262 extern int luaopen_lsqlite3(lua_State *);
1263 luaopen_lsqlite3(L);
1264 }
1265 #endif
1266 #ifdef USE_LUA_LUAXML
1267 {
1268 extern int luaopen_LuaXML_lib(lua_State *);
1269 luaopen_LuaXML_lib(L);
1270 }
1271 #endif
1272 #ifdef USE_LUA_FILE_SYSTEM
1273 {
1274 extern int luaopen_lfs(lua_State *);
1275 luaopen_lfs(L);
1276 }
1277 #endif
1278 #ifdef USE_LUA_BINARY
1279 {
1280 /* TODO (low): Test if this could be used as a replacement for bit32.
1281 * Check again with Lua 5.3 later. */
1282 extern int luaopen_binary(lua_State *);
1283
1284 luaL_requiref(L, "binary", luaopen_binary, 1);
1285 lua_pop(L, 1);
1286 }
1287 #endif
1288 }
1289
1290
1291 static void
1292 prepare_lua_environment(struct mg_context *ctx,
1293 struct mg_connection *conn,
1294 struct lua_websock_data *ws_conn_list,
1295 lua_State *L,
1296 const char *script_name,
1297 int lua_env_type)
1298 {
1299 civetweb_open_lua_libs(L);
1300
1301 #if LUA_VERSION_NUM == 502
1302 /* Keep the "connect" method for compatibility,
1303 * but do not backport it to Lua 5.1.
1304 * TODO: Redesign the interface.
1305 */
1306 luaL_newmetatable(L, LUASOCKET);
1307 lua_pushliteral(L, "__index");
1308 luaL_newlib(L, luasocket_methods);
1309 lua_rawset(L, -3);
1310 lua_pop(L, 1);
1311 lua_register(L, "connect", lsp_connect);
1312 #endif
1313
1314 /* Store context in the registry */
1315 if (ctx != NULL) {
1316 lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
1317 lua_pushlightuserdata(L, (void *)ctx);
1318 lua_settable(L, LUA_REGISTRYINDEX);
1319 }
1320 if (ws_conn_list != NULL) {
1321 lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
1322 lua_pushlightuserdata(L, (void *)ws_conn_list);
1323 lua_settable(L, LUA_REGISTRYINDEX);
1324 }
1325
1326 /* Register mg module */
1327 lua_newtable(L);
1328
1329 switch (lua_env_type) {
1330 case LUA_ENV_TYPE_LUA_SERVER_PAGE:
1331 reg_string(L, "lua_type", "page");
1332 break;
1333 case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
1334 reg_string(L, "lua_type", "script");
1335 break;
1336 case LUA_ENV_TYPE_LUA_WEBSOCKET:
1337 reg_string(L, "lua_type", "websocket");
1338 break;
1339 }
1340
1341 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
1342 || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
1343 reg_conn_function(L, "cry", lsp_cry, conn);
1344 reg_conn_function(L, "read", lsp_read, conn);
1345 reg_conn_function(L, "write", lsp_write, conn);
1346 reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
1347 reg_conn_function(L, "send_file", lsp_send_file, conn);
1348 }
1349
1350 if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
1351 reg_conn_function(L, "include", lsp_include, conn);
1352 reg_conn_function(L, "redirect", lsp_redirect, conn);
1353 }
1354
1355 if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
1356 reg_function(L, "write", lwebsock_write);
1357 #ifdef USE_TIMERS
1358 reg_function(L, "set_timeout", lwebsocket_set_timeout);
1359 reg_function(L, "set_interval", lwebsocket_set_interval);
1360 #endif
1361 /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
1362 }
1363
1364 reg_function(L, "time", lsp_get_time);
1365 reg_function(L, "get_var", lsp_get_var);
1366 reg_function(L, "get_mime_type", lsp_get_mime_type);
1367 reg_function(L, "get_cookie", lsp_get_cookie);
1368 reg_function(L, "md5", lsp_md5);
1369 reg_function(L, "url_encode", lsp_url_encode);
1370 reg_function(L, "url_decode", lsp_url_decode);
1371 reg_function(L, "base64_encode", lsp_base64_encode);
1372 reg_function(L, "base64_decode", lsp_base64_decode);
1373 reg_function(L, "get_response_code_text", lsp_get_response_code_text);
1374 reg_function(L, "random", lsp_random);
1375 if (pf_uuid_generate.f) {
1376 reg_function(L, "uuid", lsp_uuid);
1377 }
1378
1379 reg_string(L, "version", CIVETWEB_VERSION);
1380
1381 reg_string(L, "script_name", script_name);
1382
1383 if (ctx != NULL) {
1384 reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
1385 reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
1386 #if defined(USE_WEBSOCKET)
1387 reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
1388 #endif
1389
1390 if (ctx->systemName != NULL) {
1391 reg_string(L, "system", ctx->systemName);
1392 }
1393 }
1394
1395 /* Export connection specific info */
1396 if (conn != NULL) {
1397 prepare_lua_request_info(conn, L);
1398 }
1399
1400 lua_setglobal(L, "mg");
1401
1402 /* Register default mg.onerror function */
1403 IGNORE_UNUSED_RESULT(
1404 luaL_dostring(L,
1405 "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
1406 "debug.traceback(e, 1)) end"));
1407
1408 if (ctx != NULL) {
1409 /* Preload */
1410 if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
1411 IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
1412 }
1413
1414 if (ctx->callbacks.init_lua != NULL) {
1415 ctx->callbacks.init_lua(conn, L);
1416 }
1417 }
1418 }
1419
1420
1421 static int
1422 lua_error_handler(lua_State *L)
1423 {
1424 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
1425
1426 lua_getglobal(L, "mg");
1427 if (!lua_isnil(L, -1)) {
1428 lua_getfield(L, -1, "write"); /* call mg.write() */
1429 lua_pushstring(L, error_msg);
1430 lua_pushliteral(L, "\n");
1431 lua_call(L, 2, 0);
1432 IGNORE_UNUSED_RESULT(
1433 luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
1434 } else {
1435 printf("Lua error: [%s]\n", error_msg);
1436 IGNORE_UNUSED_RESULT(
1437 luaL_dostring(L, "print(debug.traceback(), '\\n')"));
1438 }
1439 /* TODO(lsm, low): leave the stack balanced */
1440
1441 return 0;
1442 }
1443
1444
1445 static void *
1446 lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
1447 {
1448
1449 (void)ud;
1450 (void)osize; /* not used */
1451
1452 if (nsize == 0) {
1453 mg_free(ptr);
1454 return NULL;
1455 }
1456 return mg_realloc(ptr, nsize);
1457 }
1458
1459
1460 static void
1461 mg_exec_lua_script(struct mg_connection *conn,
1462 const char *path,
1463 const void **exports)
1464 {
1465 int i;
1466 lua_State *L;
1467
1468 /* Assume the script does not support keep_alive. The script may change this
1469 * by calling mg.keep_alive(true). */
1470 conn->must_close = 1;
1471
1472 /* Execute a plain Lua script. */
1473 if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
1474 prepare_lua_environment(
1475 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
1476 lua_pushcclosure(L, &lua_error_handler, 0);
1477
1478 if (exports != NULL) {
1479 #if LUA_VERSION_NUM > 501
1480 lua_pushglobaltable(L);
1481 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1482 lua_CFunction func;
1483 lua_pushstring(L, (const char *)(exports[i]));
1484 *(const void **)(&func) = exports[i + 1];
1485 lua_pushcclosure(L, func, 0);
1486 lua_rawset(L, -3);
1487 }
1488 #else
1489 for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
1490 lua_CFunction func;
1491 const char *name = (const char *)(exports[i]);
1492 *(const void **)(&func) = exports[i + 1];
1493 lua_register(L, name, func);
1494 }
1495 #endif
1496 }
1497
1498 if (luaL_loadfile(L, path) != 0) {
1499 lua_error_handler(L);
1500 }
1501 lua_pcall(L, 0, 0, -2);
1502 lua_close(L);
1503 }
1504 }
1505
1506
1507 static int
1508 handle_lsp_request(struct mg_connection *conn,
1509 const char *path,
1510 struct file *filep,
1511 struct lua_State *ls)
1512 {
1513 void *p = NULL;
1514 lua_State *L = NULL;
1515 int error = 1;
1516 struct file filesize = STRUCT_FILE_INITIALIZER;
1517
1518 /* Assume the script does not support keep_alive. The script may change this
1519 * by calling mg.keep_alive(true). */
1520 conn->must_close = 1;
1521
1522 /* We need both mg_stat to get file size, and mg_fopen to get fd */
1523 if (!mg_stat(conn, path, &filesize)) {
1524
1525 /* File not found */
1526 if (ls == NULL) {
1527 send_http_error(conn, 500, "Error: File %s not found", path);
1528 } else {
1529 luaL_error(ls, "File [%s] not found", path);
1530 }
1531
1532 goto cleanup_handle_lsp_request;
1533 }
1534
1535 if (!mg_fopen(conn, path, "r", filep)) {
1536
1537 /* File not found or not accessible */
1538 if (ls == NULL) {
1539 send_http_error(conn,
1540 500,
1541 "Error: Cannot open script file %s",
1542 path);
1543 } else {
1544 luaL_error(ls, "Cannot [%s] not found", path);
1545 }
1546
1547 goto cleanup_handle_lsp_request;
1548 }
1549
1550 /* TODO: Operations mg_fopen and mg_stat should do what their names
1551 * indicate. They should not fill in different members of the same
1552 * struct file.
1553 * See Github issue #225 */
1554 filep->size = filesize.size;
1555
1556 if (filep->membuf == NULL
1557 && (p = mmap(NULL,
1558 (size_t)filep->size,
1559 PROT_READ,
1560 MAP_PRIVATE,
1561 fileno(filep->fp),
1562 0)) == MAP_FAILED) {
1563
1564 /* mmap failed */
1565 if (ls == NULL) {
1566 send_http_error(
1567 conn,
1568 500,
1569 "Error: Cannot open script\nFile %s can not be mapped",
1570 path);
1571 } else {
1572 luaL_error(ls,
1573 "mmap(%s, %zu, %d): %s",
1574 path,
1575 (size_t)filep->size,
1576 fileno(filep->fp),
1577 strerror(errno));
1578 }
1579
1580 goto cleanup_handle_lsp_request;
1581 }
1582
1583 if (ls != NULL) {
1584 L = ls;
1585 } else {
1586 L = lua_newstate(lua_allocator, NULL);
1587 if (L == NULL) {
1588 send_http_error(
1589 conn,
1590 500,
1591 "%s",
1592 "Error: Cannot execute script\nlua_newstate failed");
1593
1594 goto cleanup_handle_lsp_request;
1595 }
1596 prepare_lua_environment(
1597 conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
1598 }
1599
1600 /* Lua state is ready to use */
1601 /* We're not sending HTTP headers here, Lua page must do it. */
1602 error = lsp(conn,
1603 path,
1604 (filep->membuf == NULL) ? (const char *)p
1605 : (const char *)filep->membuf,
1606 filep->size,
1607 L);
1608
1609
1610 cleanup_handle_lsp_request:
1611
1612 if (L != NULL && ls == NULL)
1613 lua_close(L);
1614 if (p != NULL)
1615 munmap(p, filep->size);
1616 mg_fclose(filep);
1617
1618 return error;
1619 }
1620
1621
1622 #ifdef USE_WEBSOCKET
1623 struct mg_shared_lua_websocket_list {
1624 struct lua_websock_data ws;
1625 struct mg_shared_lua_websocket_list *next;
1626 };
1627
1628
1629 static void *
1630 lua_websocket_new(const char *script, struct mg_connection *conn)
1631 {
1632 struct mg_shared_lua_websocket_list **shared_websock_list =
1633 &(conn->ctx->shared_lua_websockets);
1634 struct lua_websock_data *ws;
1635 int err, ok = 0;
1636
1637 assert(conn->lua_websocket_state == NULL);
1638
1639 /* lock list (mg_context global) */
1640 mg_lock_context(conn->ctx);
1641 while (*shared_websock_list) {
1642 /* check if ws already in list */
1643 if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
1644 break;
1645 }
1646 shared_websock_list = &((*shared_websock_list)->next);
1647 }
1648
1649 if (*shared_websock_list == NULL) {
1650 /* add ws to list */
1651 *shared_websock_list = (struct mg_shared_lua_websocket_list *)
1652 mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
1653 if (*shared_websock_list == NULL) {
1654 mg_unlock_context(conn->ctx);
1655 mg_cry(conn, "Cannot create shared websocket struct, OOM");
1656 return NULL;
1657 }
1658 /* init ws list element */
1659 ws = &(*shared_websock_list)->ws;
1660 ws->script = mg_strdup(script); /* TODO (low): handle OOM */
1661 pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
1662 (void)pthread_mutex_lock(&(ws->ws_mutex));
1663 ws->state = lua_newstate(lua_allocator, NULL);
1664 ws->conn[0] = conn;
1665 ws->references = 1;
1666 prepare_lua_environment(
1667 conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
1668 err = luaL_loadfile(ws->state, script);
1669 if (err != 0) {
1670 lua_cry(conn, err, ws->state, script, "load");
1671 }
1672 err = lua_pcall(ws->state, 0, 0, 0);
1673 if (err != 0) {
1674 lua_cry(conn, err, ws->state, script, "init");
1675 }
1676 } else {
1677 /* inc ref count */
1678 ws = &(*shared_websock_list)->ws;
1679 (void)pthread_mutex_lock(&(ws->ws_mutex));
1680 (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
1681 }
1682 mg_unlock_context(conn->ctx);
1683
1684 /* call add */
1685 lua_getglobal(ws->state, "open");
1686 lua_newtable(ws->state);
1687 prepare_lua_request_info(conn, ws->state);
1688 lua_pushstring(ws->state, "client");
1689 lua_pushlightuserdata(ws->state, (void *)conn);
1690 lua_rawset(ws->state, -3);
1691
1692 err = lua_pcall(ws->state, 1, 1, 0);
1693 if (err != 0) {
1694 lua_cry(conn, err, ws->state, script, "open handler");
1695 } else {
1696 if (lua_isboolean(ws->state, -1)) {
1697 ok = lua_toboolean(ws->state, -1);
1698 }
1699 lua_pop(ws->state, 1);
1700 }
1701 if (!ok) {
1702 /* Remove from ws connection list. */
1703 /* TODO (mid): Check if list entry and Lua state needs to be deleted
1704 * (see websocket_close). */
1705 (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
1706 }
1707
1708 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1709
1710 return ok ? (void *)ws : NULL;
1711 }
1712
1713
1714 static int
1715 lua_websocket_data(struct mg_connection *conn,
1716 int bits,
1717 char *data,
1718 size_t data_len,
1719 void *ws_arg)
1720 {
1721 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
1722 int err, ok = 0;
1723
1724 assert(ws != NULL);
1725 assert(ws->state != NULL);
1726
1727 (void)pthread_mutex_lock(&(ws->ws_mutex));
1728
1729 lua_getglobal(ws->state, "data");
1730 lua_newtable(ws->state);
1731 lua_pushstring(ws->state, "client");
1732 lua_pushlightuserdata(ws->state, (void *)conn);
1733 lua_rawset(ws->state, -3);
1734 lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
1735 a meaning according to
1736 http://tools.ietf.org/html/rfc6455,
1737 section 5.2 */
1738 lua_pushnumber(ws->state, bits);
1739 lua_rawset(ws->state, -3);
1740 lua_pushstring(ws->state, "data");
1741 lua_pushlstring(ws->state, data, data_len);
1742 lua_rawset(ws->state, -3);
1743
1744 err = lua_pcall(ws->state, 1, 1, 0);
1745 if (err != 0) {
1746 lua_cry(conn, err, ws->state, ws->script, "data handler");
1747 } else {
1748 if (lua_isboolean(ws->state, -1)) {
1749 ok = lua_toboolean(ws->state, -1);
1750 }
1751 lua_pop(ws->state, 1);
1752 }
1753 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1754
1755 return ok;
1756 }
1757
1758
1759 static int
1760 lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
1761 {
1762 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
1763 int err, ok = 0;
1764
1765 assert(ws != NULL);
1766 assert(ws->state != NULL);
1767
1768 (void)pthread_mutex_lock(&(ws->ws_mutex));
1769
1770 lua_getglobal(ws->state, "ready");
1771 lua_newtable(ws->state);
1772 lua_pushstring(ws->state, "client");
1773 lua_pushlightuserdata(ws->state, (void *)conn);
1774 lua_rawset(ws->state, -3);
1775 err = lua_pcall(ws->state, 1, 1, 0);
1776 if (err != 0) {
1777 lua_cry(conn, err, ws->state, ws->script, "ready handler");
1778 } else {
1779 if (lua_isboolean(ws->state, -1)) {
1780 ok = lua_toboolean(ws->state, -1);
1781 }
1782 lua_pop(ws->state, 1);
1783 }
1784
1785 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1786
1787 return ok;
1788 }
1789
1790
1791 static void
1792 lua_websocket_close(struct mg_connection *conn, void *ws_arg)
1793 {
1794 struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
1795 struct mg_shared_lua_websocket_list **shared_websock_list =
1796 &(conn->ctx->shared_lua_websockets);
1797 int err = 0;
1798 unsigned i;
1799
1800 assert(ws != NULL);
1801 assert(ws->state != NULL);
1802
1803 (void)pthread_mutex_lock(&(ws->ws_mutex));
1804
1805 lua_getglobal(ws->state, "close");
1806 lua_newtable(ws->state);
1807 lua_pushstring(ws->state, "client");
1808 lua_pushlightuserdata(ws->state, (void *)conn);
1809 lua_rawset(ws->state, -3);
1810
1811 err = lua_pcall(ws->state, 1, 0, 0);
1812 if (err != 0) {
1813 lua_cry(conn, err, ws->state, ws->script, "close handler");
1814 }
1815 for (i = 0; i < ws->references; i++) {
1816 if (ws->conn[i] == conn) {
1817 ws->references--;
1818 ws->conn[i] = ws->conn[ws->references];
1819 }
1820 }
1821 /* TODO: Delete lua_websock_data and remove it from the websocket list.
1822 This must only be done, when all connections are closed, and all
1823 asynchronous operations and timers are completed/expired. */
1824 (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
1825
1826 (void)pthread_mutex_unlock(&(ws->ws_mutex));
1827 }
1828 #endif
1829
1830
1831 static void
1832 lua_init_optional_libraries(void)
1833 {
1834 #if !defined(_WIN32)
1835 void *dll_handle = dlopen("libuuid.so", RTLD_LAZY);
1836 pf_uuid_generate.p = dlsym(dll_handle, "uuid_generate");
1837 #else
1838 pf_uuid_generate.p = 0;
1839 #endif
1840 }