*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
+ * 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
- * General Public License for more details.
+ * 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 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
+ * 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 "private-libwebsockets.h"
#include <dirent.h>
#endif
+#define ESC_INSTALL_DATADIR "_lws_ddir_"
+
static const char * const paths_global[] = {
"global.uid",
"global.gid",
"global.count-threads",
"global.init-ssl",
"global.server-string",
- "global.plugin-dir"
+ "global.plugin-dir",
+ "global.ws-pingpong-secs",
+ "global.timeout-secs",
+ "global.reject-service-keywords[].*",
+ "global.reject-service-keywords[]",
};
enum lejp_global_paths {
LEJPGP_COUNT_THREADS,
LWJPGP_INIT_SSL,
LEJPGP_SERVER_STRING,
- LEJPGP_PLUGIN_DIR
+ LEJPGP_PLUGIN_DIR,
+ LWJPGP_PINGPONG_SECS,
+ LWJPGP_TIMEOUT_SECS,
+ LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
+ LWJPGP_REJECT_SERVICE_KEYWORDS
};
static const char * const paths_vhosts[] = {
"vhosts[].access-log",
"vhosts[].mounts[].mountpoint",
"vhosts[].mounts[].origin",
+ "vhosts[].mounts[].protocol",
"vhosts[].mounts[].default",
+ "vhosts[].mounts[].auth-mask",
"vhosts[].mounts[].cgi-timeout",
"vhosts[].mounts[].cgi-env[].*",
"vhosts[].mounts[].cache-max-age",
"vhosts[].mounts[].cache-reuse",
"vhosts[].mounts[].cache-revalidate",
+ "vhosts[].mounts[].basic-auth",
"vhosts[].mounts[].cache-intermediaries",
"vhosts[].mounts[].extra-mimetypes.*",
+ "vhosts[].mounts[].interpret.*",
"vhosts[].ws-protocols[].*.*",
"vhosts[].ws-protocols[].*",
"vhosts[].ws-protocols[]",
"vhosts[].enable-client-ssl",
"vhosts[].ciphers",
"vhosts[].ecdh-curve",
+ "vhosts[].noipv6",
+ "vhosts[].ipv6only",
+ "vhosts[].ssl-option-set",
+ "vhosts[].ssl-option-clear",
+ "vhosts[].mounts[].pmo[].*",
+ "vhosts[].headers[].*",
+ "vhosts[].headers[]",
+ "vhosts[].client-ssl-key",
+ "vhosts[].client-ssl-cert",
+ "vhosts[].client-ssl-ca",
+ "vhosts[].client-ssl-ciphers",
};
enum lejp_vhost_paths {
LEJPVP_ACCESS_LOG,
LEJPVP_MOUNTPOINT,
LEJPVP_ORIGIN,
+ LEJPVP_MOUNT_PROTOCOL,
LEJPVP_DEFAULT,
+ LEJPVP_DEFAULT_AUTH_MASK,
LEJPVP_CGI_TIMEOUT,
LEJPVP_CGI_ENV,
LEJPVP_MOUNT_CACHE_MAX_AGE,
LEJPVP_MOUNT_CACHE_REUSE,
LEJPVP_MOUNT_CACHE_REVALIDATE,
+ LEJPVP_MOUNT_BASIC_AUTH,
LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
LEJPVP_MOUNT_EXTRA_MIMETYPES,
+ LEJPVP_MOUNT_INTERPRET,
LEJPVP_PROTOCOL_NAME_OPT,
LEJPVP_PROTOCOL_NAME,
LEJPVP_PROTOCOL,
LEJPVP_ENABLE_CLIENT_SSL,
LEJPVP_CIPHERS,
LEJPVP_ECDH_CURVE,
+ LEJPVP_NOIPV6,
+ LEJPVP_IPV6ONLY,
+ LEJPVP_SSL_OPTION_SET,
+ LEJPVP_SSL_OPTION_CLEAR,
+ LEJPVP_PMO,
+ LEJPVP_HEADERS_NAME,
+ LEJPVP_HEADERS,
+ LEJPVP_CLIENT_SSL_KEY,
+ LEJPVP_CLIENT_SSL_CERT,
+ LEJPVP_CLIENT_SSL_CA,
+ LEJPVP_CLIENT_CIPHERS,
+};
+
+static const char * const parser_errs[] = {
+ "",
+ "",
+ "No opening '{'",
+ "Expected closing '}'",
+ "Expected '\"'",
+ "String underrun",
+ "Illegal unescaped control char",
+ "Illegal escape format",
+ "Illegal hex number",
+ "Expected ':'",
+ "Illegal value start",
+ "Digit required after decimal point",
+ "Bad number format",
+ "Bad exponent format",
+ "Unknown token",
+ "Too many ']'",
+ "Mismatched ']'",
+ "Expected ']'",
+ "JSON nesting limit exceeded",
+ "Nesting tracking used up",
+ "Number too long",
+ "Comma or block end expected",
+ "Unknown",
+ "Parser callback errored (see earlier error)",
};
#define MAX_PLUGIN_DIRS 10
struct lws_protocol_vhost_options *pvo;
struct lws_protocol_vhost_options *pvo_em;
+ struct lws_protocol_vhost_options *pvo_int;
struct lws_http_mount m;
const char **plugin_dirs;
int count_plugin_dirs;
static void *
lwsws_align(struct jpargs *a)
{
- if ((unsigned long)(a->p) & 15)
- a->p += 16 - ((unsigned long)(a->p) & 15);
+ if ((lws_intptr_t)(a->p) & 15)
+ a->p += 16 - ((lws_intptr_t)(a->p) & 15);
return a->p;
}
lejp_globals_cb(struct lejp_ctx *ctx, char reason)
{
struct jpargs *a = (struct jpargs *)ctx->user;
+ struct lws_protocol_vhost_options *rej;
+ int n;
/* we only match on the prepared path strings */
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
return 0;
+ /* this catches, eg, vhosts[].headers[].xxx */
+ if (reason == LEJPCB_VAL_STR_END &&
+ ctx->path_match == LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {
+ rej = lwsws_align(a);
+ a->p += sizeof(*rej);
+
+ n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
+ rej->next = a->info->reject_service_keywords;
+ a->info->reject_service_keywords = rej;
+ rej->name = a->p;
+ lwsl_notice(" adding rej %s=%s\n", a->p, ctx->buf);
+ a->p += n - 1;
+ *(a->p++) = '\0';
+ rej->value = a->p;
+ rej->options = NULL;
+ goto dostring;
+ }
+
switch (ctx->path_match - 1) {
case LEJPGP_UID:
a->info->uid = atoi(ctx->buf);
a->plugin_dirs[a->count_plugin_dirs++] = a->p;
break;
+ case LWJPGP_PINGPONG_SECS:
+ a->info->ws_ping_pong_interval = atoi(ctx->buf);
+ return 0;
+
+ case LWJPGP_TIMEOUT_SECS:
+ a->info->timeout_secs = atoi(ctx->buf);
+ return 0;
+
default:
return 0;
}
- a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
+dostring:
+ a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
+ *(a->p)++ = '\0';
return 0;
}
lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
{
struct jpargs *a = (struct jpargs *)ctx->user;
- struct lws_protocol_vhost_options *pvo, *mp_cgienv;
+ struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
struct lws_http_mount *m;
+ char *p, *p1;
int n;
#if 0
a->info->ssl_cert_filepath = NULL;
a->info->ssl_private_key_filepath = NULL;
a->info->ssl_ca_filepath = NULL;
+ a->info->client_ssl_cert_filepath = NULL;
+ a->info->client_ssl_private_key_filepath = NULL;
+ a->info->client_ssl_ca_filepath = NULL;
+ a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "DHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "HIGH:!aNULL:!eNULL:!EXPORT:"
+ "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
+ "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
+ "!DHE-RSA-AES128-SHA256:"
+ "!AES128-GCM-SHA256:"
+ "!AES128-SHA256:"
+ "!DHE-RSA-AES256-SHA256:"
+ "!AES256-GCM-SHA384:"
+ "!AES256-SHA256";
a->info->timeout_secs = 5;
a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"!AES256-GCM-SHA384:"
"!AES256-SHA256";
a->info->pvo = NULL;
- a->info->keepalive_timeout = 60;
+ a->info->headers = NULL;
+ a->info->keepalive_timeout = 5;
a->info->log_filepath = NULL;
a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
LWS_SERVER_OPTION_STS);
a->p += n;
a->pvo->value = a->p;
a->pvo->options = NULL;
- a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
- *(a->p)++ = '\0';
+ goto dostring;
+ }
+
+ /* this catches, eg, vhosts[].headers[].xxx */
+ if (reason == LEJPCB_VAL_STR_END &&
+ ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
+ headers = lwsws_align(a);
+ a->p += sizeof(*headers);
+
+ n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
+ /* ie, enable this protocol, no options yet */
+ headers->next = a->info->headers;
+ a->info->headers = headers;
+ headers->name = a->p;
+ // lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
+ a->p += n - 1;
+ *(a->p++) = ':';
+ if (a->p < a->end)
+ *(a->p++) = '\0';
+ else
+ *(a->p - 1) = '\0';
+ headers->value = a->p;
+ headers->options = NULL;
+ goto dostring;
}
if (reason == LEJPCB_OBJECT_END &&
a->any_vhosts = 1;
if (a->enable_client_ssl) {
+ const char *cert_filepath = a->info->client_ssl_cert_filepath;
+ const char *private_key_filepath = a->info->client_ssl_private_key_filepath;
+ const char *ca_filepath = a->info->client_ssl_ca_filepath;
+ const char *cipher_list = a->info->client_ssl_cipher_list;
memset(a->info, 0, sizeof(*a->info));
+ a->info->client_ssl_cert_filepath = cert_filepath;
+ a->info->client_ssl_private_key_filepath = private_key_filepath;
+ a->info->client_ssl_ca_filepath = ca_filepath;
+ a->info->client_ssl_cipher_list = cipher_list;
a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
lws_init_vhost_client_ssl(a->info, vhost);
}
"cgi://",
">http://",
">https://",
- "callback://"
+ "callback://",
+ "gzip://",
};
if (!a->fresh_mount)
for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
if (!strncmp(a->m.origin, mount_protocols[n],
strlen(mount_protocols[n]))) {
+ lwsl_err("----%s\n", a->m.origin);
m->origin_protocol = n;
- m->origin = a->m.origin + strlen(mount_protocols[n]);
+ m->origin = a->m.origin +
+ strlen(mount_protocols[n]);
break;
}
a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
break;
case LEJPVP_ORIGIN:
- a->m.origin = a->p;
+ if (!strncmp(ctx->buf, "callback://", 11))
+ a->m.protocol = a->p + 11;
+
+ if (!a->m.origin)
+ a->m.origin = a->p;
break;
case LEJPVP_DEFAULT:
a->m.def = a->p;
break;
+ case LEJPVP_DEFAULT_AUTH_MASK:
+ a->m.auth_mask = atoi(ctx->buf);
+ return 0;
case LEJPVP_MOUNT_CACHE_MAX_AGE:
a->m.cache_max_age = atoi(ctx->buf);
return 0;
case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
return 0;
+ case LEJPVP_MOUNT_BASIC_AUTH:
+ a->m.basic_auth_login_file = a->p;
+ break;
case LEJPVP_CGI_TIMEOUT:
a->m.cgi_timeout = atoi(ctx->buf);
return 0;
case LEJPVP_KEEPALIVE_TIMEOUT:
a->info->keepalive_timeout = atoi(ctx->buf);
return 0;
+ case LEJPVP_CLIENT_CIPHERS:
+ a->info->client_ssl_cipher_list = a->p;
+ break;
case LEJPVP_CIPHERS:
a->info->ssl_cipher_list = a->p;
break;
case LEJPVP_ECDH_CURVE:
a->info->ecdh_curve = a->p;
break;
+ case LEJPVP_PMO:
case LEJPVP_CGI_ENV:
mp_cgienv = lwsws_align(a);
a->p += sizeof(*a->m.cgienv);
a->p += n;
mp_cgienv->value = a->p;
mp_cgienv->options = NULL;
- a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
- *(a->p)++ = '\0';
-
- lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
- mp_cgienv->value);
+ //lwsl_notice(" adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name,
+ // mp_cgienv->value);
+ goto dostring;
- break;
case LEJPVP_PROTOCOL_NAME_OPT:
/* this catches, eg,
* vhosts[].ws-protocols[].xxx-protocol.yyy-option
a->pvo_em->options = NULL;
break;
+ case LEJPVP_MOUNT_INTERPRET:
+ a->pvo_int = lwsws_align(a);
+ a->p += sizeof(*a->pvo_int);
+
+ n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
+ /* ie, enable this protocol, no options yet */
+ a->pvo_int->next = a->m.interpret;
+ a->m.interpret = a->pvo_int;
+ a->pvo_int->name = a->p;
+ lwsl_notice(" adding interpret %s -> %s\n", a->p,
+ ctx->buf);
+ a->p += n;
+ a->pvo_int->value = a->p;
+ a->pvo_int->options = NULL;
+ break;
+
case LEJPVP_ENABLE_CLIENT_SSL:
a->enable_client_ssl = arg_to_bool(ctx->buf);
return 0;
+ case LEJPVP_CLIENT_SSL_KEY:
+ a->info->client_ssl_private_key_filepath = a->p;
+ break;
+ case LEJPVP_CLIENT_SSL_CERT:
+ a->info->client_ssl_cert_filepath = a->p;
+ break;
+ case LEJPVP_CLIENT_SSL_CA:
+ a->info->client_ssl_ca_filepath = a->p;
+ break;
+
+ case LEJPVP_NOIPV6:
+ if (arg_to_bool(ctx->buf))
+ a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
+ else
+ a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
+ return 0;
+
+ case LEJPVP_IPV6ONLY:
+ a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
+ if (arg_to_bool(ctx->buf))
+ a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
+ else
+ a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
+ return 0;
+
+ case LEJPVP_SSL_OPTION_SET:
+ a->info->ssl_options_set |= atol(ctx->buf);
+ return 0;
+ case LEJPVP_SSL_OPTION_CLEAR:
+ a->info->ssl_options_clear |= atol(ctx->buf);
+ return 0;
default:
return 0;
}
- a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
+dostring:
+ p = ctx->buf;
+ p1 = strstr(p, ESC_INSTALL_DATADIR);
+ if (p1) {
+ n = p1 - p;
+ if (n > a->end - a->p)
+ n = a->end - a->p;
+ strncpy(a->p, p, n);
+ a->p += n;
+ a->p += lws_snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR);
+ p += n + strlen(ESC_INSTALL_DATADIR);
+ }
+
+ a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
*(a->p)++ = '\0';
return 0;
lejp_destruct(&ctx);
if (m < 0) {
- lwsl_err("%s(%u): parsing error %d\n", f, n, m);
+ lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
+ parser_errs[-m]);
return 2;
}
uv_dirent_t dent;
uv_fs_t req;
char path[256];
- int ret = 0;
+ int ret = 0, ir;
uv_loop_t loop;
- uv_loop_init(&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);
}
while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
- snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
+ 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);
- uv_loop_close(&loop);
+ while (uv_loop_close(&loop))
+ ;
return ret;
}
n = scandir(d, &namelist, filter, alphasort);
if (n < 0) {
- lwsl_err("Scandir on %d failed\n", d);
+ lwsl_err("Scandir on %s failed\n", d);
}
for (i = 0; i < n; i++) {
- snprintf(path, sizeof(path) - 1, "%s/%s", d,
+ 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) {
old++;
}
- snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
+ lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_global,
ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
- snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
+ lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_global,
ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
return 1;
a.protocols = info->protocols;
a.extensions = info->extensions;
- snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
+ lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
if (lwsws_get_config(&a, dd, paths_vhosts,
ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
- snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
+ lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
if (lwsws_get_config_d(&a, dd, paths_vhosts,
ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
return 1;
return 1;
}
- lws_finalize_startup(context);
+// lws_finalize_startup(context);
return 0;
}