kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

lua.c (12865B)



      1 /*
      2  * Copyright (c) 2023 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/types.h>
     18 
     19 #include "kore.h"
     20 
     21 #if !defined(KORE_NO_HTTP)
     22 #include "http.h"
     23 #endif
     24 
     25 #include "lua_api.h"
     26 #include "lua_methods.h"
     27 
     28 struct lua_http_request {
     29 	struct http_request	*req;
     30 };
     31 
     32 struct lua_symbol {
     33 	lua_State		*L;
     34 	int			ref;
     35 	LIST_ENTRY(lua_symbol)	list;
     36 };
     37 
     38 struct lua_module {
     39 	lua_State			*L;
     40 	LIST_HEAD(, lua_symbol)		symbols;
     41 };
     42 
     43 static int	lua_runtime_resolve(const char *, const struct stat *);
     44 static int	lua_runtime_http_request(void *, struct http_request *);
     45 static void	lua_runtime_http_request_free(void *, struct http_request *);
     46 static void	lua_runtime_http_body_chunk(void *, struct http_request *,
     47 		    const void *, size_t);
     48 static int	lua_runtime_validator(void *, struct http_request *,
     49 		    const void *);
     50 static void	lua_runtime_wsmessage(void *, struct connection *,
     51 		    u_int8_t, const void *, size_t);
     52 static void	lua_runtime_execute(void *);
     53 static int	lua_runtime_onload(void *, int);
     54 static void	lua_runtime_signal(void *, int);
     55 static void	lua_runtime_configure(void *, int, char **);
     56 static void	lua_runtime_connect(void *, struct connection *);
     57 
     58 static void	lua_module_load(struct kore_module *);
     59 static void	lua_module_free(struct kore_module *);
     60 static void	lua_module_reload(struct kore_module *);
     61 static void	*lua_module_getsym(struct kore_module *, const char *);
     62 
     63 static void	*lua_mem_alloc(void *, void *, size_t, size_t);
     64 
     65 static int	lua_kore_module_init(lua_State *);
     66 static void	lua_symbol_resolve(struct lua_symbol *, lua_State **);
     67 
     68 static int		lua_argument_get_bool(lua_State *, const char *);
     69 static const char	*lua_argument_get_string(lua_State *, const char *);
     70 
     71 struct kore_module_functions kore_lua_module = {
     72 	.free = lua_module_free,
     73 	.load = lua_module_load,
     74 	.getsym = lua_module_getsym,
     75 	.reload = lua_module_reload
     76 };
     77 
     78 struct kore_runtime kore_lua_runtime = {
     79 	KORE_RUNTIME_LUA,
     80 	.resolve = lua_runtime_resolve,
     81 	.http_request = lua_runtime_http_request,
     82 	.http_body_chunk = lua_runtime_http_body_chunk,
     83 	.http_request_free = lua_runtime_http_request_free,
     84 	.validator = lua_runtime_validator,
     85 	.wsconnect = lua_runtime_connect,
     86 	.wsmessage = lua_runtime_wsmessage,
     87 	.wsdisconnect = lua_runtime_connect,
     88 	.onload = lua_runtime_onload,
     89 	.signal = lua_runtime_signal,
     90 	.connect = lua_runtime_connect,
     91 	.execute = lua_runtime_execute,
     92 	.configure = lua_runtime_configure,
     93 };
     94 
     95 #define LUA_CONSTANT(x)		{ #x, x }
     96 
     97 static struct {
     98 	const char		*symbol;
     99 	int			value;
    100 } lua_integers[] = {
    101 	LUA_CONSTANT(LOG_ERR),
    102 	LUA_CONSTANT(LOG_INFO),
    103 	LUA_CONSTANT(LOG_NOTICE),
    104 	LUA_CONSTANT(HTTP_METHOD_GET),
    105 	LUA_CONSTANT(HTTP_METHOD_PUT),
    106 	LUA_CONSTANT(HTTP_METHOD_POST),
    107 	LUA_CONSTANT(HTTP_METHOD_HEAD),
    108 	LUA_CONSTANT(HTTP_METHOD_PATCH),
    109 	LUA_CONSTANT(HTTP_METHOD_DELETE),
    110 	LUA_CONSTANT(HTTP_METHOD_OPTIONS),
    111 	{ NULL, -1 },
    112 };
    113 
    114 void
    115 kore_lua_init(void)
    116 {
    117 	if (!kore_configure_setting("deployment", "dev"))
    118 		fatal("failed to set initial deployment to dev");
    119 }
    120 
    121 void
    122 kore_lua_cleanup(void)
    123 {
    124 }
    125 
    126 static void *
    127 lua_mem_alloc(void *uptr, void *ptr, size_t osize, size_t nsize)
    128 {
    129 	if (nsize == 0) {
    130 		kore_free(ptr);
    131 		return (NULL);
    132 	}
    133 
    134 	return (kore_realloc(ptr, nsize));
    135 }
    136 
    137 static void
    138 lua_symbol_resolve(struct lua_symbol *sym, lua_State **L)
    139 {
    140 	lua_rawgeti(sym->L, LUA_REGISTRYINDEX, sym->ref);
    141 	*L = sym->L;
    142 }
    143 
    144 static int
    145 lua_argument_get_bool(lua_State *L, const char *field)
    146 {
    147 	int		ret;
    148 
    149 	lua_pushstring(L, field);
    150 	ret = lua_gettable(L, -2);
    151 
    152 	if (ret == LUA_TNIL) {
    153 		lua_pop(L, 1);
    154 		return (0);
    155 	}
    156 
    157 	luaL_argcheck(L, ret == LUA_TBOOLEAN, 0, field);
    158 
    159 	ret = lua_toboolean(L, -1);
    160 	lua_pop(L, 1);
    161 
    162 	return (ret);
    163 }
    164 
    165 static const char *
    166 lua_argument_get_string(lua_State *L, const char *field)
    167 {
    168 	const char	*v;
    169 	int		type;
    170 
    171 	lua_pushstring(L, field);
    172 	type = lua_gettable(L, -2);
    173 
    174 	if (type == LUA_TNIL) {
    175 		lua_pop(L, 1);
    176 		return (NULL);
    177 	}
    178 
    179 	luaL_argcheck(L, type == LUA_TSTRING, 0, field);
    180 
    181 	v = lua_tostring(L, -1);
    182 	lua_pop(L, 1);
    183 
    184 	return (v);
    185 }
    186 
    187 static int
    188 lua_kore_module_init(lua_State *L)
    189 {
    190 	int		i;
    191 
    192 	luaL_newlib(L, lua_kore_functions);
    193 
    194 	for (i = 0; lua_integers[i].symbol != NULL; i++) {
    195 		lua_pushstring(L, lua_integers[i].symbol);
    196 		lua_pushnumber(L, lua_integers[i].value);
    197 		lua_settable(L, -3);
    198 	}
    199 
    200 	return (1);
    201 }
    202 
    203 static void
    204 lua_module_free(struct kore_module *module)
    205 {
    206 	struct lua_symbol	*sym;
    207 	struct lua_module	*lua;
    208 
    209 	lua = module->handle;
    210 
    211 	while ((sym = LIST_FIRST(&lua->symbols)) != NULL) {
    212 		LIST_REMOVE(sym, list);
    213 		kore_free(sym);
    214 	}
    215 
    216 	kore_free(lua);
    217 }
    218 
    219 static void
    220 lua_module_reload(struct kore_module *module)
    221 {
    222 	lua_module_free(module);
    223 	lua_module_load(module);
    224 }
    225 
    226 static void
    227 lua_module_load(struct kore_module *module)
    228 {
    229 	struct lua_module	*lua;
    230 
    231 	lua = kore_calloc(1, sizeof(*lua));
    232 	LIST_INIT(&lua->symbols);
    233 
    234 	if ((lua->L = lua_newstate(lua_mem_alloc, NULL)) == NULL)
    235 		fatal("luaL_newstate");
    236 
    237 	luaL_openlibs(lua->L);
    238 
    239 	luaL_requiref(lua->L, "kore", lua_kore_module_init, 1);
    240 	lua_pop(lua->L, 1);
    241 
    242 	luaL_newmetatable(lua->L, "http_request");
    243 	luaL_setfuncs(lua->L, lua_http_request_meta, 0);
    244 	lua_pop(lua->L, 1);
    245 
    246 	lua_pushliteral(lua->L, "http_request_methods");
    247 	luaL_newlib(lua->L, lua_http_request_methods);
    248 	lua_settable(lua->L, LUA_REGISTRYINDEX);
    249 
    250 	luaL_newlib(lua->L, lua_http_request_methods);
    251 	lua_pop(lua->L, 1);
    252 
    253 	if (luaL_loadfile(lua->L, module->path) != LUA_OK) {
    254 		fatal("%s: failed to import module (%s)", module->path,
    255 		    lua_tostring(lua->L, -1));
    256 	}
    257 
    258 	if (lua_pcall(lua->L, 0, 0, 0) != LUA_OK) {
    259 		fatal("%s: failed to import module (%s)", module->path,
    260 		    lua_tostring(lua->L, -1));
    261 	}
    262 
    263 	module->handle = lua;
    264 }
    265 
    266 static void *
    267 lua_module_getsym(struct kore_module *module, const char *symbol)
    268 {
    269 	int			ref;
    270 	struct lua_module	*lua;
    271 	struct lua_symbol	*sym;
    272 
    273 	lua = module->handle;
    274 
    275 	if (lua_getglobal(lua->L, symbol) != LUA_TFUNCTION)
    276 		return (NULL);
    277 
    278 	if ((ref = luaL_ref(lua->L, LUA_REGISTRYINDEX)) == LUA_REFNIL)
    279 		return (NULL);
    280 
    281 	sym = kore_calloc(1, sizeof(*sym));
    282 
    283 	sym->ref = ref;
    284 	sym->L = lua->L;
    285 
    286 	LIST_INSERT_HEAD(&lua->symbols, sym, list);
    287 
    288 	return (sym);
    289 }
    290 
    291 static int
    292 lua_runtime_resolve(const char *module, const struct stat *st)
    293 {
    294 	const char	*ext;
    295 
    296 	if (!S_ISREG(st->st_mode))
    297 		return (KORE_RESULT_ERROR);
    298 
    299 	ext = strrchr(module, '.');
    300 
    301 	if (ext == NULL || strcasecmp(ext, ".lua"))
    302 		return (KORE_RESULT_ERROR);
    303 
    304 	kore_module_load(module, NULL, KORE_MODULE_LUA);
    305 
    306 	return (KORE_RESULT_OK);
    307 }
    308 
    309 static int
    310 lua_runtime_http_request(void *addr, struct http_request *req)
    311 {
    312 	lua_State			*L;
    313 	struct lua_http_request		*lreq;
    314 
    315 	lua_symbol_resolve(addr, &L);
    316 
    317 	lreq = lua_newuserdata(L, sizeof(*lreq));
    318 	luaL_setmetatable(L, "http_request");
    319 
    320 	lreq->req = req;
    321 
    322 	if (lua_pcall(L, 1, 0, 0)) {
    323 		kore_log(LOG_NOTICE, "%s: failed to call handler: %s", __func__,
    324 		    lua_tostring(L, -1));
    325 		http_response(req, 500, NULL, 0);
    326 		return (KORE_RESULT_OK);
    327 	}
    328 
    329 	return (KORE_RESULT_OK);
    330 }
    331 
    332 static void
    333 lua_runtime_http_request_free(void *addr, struct http_request *req)
    334 {
    335 	fatal("%s: not yet implemented", __func__);
    336 }
    337 
    338 static void
    339 lua_runtime_http_body_chunk(void *addr, struct http_request *req,
    340     const void *data, size_t len)
    341 {
    342 	fatal("%s: not yet implemented", __func__);
    343 }
    344 
    345 static int
    346 lua_runtime_validator(void *addr, struct http_request *req, const void *data)
    347 {
    348 	fatal("%s: not yet implemented", __func__);
    349 
    350 	return (KORE_RESULT_ERROR);
    351 }
    352 
    353 static void
    354 lua_runtime_wsmessage(void *addr, struct connection *c, u_int8_t op,
    355     const void *data, size_t len)
    356 {
    357 	fatal("%s: not yet implemented", __func__);
    358 }
    359 
    360 static void
    361 lua_runtime_execute(void *addr)
    362 {
    363 	lua_State	*L;
    364 
    365 	lua_symbol_resolve(addr, &L);
    366 
    367 	if (lua_pcall(L, 0, 0, 0)) {
    368 		fatal("failed to execute function: %s",
    369 		    lua_tostring(L, -1));
    370 	}
    371 }
    372 
    373 static void
    374 lua_runtime_configure(void *addr, int argc, char **argv)
    375 {
    376 	lua_State	*L;
    377 	int		idx;
    378 
    379 	lua_symbol_resolve(addr, &L);
    380 
    381 	lua_pushinteger(L, argc);
    382 	lua_newtable(L);
    383 
    384 	for (idx = 0; idx < argc; idx++) {
    385 		lua_pushstring(L, argv[idx]);
    386 		lua_rawseti(L, -2, idx);
    387 	}
    388 
    389 	if (lua_pcall(L, 2, 0, 0)) {
    390 		fatal("failed to configure your application (%s)",
    391 		    lua_tostring(L, -1));
    392 	}
    393 }
    394 
    395 static int
    396 lua_runtime_onload(void *addr, int action)
    397 {
    398 	fatal("%s: not yet implemented", __func__);
    399 
    400 	return (KORE_RESULT_ERROR);
    401 }
    402 
    403 static void
    404 lua_runtime_connect(void *addr, struct connection *c)
    405 {
    406 	fatal("%s: not yet implemented", __func__);
    407 }
    408 
    409 static void
    410 lua_runtime_signal(void *addr, int sig)
    411 {
    412 	fatal("%s: not yet implemented", __func__);
    413 }
    414 
    415 static int
    416 lua_kore_config(lua_State *L)
    417 {
    418 	char		*v;
    419 	const char	*opt, *val;
    420 
    421 	lua_pushnil(L);
    422 
    423 	while (lua_next(L, -2) != 0) {
    424 		if (!lua_isstring(L, -2))
    425 			fatal("kore.config: keyword not a string");
    426 
    427 		opt = lua_tostring(L, -2);
    428 
    429 		if (lua_isinteger(L, -1)) {
    430 			lua_pushvalue(L, -1);
    431 			val = lua_tostring(L, -1);
    432 			lua_pop(L, 1);
    433 		} else if (lua_isstring(L, -1)) {
    434 			val = lua_tostring(L, -1);
    435 		} else {
    436 			fatal("kore.config: value not a string or integer");
    437 		}
    438 
    439 		v = kore_strdup(val);
    440 
    441 		if (!kore_configure_setting(opt, v)) {
    442 			kore_free(v);
    443 			luaL_error(L, "kore.config: cannot be set at runtime");
    444 			lua_pop(L, 1);
    445 			return (0);
    446 		}
    447 
    448 		kore_free(v);
    449 		lua_pop(L, 1);
    450 	}
    451 
    452 	return (0);
    453 }
    454 
    455 static int
    456 lua_kore_server(lua_State *L)
    457 {
    458 	struct kore_server	*srv;
    459 	const char		*name, *ip, *port;
    460 
    461 	if ((name = lua_argument_get_string(L, "name")) == NULL)
    462 		name = "default";
    463 
    464 	if ((ip = lua_argument_get_string(L, "ip")) == NULL) {
    465 		luaL_error(L, "kore.server: missing ip keyword");
    466 		return (0);
    467 	}
    468 
    469 	if ((port = lua_argument_get_string(L, "port")) == NULL) {
    470 		luaL_error(L, "kore.server: missing port keyword");
    471 		return (0);
    472 	}
    473 
    474 	if ((srv = kore_server_lookup(name)) != NULL) {
    475 		luaL_error(L, "kore.server: server '%s' exists", name);
    476 		return (0);
    477 	}
    478 
    479 	srv = kore_server_create(name);
    480 	srv->tls = lua_argument_get_bool(L, "tls");
    481 
    482 	if (srv->tls && !kore_tls_supported()) {
    483 		kore_server_free(srv);
    484 		luaL_error(L, "kore.server: TLS not supported");
    485 		return (0);
    486 	}
    487 
    488 	if (!kore_server_bind(srv, ip, port, NULL)) {
    489 		kore_server_free(srv);
    490 		luaL_error(L, "kore.server: failed to bind %s:%s", ip, port);
    491 		return (0);
    492 	}
    493 
    494 	kore_server_finalize(srv);
    495 
    496 	return (0);
    497 }
    498 
    499 static int
    500 lua_http_request_gc(lua_State *L)
    501 {
    502 	struct lua_http_request		*lreq;
    503 
    504 	lreq = luaL_checkudata(L, 1, "http_request");
    505 	kore_free(lreq);
    506 
    507 	return (0);
    508 }
    509 
    510 static int
    511 lua_http_request_index(lua_State *L)
    512 {
    513 	struct lua_http_request		*lreq;
    514 	const char			*field;
    515 
    516 	lreq = luaL_checkudata(L, 1, "http_request");
    517 	field = luaL_checkstring(L, 2);
    518 
    519 	lua_getfield(L, LUA_REGISTRYINDEX, "http_request_methods");
    520 	lua_getfield(L, -1, field);
    521 
    522 	if (!lua_isnil(L, -1))
    523 		return (1);
    524 
    525 	lua_pop(L, 2);
    526 
    527 	if (!strcmp(field, "path")) {
    528 		lua_pushstring(L, lreq->req->path);
    529 		return (1);
    530 	} else if (!strcmp(field, "host")) {
    531 		lua_pushstring(L, lreq->req->host);
    532 		return (1);
    533 	} else if (!strcmp(field, "agent")) {
    534 		lua_pushstring(L, lreq->req->agent);
    535 		return (1);
    536 	} else if (!strcmp(field, "referer")) {
    537 		lua_pushstring(L, lreq->req->referer);
    538 		return (1);
    539 	} else if (!strcmp(field, "method")) {
    540 		lua_pushinteger(L, lreq->req->method);
    541 		return (1);
    542 	}
    543 
    544 	return (0);
    545 }
    546 
    547 static int
    548 lua_http_response_header(lua_State *L)
    549 {
    550 	struct lua_http_request		*lreq;
    551 	const char			*header, *value;
    552 
    553 	lreq = luaL_checkudata(L, 1, "http_request");
    554 	header = luaL_checkstring(L, 2);
    555 	value = luaL_checkstring(L, 3);
    556 
    557 	http_response_header(lreq->req, header, value);
    558 
    559 	return (0);
    560 }
    561 
    562 static int
    563 lua_http_request_header(lua_State *L)
    564 {
    565 	struct lua_http_request		*lreq;
    566 	const char			*header, *value;
    567 
    568 	lreq = luaL_checkudata(L, 1, "http_request");
    569 	header = luaL_checkstring(L, 2);
    570 
    571 	if (!http_request_header(lreq->req, header, &value)) {
    572 		lua_pushnil(L);
    573 	} else {
    574 		lua_pushstring(L, value);
    575 	}
    576 
    577 	return (1);
    578 }
    579 
    580 static int
    581 lua_http_response(lua_State *L)
    582 {
    583 	size_t				len;
    584 	struct lua_http_request		*lreq;
    585 	const void			*data;
    586 	int				status;
    587 
    588 	lreq = luaL_checkudata(L, 1, "http_request");
    589 	status = luaL_checkinteger(L, 2);
    590 
    591 	if (lua_isnil(L, 3)) {
    592 		len = 0;
    593 		data = NULL;
    594 	} else {
    595 		data = luaL_checklstring(L, 3, &len);
    596 	}
    597 
    598 	http_response(lreq->req, status, data, len);
    599 
    600 	return (0);
    601 }