2 * libwebsockets web server application
4 * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "private-libwebsockets.h"
26 /* this is needed for Travis CI */
30 #define ESC_INSTALL_DATADIR "_lws_ddir_"
32 static const char * const paths_global[] = {
35 "global.count-threads",
37 "global.server-string",
39 "global.ws-pingpong-secs",
42 enum lejp_global_paths {
52 static const char * const paths_vhosts[] = {
58 "vhosts[].unix-socket",
60 "vhosts[].host-ssl-key",
61 "vhosts[].host-ssl-cert",
62 "vhosts[].host-ssl-ca",
63 "vhosts[].access-log",
64 "vhosts[].mounts[].mountpoint",
65 "vhosts[].mounts[].origin",
66 "vhosts[].mounts[].protocol",
67 "vhosts[].mounts[].default",
68 "vhosts[].mounts[].auth-mask",
69 "vhosts[].mounts[].cgi-timeout",
70 "vhosts[].mounts[].cgi-env[].*",
71 "vhosts[].mounts[].cache-max-age",
72 "vhosts[].mounts[].cache-reuse",
73 "vhosts[].mounts[].cache-revalidate",
74 "vhosts[].mounts[].cache-intermediaries",
75 "vhosts[].mounts[].extra-mimetypes.*",
76 "vhosts[].mounts[].interpret.*",
77 "vhosts[].ws-protocols[].*.*",
78 "vhosts[].ws-protocols[].*",
79 "vhosts[].ws-protocols[]",
80 "vhosts[].keepalive_timeout",
81 "vhosts[].enable-client-ssl",
83 "vhosts[].ecdh-curve",
86 "vhosts[].ssl-option-set",
87 "vhosts[].ssl-option-clear",
88 "vhosts[].mounts[].pmo[].*",
89 "vhosts[].headers[].*",
93 enum lejp_vhost_paths {
102 LEJPVP_HOST_SSL_CERT,
107 LEJPVP_MOUNT_PROTOCOL,
109 LEJPVP_DEFAULT_AUTH_MASK,
112 LEJPVP_MOUNT_CACHE_MAX_AGE,
113 LEJPVP_MOUNT_CACHE_REUSE,
114 LEJPVP_MOUNT_CACHE_REVALIDATE,
115 LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
116 LEJPVP_MOUNT_EXTRA_MIMETYPES,
117 LEJPVP_MOUNT_INTERPRET,
118 LEJPVP_PROTOCOL_NAME_OPT,
119 LEJPVP_PROTOCOL_NAME,
121 LEJPVP_KEEPALIVE_TIMEOUT,
122 LEJPVP_ENABLE_CLIENT_SSL,
127 LEJPVP_SSL_OPTION_SET,
128 LEJPVP_SSL_OPTION_CLEAR,
134 static const char * const parser_errs[] = {
138 "Expected closing '}'",
141 "Illegal unescaped control char",
142 "Illegal escape format",
143 "Illegal hex number",
145 "Illegal value start",
146 "Digit required after decimal point",
148 "Bad exponent format",
153 "JSON nesting limit exceeded",
154 "Nesting tracking used up",
156 "Comma or block end expected",
158 "Parser callback errored (see earlier error)",
161 #define MAX_PLUGIN_DIRS 10
164 struct lws_context_creation_info *info;
165 struct lws_context *context;
166 const struct lws_protocols *protocols;
167 const struct lws_extension *extensions;
168 char *p, *end, valid;
169 struct lws_http_mount *head, *last;
171 struct lws_protocol_vhost_options *pvo;
172 struct lws_protocol_vhost_options *pvo_em;
173 struct lws_protocol_vhost_options *pvo_int;
174 struct lws_http_mount m;
175 const char **plugin_dirs;
176 int count_plugin_dirs;
178 unsigned int enable_client_ssl:1;
179 unsigned int fresh_mount:1;
180 unsigned int any_vhosts:1;
184 lwsws_align(struct jpargs *a)
186 if ((unsigned long)(a->p) & 15)
187 a->p += 16 - ((unsigned long)(a->p) & 15);
193 arg_to_bool(const char *s)
195 static const char * const on[] = { "on", "yes", "true" };
201 for (n = 0; n < ARRAY_SIZE(on); n++)
202 if (!strcasecmp(s, on[n]))
209 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
211 struct jpargs *a = (struct jpargs *)ctx->user;
213 /* we only match on the prepared path strings */
214 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
217 switch (ctx->path_match - 1) {
219 a->info->uid = atoi(ctx->buf);
222 a->info->gid = atoi(ctx->buf);
224 case LEJPGP_COUNT_THREADS:
225 a->info->count_threads = atoi(ctx->buf);
227 case LWJPGP_INIT_SSL:
228 if (arg_to_bool(ctx->buf))
229 a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
231 case LEJPGP_SERVER_STRING:
232 a->info->server_string = a->p;
234 case LEJPGP_PLUGIN_DIR:
235 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
236 lwsl_err("Too many plugin dirs\n");
239 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
242 case LWJPGP_PINGPONG_SECS:
243 a->info->ws_ping_pong_interval = atoi(ctx->buf);
250 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
257 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
259 struct jpargs *a = (struct jpargs *)ctx->user;
260 struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
261 struct lws_http_mount *m;
266 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
267 for (n = 0; n < ctx->wildcount; n++)
268 lwsl_notice(" %d\n", ctx->wild[n]);
271 if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
272 /* set the defaults for this vhost */
277 a->info->iface = NULL;
278 a->info->protocols = a->protocols;
279 a->info->extensions = a->extensions;
280 a->info->ssl_cert_filepath = NULL;
281 a->info->ssl_private_key_filepath = NULL;
282 a->info->ssl_ca_filepath = NULL;
283 a->info->timeout_secs = 5;
284 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
285 "ECDHE-RSA-AES256-GCM-SHA384:"
286 "DHE-RSA-AES256-GCM-SHA384:"
287 "ECDHE-RSA-AES256-SHA384:"
288 "HIGH:!aNULL:!eNULL:!EXPORT:"
289 "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
290 "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
291 "!DHE-RSA-AES128-SHA256:"
292 "!AES128-GCM-SHA256:"
294 "!DHE-RSA-AES256-SHA256:"
295 "!AES256-GCM-SHA384:"
298 a->info->headers = NULL;
299 a->info->keepalive_timeout = 5;
300 a->info->log_filepath = NULL;
301 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
302 LWS_SERVER_OPTION_STS);
303 a->enable_client_ssl = 0;
306 if (reason == LEJPCB_OBJECT_START &&
307 ctx->path_match == LEJPVP_MOUNTS + 1) {
309 memset(&a->m, 0, sizeof(a->m));
312 /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
313 if (reason == LEJPCB_OBJECT_START &&
314 ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
315 a->pvo = lwsws_align(a);
316 a->p += sizeof(*a->pvo);
318 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
319 /* ie, enable this protocol, no options yet */
320 a->pvo->next = a->info->pvo;
321 a->info->pvo = a->pvo;
323 lwsl_notice(" adding protocol %s\n", a->p);
325 a->pvo->value = a->p;
326 a->pvo->options = NULL;
330 /* this catches, eg, vhosts[].headers[].xxx */
331 if (reason == LEJPCB_VAL_STR_END &&
332 ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
333 headers = lwsws_align(a);
334 a->p += sizeof(*headers);
336 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
337 /* ie, enable this protocol, no options yet */
338 headers->next = a->info->headers;
339 a->info->headers = headers;
340 headers->name = a->p;
341 // lwsl_notice(" adding header %s=%s\n", a->p, ctx->buf);
348 headers->value = a->p;
349 headers->options = NULL;
353 if (reason == LEJPCB_OBJECT_END &&
354 (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
357 struct lws_vhost *vhost;
359 //lwsl_notice("%s\n", ctx->path);
360 if (!a->info->port) {
361 lwsl_err("Port required (eg, 443)");
365 a->info->mounts = a->head;
367 vhost = lws_create_vhost(a->context, a->info);
369 lwsl_err("Failed to create vhost %s\n",
370 a->info->vhost_name);
375 if (a->enable_client_ssl) {
376 memset(a->info, 0, sizeof(*a->info));
377 a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
378 lws_init_vhost_client_ssl(a->info, vhost);
384 if (reason == LEJPCB_OBJECT_END &&
385 ctx->path_match == LEJPVP_MOUNTS + 1) {
386 static const char * const mount_protocols[] = {
399 if (!a->m.mountpoint || !a->m.origin) {
400 lwsl_err("mountpoint and origin required\n");
403 lwsl_debug("adding mount %s\n", a->m.mountpoint);
405 memcpy(m, &a->m, sizeof(*m));
407 a->last->mount_next = m;
409 for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
410 if (!strncmp(a->m.origin, mount_protocols[n],
411 strlen(mount_protocols[n]))) {
412 lwsl_err("----%s\n", a->m.origin);
413 m->origin_protocol = n;
414 m->origin = a->m.origin +
415 strlen(mount_protocols[n]);
419 if (n == ARRAY_SIZE(mount_protocols)) {
420 lwsl_err("unsupported protocol:// %s\n", a->m.origin);
432 /* we only match on the prepared path strings */
433 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
436 switch (ctx->path_match - 1) {
438 a->info->vhost_name = a->p;
441 a->info->port = atoi(ctx->buf);
443 case LEJPVP_INTERFACE:
444 a->info->iface = a->p;
447 if (arg_to_bool(ctx->buf))
448 a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
450 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
453 if (arg_to_bool(ctx->buf))
454 a->info->options |= LWS_SERVER_OPTION_STS;
456 a->info->options &= ~(LWS_SERVER_OPTION_STS);
458 case LEJPVP_HOST_SSL_KEY:
459 a->info->ssl_private_key_filepath = a->p;
461 case LEJPVP_HOST_SSL_CERT:
462 a->info->ssl_cert_filepath = a->p;
464 case LEJPVP_HOST_SSL_CA:
465 a->info->ssl_ca_filepath = a->p;
467 case LEJPVP_ACCESS_LOG:
468 a->info->log_filepath = a->p;
470 case LEJPVP_MOUNTPOINT:
471 a->m.mountpoint = a->p;
472 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
475 if (!strncmp(ctx->buf, "callback://", 11))
476 a->m.protocol = a->p + 11;
484 case LEJPVP_DEFAULT_AUTH_MASK:
485 a->m.auth_mask = atoi(ctx->buf);
487 case LEJPVP_MOUNT_CACHE_MAX_AGE:
488 a->m.cache_max_age = atoi(ctx->buf);
490 case LEJPVP_MOUNT_CACHE_REUSE:
491 a->m.cache_reusable = arg_to_bool(ctx->buf);
493 case LEJPVP_MOUNT_CACHE_REVALIDATE:
494 a->m.cache_revalidate = arg_to_bool(ctx->buf);
496 case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
497 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
499 case LEJPVP_CGI_TIMEOUT:
500 a->m.cgi_timeout = atoi(ctx->buf);
502 case LEJPVP_KEEPALIVE_TIMEOUT:
503 a->info->keepalive_timeout = atoi(ctx->buf);
506 a->info->ssl_cipher_list = a->p;
508 case LEJPVP_ECDH_CURVE:
509 a->info->ecdh_curve = a->p;
513 mp_cgienv = lwsws_align(a);
514 a->p += sizeof(*a->m.cgienv);
516 mp_cgienv->next = a->m.cgienv;
517 a->m.cgienv = mp_cgienv;
519 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
520 mp_cgienv->name = a->p;
522 mp_cgienv->value = a->p;
523 mp_cgienv->options = NULL;
524 lwsl_notice(" adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name,
528 case LEJPVP_PROTOCOL_NAME_OPT:
530 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
531 * ie, these are options attached to a protocol with { }
533 pvo = lwsws_align(a);
534 a->p += sizeof(*a->pvo);
536 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
537 /* ie, enable this protocol, no options yet */
538 pvo->next = a->pvo->options;
539 a->pvo->options = pvo;
546 case LEJPVP_MOUNT_EXTRA_MIMETYPES:
547 a->pvo_em = lwsws_align(a);
548 a->p += sizeof(*a->pvo_em);
550 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
551 /* ie, enable this protocol, no options yet */
552 a->pvo_em->next = a->m.extra_mimetypes;
553 a->m.extra_mimetypes = a->pvo_em;
554 a->pvo_em->name = a->p;
555 lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
557 a->pvo_em->value = a->p;
558 a->pvo_em->options = NULL;
561 case LEJPVP_MOUNT_INTERPRET:
562 a->pvo_int = lwsws_align(a);
563 a->p += sizeof(*a->pvo_int);
565 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
566 /* ie, enable this protocol, no options yet */
567 a->pvo_int->next = a->m.interpret;
568 a->m.interpret = a->pvo_int;
569 a->pvo_int->name = a->p;
570 lwsl_notice(" adding interpret %s -> %s\n", a->p,
573 a->pvo_int->value = a->p;
574 a->pvo_int->options = NULL;
577 case LEJPVP_ENABLE_CLIENT_SSL:
578 a->enable_client_ssl = arg_to_bool(ctx->buf);
582 if (arg_to_bool(ctx->buf))
583 a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
585 a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
588 case LEJPVP_IPV6ONLY:
589 a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
590 if (arg_to_bool(ctx->buf))
591 a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
593 a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
596 case LEJPVP_SSL_OPTION_SET:
597 a->info->ssl_options_set |= atol(ctx->buf);
599 case LEJPVP_SSL_OPTION_CLEAR:
600 a->info->ssl_options_clear |= atol(ctx->buf);
609 p1 = strstr(p, ESC_INSTALL_DATADIR);
612 if (n > a->end - a->p)
616 a->p += snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR);
617 p += n + strlen(ESC_INSTALL_DATADIR);
620 a->p += snprintf(a->p, a->end - a->p, "%s", p);
627 * returns 0 = OK, 1 = can't open, 2 = parsing error
631 lwsws_get_config(void *user, const char *f, const char * const *paths,
632 int count_paths, lejp_callback cb)
634 unsigned char buf[128];
638 fd = open(f, O_RDONLY);
640 lwsl_err("Cannot open %s\n", f);
643 lwsl_info("%s: %s\n", __func__, f);
644 lejp_construct(&ctx, cb, user, paths, count_paths);
647 n = read(fd, buf, sizeof(buf));
651 m = (int)(signed char)lejp_parse(&ctx, buf, n);
652 } while (m == LEJP_CONTINUE);
659 lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
667 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
670 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
671 int count_paths, lejp_callback cb)
681 if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
682 lwsl_err("Scandir on %s failed\n", d);
686 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
687 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
688 ret = lwsws_get_config(user, path, paths, count_paths, cb);
694 uv_fs_req_cleanup(&req);
695 uv_loop_close(&loop);
703 static int filter(const struct dirent *ent)
705 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
713 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
714 int count_paths, lejp_callback cb)
717 struct dirent **namelist;
721 n = scandir(d, &namelist, filter, alphasort);
723 lwsl_err("Scandir on %d failed\n", d);
726 for (i = 0; i < n; i++) {
727 snprintf(path, sizeof(path) - 1, "%s/%s", d,
728 namelist[i]->d_name);
729 ret = lwsws_get_config(user, path, paths, count_paths, cb);
750 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
754 const char * const *old = info->plugin_dirs;
757 memset(&a, 0, sizeof(a));
761 a.end = (a.p + *len) - 1;
765 info->plugin_dirs = (void *)a.p;
766 a.plugin_dirs = (void *)a.p; /* writeable version */
767 a.p += MAX_PLUGIN_DIRS * sizeof(void *);
769 /* copy any default paths */
771 while (old && *old) {
772 a.plugin_dirs[a.count_plugin_dirs++] = *old;
776 snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
777 if (lwsws_get_config(&a, dd, paths_global,
778 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
780 snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
781 if (lwsws_get_config_d(&a, dd, paths_global,
782 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
785 a.plugin_dirs[a.count_plugin_dirs] = NULL;
794 lwsws_get_config_vhosts(struct lws_context *context,
795 struct lws_context_creation_info *info, const char *d,
801 memset(&a, 0, sizeof(a));
808 a.protocols = info->protocols;
809 a.extensions = info->extensions;
811 snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
812 if (lwsws_get_config(&a, dd, paths_vhosts,
813 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
815 snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
816 if (lwsws_get_config_d(&a, dd, paths_vhosts,
817 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
824 lwsl_err("Need at least one vhost\n");
828 lws_finalize_startup(context);