http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/mod_duktape.inl ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/mod_duktape.inl b/thirdparty/civetweb-1.9.1/src/mod_duktape.inl new file mode 100644 index 0000000..d4e53cd --- /dev/null +++ b/thirdparty/civetweb-1.9.1/src/mod_duktape.inl @@ -0,0 +1,250 @@ +/* This file is part of the CivetWeb web server. + * See https://github.com/civetweb/civetweb/ + * (C) 2015-2017 by the CivetWeb authors, MIT license. + */ + +#include "duktape.h" + +/* TODO: the mg context should be added to duktape as well */ +/* Alternative: redefine a new, clean API from scratch (instead of using mg), + * or at least do not add problematic functions. */ +/* For evaluation purposes, currently only "send" is supported. + * All other ~50 functions will be added later. */ + +/* Note: This is only experimental support, so the API may still change. */ + +static const char *civetweb_conn_id = "\xFF" + "civetweb_conn"; +static const char *civetweb_ctx_id = "\xFF" + "civetweb_ctx"; + + +static void * +mg_duk_mem_alloc(void *udata, duk_size_t size) +{ + return mg_malloc(size); +} + + +static void * +mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize) +{ + return mg_realloc(ptr, newsize); +} + + +static void +mg_duk_mem_free(void *udata, void *ptr) +{ + mg_free(ptr); +} + + +static void +mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) +{ + /* Script is called "protected" (duk_peval_file), so script errors should + * never yield in a call to this function. Maybe calls prior to executing + * the script could raise a fatal error. */ + struct mg_connection *conn; + + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, civetweb_conn_id); + conn = (struct mg_connection *)duk_to_pointer(ctx, -1); + + mg_cry(conn, "%s", msg); +} + + +static duk_ret_t +duk_itf_write(duk_context *ctx) +{ + struct mg_connection *conn; + duk_double_t ret; + duk_size_t len = 0; + const char *val = duk_require_lstring(ctx, -1, &len); + + /* + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, civetweb_conn_id); + conn = (struct mg_connection *)duk_to_pointer(ctx, -1); + */ + duk_push_current_function(ctx); + duk_get_prop_string(ctx, -1, civetweb_conn_id); + conn = (struct mg_connection *)duk_to_pointer(ctx, -1); + + if (!conn) { + duk_error(ctx, + DUK_ERR_INTERNAL_ERROR, + "function not available without connection object"); + /* probably never reached, but satisfies static code analysis */ + return DUK_RET_INTERNAL_ERROR; + } + + ret = mg_write(conn, val, len); + + duk_push_number(ctx, ret); + return 1; +} + + +static duk_ret_t +duk_itf_read(duk_context *ctx) +{ + struct mg_connection *conn; + char buf[1024]; + int len; + + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, civetweb_conn_id); + conn = (struct mg_connection *)duk_to_pointer(ctx, -1); + + if (!conn) { + duk_error(ctx, + DUK_ERR_INTERNAL_ERROR, + "function not available without connection object"); + /* probably never reached, but satisfies static code analysis */ + return DUK_RET_INTERNAL_ERROR; + } + + len = mg_read(conn, buf, sizeof(buf)); + + duk_push_lstring(ctx, buf, len); + return 1; +} + + +static duk_ret_t +duk_itf_getoption(duk_context *ctx) +{ + struct mg_context *cv_ctx; + const char *ret; + duk_size_t len = 0; + const char *val = duk_require_lstring(ctx, -1, &len); + + duk_push_current_function(ctx); + duk_get_prop_string(ctx, -1, civetweb_ctx_id); + cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1); + + if (!cv_ctx) { + duk_error(ctx, + DUK_ERR_INTERNAL_ERROR, + "function not available without connection object"); + /* probably never reached, but satisfies static code analysis */ + return DUK_RET_INTERNAL_ERROR; + } + + ret = mg_get_option(cv_ctx, val); + if (ret) { + duk_push_string(ctx, ret); + } else { + duk_push_null(ctx); + } + + return 1; +} + + +static void +mg_exec_duktape_script(struct mg_connection *conn, const char *script_name) +{ + int i; + duk_context *ctx = NULL; + + conn->must_close = 1; + + /* Create Duktape interpreter state */ + ctx = duk_create_heap(mg_duk_mem_alloc, + mg_duk_mem_realloc, + mg_duk_mem_free, + NULL, + mg_duk_fatal_handler); + if (!ctx) { + mg_cry(conn, "Failed to create a Duktape heap."); + goto exec_duktape_finished; + } + + /* Add "conn" object */ + duk_push_global_object(ctx); + duk_push_object(ctx); /* create a new table/object ("conn") */ + + duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */); + duk_push_pointer(ctx, (void *)conn); + duk_put_prop_string(ctx, -2, civetweb_conn_id); + duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */ + + duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */); + duk_push_pointer(ctx, (void *)conn); + duk_put_prop_string(ctx, -2, civetweb_conn_id); + duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */ + + duk_push_string(ctx, conn->request_info.request_method); + duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */ + + duk_push_string(ctx, conn->request_info.request_uri); + duk_put_prop_string(ctx, -2, "request_uri"); + + duk_push_string(ctx, conn->request_info.local_uri); + duk_put_prop_string(ctx, -2, "uri"); + + duk_push_string(ctx, conn->request_info.http_version); + duk_put_prop_string(ctx, -2, "http_version"); + + duk_push_string(ctx, conn->request_info.query_string); + duk_put_prop_string(ctx, -2, "query_string"); + + duk_push_string(ctx, conn->request_info.remote_addr); + duk_put_prop_string(ctx, -2, "remote_addr"); + + duk_push_int(ctx, conn->request_info.remote_port); + duk_put_prop_string(ctx, -2, "remote_port"); + + duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port)); + duk_put_prop_string(ctx, -2, "server_port"); + + duk_push_object(ctx); /* subfolder "conn.http_headers" */ + for (i = 0; i < conn->request_info.num_headers; i++) { + duk_push_string(ctx, conn->request_info.http_headers[i].value); + duk_put_prop_string(ctx, -2, conn->request_info.http_headers[i].name); + } + duk_put_prop_string(ctx, -2, "http_headers"); + + duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */ + + /* Add "civetweb" object */ + duk_push_global_object(ctx); + duk_push_object(ctx); /* create a new table/object ("conn") */ + + duk_push_string(ctx, CIVETWEB_VERSION); + duk_put_prop_string(ctx, -2, "version"); + + duk_push_string(ctx, script_name); + duk_put_prop_string(ctx, -2, "script_name"); + + if (conn->ctx != NULL) { + duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */); + duk_push_pointer(ctx, (void *)(conn->ctx)); + duk_put_prop_string(ctx, -2, civetweb_ctx_id); + duk_put_prop_string(ctx, -2, "getoption"); /* add function conn.write */ + + if (conn->ctx->systemName != NULL) { + duk_push_string(ctx, conn->ctx->systemName); + duk_put_prop_string(ctx, -2, "system"); + } + } + + duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" */ + + duk_push_global_stash(ctx); + duk_push_pointer(ctx, (void *)conn); + duk_put_prop_string(ctx, -2, civetweb_conn_id); + + if (duk_peval_file(ctx, script_name) != 0) { + mg_cry(conn, "%s", duk_safe_to_string(ctx, -1)); + goto exec_duktape_finished; + } + duk_pop(ctx); /* ignore result */ + +exec_duktape_finished: + duk_destroy_heap(ctx); +}
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/mod_lua.inl ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/mod_lua.inl b/thirdparty/civetweb-1.9.1/src/mod_lua.inl new file mode 100644 index 0000000..58a67dc --- /dev/null +++ b/thirdparty/civetweb-1.9.1/src/mod_lua.inl @@ -0,0 +1,2000 @@ +/* This file is part of the CivetWeb web server. + * See https://github.com/civetweb/civetweb/ + */ + +#include "civetweb_lua.h" +#include "civetweb_private_lua.h" + +#ifdef _WIN32 +static void * +mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset) +{ + /* TODO (low): This is an incomplete implementation of mmap for windows. + * Currently it is sufficient, but there are a lot of unused parameters. + * Better use a function "mg_map" which only has the required parameters, + * and implement it using mmap in Linux and CreateFileMapping in Windows. + * Noone should expect a full mmap for Windows here. + */ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0); + void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len); + CloseHandle(mh); + + /* unused parameters */ + (void)addr; + (void)prot; + (void)flags; + (void)offset; + + return p; +} + +static void +munmap(void *addr, int64_t length) +{ + /* unused parameters */ + (void)length; + + UnmapViewOfFile(addr); +} + +#define MAP_FAILED (NULL) +#define MAP_PRIVATE (0) +#define PROT_READ (0) +#else +#include <sys/mman.h> +#endif + +static const char *LUASOCKET = "luasocket"; +static const char lua_regkey_ctx = 1; +static const char lua_regkey_connlist = 2; + +/* Forward declarations */ +static void handle_request(struct mg_connection *); +static int handle_lsp_request(struct mg_connection *, + const char *, + struct mg_file *, + struct lua_State *); + +static void +reg_lstring(struct lua_State *L, + const char *name, + const void *buffer, + size_t buflen) +{ + if (name != NULL && buffer != NULL) { + lua_pushstring(L, name); + lua_pushlstring(L, (const char *)buffer, buflen); + lua_rawset(L, -3); + } +} + +#define reg_string(L, name, val) \ + reg_lstring(L, name, val, val ? strlen(val) : 0) + +static void +reg_int(struct lua_State *L, const char *name, int val) +{ + if (name != NULL) { + lua_pushstring(L, name); + lua_pushinteger(L, val); + lua_rawset(L, -3); + } +} + +static void +reg_boolean(struct lua_State *L, const char *name, int val) +{ + if (name != NULL) { + lua_pushstring(L, name); + lua_pushboolean(L, val != 0); + lua_rawset(L, -3); + } +} + +static void +reg_conn_function(struct lua_State *L, + const char *name, + lua_CFunction func, + struct mg_connection *conn) +{ + if (name != NULL && func != NULL && conn != NULL) { + lua_pushstring(L, name); + lua_pushlightuserdata(L, conn); + lua_pushcclosure(L, func, 1); + lua_rawset(L, -3); + } +} + +static void +reg_function(struct lua_State *L, const char *name, lua_CFunction func) +{ + if (name != NULL && func != NULL) { + lua_pushstring(L, name); + lua_pushcclosure(L, func, 0); + lua_rawset(L, -3); + } +} + +static void +lua_cry(struct mg_connection *conn, + int err, + lua_State *L, + const char *lua_title, + 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", + lua_title, + lua_operation, + lua_tostring(L, -1)); + break; + case LUA_ERRSYNTAX: + mg_cry(conn, + "%s: %s failed: syntax error: %s", + lua_title, + lua_operation, + lua_tostring(L, -1)); + break; + case LUA_ERRMEM: + mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation); + break; + case LUA_ERRGCMM: + mg_cry(conn, + "%s: %s failed: error during garbage collection", + lua_title, + lua_operation); + break; + case LUA_ERRERR: + mg_cry(conn, + "%s: %s failed: error in error handling: %s", + lua_title, + lua_operation, + lua_tostring(L, -1)); + break; + default: + mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err); + break; + } +} + +static int +lsp_sock_close(lua_State *L) +{ + int num_args = lua_gettop(L); + size_t s; + SOCKET *psock; + + if ((num_args == 1) && lua_istable(L, -1)) { + lua_getfield(L, -1, "sock"); + psock = (SOCKET *)lua_tolstring(L, -1, &s); + if (s != sizeof(SOCKET)) { + return luaL_error(L, "invalid internal state in :close() call"); + } + /* Do not closesocket(*psock); here, close it in __gc */ + (void)psock; + } else { + return luaL_error(L, "invalid :close() call"); + } + return 0; +} + +static int +lsp_sock_recv(lua_State *L) +{ + int num_args = lua_gettop(L); + char buf[2000]; + int n; + size_t s; + SOCKET *psock; + + if ((num_args == 1) && lua_istable(L, -1)) { + lua_getfield(L, -1, "sock"); + psock = (SOCKET *)lua_tolstring(L, -1, &s); + if (s != sizeof(SOCKET)) { + return luaL_error(L, "invalid internal state in :recv() call"); + } + n = recv(*psock, buf, sizeof(buf), 0); + if (n <= 0) { + lua_pushnil(L); + } else { + lua_pushlstring(L, buf, n); + } + } else { + return luaL_error(L, "invalid :recv() call"); + } + return 1; +} + +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; + size_t s; + SOCKET *psock; + + if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) { + buf = lua_tolstring(L, -1, &len); + lua_getfield(L, -2, "sock"); + psock = (SOCKET *)lua_tolstring(L, -1, &s); + if (s != sizeof(SOCKET)) { + return luaL_error(L, "invalid internal state in :close() call"); + } + + while (sent < len) { + if ((n = send(*psock, buf + sent, (int)(len - sent), 0)) <= 0) { + break; + } + sent += n; + } + lua_pushnumber(L, n); + } else { + return luaL_error(L, "invalid :close() call"); + } + return 1; +} + +static int +lsp_sock_gc(lua_State *L) +{ + int num_args = lua_gettop(L); + size_t s; + SOCKET *psock; + + if ((num_args == 1) && lua_istable(L, -1)) { + lua_getfield(L, -1, "sock"); + psock = (SOCKET *)lua_tolstring(L, -1, &s); + if (s != sizeof(SOCKET)) { + return luaL_error( + L, + "invalid internal state in __gc for object created by connect"); + } + closesocket(*psock); + } else { + return luaL_error(L, "__gc for object created by connect failed"); + } + return 0; +} + +/* Methods and meta-methods supported by the object returned by connect. + * For meta-methods, see http://lua-users.org/wiki/MetatableEvents */ +static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close}, + {"send", lsp_sock_send}, + {"recv", lsp_sock_recv}, + {"__gc", lsp_sock_gc}, + {NULL, NULL}}; + +static int +lsp_connect(lua_State *L) +{ + int num_args = lua_gettop(L); + char ebuf[100]; + SOCKET sock; + union usa sa; + int ok; + + if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2) + && lua_isnumber(L, -1)) { + ok = connect_socket(NULL, + lua_tostring(L, -3), + (int)lua_tonumber(L, -2), + (int)lua_tonumber(L, -1), + ebuf, + sizeof(ebuf), + &sock, + &sa); + if (!ok) { + return luaL_error(L, ebuf); + } else { + lua_newtable(L); + reg_lstring(L, "sock", (const char *)&sock, sizeof(SOCKET)); + reg_string(L, "host", lua_tostring(L, -4)); + luaL_getmetatable(L, LUASOCKET); + lua_setmetatable(L, -2); + } + } else { + return luaL_error( + L, "connect(host,port,is_ssl): invalid parameter given."); + } + return 1; +} + +static int +lsp_error(lua_State *L) +{ + lua_getglobal(L, "mg"); + lua_getfield(L, -1, "onerror"); + lua_pushvalue(L, -3); + lua_pcall(L, 1, 0, 0); + return 0; +} + +/* Silently stop processing chunks. */ +static void +lsp_abort(lua_State *L) +{ + int top = lua_gettop(L); + lua_getglobal(L, "mg"); + lua_pushnil(L); + lua_setfield(L, -2, "onerror"); + lua_settop(L, top); + lua_pushstring(L, "aborting"); + lua_error(L); +} + +struct lsp_var_reader_data { + const char *begin; + unsigned len; + unsigned state; +}; + + +static const char * +lsp_var_reader(lua_State *L, void *ud, size_t *sz) +{ + struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud; + const char *ret; + (void)(L); /* unused */ + + 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; + } + + reader->state++; + return ret; +} + + +static int +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]; + struct lsp_var_reader_data data; + + for (i = 0; i < len; i++) { + 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; + else + j = i + 1; + + while (j < len) { + if (p[j] == '\n') + lualines++; + if (((j + 1) < len) && (p[j] == '?') && (p[j + 1] == '>')) { + mg_write(conn, p + pos, i - pos); + + mg_snprintf(conn, + NULL, /* name only used for debugging */ + chunkname, + sizeof(chunkname), + "@%s+%i", + path, + lines); + lua_pushlightuserdata(L, conn); + lua_pushcclosure(L, lsp_error, 1); + + if (is_var) { + data.begin = p + (i + 3); + data.len = j - (i + 3); + data.state = 0; + lua_ok = mg_lua_load( + L, lsp_var_reader, &data, chunkname, NULL); + } else { + lua_ok = luaL_loadbuffer(L, + p + (i + 2), + j - (i + 2), + chunkname); + } + + if (lua_ok) { + /* Syntax error or OOM. Error message is pushed on + * stack. */ + lua_pcall(L, 1, 0, 0); + } else { + /* Success loading chunk. Call it. */ + lua_pcall(L, 0, 0, 1); + } + + pos = j + 2; + i = pos - 1; + break; + } + j++; + } + + if (lualines > 0) { + lines += lualines; + lualines = 0; + } + } + } + + if (i > pos) { + mg_write(conn, p + pos, i - pos); + } + + return 0; +} + + +/* mg.write: Send data to the client */ +static int +lsp_write(lua_State *L) +{ + struct mg_connection *conn = + (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1)); + int num_args = lua_gettop(L); + const char *str; + size_t size; + int i; + int rv = 1; + + for (i = 1; i <= num_args; i++) { + if (lua_isstring(L, i)) { + str = lua_tolstring(L, i, &size); + if (mg_write(conn, str, size) != (int)size) { + rv = 0; + } + } + } + lua_pushboolean(L, rv); + + return 1; +} + + +/* mg.read: Read data from the client (e.g., from a POST request) */ +static int +lsp_read(lua_State *L) +{ + struct mg_connection *conn = + (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1)); + char buf[1024]; + int len = mg_read(conn, buf, sizeof(buf)); + + if (len <= 0) + return 0; + lua_pushlstring(L, buf, len); + + 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 = + (struct mg_connection *)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 = + (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; + + 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; +} + + +/* mg.cry: Log an error. Default value for mg.onerror. */ +static int +lsp_cry(lua_State *L) +{ + struct mg_connection *conn = + (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(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; +} + + +/* mg.redirect: Redirect the request (internally). */ +static int +lsp_redirect(lua_State *L) +{ + struct mg_connection *conn = + (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1)); + int num_args = lua_gettop(L); + const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL; + + if (target) { + conn->request_info.local_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 = + (struct mg_connection *)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_time */ +static int +lsp_get_time(lua_State *L) +{ + int num_args = lua_gettop(L); + int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0; + struct timespec ts; + double d; + + clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts); + d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9); + lua_pushnumber(L, d); + return 1; +} + + +/* mg.get_var */ +static int +lsp_get_var(lua_State *L) +{ + 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 (mid): 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) +{ + int num_args = lua_gettop(L); + struct vec mime_type = {0, 0}; + struct mg_context *ctx; + const char *text; + + 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_tostring(L, 1); + if (text) { + if (ctx) { + get_mime_type(ctx, text, &mime_type); + lua_pushlstring(L, mime_type.ptr, mime_type.len); + } else { + text = mg_get_builtin_mime_type(text); + lua_pushstring(L, text); + } + } else { + /* Syntax error */ + return luaL_error(L, "invalid argument for get_mime_type() call"); + } + } 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); + 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 * 3]; + + 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, (int)text_len, dst, (int)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.base64_encode */ +static int +lsp_base64_encode(lua_State *L) +{ + int num_args = lua_gettop(L); + const char *text; + size_t text_len; + char *dst; + + if (num_args == 1) { + text = lua_tolstring(L, 1, &text_len); + if (text) { + dst = (char *)mg_malloc(text_len * 8 / 6 + 4); + if (dst) { + base64_encode((const unsigned char *)text, (int)text_len, dst); + lua_pushstring(L, dst); + mg_free(dst); + } else { + return luaL_error(L, "out of memory in base64_encode() call"); + } + } else { + lua_pushnil(L); + } + } else { + /* Syntax error */ + return luaL_error(L, "invalid base64_encode() call"); + } + return 1; +} + + +/* mg.base64_encode */ +static int +lsp_base64_decode(lua_State *L) +{ + int num_args = lua_gettop(L); + const char *text; + size_t text_len, dst_len; + int ret; + char *dst; + + if (num_args == 1) { + text = lua_tolstring(L, 1, &text_len); + if (text) { + dst = (char *)mg_malloc(text_len); + if (dst) { + ret = base64_decode((const unsigned char *)text, + (int)text_len, + dst, + &dst_len); + if (ret != -1) { + mg_free(dst); + return luaL_error( + L, "illegal character in lsp_base64_decode() call"); + } else { + lua_pushlstring(L, dst, dst_len); + mg_free(dst); + } + } else { + return luaL_error(L, + "out of memory in lsp_base64_decode() call"); + } + } else { + lua_pushnil(L); + } + } else { + /* Syntax error */ + return luaL_error(L, "invalid lsp_base64_decode() call"); + } + return 1; +} + + +/* mg.get_response_code_text */ +static int +lsp_get_response_code_text(lua_State *L) +{ + int num_args = lua_gettop(L); + int type1; + double code; + const char *text; + + if (num_args == 1) { + type1 = lua_type(L, 1); + if (type1 == LUA_TNUMBER) { + /* If the first argument is a number, + convert it to the corresponding text. */ + code = lua_tonumber(L, 1); + text = mg_get_response_code_text(NULL, (int)code); + if (text) + lua_pushstring(L, text); + return text ? 1 : 0; + } + } + + /* Syntax error */ + return luaL_error(L, "invalid get_response_code_text() call"); +} + + +/* mg.random - might be better than math.random on some systems */ +static int +lsp_random(lua_State *L) +{ + int num_args = lua_gettop(L); + if (num_args == 0) { + /* The civetweb internal random number generator will generate + * a 64 bit random number. */ + uint64_t r = get_random(); + /* Lua "number" is a IEEE 754 double precission float: + * https://en.wikipedia.org/wiki/Double-precision_floating-point_format + * Thus, mask with 2^53-1 to get an integer with the maximum + * precission available. */ + r &= ((((uint64_t)1) << 53) - 1); + lua_pushnumber(L, (double)r); + return 1; + } + + /* Syntax error */ + return luaL_error(L, "invalid random() call"); +} + + +union { + void *p; + void (*f)(unsigned char uuid[16]); +} pf_uuid_generate; + + +/* mg.uuid */ +static int +lsp_uuid(lua_State *L) +{ + union { + unsigned char uuid_array[16]; + struct uuid_struct_type { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; + } uuid_struct; + } uuid; + + char uuid_str[40]; + int num_args = lua_gettop(L); + + memset(&uuid, 0, sizeof(uuid)); + memset(uuid_str, 0, sizeof(uuid_str)); + + if (num_args == 0) { + + pf_uuid_generate.f(uuid.uuid_array); + + sprintf(uuid_str, + "{%08lX-%04X-%04X-%02X%02X-" + "%02X%02X%02X%02X%02X%02X}", + (unsigned long)uuid.uuid_struct.data1, + (unsigned)uuid.uuid_struct.data2, + (unsigned)uuid.uuid_struct.data3, + (unsigned)uuid.uuid_struct.data4[0], + (unsigned)uuid.uuid_struct.data4[1], + (unsigned)uuid.uuid_struct.data4[2], + (unsigned)uuid.uuid_struct.data4[3], + (unsigned)uuid.uuid_struct.data4[4], + (unsigned)uuid.uuid_struct.data4[5], + (unsigned)uuid.uuid_struct.data4[6], + (unsigned)uuid.uuid_struct.data4[7]); + + lua_pushstring(L, uuid_str); + return 1; + } + + /* Syntax error */ + return luaL_error(L, "invalid random() call"); +} + + +#ifdef USE_WEBSOCKET +struct lua_websock_data { + lua_State *state; + char *script; + unsigned references; + struct mg_connection *conn[MAX_WORKER_THREADS]; + pthread_mutex_t ws_mutex; +}; +#endif + + +/* mg.write for websockets */ +static int +lwebsock_write(lua_State *L) +{ +#ifdef USE_WEBSOCKET + int num_args = lua_gettop(L); + struct lua_websock_data *ws; + const char *str; + size_t size; + int opcode = -1; + unsigned i; + struct mg_connection *client = NULL; + + lua_pushlightuserdata(L, (void *)&lua_regkey_connlist); + lua_gettable(L, LUA_REGISTRYINDEX); + ws = (struct lua_websock_data *)lua_touserdata(L, -1); + + (void)pthread_mutex_lock(&(ws->ws_mutex)); + + if (num_args == 1) { + /* just one text: send it to all client */ + if (lua_isstring(L, 1)) { + opcode = WEBSOCKET_OPCODE_TEXT; + } + } else if (num_args == 2) { + if (lua_isnumber(L, 1)) { + /* opcode number and message text */ + opcode = (int)lua_tointeger(L, 1); + } else if (lua_isstring(L, 1)) { + /* opcode string and message text */ + str = lua_tostring(L, 1); + if (!mg_strncasecmp(str, "text", 4)) + opcode = WEBSOCKET_OPCODE_TEXT; + else if (!mg_strncasecmp(str, "bin", 3)) + opcode = WEBSOCKET_OPCODE_BINARY; + else if (!mg_strncasecmp(str, "close", 5)) + opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE; + else if (!mg_strncasecmp(str, "ping", 4)) + opcode = WEBSOCKET_OPCODE_PING; + else if (!mg_strncasecmp(str, "pong", 4)) + opcode = WEBSOCKET_OPCODE_PONG; + else if (!mg_strncasecmp(str, "cont", 4)) + opcode = WEBSOCKET_OPCODE_CONTINUATION; + } else if (lua_isuserdata(L, 1)) { + /* client id and message text */ + client = (struct mg_connection *)lua_touserdata(L, 1); + opcode = WEBSOCKET_OPCODE_TEXT; + } + } else if (num_args == 3) { + if (lua_isuserdata(L, 1)) { + client = (struct mg_connection *)lua_touserdata(L, 1); + if (lua_isnumber(L, 2)) { + /* client id, opcode number and message text */ + opcode = (int)lua_tointeger(L, 2); + } else if (lua_isstring(L, 2)) { + /* client id, opcode string and message text */ + str = lua_tostring(L, 2); + if (!mg_strncasecmp(str, "text", 4)) + opcode = WEBSOCKET_OPCODE_TEXT; + else if (!mg_strncasecmp(str, "bin", 3)) + opcode = WEBSOCKET_OPCODE_BINARY; + else if (!mg_strncasecmp(str, "close", 5)) + opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE; + else if (!mg_strncasecmp(str, "ping", 4)) + opcode = WEBSOCKET_OPCODE_PING; + else if (!mg_strncasecmp(str, "pong", 4)) + opcode = WEBSOCKET_OPCODE_PONG; + else if (!mg_strncasecmp(str, "cont", 4)) + opcode = WEBSOCKET_OPCODE_CONTINUATION; + } + } + } + + if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) { + str = lua_tolstring(L, num_args, &size); + if (client) { + for (i = 0; i < ws->references; i++) { + if (client == ws->conn[i]) { + mg_websocket_write(ws->conn[i], opcode, str, size); + } + } + } else { + for (i = 0; i < ws->references; i++) { + mg_websocket_write(ws->conn[i], opcode, str, size); + } + } + } else { + (void)pthread_mutex_unlock(&(ws->ws_mutex)); + return luaL_error(L, "invalid websocket write() call"); + } + + (void)pthread_mutex_unlock(&(ws->ws_mutex)); + +#else + (void)(L); /* unused */ +#endif + return 0; +} + + +struct laction_arg { + lua_State *state; + const char *script; + pthread_mutex_t *pmutex; + char txt[1]; +}; + + +static int +lua_action(struct laction_arg *arg) +{ + int err, ok; + struct mg_context *ctx; + + (void)pthread_mutex_lock(arg->pmutex); + + lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx); + lua_gettable(arg->state, LUA_REGISTRYINDEX); + ctx = (struct mg_context *)lua_touserdata(arg->state, -1); + + err = luaL_loadstring(arg->state, arg->txt); + if (err != 0) { + lua_cry(fc(ctx), err, arg->state, arg->script, "timer"); + (void)pthread_mutex_unlock(arg->pmutex); + mg_free(arg); + return 0; + } + err = lua_pcall(arg->state, 0, 1, 0); + if (err != 0) { + lua_cry(fc(ctx), err, arg->state, arg->script, "timer"); + (void)pthread_mutex_unlock(arg->pmutex); + mg_free(arg); + return 0; + } + + ok = lua_type(arg->state, -1); + if (lua_isboolean(arg->state, -1)) { + ok = lua_toboolean(arg->state, -1); + } else { + ok = 0; + } + lua_pop(arg->state, 1); + + (void)pthread_mutex_unlock(arg->pmutex); + + if (!ok) { + mg_free(arg); + } + return ok; +} + + +static int +lua_action_free(struct laction_arg *arg) +{ + if (lua_action(arg)) { + mg_free(arg); + } + return 0; +} + + +static int +lwebsocket_set_timer(lua_State *L, int is_periodic) +{ +#if defined(USE_TIMERS) && defined(USE_WEBSOCKET) + int num_args = lua_gettop(L); + struct lua_websock_data *ws; + int type1, type2, ok = 0; + double timediff; + struct mg_context *ctx; + struct laction_arg *arg; + const char *txt; + size_t txt_len; + + lua_pushlightuserdata(L, (void *)&lua_regkey_ctx); + lua_gettable(L, LUA_REGISTRYINDEX); + ctx = (struct mg_context *)lua_touserdata(L, -1); + + lua_pushlightuserdata(L, (void *)&lua_regkey_connlist); + lua_gettable(L, LUA_REGISTRYINDEX); + ws = (struct lua_websock_data *)lua_touserdata(L, -1); + + if (num_args < 2) { + return luaL_error(L, + "not enough arguments for set_timer/interval() call"); + } + + type1 = lua_type(L, 1); + type2 = lua_type(L, 2); + + if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) { + 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->state = L; + arg->script = ws->script; + arg->pmutex = &(ws->ws_mutex); + memcpy(arg->txt, "return(", 7); + memcpy(arg->txt + 7, txt, txt_len); + arg->txt[txt_len + 7] = ')'; + arg->txt[txt_len + 8] = 0; + ok = + (0 + == timer_add(ctx, + timediff, + is_periodic, + 1, + (taction)(is_periodic ? lua_action : lua_action_free), + (void *)arg)); + } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) { + /* TODO (mid): not implemented yet */ + return luaL_error(L, "invalid arguments for set_timer/interval() call"); + } else { + return luaL_error(L, "invalid arguments for set_timer/interval() call"); + } + + lua_pushboolean(L, ok); + return 1; + +#else + (void)(L); /* unused */ + (void)(is_periodic); /* unused */ + return 0; +#endif +} + + +/* mg.set_timeout for websockets */ +static int +lwebsocket_set_timeout(lua_State *L) +{ + return lwebsocket_set_timer(L, 0); +} + + +/* mg.set_interval for websockets */ +static int +lwebsocket_set_interval(lua_State *L) +{ + return lwebsocket_set_timer(L, 1); +} + +enum { + LUA_ENV_TYPE_LUA_SERVER_PAGE = 0, + LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1, + LUA_ENV_TYPE_LUA_WEBSOCKET = 2, +}; + + +static void +prepare_lua_request_info(struct mg_connection *conn, lua_State *L) +{ + const char *s; + int i; + + /* Export mg.request_info */ + lua_pushstring(L, "request_info"); + lua_newtable(L); + reg_string(L, "request_method", conn->request_info.request_method); + reg_string(L, "request_uri", conn->request_info.request_uri); + reg_string(L, "uri", conn->request_info.local_uri); + reg_string(L, "http_version", conn->request_info.http_version); + reg_string(L, "query_string", conn->request_info.query_string); +#if defined(MG_LEGACY_INTERFACE) + reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is + deprecated, use + remote_addr + instead */ +#endif + reg_string(L, "remote_addr", conn->request_info.remote_addr); + /* TODO (high): ip version */ + reg_int(L, "remote_port", conn->request_info.remote_port); + reg_int(L, "num_headers", conn->request_info.num_headers); + reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port)); + + if (conn->path_info != NULL) { + reg_string(L, "path_info", conn->path_info); + } + + if (conn->request_info.content_length >= 0) { + /* reg_int64: content_length */ + lua_pushstring(L, "content_length"); + lua_pushnumber( + L, + (lua_Number)conn->request_info + .content_length); /* lua_Number may be used as 52 bit integer */ + lua_rawset(L, -3); + } + if ((s = mg_get_header(conn, "Content-Type")) != NULL) { + reg_string(L, "content_type", s); + } + + if (conn->request_info.remote_user != NULL) { + reg_string(L, "remote_user", conn->request_info.remote_user); + reg_string(L, "auth_type", "Digest"); + } + + reg_boolean(L, "https", conn->ssl != NULL); + + if (conn->status_code > 0) { + /* Lua error handler should show the status code */ + reg_int(L, "status", conn->status_code); + } + + lua_pushstring(L, "http_headers"); + lua_newtable(L); + for (i = 0; i < conn->request_info.num_headers; i++) { + reg_string(L, + conn->request_info.http_headers[i].name, + conn->request_info.http_headers[i].value); + } + lua_rawset(L, -3); + + lua_rawset(L, -3); +} + + +void +civetweb_open_lua_libs(lua_State *L) +{ + { + extern void luaL_openlibs(lua_State *); + luaL_openlibs(L); + } + +#ifdef USE_LUA_SQLITE3 + { + extern int luaopen_lsqlite3(lua_State *); + luaopen_lsqlite3(L); + } +#endif +#ifdef USE_LUA_LUAXML + { + extern int luaopen_LuaXML_lib(lua_State *); + luaopen_LuaXML_lib(L); + } +#endif +#ifdef USE_LUA_FILE_SYSTEM + { + extern int luaopen_lfs(lua_State *); + luaopen_lfs(L); + } +#endif +#ifdef USE_LUA_BINARY + { + /* TODO (low): Test if this could be used as a replacement for bit32. + * Check again with Lua 5.3 later. */ + extern int luaopen_binary(lua_State *); + + luaL_requiref(L, "binary", luaopen_binary, 1); + lua_pop(L, 1); + } +#endif +} + + +static void +prepare_lua_environment(struct mg_context *ctx, + struct mg_connection *conn, + struct lua_websock_data *ws_conn_list, + lua_State *L, + const char *script_name, + int lua_env_type) +{ + civetweb_open_lua_libs(L); + +#if LUA_VERSION_NUM == 502 + /* Keep the "connect" method for compatibility, + * but do not backport it to Lua 5.1. + * TODO: Redesign the interface. + */ + luaL_newmetatable(L, LUASOCKET); + lua_pushliteral(L, "__index"); + luaL_newlib(L, luasocket_methods); + lua_rawset(L, -3); + lua_pop(L, 1); + lua_register(L, "connect", lsp_connect); +#endif + + /* Store context in the registry */ + if (ctx != NULL) { + lua_pushlightuserdata(L, (void *)&lua_regkey_ctx); + lua_pushlightuserdata(L, (void *)ctx); + lua_settable(L, LUA_REGISTRYINDEX); + } + if (ws_conn_list != NULL) { + lua_pushlightuserdata(L, (void *)&lua_regkey_connlist); + lua_pushlightuserdata(L, (void *)ws_conn_list); + lua_settable(L, LUA_REGISTRYINDEX); + } + + /* Register mg module */ + lua_newtable(L); + + switch (lua_env_type) { + case LUA_ENV_TYPE_LUA_SERVER_PAGE: + reg_string(L, "lua_type", "page"); + break; + case LUA_ENV_TYPE_PLAIN_LUA_PAGE: + reg_string(L, "lua_type", "script"); + break; + case LUA_ENV_TYPE_LUA_WEBSOCKET: + reg_string(L, "lua_type", "websocket"); + break; + } + + if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE + || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) { + reg_conn_function(L, "cry", lsp_cry, conn); + reg_conn_function(L, "read", lsp_read, conn); + reg_conn_function(L, "write", lsp_write, conn); + reg_conn_function(L, "keep_alive", lsp_keep_alive, conn); + reg_conn_function(L, "send_file", lsp_send_file, conn); + } + + if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) { + reg_conn_function(L, "include", lsp_include, conn); + reg_conn_function(L, "redirect", lsp_redirect, conn); + } + + if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) { + reg_function(L, "write", lwebsock_write); +#ifdef USE_TIMERS + reg_function(L, "set_timeout", lwebsocket_set_timeout); + reg_function(L, "set_interval", lwebsocket_set_interval); +#endif + /* reg_conn_function(L, "send_file", lsp_send_file, conn); */ + } + + reg_function(L, "time", lsp_get_time); + reg_function(L, "get_var", lsp_get_var); + reg_function(L, "get_mime_type", lsp_get_mime_type); + reg_function(L, "get_cookie", lsp_get_cookie); + reg_function(L, "md5", lsp_md5); + reg_function(L, "url_encode", lsp_url_encode); + reg_function(L, "url_decode", lsp_url_decode); + reg_function(L, "base64_encode", lsp_base64_encode); + 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); + if (pf_uuid_generate.f) { + reg_function(L, "uuid", lsp_uuid); + } + + reg_string(L, "version", CIVETWEB_VERSION); + + reg_string(L, "script_name", script_name); + + if (ctx != NULL) { + reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]); + reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]); +#if defined(USE_WEBSOCKET) + if (ctx->config[WEBSOCKET_ROOT]) { + reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]); + } else { + reg_string(L, "websocket_root", ctx->config[DOCUMENT_ROOT]); + } +#endif + + if (ctx->systemName != NULL) { + reg_string(L, "system", ctx->systemName); + } + } + + /* Export connection specific info */ + if (conn != NULL) { + prepare_lua_request_info(conn, L); + } + + lua_setglobal(L, "mg"); + + /* Register default mg.onerror function */ + IGNORE_UNUSED_RESULT( + luaL_dostring(L, + "mg.onerror = function(e) mg.write('\\nLua error:\\n', " + "debug.traceback(e, 1)) end")); + + if (ctx != NULL) { + /* Preload */ + if (ctx->config[LUA_PRELOAD_FILE] != NULL) { + IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE])); + } + + if (ctx->callbacks.init_lua != NULL) { + ctx->callbacks.init_lua(conn, L); + } + } +} + + +static int +lua_error_handler(lua_State *L) +{ + const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n"; + + lua_getglobal(L, "mg"); + if (!lua_isnil(L, -1)) { + lua_getfield(L, -1, "write"); /* call mg.write() */ + lua_pushstring(L, error_msg); + lua_pushliteral(L, "\n"); + lua_call(L, 2, 0); + IGNORE_UNUSED_RESULT( + luaL_dostring(L, "mg.write(debug.traceback(), '\\n')")); + } else { + printf("Lua error: [%s]\n", error_msg); + IGNORE_UNUSED_RESULT( + luaL_dostring(L, "print(debug.traceback(), '\\n')")); + } + /* TODO(lsm, low): leave the stack balanced */ + + return 0; +} + + +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); +} + + +static void +mg_exec_lua_script(struct mg_connection *conn, + const char *path, + const void **exports) +{ + 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 = lua_newstate(lua_allocator, NULL)) != NULL) { + prepare_lua_environment( + conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE); + lua_pushcclosure(L, &lua_error_handler, 0); + + if (exports != NULL) { +#if LUA_VERSION_NUM > 501 + lua_pushglobaltable(L); + for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) { + lua_CFunction func; + lua_pushstring(L, (const char *)(exports[i])); + *(const void **)(&func) = exports[i + 1]; + lua_pushcclosure(L, func, 0); + lua_rawset(L, -3); + } +#else + for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) { + lua_CFunction func; + const char *name = (const char *)(exports[i]); + *(const void **)(&func) = exports[i + 1]; + lua_register(L, name, func); + } +#endif + } + + if (luaL_loadfile(L, path) != 0) { + lua_error_handler(L); + } + lua_pcall(L, 0, 0, -2); + lua_close(L); + } +} + + +static int +handle_lsp_request(struct mg_connection *conn, + const char *path, + struct mg_file *filep, + struct lua_State *ls) +{ + void *p = NULL; + lua_State *L = NULL; + 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; + } + + 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); + } else { + luaL_error(ls, "Cannot [%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; + + if (filep->access.membuf == NULL + && (p = mmap(NULL, + (size_t)filep->stat.size, + PROT_READ, + MAP_PRIVATE, + fileno(filep->access.fp), + 0)) == MAP_FAILED) { + + /* mmap failed */ + if (ls == NULL) { + send_http_error( + conn, + 500, + "Error: Cannot open script\nFile %s can not be mapped", + path); + } else { + luaL_error(ls, + "mmap(%s, %zu, %d): %s", + path, + (size_t)filep->stat.size, + fileno(filep->access.fp), + strerror(errno)); + } + + goto cleanup_handle_lsp_request; + } + + if (ls != NULL) { + L = ls; + } else { + L = lua_newstate(lua_allocator, NULL); + if (L == NULL) { + send_http_error( + conn, + 500, + "%s", + "Error: Cannot execute script\nlua_newstate failed"); + + goto cleanup_handle_lsp_request; + } + prepare_lua_environment( + conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE); + } + + /* 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); + +cleanup_handle_lsp_request: + + if (L != NULL && ls == NULL) + lua_close(L); + if (p != NULL) + munmap(p, filep->stat.size); + (void)mg_fclose(&filep->access); + + return error; +} + + +#ifdef USE_WEBSOCKET +struct mg_shared_lua_websocket_list { + struct lua_websock_data ws; + struct mg_shared_lua_websocket_list *next; +}; + + +static void * +lua_websocket_new(const char *script, struct mg_connection *conn) +{ + struct mg_shared_lua_websocket_list **shared_websock_list = + &(conn->ctx->shared_lua_websockets); + struct lua_websock_data *ws; + int err, ok = 0; + + assert(conn->lua_websocket_state == NULL); + + /* lock list (mg_context global) */ + mg_lock_context(conn->ctx); + while (*shared_websock_list) { + /* check if ws already in list */ + if (0 == strcmp(script, (*shared_websock_list)->ws.script)) { + break; + } + shared_websock_list = &((*shared_websock_list)->next); + } + + 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); + if (*shared_websock_list == NULL) { + mg_unlock_context(conn->ctx); + mg_cry(conn, "Cannot create shared websocket struct, OOM"); + return NULL; + } + /* init ws list element */ + ws = &(*shared_websock_list)->ws; + 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->conn[0] = conn; + ws->references = 1; + prepare_lua_environment( + conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET); + err = luaL_loadfile(ws->state, script); + if (err != 0) { + lua_cry(conn, err, ws->state, script, "load"); + } + err = lua_pcall(ws->state, 0, 0, 0); + if (err != 0) { + lua_cry(conn, err, ws->state, script, "init"); + } + } else { + /* inc ref count */ + ws = &(*shared_websock_list)->ws; + (void)pthread_mutex_lock(&(ws->ws_mutex)); + (*shared_websock_list)->ws.conn[(ws->references)++] = conn; + } + mg_unlock_context(conn->ctx); + + /* call add */ + lua_getglobal(ws->state, "open"); + lua_newtable(ws->state); + prepare_lua_request_info(conn, ws->state); + lua_pushstring(ws->state, "client"); + lua_pushlightuserdata(ws->state, (void *)conn); + lua_rawset(ws->state, -3); + + err = lua_pcall(ws->state, 1, 1, 0); + if (err != 0) { + lua_cry(conn, err, ws->state, script, "open handler"); + } else { + if (lua_isboolean(ws->state, -1)) { + ok = lua_toboolean(ws->state, -1); + } + lua_pop(ws->state, 1); + } + if (!ok) { + /* Remove from ws connection list. */ + /* TODO (mid): Check if list entry and Lua state needs to be deleted + * (see websocket_close). */ + (*shared_websock_list)->ws.conn[--(ws->references)] = 0; + } + + (void)pthread_mutex_unlock(&(ws->ws_mutex)); + + return ok ? (void *)ws : NULL; +} + + +static int +lua_websocket_data(struct mg_connection *conn, + int bits, + char *data, + size_t data_len, + void *ws_arg) +{ + struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg); + int err, ok = 0; + + assert(ws != NULL); + assert(ws->state != NULL); + + (void)pthread_mutex_lock(&(ws->ws_mutex)); + + lua_getglobal(ws->state, "data"); + lua_newtable(ws->state); + lua_pushstring(ws->state, "client"); + lua_pushlightuserdata(ws->state, (void *)conn); + lua_rawset(ws->state, -3); + lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with + a meaning according to + http://tools.ietf.org/html/rfc6455, + section 5.2 */ + lua_pushnumber(ws->state, bits); + lua_rawset(ws->state, -3); + lua_pushstring(ws->state, "data"); + lua_pushlstring(ws->state, data, data_len); + lua_rawset(ws->state, -3); + + err = lua_pcall(ws->state, 1, 1, 0); + if (err != 0) { + lua_cry(conn, err, ws->state, ws->script, "data handler"); + } else { + if (lua_isboolean(ws->state, -1)) { + ok = lua_toboolean(ws->state, -1); + } + lua_pop(ws->state, 1); + } + (void)pthread_mutex_unlock(&(ws->ws_mutex)); + + return ok; +} + + +static int +lua_websocket_ready(struct mg_connection *conn, void *ws_arg) +{ + struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg); + int err, ok = 0; + + assert(ws != NULL); + assert(ws->state != NULL); + + (void)pthread_mutex_lock(&(ws->ws_mutex)); + + lua_getglobal(ws->state, "ready"); + lua_newtable(ws->state); + lua_pushstring(ws->state, "client"); + lua_pushlightuserdata(ws->state, (void *)conn); + lua_rawset(ws->state, -3); + err = lua_pcall(ws->state, 1, 1, 0); + if (err != 0) { + lua_cry(conn, err, ws->state, ws->script, "ready handler"); + } else { + if (lua_isboolean(ws->state, -1)) { + ok = lua_toboolean(ws->state, -1); + } + lua_pop(ws->state, 1); + } + + (void)pthread_mutex_unlock(&(ws->ws_mutex)); + + return ok; +} + + +static void +lua_websocket_close(struct mg_connection *conn, void *ws_arg) +{ + struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg); + struct mg_shared_lua_websocket_list **shared_websock_list = + &(conn->ctx->shared_lua_websockets); + int err = 0; + unsigned i; + + assert(ws != NULL); + assert(ws->state != NULL); + + (void)pthread_mutex_lock(&(ws->ws_mutex)); + + lua_getglobal(ws->state, "close"); + lua_newtable(ws->state); + lua_pushstring(ws->state, "client"); + lua_pushlightuserdata(ws->state, (void *)conn); + lua_rawset(ws->state, -3); + + err = lua_pcall(ws->state, 1, 0, 0); + if (err != 0) { + lua_cry(conn, err, ws->state, ws->script, "close handler"); + } + for (i = 0; i < ws->references; i++) { + if (ws->conn[i] == conn) { + ws->references--; + ws->conn[i] = ws->conn[ws->references]; + } + } + /* TODO: Delete lua_websock_data and remove it from the websocket list. + This must only be done, when all connections are closed, and all + asynchronous operations and timers are completed/expired. */ + (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */ + + (void)pthread_mutex_unlock(&(ws->ws_mutex)); +} +#endif + + +lua_State * +mg_prepare_lua_context_script(const char *file_name, + struct mg_context *ctx, + char *ebuf, + size_t ebuf_len) +{ + struct lua_State *L; + int lua_ret; + const char *lua_err_txt; + + L = luaL_newstate(); + if (L == NULL) { + mg_snprintf(NULL, + NULL, /* No truncation check for ebuf */ + ebuf, + ebuf_len, + "Error: %s", + "Cannot create Lua state"); + return 0; + } + civetweb_open_lua_libs(L); + + 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, ...) + */ + lua_err_txt = lua_tostring(L, -1); + mg_snprintf(NULL, + NULL, /* No truncation check for ebuf */ + ebuf, + ebuf_len, + "Error loading file %s: %s\n", + file_name, + lua_err_txt); + return 0; + } + + /* The script file is loaded, now call it */ + lua_ret = lua_pcall(L, + /* no arguments */ 0, + /* zero or one return value */ 1, + /* errors as strint return value */ 0); + + if (lua_ret != LUA_OK) { + /* Error when executing the script */ + lua_err_txt = lua_tostring(L, -1); + mg_snprintf(NULL, + NULL, /* No truncation check for ebuf */ + ebuf, + ebuf_len, + "Error running file %s: %s\n", + file_name, + lua_err_txt); + return 0; + } + /* lua_close(L); must be done somewhere else */ + + return L; +} + + +int +run_lua(const char *file_name) +{ + int func_ret = EXIT_FAILURE; + char ebuf[512] = {0}; + lua_State *L = + mg_prepare_lua_context_script(file_name, NULL, ebuf, sizeof(ebuf)); + if (L) { + /* Script executed */ + if (lua_type(L, -1) == LUA_TNUMBER) { + func_ret = (int)lua_tonumber(L, -1); + } else { + func_ret = EXIT_SUCCESS; + } + lua_close(L); + } else { + fprintf(stderr, "%s\n", ebuf); + } + return func_ret; +} + + +static void *lib_handle_uuid = NULL; + +static void +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"); +#else + pf_uuid_generate.p = 0; +#endif +} + + +static void +lua_exit_optional_libraries(void) +{ +#if !defined(_WIN32) + dlclose(lib_handle_uuid); +#endif + pf_uuid_generate.p = 0; + lib_handle_uuid = NULL; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/sha1.inl ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/sha1.inl b/thirdparty/civetweb-1.9.1/src/sha1.inl new file mode 100644 index 0000000..a629c2f --- /dev/null +++ b/thirdparty/civetweb-1.9.1/src/sha1.inl @@ -0,0 +1,323 @@ +/* +SHA-1 in C +By Steve Reid <[email protected]> +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown <[email protected]> +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include <process.h> for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid <[email protected]> +Still 100% public domain + +1- Removed #include <process.h> and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from [email protected] to [email protected] + +----------------- +Modified 4/01 +By Saul Kravitz <[email protected]> +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles <[email protected]> +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h +*/ + +/* +11/2016 adapted for CivetWeb: + include sha1.h in sha1.c, + rename to sha1.inl + remove unused #ifdef sections + make endian independent + align buffer to 4 bytes +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#include <string.h> +#include <stdint.h> + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; +} SHA1_CTX; + +#define SHA1_DIGEST_SIZE 20 + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ + + +typedef union { + uint8_t c[64]; + uint32_t l[16]; +} CHAR64LONG16; + + +static uint32_t +blk0(CHAR64LONG16 *block, int i) +{ + static const uint32_t n = 1u; + if ((*((uint8_t *)(&n))) == 1) { + /* little endian / intel byte order */ + block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) + | (rol(block->l[i], 8) & 0x00FF00FF); + } + return block->l[i]; +} + +#define blk(block, i) \ + (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \ + ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \ + 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void +SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e; + + /* Must use an aligned, read/write buffer */ + CHAR64LONG16 block[1]; + memcpy(block, buffer, sizeof(block)); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ +SHA_API void +SHA1_Init(SHA1_CTX *context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +SHA_API void +SHA1_Update(SHA1_CTX *context, const uint8_t *data, const uint32_t len) +{ + uint32_t i, j; + + j = context->count[0]; + if ((context->count[0] += (len << 3)) < j) { + context->count[1]++; + } + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + i = 64 - j; + memcpy(&context->buffer[j], data, i); + SHA1_Transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + SHA1_Transform(context->state, &data[i]); + } + j = 0; + } else { + i = 0; + } + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ +SHA_API void +SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]) +{ + uint32_t i; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = + (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) + & 255); /* Endian independent */ + } + SHA1_Update(context, (uint8_t *)"\x80", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (uint8_t *)"\x00", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = + (uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + + /* Wipe variables */ + i = 0; + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua new file mode 100644 index 0000000..357be7e --- /dev/null +++ b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML.lua @@ -0,0 +1,116 @@ +local base = _G + +-- symbolic name for tag index, this allows accessing the tag by var[xml.TAG] +xml.TAG = 0 + +-- sets or returns tag of a LuaXML object +function xml.tag(var,tag) + if base.type(var)~="table" then return end + if base.type(tag)=="nil" then + return var[xml.TAG] + end + var[xml.TAG] = tag +end + +-- creates a new LuaXML object either by setting the metatable of an existing Lua table or by setting its tag +function xml.new(arg) + if base.type(arg)=="table" then + base.setmetatable(arg,{__index=xml, __tostring=xml.str}) + return arg + end + local var={} + base.setmetatable(var,{__index=xml, __tostring=xml.str}) + if base.type(arg)=="string" then var[xml.TAG]=arg end + return var +end + +-- appends a new subordinate LuaXML object to an existing one, optionally sets tag +function xml.append(var,tag) + if base.type(var)~="table" then return end + local newVar = xml.new(tag) + var[#var+1] = newVar + return newVar +end + +-- converts any Lua var into an XML string +function xml.str(var,indent,tagValue) + if base.type(var)=="nil" then return end + local indent = indent or 0 + local indentStr="" + for i = 1,indent do indentStr=indentStr.." " end + local tableStr="" + + if base.type(var)=="table" then + local tag = var[0] or tagValue or base.type(var) + local s = indentStr.."<"..tag + for k,v in base.pairs(var) do -- attributes + if base.type(k)=="string" then + if base.type(v)=="table" and k~="_M" then -- otherwise recursiveness imminent + tableStr = tableStr..xml.str(v,indent+1,k) + else + s = s.." "..k.."=\""..xml.encode(base.tostring(v)).."\"" + end + end + end + if #var==0 and #tableStr==0 then + s = s.." />\n" + elseif #var==1 and base.type(var[1])~="table" and #tableStr==0 then -- single element + s = s..">"..xml.encode(base.tostring(var[1])).."</"..tag..">\n" + else + s = s..">\n" + for k,v in base.ipairs(var) do -- elements + if base.type(v)=="string" then + s = s..indentStr.." "..xml.encode(v).." \n" + else + s = s..xml.str(v,indent+1) + end + end + s=s..tableStr..indentStr.."</"..tag..">\n" + end + return s + else + local tag = base.type(var) + return indentStr.."<"..tag.."> "..xml.encode(base.tostring(var)).." </"..tag..">\n" + end +end + + +-- saves a Lua var as xml file +function xml.save(var,filename) + if not var then return end + if not filename or #filename==0 then return end + local file = base.io.open(filename,"w") + file:write("<?xml version=\"1.0\"?>\n<!-- file \"",filename, "\", generated by LuaXML -->\n\n") + file:write(xml.str(var)) + base.io.close(file) +end + + +-- recursively parses a Lua table for a substatement fitting to the provided tag and attribute +function xml.find(var, tag, attributeKey,attributeValue) + -- check input: + if base.type(var)~="table" then return end + if base.type(tag)=="string" and #tag==0 then tag=nil end + if base.type(attributeKey)~="string" or #attributeKey==0 then attributeKey=nil end + if base.type(attributeValue)=="string" and #attributeValue==0 then attributeValue=nil end + -- compare this table: + if tag~=nil then + if var[0]==tag and ( attributeValue == nil or var[attributeKey]==attributeValue ) then + base.setmetatable(var,{__index=xml, __tostring=xml.str}) + return var + end + else + if attributeValue == nil or var[attributeKey]==attributeValue then + base.setmetatable(var,{__index=xml, __tostring=xml.str}) + return var + end + end + -- recursively parse subtags: + for k,v in base.ipairs(var) do + if base.type(v)=="table" then + local ret = xml.find(v, tag, attributeKey,attributeValue) + if ret ~= nil then return ret end + end + end +end + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/a9485aeb/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c new file mode 100644 index 0000000..9ac7f9f --- /dev/null +++ b/thirdparty/civetweb-1.9.1/src/third_party/LuaXML_lib.c @@ -0,0 +1,476 @@ +/** +LuaXML License + +LuaXml is licensed under the terms of the MIT license reproduced below, +the same as Lua itself. This means that LuaXml is free software and can be +used for both academic and commercial purposes at absolutely no cost. + +Copyright (C) 2007-2013 Gerald Franz, eludi.net + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#if defined __WIN32__ || defined WIN32 +# include <windows.h> +# define _EXPORT __declspec(dllexport) +#else +# define _EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "civetweb_lua.h" + +#ifdef __cplusplus +} // extern "C" +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +static const char ESC=27; +static const char OPN=28; +static const char CLS=29; + +//--- auxliary functions ------------------------------------------- + +static const char* char2code(unsigned char ch, char buf[8]) { + unsigned char i=0; + buf[i++]='&'; + buf[i++]='#'; + if(ch>99) buf[i++]=ch/100+48; + if(ch>9) buf[i++]=(ch%100)/10+48; + buf[i++]=ch%10+48; + buf[i++]=';'; + buf[i]=0; + return buf; +} + +static size_t find(const char* s, const char* pattern, size_t start) { + const char* found =strstr(s+start, pattern); + return found ? found-s : strlen(s); +} + +//--- internal tokenizer ------------------------------------------- + +typedef struct Tokenizer_s { + /// stores string to be tokenized + const char* s; + /// stores size of string to be tokenized + size_t s_size; + /// stores current read position + size_t i; + /// stores current read context + int tagMode; + /// stores next token, if already determined + const char* m_next; + /// size of next token + size_t m_next_size; + /// pointer to current token + char* m_token; + /// size of current token + size_t m_token_size; + /// capacity of current token + size_t m_token_capacity; +} Tokenizer; + +Tokenizer* Tokenizer_new(const char* str, size_t str_size) { + Tokenizer *tok = (Tokenizer*)malloc(sizeof(Tokenizer)); + memset(tok, 0, sizeof(Tokenizer)); + tok->s_size = str_size; + tok->s = str; + return tok; +} + +void Tokenizer_delete(Tokenizer* tok) { + free(tok->m_token); + free(tok); +} + +//void Tokenizer_print(Tokenizer* tok) { printf(" @%u %s\n", tok->i, !tok->m_token ? "(null)" : (tok->m_token[0]==ESC)?"(esc)" : (tok->m_token[0]==OPN)?"(open)": (tok->m_token[0]==CLS)?"(close)" : tok->m_token); fflush(stdout); } + +static const char* Tokenizer_set(Tokenizer* tok, const char* s, size_t size) { + if(!size||!s) return 0; + free(tok->m_token); + tok->m_token = (char*)malloc(size+1); + strncpy(tok->m_token,s, size); + tok->m_token[size] = 0; + tok->m_token_size = tok->m_token_capacity = size; + //Tokenizer_print(tok); + return tok->m_token; +} + +static void Tokenizer_append(Tokenizer* tok, char ch) { + if(tok->m_token_size+1>=tok->m_token_capacity) { + tok->m_token_capacity = (tok->m_token_capacity==0) ? 16 : tok->m_token_capacity*2; + tok->m_token = (char*)realloc(tok->m_token, tok->m_token_capacity); + } + tok->m_token[tok->m_token_size]=ch; + tok->m_token[++tok->m_token_size]=0; +} + +const char* Tokenizer_next(Tokenizer* tok) { + const char* ESC_str = "\033"; + const char* OPEN_str = "\034"; + const char* CLOSE_str = "\035"; + int quotMode=0; + int tokenComplete = 0; + + if(tok->m_token) { + free(tok->m_token); + tok->m_token = 0; + tok->m_token_size=tok->m_token_capacity = 0; + } + + while(tok->m_next_size || (tok->i < tok->s_size)) { + + if(tok->m_next_size) { + Tokenizer_set(tok, tok->m_next, tok->m_next_size); + tok->m_next=0; + tok->m_next_size=0; + return tok->m_token; + } + + switch(tok->s[tok->i]) { + case '"': + case '\'': + if(tok->tagMode) { + if(!quotMode) quotMode=tok->s[tok->i]; + else if(quotMode==tok->s[tok->i]) quotMode=0; + } + Tokenizer_append(tok, tok->s[tok->i]); + break; + case '<': + if(!quotMode&&(tok->i+4<tok->s_size)&&(strncmp(tok->s+tok->i,"<!--",4)==0)) // strip comments + tok->i=find(tok->s, "-->", tok->i+4)+2; + else if(!quotMode&&(tok->i+9<tok->s_size)&&(strncmp(tok->s+tok->i,"<![CDATA[",9)==0)) { // interpet CDATA + size_t b=tok->i+9; + tok->i=find(tok->s, "]]>",b)+3; + if(!tok->m_token_size) return Tokenizer_set(tok, tok->s+b, tok->i-b-3); + tokenComplete = 1; + tok->m_next = tok->s+b; + tok->m_next_size = tok->i-b-3; + --tok->i; + } + else if(!quotMode&&(tok->i+1<tok->s_size)&&((tok->s[tok->i+1]=='?')||(tok->s[tok->i+1]=='!'))) // strip meta information + tok->i=find(tok->s, ">", tok->i+2); + else if(!quotMode&&!tok->tagMode) { + if((tok->i+1<tok->s_size)&&(tok->s[tok->i+1]=='/')) { + tok->m_next=ESC_str; + tok->m_next_size = 1; + tok->i=find(tok->s, ">", tok->i+2); + } + else { + tok->m_next = OPEN_str; + tok->m_next_size = 1; + tok->tagMode=1; + } + tokenComplete = 1; + } + else Tokenizer_append(tok, tok->s[tok->i]); + break; + case '/': + if(tok->tagMode&&!quotMode) { + tokenComplete = 1; + if((tok->i+1 < tok->s_size) && (tok->s[tok->i+1]=='>')) { + tok->tagMode=0; + tok->m_next=ESC_str; + tok->m_next_size = 1; + ++tok->i; + } + else Tokenizer_append(tok, tok->s[tok->i]); + } + else Tokenizer_append(tok, tok->s[tok->i]); + break; + case '>': + if(!quotMode&&tok->tagMode) { + tok->tagMode=0; + tokenComplete = 1; + tok->m_next = CLOSE_str; + tok->m_next_size = 1; + } + else Tokenizer_append(tok, tok->s[tok->i]); + break; + case ' ': + case '\r': + case '\n': + case '\t': + if(tok->tagMode&&!quotMode) { + if(tok->m_token_size) tokenComplete=1; + } + else if(tok->m_token_size) Tokenizer_append(tok, tok->s[tok->i]); + break; + default: Tokenizer_append(tok, tok->s[tok->i]); + } + ++tok->i; + if((tok->i>=tok->s_size)||(tokenComplete&&tok->m_token_size)) { + tokenComplete=0; + while(tok->m_token_size&&isspace(tok->m_token[tok->m_token_size-1])) // trim whitespace + tok->m_token[--tok->m_token_size]=0; + if(tok->m_token_size) break; + } + } + //Tokenizer_print(tok); + return tok->m_token; +} + +//--- local variables ---------------------------------------------- + +/// stores number of special character codes +static size_t sv_code_size=0; +/// stores currently allocated capacity for special character codes +static size_t sv_code_capacity=16; +/// stores code table for special characters +static char** sv_code=0; + +//--- public methods ----------------------------------------------- + +static void Xml_pushDecode(lua_State* L, const char* s, size_t s_size) { + + luaL_Buffer b; + const char* found = strstr(s, "&#"); + size_t start=0, pos, i; + + if(!s_size) + s_size=strlen(s); + + luaL_buffinit(L, &b); + found = strstr(s, "&#"); + pos = found ? found-s : s_size; + + while(found) { + char ch = 0; + size_t i=0; + for(found += 2; i<3; ++i, ++found) + if(isdigit(*found)) + ch = ch * 10 + (*found - 48); + else break; + if(*found == ';') { + if(pos>start) + luaL_addlstring(&b, s+start, pos-start); + luaL_addchar(&b, ch); + start = pos + 3 + i; + } + found = strstr(found+1, "&#"); + pos = found ? found-s : s_size; + } + if(pos>start) + luaL_addlstring(&b,s+start, pos-start); + luaL_pushresult(&b); + + for(i=sv_code_size-1; i<sv_code_size; i-=2) { + luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i-1]); + lua_remove(L,-2); + } +} + +int Xml_eval(lua_State *L) { + char* str = 0; + size_t str_size=0; + Tokenizer* tok; + const char* token=0; + int firstStatement = 1; + + if(lua_isuserdata(L,1)) + str = (char*)lua_touserdata(L,1); + else { + const char * sTmp = luaL_checklstring(L,1,&str_size); + str = (char*)malloc(str_size+1); + memcpy(str, sTmp, str_size); + str[str_size]=0; + } + tok = Tokenizer_new(str, str_size ? str_size : strlen(str)); + lua_settop(L,0); + + while((token=Tokenizer_next(tok))!=0) if(token[0]==OPN) { // new tag found + if(lua_gettop(L)) { + size_t newIndex=lua_rawlen(L,-1)+1; + lua_pushnumber(L, (lua_Number)newIndex); + lua_newtable(L); + lua_settable(L, -3); + lua_pushnumber(L, (lua_Number)newIndex); + lua_gettable(L,-2); + } + else { + if (firstStatement) { + lua_newtable(L); + firstStatement = 0; + } + else return lua_gettop(L); + } + // set metatable: + lua_newtable(L); + lua_pushliteral(L, "__index"); + lua_getglobal(L, "xml"); + lua_settable(L, -3); + + lua_pushliteral(L, "__tostring"); // set __tostring metamethod + lua_getglobal(L, "xml"); + lua_pushliteral(L,"str"); + lua_gettable(L, -2); + lua_remove(L, -2); + lua_settable(L, -3); + lua_setmetatable(L, -2); + + // parse tag and content: + lua_pushnumber(L,0); // use index 0 for storing the tag + lua_pushstring(L, Tokenizer_next(tok)); + lua_settable(L, -3); + + while(((token = Tokenizer_next(tok))!=0)&&(token[0]!=CLS)&&(token[0]!=ESC)) { // parse tag header + size_t sepPos=find(token, "=", 0); + if(token[sepPos]) { // regular attribute + const char* aVal =token+sepPos+2; + size_t lenVal; + + lua_pushlstring(L, token, sepPos); + lenVal = strlen(aVal)-1; + if(!lenVal) Xml_pushDecode(L, "", 0); + else Xml_pushDecode(L, aVal, lenVal); + lua_settable(L, -3); + } + } + if(!token||(token[0]==ESC)) { + if(lua_gettop(L)>1) lua_settop(L,-2); // this tag has no content, only attributes + else break; + } + } + else if(token[0]==ESC) { // previous tag is over + if(lua_gettop(L)>1) lua_settop(L,-2); // pop current table + else break; + } + else { // read elements + lua_pushnumber(L,(lua_Number)lua_rawlen(L,-1)+1); + Xml_pushDecode(L, token, 0); + lua_settable(L, -3); + } + Tokenizer_delete(tok); + free(str); + return lua_gettop(L); +} + +int Xml_load (lua_State *L) { + const char * filename = luaL_checkstring(L,1); + FILE * file=fopen(filename,"r"); + char* buffer; + size_t sz; + + if(!file) + return luaL_error(L,"LuaXml ERROR: \"%s\" file error or file not found!",filename); + + fseek (file , 0 , SEEK_END); + sz = ftell (file); + rewind (file); + buffer = (char*)malloc(sz+1); + sz = fread (buffer,1,sz,file); + fclose(file); + buffer[sz]=0; + lua_pushlightuserdata(L,buffer); + lua_replace(L,1); + return Xml_eval(L); +}; + +int Xml_registerCode(lua_State *L) { + const char * decoded = luaL_checkstring(L,1); + const char * encoded = luaL_checkstring(L,2); + + size_t i; + for(i=0; i<sv_code_size; i+=2) + if(strcmp(sv_code[i],decoded)==0) + return luaL_error(L,"LuaXml ERROR: code already exists."); + if(sv_code_size+2>sv_code_capacity) { + sv_code_capacity*=2; + sv_code = (char**)realloc(sv_code, sv_code_capacity*sizeof(char*)); + } + sv_code[sv_code_size]=(char*)malloc(strlen(decoded)+1); + strcpy(sv_code[sv_code_size++], decoded); + sv_code[sv_code_size]=(char*)malloc(strlen(encoded)+1); + strcpy(sv_code[sv_code_size++],encoded); + return 0; +} + +int Xml_encode(lua_State *L) { + + char buf[8]; + size_t start, pos; + luaL_Buffer b; + const char* s; + size_t i; + + if(lua_gettop(L)!=1) + return 0; + luaL_checkstring(L,-1); + + for(i=0; i<sv_code_size; i+=2) { + luaL_gsub(L, lua_tostring(L,-1), sv_code[i], sv_code[i+1]); + lua_remove(L,-2); + } + s=lua_tostring(L,1); + luaL_buffinit(L, &b); + for(start=pos=0; s[pos]!=0; ++pos) if(s[pos]<0) { + if(pos>start) luaL_addlstring(&b,s+start, pos-start); + luaL_addstring(&b,char2code((unsigned char)(s[pos]),buf)); + start=pos+1; + } + if(pos>start) + luaL_addlstring(&b,s+start, pos-start); + luaL_pushresult(&b); + lua_remove(L,-2); + return 1; +} + +#ifdef __cplusplus +extern "C" { +#endif +int _EXPORT luaopen_LuaXML_lib (lua_State* L) { + static const struct luaL_Reg funcs[] = { + {"load", Xml_load}, + {"eval", Xml_eval}, + {"encode", Xml_encode}, + {"registerCode", Xml_registerCode}, + {NULL, NULL} + }; + + luaL_newlibtable(L, funcs); + luaL_setfuncs(L, funcs, 0); + lua_setglobal(L, "xml"); + + // register default codes: + if(!sv_code) { + sv_code=(char**)malloc(sv_code_capacity*sizeof(char*)); + sv_code[sv_code_size++]="&"; + sv_code[sv_code_size++]="&"; + sv_code[sv_code_size++]="<"; + sv_code[sv_code_size++]="<"; + sv_code[sv_code_size++]=">"; + sv_code[sv_code_size++]=">"; + sv_code[sv_code_size++]="\""; + sv_code[sv_code_size++]="""; + sv_code[sv_code_size++]="'"; + sv_code[sv_code_size++]="'"; + } + return 1; +} +#ifdef __cplusplus +} // extern "C" +#endif
