|
@@ -72,7 +72,8 @@ static void reg_function(struct lua_State *L, const char *name,
|
|
|
|
|
|
static int lsp_sock_close(lua_State *L)
|
|
|
{
|
|
|
- if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ if ((num_args == 1) && lua_istable(L, -1)) {
|
|
|
lua_getfield(L, -1, "sock");
|
|
|
closesocket((SOCKET) lua_tonumber(L, -1));
|
|
|
} else {
|
|
@@ -83,10 +84,11 @@ static int lsp_sock_close(lua_State *L)
|
|
|
|
|
|
static int lsp_sock_recv(lua_State *L)
|
|
|
{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
char buf[2000];
|
|
|
int n;
|
|
|
|
|
|
- if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
|
|
|
+ if ((num_args == 1) && lua_istable(L, -1)) {
|
|
|
lua_getfield(L, -1, "sock");
|
|
|
n = recv((SOCKET) lua_tonumber(L, -1), buf, sizeof(buf), 0);
|
|
|
if (n <= 0) {
|
|
@@ -102,11 +104,12 @@ static int lsp_sock_recv(lua_State *L)
|
|
|
|
|
|
static int lsp_sock_send(lua_State *L)
|
|
|
{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
const char *buf;
|
|
|
size_t len, sent = 0;
|
|
|
int n = 0, sock;
|
|
|
|
|
|
- if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
|
|
|
+ if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
|
|
|
buf = lua_tolstring(L, -1, &len);
|
|
|
lua_getfield(L, -2, "sock");
|
|
|
sock = (int) lua_tonumber(L, -1);
|
|
@@ -132,10 +135,11 @@ static const struct luaL_Reg luasocket_methods[] = {
|
|
|
|
|
|
static int lsp_connect(lua_State *L)
|
|
|
{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
char ebuf[100];
|
|
|
SOCKET sock;
|
|
|
|
|
|
- if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
|
|
|
+ if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
|
|
|
sock = conn2(NULL, lua_tostring(L, -3), (int) lua_tonumber(L, -2),
|
|
|
(int) lua_tonumber(L, -1), ebuf, sizeof(ebuf));
|
|
|
if (sock == INVALID_SOCKET) {
|
|
@@ -187,21 +191,21 @@ static const char * lsp_var_reader(lua_State *L, void *ud, size_t *sz)
|
|
|
const char * ret;
|
|
|
|
|
|
switch (reader->state) {
|
|
|
- case 0:
|
|
|
- ret = "mg.write(";
|
|
|
- *sz = strlen(ret);
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- ret = reader->begin;
|
|
|
- *sz = reader->len;
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- ret = ")";
|
|
|
- *sz = strlen(ret);
|
|
|
- break;
|
|
|
- default:
|
|
|
- ret = 0;
|
|
|
- *sz = 0;
|
|
|
+ case 0:
|
|
|
+ ret = "mg.write(";
|
|
|
+ *sz = strlen(ret);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ ret = reader->begin;
|
|
|
+ *sz = reader->len;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ ret = ")";
|
|
|
+ *sz = strlen(ret);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ret = 0;
|
|
|
+ *sz = 0;
|
|
|
}
|
|
|
|
|
|
reader->state++;
|
|
@@ -219,6 +223,7 @@ static int lsp(struct mg_connection *conn, const char *path,
|
|
|
if (p[i] == '\n') lines++;
|
|
|
if ((i + 1) < len && p[i] == '<' && p[i + 1] == '?') {
|
|
|
|
|
|
+ /* <?= ?> means a variable is enclosed and its value should be printed */
|
|
|
is_var = ((i + 2) < len && p[i + 2] == '=');
|
|
|
|
|
|
if (is_var) j = i + 2;
|
|
@@ -271,14 +276,15 @@ static int lsp(struct mg_connection *conn, const char *path,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* mg.write: Send data to the client */
|
|
|
static int lsp_write(lua_State *L)
|
|
|
{
|
|
|
- int i, num_args;
|
|
|
+ struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
const char *str;
|
|
|
size_t size;
|
|
|
- struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int i;
|
|
|
|
|
|
- num_args = lua_gettop(L);
|
|
|
for (i = 1; i <= num_args; i++) {
|
|
|
if (lua_isstring(L, i)) {
|
|
|
str = lua_tolstring(L, i, &size);
|
|
@@ -289,6 +295,7 @@ static int lsp_write(lua_State *L)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* mg.read: Read data from the client (e.g., from a POST request) */
|
|
|
static int lsp_read(lua_State *L)
|
|
|
{
|
|
|
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
@@ -301,15 +308,43 @@ static int lsp_read(lua_State *L)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
|
|
|
+static int lsp_keep_alive(lua_State *L)
|
|
|
+{
|
|
|
+ struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+
|
|
|
+ /* This function may be called with one parameter (boolean) to set the keep_alive state.
|
|
|
+ Or without a parameter to just query the current keep_alive state. */
|
|
|
+ if ((num_args==1) && lua_isboolean(L, 1)) {
|
|
|
+ conn->must_close = !lua_toboolean(L, 1);
|
|
|
+ } else if (num_args != 0) {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid keep_alive() call");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Return the current "keep_alive" state. This may be false, even it keep_alive(true) has been called. */
|
|
|
+ lua_pushboolean(L, should_keep_alive(conn));
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/* mg.include: Include another .lp file */
|
|
|
static int lsp_include(lua_State *L)
|
|
|
{
|
|
|
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
struct file file = STRUCT_FILE_INITIALIZER;
|
|
|
- if (handle_lsp_request(conn, lua_tostring(L, -1), &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);
|
|
|
+ const char * filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid include() call");
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -318,7 +353,15 @@ static int lsp_include(lua_State *L)
|
|
|
static int lsp_cry(lua_State *L)
|
|
|
{
|
|
|
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
- mg_cry(conn, "%s", lua_tostring(L, -1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char * text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+
|
|
|
+ if (text) {
|
|
|
+ mg_cry(conn, "%s", lua_tostring(L, -1));
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid cry() call");
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -326,12 +369,197 @@ static int lsp_cry(lua_State *L)
|
|
|
static int lsp_redirect(lua_State *L)
|
|
|
{
|
|
|
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
- conn->request_info.uri = lua_tostring(L, -1);
|
|
|
- handle_request(conn);
|
|
|
- lsp_abort(L);
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char * target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+
|
|
|
+ if (target) {
|
|
|
+ conn->request_info.uri = target;
|
|
|
+ handle_request(conn);
|
|
|
+ lsp_abort(L);
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid redirect() call");
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.send_file */
|
|
|
+static int lsp_send_file(lua_State *L)
|
|
|
+{
|
|
|
+ struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char * filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
|
|
|
+
|
|
|
+ if (filename) {
|
|
|
+ mg_send_file(conn, filename);
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid send_file() call");
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* mg.get_var */
|
|
|
+static int lsp_get_var(lua_State *L)
|
|
|
+{
|
|
|
+ struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char *data, *var_name;
|
|
|
+ size_t data_len, occurrence;
|
|
|
+ int ret;
|
|
|
+ char dst[512];
|
|
|
+
|
|
|
+ if (num_args>=2 && num_args<=3) {
|
|
|
+ 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);
|
|
|
+ if (ret>=0) {
|
|
|
+ /* Variable found: return value to Lua */
|
|
|
+ lua_pushstring(L, dst);
|
|
|
+ } else {
|
|
|
+ /* Variable not found (TODO: may be string too long) */
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_var() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.get_mime_type */
|
|
|
+static int lsp_get_mime_type(lua_State *L)
|
|
|
+{
|
|
|
+ struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ struct vec mime_type = {0};
|
|
|
+ const char *text;
|
|
|
+
|
|
|
+ if (num_args==1) {
|
|
|
+ text = lua_tostring(L, 1);
|
|
|
+ if (text) {
|
|
|
+ get_mime_type(conn->ctx, text, &mime_type);
|
|
|
+ lua_pushlstring(L, mime_type.ptr, mime_type.len);
|
|
|
+ } else {
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_mime_type() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.get_cookie */
|
|
|
+static int lsp_get_cookie(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ struct vec mime_type = {0};
|
|
|
+ const char *cookie;
|
|
|
+ const char *var_name;
|
|
|
+ int ret;
|
|
|
+ char dst[512];
|
|
|
+
|
|
|
+ if (num_args==2) {
|
|
|
+ cookie = lua_tostring(L, 1);
|
|
|
+ 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 (ret>=0) {
|
|
|
+ lua_pushlstring(L, dst, ret);
|
|
|
+ } else {
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid get_cookie() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.md5 */
|
|
|
+static int lsp_md5(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char *text;
|
|
|
+ md5_byte_t hash[16];
|
|
|
+ md5_state_t ctx;
|
|
|
+ size_t text_len;
|
|
|
+ char buf[40];
|
|
|
+
|
|
|
+ if (num_args==1) {
|
|
|
+ text = lua_tolstring(L, 1, &text_len);
|
|
|
+ if (text) {
|
|
|
+ md5_init(&ctx);
|
|
|
+ md5_append(&ctx, (const md5_byte_t *) text, text_len);
|
|
|
+ md5_finish(&ctx, hash);
|
|
|
+ bin2str(buf, hash, sizeof(hash));
|
|
|
+ lua_pushstring(L, buf);
|
|
|
+ } else {
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid md5() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.url_encode */
|
|
|
+static int lsp_url_encode(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char *text;
|
|
|
+ size_t text_len;
|
|
|
+ char dst[512];
|
|
|
+
|
|
|
+ if (num_args==1) {
|
|
|
+ text = lua_tolstring(L, 1, &text_len);
|
|
|
+ if (text) {
|
|
|
+ mg_url_encode(text, dst, sizeof(dst));
|
|
|
+ lua_pushstring(L, dst);
|
|
|
+ } else {
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid url_encode() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.url_decode */
|
|
|
+static int lsp_url_decode(lua_State *L)
|
|
|
+{
|
|
|
+ int num_args = lua_gettop(L);
|
|
|
+ const char *text;
|
|
|
+ size_t text_len;
|
|
|
+ int is_form;
|
|
|
+ char dst[512];
|
|
|
+
|
|
|
+ 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, text_len, dst, sizeof(dst), is_form);
|
|
|
+ lua_pushstring(L, dst);
|
|
|
+ } else {
|
|
|
+ lua_pushnil(L);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Syntax error */
|
|
|
+ return luaL_error(L, "invalid url_decode() call");
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* mg.write for websockets */
|
|
|
static int lwebsock_write(lua_State *L)
|
|
|
{
|
|
|
#ifdef USE_WEBSOCKET
|
|
@@ -404,7 +632,10 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|
|
lua_pop(L, 1);
|
|
|
lua_register(L, "connect", lsp_connect);
|
|
|
|
|
|
- if (conn == NULL) return;
|
|
|
+ if (conn == NULL) {
|
|
|
+ /* Do not register any connection specific functions or variables */
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
/* Register mg module */
|
|
|
lua_newtable(L);
|
|
@@ -426,6 +657,7 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|
|
if (lua_env_type==LUA_ENV_TYPE_LUA_SERVER_PAGE || lua_env_type==LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
|
|
|
reg_function(L, "read", lsp_read, conn);
|
|
|
reg_function(L, "write", lsp_write, conn);
|
|
|
+ reg_function(L, "keep_alive", lsp_keep_alive, conn);
|
|
|
}
|
|
|
|
|
|
if (lua_env_type==LUA_ENV_TYPE_LUA_SERVER_PAGE) {
|
|
@@ -437,6 +669,14 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L, co
|
|
|
reg_function(L, "write", lwebsock_write, conn);
|
|
|
}
|
|
|
|
|
|
+ reg_function(L, "send_file", lsp_send_file, conn);
|
|
|
+ reg_function(L, "get_var", lsp_get_var, conn);
|
|
|
+ reg_function(L, "get_mime_type", lsp_get_mime_type, conn);
|
|
|
+ reg_function(L, "get_cookie", lsp_get_cookie, conn);
|
|
|
+ reg_function(L, "md5", lsp_md5, conn);
|
|
|
+ reg_function(L, "url_encode", lsp_url_encode, conn);
|
|
|
+ reg_function(L, "url_decode", lsp_url_decode, conn);
|
|
|
+
|
|
|
reg_string(L, "version", CIVETWEB_VERSION);
|
|
|
reg_string(L, "document_root", conn->ctx->config[DOCUMENT_ROOT]);
|
|
|
reg_string(L, "auth_domain", conn->ctx->config[AUTHENTICATION_DOMAIN]);
|
|
@@ -507,6 +747,10 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
|
|
|
int i;
|
|
|
lua_State *L;
|
|
|
|
|
|
+ /* Assume the script does not support keep_alive. The script may change this by calling mg.keep_alive(true). */
|
|
|
+ conn->must_close=1;
|
|
|
+
|
|
|
+ /* Execute a plain Lua script. */
|
|
|
if (path != NULL && (L = luaL_newstate()) != NULL) {
|
|
|
prepare_lua_environment(conn, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
|
|
|
lua_pushcclosure(L, &lua_error_handler, 0);
|
|
@@ -526,7 +770,6 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
|
|
|
lua_pcall(L, 0, 0, -2);
|
|
|
lua_close(L);
|
|
|
}
|
|
|
- conn->must_close=1;
|
|
|
}
|
|
|
|
|
|
static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
|
|
@@ -555,6 +798,9 @@ struct file *filep, struct lua_State *ls)
|
|
|
lua_State *L = NULL;
|
|
|
int error = 1;
|
|
|
|
|
|
+ /* 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, filep) || !mg_fopen(conn, path, "r", filep)) {
|
|
|
lsp_send_err(conn, ls, "File [%s] not found", path);
|
|
@@ -580,7 +826,6 @@ struct file *filep, struct lua_State *ls)
|
|
|
if (L != NULL && ls == NULL) lua_close(L);
|
|
|
if (p != NULL) munmap(p, filep->size);
|
|
|
mg_fclose(filep);
|
|
|
- conn->must_close=1;
|
|
|
return error;
|
|
|
}
|
|
|
|
|
@@ -588,36 +833,37 @@ struct file *filep, struct lua_State *ls)
|
|
|
struct lua_websock_data {
|
|
|
lua_State *main;
|
|
|
lua_State *thread;
|
|
|
+ struct mg_connection *conn;
|
|
|
};
|
|
|
|
|
|
static void websock_cry(struct mg_connection *conn, int err, lua_State * L, const char * ws_operation, const char * lua_operation)
|
|
|
{
|
|
|
switch (err) {
|
|
|
- case LUA_OK:
|
|
|
- case LUA_YIELD:
|
|
|
- break;
|
|
|
- case LUA_ERRRUN:
|
|
|
- mg_cry(conn, "%s: %s failed: runtime error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
- break;
|
|
|
- case LUA_ERRSYNTAX:
|
|
|
- mg_cry(conn, "%s: %s failed: syntax error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
- break;
|
|
|
- case LUA_ERRMEM:
|
|
|
- mg_cry(conn, "%s: %s failed: out of memory", ws_operation, lua_operation);
|
|
|
- break;
|
|
|
- case LUA_ERRGCMM:
|
|
|
- mg_cry(conn, "%s: %s failed: error during garbage collection", ws_operation, lua_operation);
|
|
|
- break;
|
|
|
- case LUA_ERRERR:
|
|
|
- mg_cry(conn, "%s: %s failed: error in error handling: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
- break;
|
|
|
- default:
|
|
|
- mg_cry(conn, "%s: %s failed: error %i", ws_operation, lua_operation, err);
|
|
|
- break;
|
|
|
+ case LUA_OK:
|
|
|
+ case LUA_YIELD:
|
|
|
+ break;
|
|
|
+ case LUA_ERRRUN:
|
|
|
+ mg_cry(conn, "%s: %s failed: runtime error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
+ break;
|
|
|
+ case LUA_ERRSYNTAX:
|
|
|
+ mg_cry(conn, "%s: %s failed: syntax error: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
+ break;
|
|
|
+ case LUA_ERRMEM:
|
|
|
+ mg_cry(conn, "%s: %s failed: out of memory", ws_operation, lua_operation);
|
|
|
+ break;
|
|
|
+ case LUA_ERRGCMM:
|
|
|
+ mg_cry(conn, "%s: %s failed: error during garbage collection", ws_operation, lua_operation);
|
|
|
+ break;
|
|
|
+ case LUA_ERRERR:
|
|
|
+ mg_cry(conn, "%s: %s failed: error in error handling: %s", ws_operation, lua_operation, lua_tostring(L, -1));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ mg_cry(conn, "%s: %s failed: error %i", ws_operation, lua_operation, err);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void * new_lua_websocket(const char * script, struct mg_connection *conn)
|
|
|
+static void * lua_websocket_new(const char * script, struct mg_connection *conn, int is_shared)
|
|
|
{
|
|
|
struct lua_websock_data *lws_data;
|
|
|
int ok = 0;
|
|
@@ -627,6 +873,14 @@ static void * new_lua_websocket(const char * script, struct mg_connection *conn)
|
|
|
lws_data = (struct lua_websock_data *) malloc(sizeof(*lws_data));
|
|
|
|
|
|
if (lws_data) {
|
|
|
+ lws_data->conn = conn;
|
|
|
+
|
|
|
+ if (is_shared) {
|
|
|
+ (void)pthread_mutex_lock(&conn->ctx->mutex);
|
|
|
+ // TODO: add_to_websocket_list(lws_data);
|
|
|
+ (void)pthread_mutex_unlock(&conn->ctx->mutex);
|
|
|
+ }
|
|
|
+
|
|
|
lws_data->main = luaL_newstate();
|
|
|
if (lws_data->main) {
|
|
|
prepare_lua_environment(conn, lws_data->main, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
|
|
@@ -657,6 +911,8 @@ static void * new_lua_websocket(const char * script, struct mg_connection *conn)
|
|
|
free(lws_data);
|
|
|
lws_data=0;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ mg_cry(conn, "%s: out of memory", __func__);
|
|
|
}
|
|
|
|
|
|
return lws_data;
|
|
@@ -674,8 +930,11 @@ static int lua_websocket_data(struct mg_connection *conn, int bits, char *data,
|
|
|
|
|
|
do {
|
|
|
retry=0;
|
|
|
+
|
|
|
+ /* Push the data to Lua, then resume the Lua state. */
|
|
|
+ /* The data will be available to Lua as the result of the coroutine.yield function. */
|
|
|
lua_pushboolean(lws_data->thread, 1);
|
|
|
- if (bits > 0) {
|
|
|
+ if (bits >= 0) {
|
|
|
lua_pushinteger(lws_data->thread, bits);
|
|
|
if (data) {
|
|
|
lua_pushlstring(lws_data->thread, data, data_len);
|
|
@@ -687,6 +946,7 @@ static int lua_websocket_data(struct mg_connection *conn, int bits, char *data,
|
|
|
err = lua_resume(lws_data->thread, NULL, 1);
|
|
|
}
|
|
|
|
|
|
+ /* Check if Lua returned by a call to the coroutine.yield function. */
|
|
|
if (err!=LUA_YIELD) {
|
|
|
websock_cry(conn, err, lws_data->thread, __func__, "lua_resume");
|
|
|
} else {
|
|
@@ -697,7 +957,7 @@ static int lua_websocket_data(struct mg_connection *conn, int bits, char *data,
|
|
|
fd_set rfds;
|
|
|
struct timeval tv;
|
|
|
|
|
|
- FD_ZERO(&rfds);
|
|
|
+ FD_ZERO(&rfds);
|
|
|
FD_SET(conn->client.sock, &rfds);
|
|
|
|
|
|
tv.tv_sec = (unsigned long)delay;
|
|
@@ -731,4 +991,4 @@ static void lua_websocket_close(struct mg_connection *conn)
|
|
|
free(lws_data);
|
|
|
conn->lua_websocket_state = NULL;
|
|
|
}
|
|
|
-#endif
|
|
|
+#endif
|