|
@@ -48,6 +48,13 @@ munmap(void *addr, int64_t length)
|
|
|
static const char *LUASOCKET = "luasocket";
|
|
|
static const char lua_regkey_ctx = 1;
|
|
|
static const char lua_regkey_connlist = 2;
|
|
|
+static const char lua_regkey_lsp_include_history = 3;
|
|
|
+static const char *LUABACKGROUNDPARAMS = "mg";
|
|
|
+
|
|
|
+#ifndef LSP_INCLUDE_MAX_DEPTH
|
|
|
+#define LSP_INCLUDE_MAX_DEPTH (32)
|
|
|
+#endif
|
|
|
+
|
|
|
|
|
|
/* Forward declarations */
|
|
|
static void handle_request(struct mg_connection *);
|
|
@@ -69,6 +76,20 @@ reg_lstring(struct lua_State *L,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+reg_llstring(struct lua_State *L,
|
|
|
+ const void *buffer1,
|
|
|
+ size_t buflen1,
|
|
|
+ const void *buffer2,
|
|
|
+ size_t buflen2)
|
|
|
+{
|
|
|
+ if (buffer1 != NULL && buffer2 != NULL) {
|
|
|
+ lua_pushlstring(L, (const char *)buffer1, buflen1);
|
|
|
+ lua_pushlstring(L, (const char *)buffer2, buflen2);
|
|
|
+ lua_rawset(L, -3);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#define reg_string(L, name, val) \
|
|
|
reg_lstring(L, name, val, val ? strlen(val) : 0)
|
|
|
|
|
@@ -368,11 +389,11 @@ lsp_var_reader(lua_State *L, void *ud, size_t *sz)
|
|
|
|
|
|
|
|
|
static int
|
|
|
-lsp(struct mg_connection *conn,
|
|
|
- const char *path,
|
|
|
- const char *p,
|
|
|
- int64_t len,
|
|
|
- lua_State *L)
|
|
|
+run_lsp(struct mg_connection *conn,
|
|
|
+ const char *path,
|
|
|
+ const char *p,
|
|
|
+ int64_t len,
|
|
|
+ lua_State *L)
|
|
|
{
|
|
|
int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
|
|
|
char chunkname[MG_BUF_LEN];
|
|
@@ -520,6 +541,13 @@ lsp_keep_alive(lua_State *L)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* Stack of includes */
|
|
|
+struct lsp_include_history {
|
|
|
+ int depth;
|
|
|
+ const char *script[LSP_INCLUDE_MAX_DEPTH + 1];
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
/* mg.include: Include another .lp file */
|
|
|
static int
|
|
|
lsp_include(lua_State *L)
|
|
@@ -528,16 +556,92 @@ lsp_include(lua_State *L)
|
|
|
(struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
|
|
|
int num_args = lua_gettop(L);
|
|
|
struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
|
- const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+ const char *file_name = (num_args >= 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+ const char *path_type = (num_args >= 2) ? lua_tostring(L, 2) : NULL;
|
|
|
+ struct lsp_include_history *include_history;
|
|
|
|
|
|
- if (filename) {
|
|
|
- if (handle_lsp_request(conn, filename, &file, L)) {
|
|
|
- /* handle_lsp_request returned an error code, meaning an error
|
|
|
- occured in
|
|
|
- the included page and mg.onerror returned non-zero. Stop processing.
|
|
|
- */
|
|
|
- lsp_abort(L);
|
|
|
+ if ((file_name) && (num_args <= 2)) {
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
|
|
|
+
|
|
|
+ if (include_history->depth >= ((int)(LSP_INCLUDE_MAX_DEPTH))) {
|
|
|
+ mg_cry(conn,
|
|
|
+ "lsp max include depth of %i reached while including %s",
|
|
|
+ (int)(LSP_INCLUDE_MAX_DEPTH),
|
|
|
+ file_name);
|
|
|
+ } else {
|
|
|
+ char file_name_path[512];
|
|
|
+ char *p;
|
|
|
+ size_t len;
|
|
|
+ int truncated = 0;
|
|
|
+
|
|
|
+ file_name_path[511] = 0;
|
|
|
+
|
|
|
+ if (path_type && (*path_type == 'v')) {
|
|
|
+ /* "virtual" = relative to document root. */
|
|
|
+ (void)mg_snprintf(conn,
|
|
|
+ &truncated,
|
|
|
+ file_name_path,
|
|
|
+ sizeof(file_name_path),
|
|
|
+ "%s/%s",
|
|
|
+ conn->ctx->config[DOCUMENT_ROOT],
|
|
|
+ file_name);
|
|
|
+
|
|
|
+ } else if ((path_type && (*path_type == 'a'))
|
|
|
+ || (path_type == NULL)) {
|
|
|
+ /* "absolute" = file name is relative to the
|
|
|
+ * webserver working directory
|
|
|
+ * or it is absolute system path. */
|
|
|
+ /* path_type==NULL is the legacy use case with 1 argument */
|
|
|
+ (void)mg_snprintf(conn,
|
|
|
+ &truncated,
|
|
|
+ file_name_path,
|
|
|
+ sizeof(file_name_path),
|
|
|
+ "%s",
|
|
|
+ file_name);
|
|
|
+
|
|
|
+ } else if (path_type && (*path_type == 'r' || *path_type == 'f')) {
|
|
|
+ /* "relative" = file name is relative to the
|
|
|
+ * currect document */
|
|
|
+ (void)mg_snprintf(
|
|
|
+ conn,
|
|
|
+ &truncated,
|
|
|
+ file_name_path,
|
|
|
+ sizeof(file_name_path),
|
|
|
+ "%s",
|
|
|
+ include_history->script[include_history->depth]);
|
|
|
+
|
|
|
+ if (!truncated) {
|
|
|
+ if ((p = strrchr(file_name_path, '/')) != NULL) {
|
|
|
+ p[1] = '\0';
|
|
|
+ }
|
|
|
+ len = strlen(file_name_path);
|
|
|
+ (void)mg_snprintf(conn,
|
|
|
+ &truncated,
|
|
|
+ file_name_path + len,
|
|
|
+ sizeof(file_name_path) - len,
|
|
|
+ "%s",
|
|
|
+ file_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ return luaL_error(
|
|
|
+ L,
|
|
|
+ "invalid path_type in include(file_name, path_type) call");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (handle_lsp_request(conn, file_name_path, &file, L)) {
|
|
|
+ /* handle_lsp_request returned an error code, meaning an error
|
|
|
+ * occured in the included page and mg.onerror returned non-zero.
|
|
|
+ * Stop processing.
|
|
|
+ */
|
|
|
+
|
|
|
+ lsp_abort(L);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
} else {
|
|
|
/* Syntax error */
|
|
|
return luaL_error(L, "invalid include() call");
|
|
@@ -629,15 +733,25 @@ lsp_get_var(lua_State *L)
|
|
|
const char *data, *var_name;
|
|
|
size_t data_len, occurrence;
|
|
|
int ret;
|
|
|
- char dst[512];
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args >= 2 && num_args <= 3) {
|
|
|
+ char *dst;
|
|
|
data = lua_tolstring(L, 1, &data_len);
|
|
|
var_name = lua_tostring(L, 2);
|
|
|
occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
|
|
|
|
|
|
- ret =
|
|
|
- mg_get_var2(data, data_len, var_name, dst, sizeof(dst), occurrence);
|
|
|
+ /* Allocate dynamically, so there is no internal limit for get_var */
|
|
|
+ dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
|
|
|
+ if (!dst) {
|
|
|
+ return luaL_error(L, "out of memory in get_var() call");
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = mg_get_var2(data, data_len, var_name, dst, data_len, occurrence);
|
|
|
if (ret >= 0) {
|
|
|
/* Variable found: return value to Lua */
|
|
|
lua_pushstring(L, dst);
|
|
@@ -645,6 +759,7 @@ lsp_get_var(lua_State *L)
|
|
|
/* Variable not found (TODO (mid): may be string too long) */
|
|
|
lua_pushnil(L);
|
|
|
}
|
|
|
+ mg_free(dst);
|
|
|
} else {
|
|
|
/* Syntax error */
|
|
|
return luaL_error(L, "invalid get_var() call");
|
|
@@ -696,22 +811,39 @@ lsp_get_cookie(lua_State *L)
|
|
|
const char *cookie;
|
|
|
const char *var_name;
|
|
|
int ret;
|
|
|
- char dst[512];
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args == 2) {
|
|
|
- cookie = lua_tostring(L, 1);
|
|
|
+ /* Correct number of arguments */
|
|
|
+ size_t data_len;
|
|
|
+ char *dst;
|
|
|
+
|
|
|
+ cookie = lua_tolstring(L, 1, &data_len);
|
|
|
var_name = lua_tostring(L, 2);
|
|
|
- if (cookie != NULL && var_name != NULL) {
|
|
|
- ret = mg_get_cookie(cookie, var_name, dst, sizeof(dst));
|
|
|
- } else {
|
|
|
- ret = -1;
|
|
|
+
|
|
|
+ if (cookie == NULL || var_name == NULL) {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_cookie() call");
|
|
|
}
|
|
|
|
|
|
+ dst = (char *)mg_malloc_ctx(data_len + 1, ctx);
|
|
|
+ if (!dst) {
|
|
|
+ return luaL_error(L, "out of memory in get_cookie() call");
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = mg_get_cookie(cookie, var_name, dst, data_len);
|
|
|
+
|
|
|
if (ret >= 0) {
|
|
|
lua_pushlstring(L, dst, ret);
|
|
|
} else {
|
|
|
lua_pushnil(L);
|
|
|
}
|
|
|
+ mg_free(dst);
|
|
|
+
|
|
|
} else {
|
|
|
/* Syntax error */
|
|
|
return luaL_error(L, "invalid get_cookie() call");
|
|
@@ -757,13 +889,27 @@ lsp_url_encode(lua_State *L)
|
|
|
int num_args = lua_gettop(L);
|
|
|
const char *text;
|
|
|
size_t text_len;
|
|
|
- char dst[512 * 3];
|
|
|
+ char *dst;
|
|
|
+ int dst_len;
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args == 1) {
|
|
|
text = lua_tolstring(L, 1, &text_len);
|
|
|
if (text) {
|
|
|
- mg_url_encode(text, dst, sizeof(dst));
|
|
|
- lua_pushstring(L, dst);
|
|
|
+ dst_len = 3 * (int)text_len + 1;
|
|
|
+ dst = ((text_len < 0x2AAAAAAA) ? (char *)mg_malloc_ctx(dst_len, ctx)
|
|
|
+ : (char *)NULL);
|
|
|
+ if (dst) {
|
|
|
+ mg_url_encode(text, dst, dst_len);
|
|
|
+ lua_pushstring(L, dst);
|
|
|
+ mg_free(dst);
|
|
|
+ } else {
|
|
|
+ return luaL_error(L, "out of memory in url_decode() call");
|
|
|
+ }
|
|
|
} else {
|
|
|
lua_pushnil(L);
|
|
|
}
|
|
@@ -783,14 +929,28 @@ lsp_url_decode(lua_State *L)
|
|
|
const char *text;
|
|
|
size_t text_len;
|
|
|
int is_form;
|
|
|
- char dst[512];
|
|
|
+ char *dst;
|
|
|
+ int dst_len;
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
|
|
|
text = lua_tolstring(L, 1, &text_len);
|
|
|
is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
|
|
|
if (text) {
|
|
|
- mg_url_decode(text, (int)text_len, dst, (int)sizeof(dst), is_form);
|
|
|
- lua_pushstring(L, dst);
|
|
|
+ dst_len = (int)text_len + 1;
|
|
|
+ dst = ((text_len < 0x7FFFFFFF) ? (char *)mg_malloc_ctx(dst_len, ctx)
|
|
|
+ : (char *)NULL);
|
|
|
+ if (dst) {
|
|
|
+ mg_url_decode(text, (int)text_len, dst, dst_len, is_form);
|
|
|
+ lua_pushstring(L, dst);
|
|
|
+ mg_free(dst);
|
|
|
+ } else {
|
|
|
+ return luaL_error(L, "out of memory in url_decode() call");
|
|
|
+ }
|
|
|
} else {
|
|
|
lua_pushnil(L);
|
|
|
}
|
|
@@ -810,11 +970,16 @@ lsp_base64_encode(lua_State *L)
|
|
|
const char *text;
|
|
|
size_t text_len;
|
|
|
char *dst;
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args == 1) {
|
|
|
text = lua_tolstring(L, 1, &text_len);
|
|
|
if (text) {
|
|
|
- dst = (char *)mg_malloc(text_len * 8 / 6 + 4);
|
|
|
+ dst = (char *)mg_malloc_ctx(text_len * 8 / 6 + 4, ctx);
|
|
|
if (dst) {
|
|
|
base64_encode((const unsigned char *)text, (int)text_len, dst);
|
|
|
lua_pushstring(L, dst);
|
|
@@ -842,11 +1007,16 @@ lsp_base64_decode(lua_State *L)
|
|
|
size_t text_len, dst_len;
|
|
|
int ret;
|
|
|
char *dst;
|
|
|
+ struct mg_context *ctx;
|
|
|
+
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
|
|
if (num_args == 1) {
|
|
|
text = lua_tolstring(L, 1, &text_len);
|
|
|
if (text) {
|
|
|
- dst = (char *)mg_malloc(text_len);
|
|
|
+ dst = (char *)mg_malloc_ctx(text_len, ctx);
|
|
|
if (dst) {
|
|
|
ret = base64_decode((const unsigned char *)text,
|
|
|
(int)text_len,
|
|
@@ -925,6 +1095,186 @@ lsp_random(lua_State *L)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* mg.get_info */
|
|
|
+static int
|
|
|
+lsp_get_info(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ int type1, type2;
|
|
|
+ const char *arg1;
|
|
|
+ double arg2;
|
|
|
+ int len;
|
|
|
+ char *buf;
|
|
|
+
|
|
|
+ if (num_args == 1) {
|
|
|
+ type1 = lua_type(L, 1);
|
|
|
+ if (type1 == LUA_TSTRING) {
|
|
|
+ arg1 = lua_tostring(L, 1);
|
|
|
+ /* Get info according to argument */
|
|
|
+ if (!mg_strcasecmp(arg1, "system")) {
|
|
|
+ /* Get system info */
|
|
|
+ len = mg_get_system_info(NULL, 0);
|
|
|
+ if (len > 0) {
|
|
|
+ buf = mg_malloc(len + 64);
|
|
|
+ if (!buf) {
|
|
|
+ return luaL_error(L, "OOM in get_info() call");
|
|
|
+ }
|
|
|
+ len = mg_get_system_info(buf, len + 63);
|
|
|
+ lua_pushlstring(L, buf, len);
|
|
|
+ mg_free(buf);
|
|
|
+ } else {
|
|
|
+ lua_pushstring(L, "");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (!mg_strcasecmp(arg1, "context")) {
|
|
|
+ /* Get context */
|
|
|
+ struct mg_context *ctx;
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
+
|
|
|
+ /* Get context info for server context */
|
|
|
+ len = mg_get_context_info(ctx, NULL, 0);
|
|
|
+ if (len > 0) {
|
|
|
+ buf = mg_malloc(len + 64);
|
|
|
+ if (!buf) {
|
|
|
+ return luaL_error(L, "OOM in get_info() call");
|
|
|
+ }
|
|
|
+ len = mg_get_context_info(ctx, buf, len + 63);
|
|
|
+ lua_pushlstring(L, buf, len);
|
|
|
+ mg_free(buf);
|
|
|
+ } else {
|
|
|
+ lua_pushstring(L, "");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (!mg_strcasecmp(arg1, "common")) {
|
|
|
+ /* Get context info for NULL context */
|
|
|
+ len = mg_get_context_info(NULL, NULL, 0);
|
|
|
+ if (len > 0) {
|
|
|
+ buf = mg_malloc(len + 64);
|
|
|
+ if (!buf) {
|
|
|
+ return luaL_error(L, "OOM in get_info() call");
|
|
|
+ }
|
|
|
+ len = mg_get_context_info(NULL, buf, len + 63);
|
|
|
+ lua_pushlstring(L, buf, len);
|
|
|
+ mg_free(buf);
|
|
|
+ } else {
|
|
|
+ lua_pushstring(L, "");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num_args == 2) {
|
|
|
+ type1 = lua_type(L, 1);
|
|
|
+ type2 = lua_type(L, 2);
|
|
|
+ if ((type1 == LUA_TSTRING) && (type2 == LUA_TNUMBER)) {
|
|
|
+ arg1 = lua_tostring(L, 1);
|
|
|
+ arg2 = lua_tonumber(L, 2);
|
|
|
+
|
|
|
+ /* Get info according to argument */
|
|
|
+ if (!mg_strcasecmp(arg1, "connection")) {
|
|
|
+
|
|
|
+ /* Get context */
|
|
|
+ struct mg_context *ctx;
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
+
|
|
|
+ /* Get connection info for connection idx */
|
|
|
+ int idx = (int)(arg2 + 0.5);
|
|
|
+
|
|
|
+ /* Lua uses 1 based index, C uses 0 based index */
|
|
|
+ idx--;
|
|
|
+
|
|
|
+#ifdef MG_EXPERIMENTAL_INTERFACES
|
|
|
+ len = mg_get_connection_info(ctx, idx, NULL, 0);
|
|
|
+ if (len > 0) {
|
|
|
+ buf = mg_malloc(len + 64);
|
|
|
+ if (!buf) {
|
|
|
+ return luaL_error(L, "OOM in get_info() call");
|
|
|
+ }
|
|
|
+ len = mg_get_connection_info(ctx, idx, buf, len + 63);
|
|
|
+ lua_pushlstring(L, buf, len);
|
|
|
+ mg_free(buf);
|
|
|
+ } else {
|
|
|
+ lua_pushstring(L, "");
|
|
|
+ }
|
|
|
+#else
|
|
|
+ (void)ctx;
|
|
|
+ (void)idx;
|
|
|
+ lua_pushstring(L, "");
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_info() call");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* mg.get_option */
|
|
|
+static int
|
|
|
+lsp_get_option(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ int type1;
|
|
|
+ const char *arg1;
|
|
|
+ const char *data;
|
|
|
+
|
|
|
+ /* Get context */
|
|
|
+ struct mg_context *ctx;
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
+
|
|
|
+ if (num_args == 0) {
|
|
|
+ const struct mg_option *opts = mg_get_valid_options();
|
|
|
+
|
|
|
+ if (!opts) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ lua_newtable(L);
|
|
|
+ while (opts->name) {
|
|
|
+ data = mg_get_option(ctx, opts->name);
|
|
|
+ if (data) {
|
|
|
+ reg_string(L, opts->name, data);
|
|
|
+ }
|
|
|
+ opts++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num_args == 1) {
|
|
|
+ type1 = lua_type(L, 1);
|
|
|
+ if (type1 == LUA_TSTRING) {
|
|
|
+ arg1 = lua_tostring(L, 1);
|
|
|
+ /* Get option according to argument */
|
|
|
+ data = mg_get_option(ctx, arg1);
|
|
|
+ if (data) {
|
|
|
+ lua_pushstring(L, data);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_option() call");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* UUID library and function pointer */
|
|
|
union {
|
|
|
void *p;
|
|
|
void (*f)(unsigned char uuid[16]);
|
|
@@ -1068,12 +1418,16 @@ lwebsock_write(lua_State *L)
|
|
|
if (client) {
|
|
|
for (i = 0; i < ws->references; i++) {
|
|
|
if (client == ws->conn[i]) {
|
|
|
+ mg_lock_connection(ws->conn[i]);
|
|
|
mg_websocket_write(ws->conn[i], opcode, str, size);
|
|
|
+ mg_unlock_connection(ws->conn[i]);
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
for (i = 0; i < ws->references; i++) {
|
|
|
+ mg_lock_connection(ws->conn[i]);
|
|
|
mg_websocket_write(ws->conn[i], opcode, str, size);
|
|
|
+ mg_unlock_connection(ws->conn[i]);
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
@@ -1185,8 +1539,9 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
|
|
|
timediff = (double)lua_tonumber(L, 2);
|
|
|
txt = lua_tostring(L, 1);
|
|
|
txt_len = strlen(txt);
|
|
|
- arg = (struct laction_arg *)mg_malloc(sizeof(struct laction_arg)
|
|
|
- + txt_len + 10);
|
|
|
+ arg = (struct laction_arg *)mg_malloc_ctx(sizeof(struct laction_arg)
|
|
|
+ + txt_len + 10,
|
|
|
+ ctx);
|
|
|
arg->state = L;
|
|
|
arg->script = ws->script;
|
|
|
arg->pmutex = &(ws->ws_mutex);
|
|
@@ -1310,7 +1665,7 @@ prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
|
|
|
}
|
|
|
|
|
|
|
|
|
-void
|
|
|
+static void
|
|
|
civetweb_open_lua_libs(lua_State *L)
|
|
|
{
|
|
|
{
|
|
@@ -1384,6 +1739,17 @@ prepare_lua_environment(struct mg_context *ctx,
|
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
|
}
|
|
|
|
|
|
+ /* Lua server pages store the depth of mg.include, in order
|
|
|
+ * to detect recursions and prevent stack overflows. */
|
|
|
+ if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
|
|
|
+ struct lsp_include_history *h;
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
|
|
|
+ h = (struct lsp_include_history *)
|
|
|
+ lua_newuserdata(L, sizeof(struct lsp_include_history));
|
|
|
+ lua_settable(L, LUA_REGISTRYINDEX);
|
|
|
+ memset(h, 0, sizeof(struct lsp_include_history));
|
|
|
+ }
|
|
|
+
|
|
|
/* Register mg module */
|
|
|
lua_newtable(L);
|
|
|
|
|
@@ -1433,6 +1799,9 @@ prepare_lua_environment(struct mg_context *ctx,
|
|
|
reg_function(L, "base64_decode", lsp_base64_decode);
|
|
|
reg_function(L, "get_response_code_text", lsp_get_response_code_text);
|
|
|
reg_function(L, "random", lsp_random);
|
|
|
+ reg_function(L, "get_info", lsp_get_info);
|
|
|
+ reg_function(L, "get_option", lsp_get_option);
|
|
|
+
|
|
|
if (pf_uuid_generate.f) {
|
|
|
reg_function(L, "uuid", lsp_uuid);
|
|
|
}
|
|
@@ -1510,14 +1879,13 @@ lua_error_handler(lua_State *L)
|
|
|
static void *
|
|
|
lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
|
|
|
{
|
|
|
- (void)ud;
|
|
|
(void)osize; /* not used */
|
|
|
|
|
|
if (nsize == 0) {
|
|
|
mg_free(ptr);
|
|
|
return NULL;
|
|
|
}
|
|
|
- return mg_realloc(ptr, nsize);
|
|
|
+ return mg_realloc_ctx(ptr, nsize, (struct mg_context *)ud);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1534,7 +1902,8 @@ mg_exec_lua_script(struct mg_connection *conn,
|
|
|
conn->must_close = 1;
|
|
|
|
|
|
/* Execute a plain Lua script. */
|
|
|
- if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
|
|
|
+ if (path != NULL
|
|
|
+ && (L = lua_newstate(lua_allocator, (void *)(conn->ctx))) != NULL) {
|
|
|
prepare_lua_environment(
|
|
|
conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
|
|
|
lua_pushcclosure(L, &lua_error_handler, 0);
|
|
@@ -1576,47 +1945,30 @@ handle_lsp_request(struct mg_connection *conn,
|
|
|
{
|
|
|
void *p = NULL;
|
|
|
lua_State *L = NULL;
|
|
|
+ struct lsp_include_history *include_history;
|
|
|
int error = 1;
|
|
|
- struct mg_file filesize = STRUCT_FILE_INITIALIZER;
|
|
|
|
|
|
/* Assume the script does not support keep_alive. The script may change this
|
|
|
* by calling mg.keep_alive(true). */
|
|
|
conn->must_close = 1;
|
|
|
|
|
|
- /* We need both mg_stat to get file size, and mg_fopen to get fd */
|
|
|
- if (!mg_stat(conn, path, &filesize.stat)) {
|
|
|
-
|
|
|
- /* File not found */
|
|
|
- if (ls == NULL) {
|
|
|
- send_http_error(conn, 500, "Error: File %s not found", path);
|
|
|
- } else {
|
|
|
- luaL_error(ls, "File [%s] not found", path);
|
|
|
- }
|
|
|
-
|
|
|
- goto cleanup_handle_lsp_request;
|
|
|
- }
|
|
|
-
|
|
|
+ /* mg_fopen opens the file and sets the size accordingly */
|
|
|
if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
|
|
|
|
|
|
/* File not found or not accessible */
|
|
|
if (ls == NULL) {
|
|
|
- send_http_error(conn,
|
|
|
- 500,
|
|
|
- "Error: Cannot open script file %s",
|
|
|
- path);
|
|
|
+ mg_send_http_error(conn,
|
|
|
+ 500,
|
|
|
+ "Error: Cannot open script file %s",
|
|
|
+ path);
|
|
|
} else {
|
|
|
- luaL_error(ls, "Cannot [%s] not found", path);
|
|
|
+ luaL_error(ls, "Cannot include [%s]: not found", path);
|
|
|
}
|
|
|
|
|
|
goto cleanup_handle_lsp_request;
|
|
|
}
|
|
|
|
|
|
- /* TODO: Operations mg_fopen and mg_stat should do what their names
|
|
|
- * indicate. They should not fill in different members of the same
|
|
|
- * struct mg_file.
|
|
|
- * See Github issue #225 */
|
|
|
- filep->stat.size = filesize.stat.size;
|
|
|
-
|
|
|
+ /* Map file in memory (size is known). */
|
|
|
if (filep->access.membuf == NULL
|
|
|
&& (p = mmap(NULL,
|
|
|
(size_t)filep->stat.size,
|
|
@@ -1627,7 +1979,7 @@ handle_lsp_request(struct mg_connection *conn,
|
|
|
|
|
|
/* mmap failed */
|
|
|
if (ls == NULL) {
|
|
|
- send_http_error(
|
|
|
+ mg_send_http_error(
|
|
|
conn,
|
|
|
500,
|
|
|
"Error: Cannot open script\nFile %s can not be mapped",
|
|
@@ -1647,9 +1999,9 @@ handle_lsp_request(struct mg_connection *conn,
|
|
|
if (ls != NULL) {
|
|
|
L = ls;
|
|
|
} else {
|
|
|
- L = lua_newstate(lua_allocator, NULL);
|
|
|
+ L = lua_newstate(lua_allocator, (void *)(conn->ctx));
|
|
|
if (L == NULL) {
|
|
|
- send_http_error(
|
|
|
+ mg_send_http_error(
|
|
|
conn,
|
|
|
500,
|
|
|
"%s",
|
|
@@ -1661,15 +2013,24 @@ handle_lsp_request(struct mg_connection *conn,
|
|
|
conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
|
|
|
}
|
|
|
|
|
|
+ /* Get LSP include history table */
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_lsp_include_history);
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
+ include_history = (struct lsp_include_history *)lua_touserdata(L, -1);
|
|
|
+
|
|
|
+ /* Store script name and increment depth */
|
|
|
+ include_history->depth++;
|
|
|
+ include_history->script[include_history->depth] = path;
|
|
|
+
|
|
|
/* Lua state is ready to use */
|
|
|
/* We're not sending HTTP headers here, Lua page must do it. */
|
|
|
- error =
|
|
|
- lsp(conn,
|
|
|
- path,
|
|
|
- (filep->access.membuf == NULL) ? (const char *)p
|
|
|
- : (const char *)filep->access.membuf,
|
|
|
- filep->stat.size,
|
|
|
- L);
|
|
|
+ error = run_lsp(conn,
|
|
|
+ path,
|
|
|
+ (filep->access.membuf == NULL)
|
|
|
+ ? (const char *)p
|
|
|
+ : (const char *)filep->access.membuf,
|
|
|
+ filep->stat.size,
|
|
|
+ L);
|
|
|
|
|
|
cleanup_handle_lsp_request:
|
|
|
|
|
@@ -1712,8 +2073,9 @@ lua_websocket_new(const char *script, struct mg_connection *conn)
|
|
|
|
|
|
if (*shared_websock_list == NULL) {
|
|
|
/* add ws to list */
|
|
|
- *shared_websock_list = (struct mg_shared_lua_websocket_list *)
|
|
|
- mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
|
|
|
+ *shared_websock_list =
|
|
|
+ (struct mg_shared_lua_websocket_list *)mg_calloc_ctx(
|
|
|
+ sizeof(struct mg_shared_lua_websocket_list), 1, conn->ctx);
|
|
|
if (*shared_websock_list == NULL) {
|
|
|
mg_unlock_context(conn->ctx);
|
|
|
mg_cry(conn, "Cannot create shared websocket struct, OOM");
|
|
@@ -1724,7 +2086,7 @@ lua_websocket_new(const char *script, struct mg_connection *conn)
|
|
|
ws->script = mg_strdup(script); /* TODO (low): handle OOM */
|
|
|
pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
|
|
|
(void)pthread_mutex_lock(&(ws->ws_mutex));
|
|
|
- ws->state = lua_newstate(lua_allocator, NULL);
|
|
|
+ ws->state = lua_newstate(lua_allocator, (void *)(conn->ctx));
|
|
|
ws->conn[0] = conn;
|
|
|
ws->references = 1;
|
|
|
prepare_lua_environment(
|
|
@@ -1892,7 +2254,7 @@ lua_websocket_close(struct mg_connection *conn, void *ws_arg)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-lua_State *
|
|
|
+static lua_State *
|
|
|
mg_prepare_lua_context_script(const char *file_name,
|
|
|
struct mg_context *ctx,
|
|
|
char *ebuf,
|
|
@@ -1902,6 +2264,8 @@ mg_prepare_lua_context_script(const char *file_name,
|
|
|
int lua_ret;
|
|
|
const char *lua_err_txt;
|
|
|
|
|
|
+ (void)ctx;
|
|
|
+
|
|
|
L = luaL_newstate();
|
|
|
if (L == NULL) {
|
|
|
mg_snprintf(NULL,
|
|
@@ -1916,7 +2280,8 @@ mg_prepare_lua_context_script(const char *file_name,
|
|
|
|
|
|
lua_ret = luaL_loadfile(L, file_name);
|
|
|
if (lua_ret != LUA_OK) {
|
|
|
- /* Error when loading the file (e.g. file not found, out of memory, ...)
|
|
|
+ /* Error when loading the file (e.g. file not found,
|
|
|
+ * out of memory, ...)
|
|
|
*/
|
|
|
lua_err_txt = lua_tostring(L, -1);
|
|
|
mg_snprintf(NULL,
|
|
@@ -1982,7 +2347,8 @@ lua_init_optional_libraries(void)
|
|
|
{
|
|
|
#if !defined(_WIN32)
|
|
|
lib_handle_uuid = dlopen("libuuid.so", RTLD_LAZY);
|
|
|
- pf_uuid_generate.p = dlsym(lib_handle_uuid, "uuid_generate");
|
|
|
+ pf_uuid_generate.p =
|
|
|
+ (lib_handle_uuid ? dlsym(lib_handle_uuid, "uuid_generate") : 0);
|
|
|
#else
|
|
|
pf_uuid_generate.p = 0;
|
|
|
#endif
|
|
@@ -1993,8 +2359,13 @@ static void
|
|
|
lua_exit_optional_libraries(void)
|
|
|
{
|
|
|
#if !defined(_WIN32)
|
|
|
- dlclose(lib_handle_uuid);
|
|
|
+ if (lib_handle_uuid) {
|
|
|
+ dlclose(lib_handle_uuid);
|
|
|
+ }
|
|
|
#endif
|
|
|
pf_uuid_generate.p = 0;
|
|
|
lib_handle_uuid = NULL;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+/* End of mod_lua.inl */
|