diff --git a/CMakeLists.txt b/CMakeLists.txt index 73002a842..eceda5da1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,11 @@ option(LWS_WITH_LEJP "With the Lightweight JSON Parser" ON) option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" ON) option(LWS_WITH_SQLITE3 "Require SQLITE3 support" OFF) option(LWS_WITH_SMTP "Provide SMTP support" OFF) +if (WIN32 OR LWS_WITH_ESP32) +option(LWS_WITH_DIR "Directory scanning api support" OFF) +else() +option(LWS_WITH_DIR "Directory scanning api support" ON) +endif() option(LWS_WITH_NO_LOGS "Disable all logging from being compiled in" OFF) option(LWS_AVOID_SIGPIPE_IGN "Android 7+ reportedly needs this" OFF) option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF) @@ -293,7 +298,6 @@ if (NOT LWS_ROLE_WS) set(LWS_WITHOUT_EXTENSIONS 1) endif() - include_directories(include plugins) @@ -378,11 +382,13 @@ set(LWS_MAX_SMP 1) set(LWS_WITH_THREADPOOL 0) endif() - if (LWS_WITHOUT_SERVER) set(LWS_WITH_LWSWS OFF) endif() +if (LWS_WITH_LEJP_CONF) + set(LWS_WITH_DIR 1) +endif() # confirm H1 relationships @@ -913,6 +919,10 @@ if (LWS_WITH_NETWORK) ) endif() endif() + +if (LWS_WITH_DIR) + list(APPEND SOURCES lib/misc/dir.c) +endif() if (LWS_WITH_THREADPOOL AND UNIX AND LWS_HAVE_PTHREAD_H) list(APPEND SOURCES lib/misc/threadpool/threadpool.c) diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 079f611b2..3d6eaa432 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -81,6 +81,7 @@ #cmakedefine LWS_WITH_BORINGSSL #cmakedefine LWS_WITH_CGI #cmakedefine LWS_WITH_CUSTOM_HEADERS +#cmakedefine LWS_WITH_DIR #cmakedefine LWS_WITH_ESP32 #cmakedefine LWS_WITH_FTS #cmakedefine LWS_WITH_GENCRYPTO diff --git a/include/libwebsockets/lws-misc.h b/include/libwebsockets/lws-misc.h index 9d0729b6b..d962bc0a4 100644 --- a/include/libwebsockets/lws-misc.h +++ b/include/libwebsockets/lws-misc.h @@ -677,7 +677,43 @@ lws_rx_flow_allow_all_protocol(const struct lws_context *context, LWS_VISIBLE LWS_EXTERN size_t lws_remaining_packet_payload(struct lws *wsi); +#if defined(LWS_WITH_DIR) +typedef enum { + LDOT_UNKNOWN, + LDOT_FILE, + LDOT_DIR, + LDOT_LINK, + LDOT_FIFO, + LDOTT_SOCKET, + LDOT_CHAR, + LDOT_BLOCK +} lws_dir_obj_type_t; + +struct lws_dir_entry { + const char *name; + lws_dir_obj_type_t type; +}; + +typedef int +lws_dir_callback_function(const char *dirpath, void *user, + struct lws_dir_entry *lde); + +/** + * lws_dir() - get a callback for everything in a directory + * + * \param dirpath: the directory to scan + * \param user: pointer to give to callback + * \param cb: callback to receive information on each file or dir + * + * Calls \p cb (with \p user) for every object in dirpath. + * + * This wraps whether it's using POSIX apis, or libuv (as needed for windows, + * since it refuses to support POSIX apis for this). + */ +LWS_VISIBLE LWS_EXTERN int +lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb); +#endif /** * lws_is_ssl() - Find out if connection is using SSL diff --git a/lib/misc/dir.c b/lib/misc/dir.c new file mode 100644 index 000000000..7a491a80a --- /dev/null +++ b/lib/misc/dir.c @@ -0,0 +1,143 @@ +/* + * Lws directory scan wrapper + * + * Copyright (C) 2019 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include "core/private.h" +#include +#include + +#if defined(LWS_WITH_LIBUV) && UV_VERSION_MAJOR > 0 + +int +lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb) +{ + struct lws_dir_entry lde; + uv_dirent_t dent; + uv_fs_t req; + int ret = 1, ir; + uv_loop_t loop; + + ir = uv_loop_init(&loop); + if (ir) { + lwsl_err("%s: loop init failed %d\n", __func__, ir); + } + + ir = uv_fs_scandir(&loop, &req, dirpath, 0, NULL); + if (ir < 0) { + lwsl_err("Scandir on %s failed, errno %d\n", dirpath, LWS_ERRNO); + return 2; + } + + while (uv_fs_scandir_next(&req, &dent) != UV_EOF) { + lde.name = dent.name; + lde.type = (int)dent.type; + if (cb(dirpath, user, &lde)) + goto bail; + } + + ret = 0; + +bail: + uv_fs_req_cleanup(&req); + while (uv_loop_close(&loop)) + ; + + return ret; +} + +#else + +#if !defined(_WIN32) && !defined(LWS_WITH_ESP32) + +#include + +static int filter(const struct dirent *ent) +{ + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + return 0; + + return 1; +} + +int +lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb) +{ + struct lws_dir_entry lde; + struct dirent **namelist; + int n, i, ret = 1; + + n = scandir((char *)dirpath, &namelist, filter, alphasort); + if (n < 0) { + lwsl_err("Scandir on '%s' failed, errno %d\n", dirpath, LWS_ERRNO); + return 1; + } + + for (i = 0; i < n; i++) { + if (strchr(namelist[i]->d_name, '~')) + goto skip; + lde.name = namelist[i]->d_name; + switch (namelist[i]->d_type) { + case DT_BLK: + lde.type = LDOT_BLOCK; + break; + case DT_CHR: + lde.type = LDOT_CHAR; + break; + case DT_DIR: + lde.type = LDOT_DIR; + break; + case DT_FIFO: + lde.type = LDOT_FIFO; + break; + case DT_LNK: + lde.type = LDOT_LINK; + break; + case DT_REG: + lde.type = LDOT_FILE; + break; + case DT_SOCK: + lde.type = LDOTT_SOCKET; + break; + default: + lde.type = LDOT_UNKNOWN; + break; + } + if (cb(dirpath, user, &lde)) { + while (i++ < n) + free(namelist[i]); + goto bail; + } +skip: + free(namelist[i]); + } + + ret = 0; + +bail: + free(namelist); + + return ret; +} + +#else +#error "If you want lws_dir onw windows, you need libuv" +#endif +#endif diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index 543fe4794..3e3d3443e 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -893,100 +893,34 @@ lwsws_get_config(void *user, const char *f, const char * const *paths, return 0; } -#if defined(LWS_WITH_LIBUV) && UV_VERSION_MAJOR > 0 +struct lws_dir_args { + void *user; + const char * const *paths; + int count_paths; + lejp_callback cb; +}; static int -lwsws_get_config_d(void *user, const char *d, const char * const *paths, - int count_paths, lejp_callback cb) +lwsws_get_config_d_cb(const char *dirpath, void *user, + struct lws_dir_entry *lde) { - uv_dirent_t dent; - uv_fs_t req; + struct lws_dir_args *da = (struct lws_dir_args *)user; char path[256]; - int ret = 0, ir; - uv_loop_t loop; - ir = uv_loop_init(&loop); - if (ir) { - lwsl_err("%s: loop init failed %d\n", __func__, ir); - } - - if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) { - lwsl_err("Scandir on %s failed\n", d); - return 2; - } - - while (uv_fs_scandir_next(&req, &dent) != UV_EOF) { - lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name); - ret = lwsws_get_config(user, path, paths, count_paths, cb); - if (ret) - goto bail; - } - -bail: - uv_fs_req_cleanup(&req); - while (uv_loop_close(&loop)) - ; - - return ret; -} - -#else - -#ifndef _WIN32 -static int filter(const struct dirent *ent) -{ - if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + if (lde->type != LDOT_FILE) return 0; - return 1; + lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name); + + return lwsws_get_config(da->user, path, da->paths, + da->count_paths, da->cb); } -#endif - -static int -lwsws_get_config_d(void *user, const char *d, const char * const *paths, - int count_paths, lejp_callback cb) -{ -#if !defined(_WIN32) && !defined(LWS_WITH_ESP32) - struct dirent **namelist; - char path[256]; - int n, i, ret = 0; - - n = scandir((char *) d, &namelist, filter, alphasort); - if (n < 0) { - lwsl_err("Scandir on %s failed\n", d); - return 1; - } - - for (i = 0; i < n; i++) { - if (strchr(namelist[i]->d_name, '~')) - goto skip; - lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, - namelist[i]->d_name); - ret = lwsws_get_config(user, path, paths, count_paths, cb); - if (ret) { - while (i++ < n) - free(namelist[i]); - goto bail; - } -skip: - free(namelist[i]); - } - -bail: - free(namelist); - - return ret; -#else - return 0; -#endif -} - -#endif int lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d, char **cs, int *len) { + struct lws_dir_args da; struct jpargs a; const char * const *old = info->plugin_dirs; char dd[128]; @@ -1015,9 +949,13 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d, LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1) return 1; lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d); - if (lwsws_get_config_d(&a, dd, paths_global, - LWS_ARRAY_SIZE(paths_global), - lejp_globals_cb) > 1) + + da.user = &a; + da.paths = paths_global; + da.count_paths = LWS_ARRAY_SIZE(paths_global), + da.cb = lejp_globals_cb; + + if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1) return 1; a.plugin_dirs[a.count_plugin_dirs] = NULL; @@ -1033,6 +971,7 @@ lwsws_get_config_vhosts(struct lws_context *context, struct lws_context_creation_info *info, const char *d, char **cs, int *len) { + struct lws_dir_args da; struct jpargs a; char dd[128]; @@ -1052,8 +991,13 @@ lwsws_get_config_vhosts(struct lws_context *context, LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1) return 1; lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d); - if (lwsws_get_config_d(&a, dd, paths_vhosts, - LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1) + + da.user = &a; + da.paths = paths_vhosts; + da.count_paths = LWS_ARRAY_SIZE(paths_vhosts), + da.cb = lejp_vhosts_cb; + + if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1) return 1; *cs = a.p;