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,
24 static const char * const paths_global[] = {
27 "global.count-threads",
29 "global.server-string",
33 enum lejp_global_paths {
42 static const char * const paths_vhosts[] = {
48 "vhosts[].unix-socket",
50 "vhosts[].host-ssl-key",
51 "vhosts[].host-ssl-cert",
52 "vhosts[].host-ssl-ca",
53 "vhosts[].access-log",
54 "vhosts[].mounts[].mountpoint",
55 "vhosts[].mounts[].origin",
56 "vhosts[].mounts[].default",
57 "vhosts[].mounts[].cgi-timeout",
58 "vhosts[].mounts[].cgi-env[].*",
59 "vhosts[].mounts[].cache-max-age",
60 "vhosts[].mounts[].cache-reuse",
61 "vhosts[].mounts[].cache-revalidate",
62 "vhosts[].mounts[].cache-intermediaries",
63 "vhosts[].mounts[].extra-mimetypes.*",
64 "vhosts[].ws-protocols[].*.*",
65 "vhosts[].ws-protocols[].*",
66 "vhosts[].ws-protocols[]",
67 "vhosts[].keepalive_timeout",
68 "vhosts[].enable-client-ssl",
70 "vhosts[].ecdh-curve",
73 enum lejp_vhost_paths {
90 LEJPVP_MOUNT_CACHE_MAX_AGE,
91 LEJPVP_MOUNT_CACHE_REUSE,
92 LEJPVP_MOUNT_CACHE_REVALIDATE,
93 LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
94 LEJPVP_MOUNT_EXTRA_MIMETYPES,
95 LEJPVP_PROTOCOL_NAME_OPT,
98 LEJPVP_KEEPALIVE_TIMEOUT,
99 LEJPVP_ENABLE_CLIENT_SSL,
104 #define MAX_PLUGIN_DIRS 10
107 struct lws_context_creation_info *info;
108 struct lws_context *context;
109 const struct lws_protocols *protocols;
110 const struct lws_extension *extensions;
111 char *p, *end, valid;
112 struct lws_http_mount *head, *last;
114 struct lws_protocol_vhost_options *pvo;
115 struct lws_protocol_vhost_options *pvo_em;
116 struct lws_http_mount m;
117 const char **plugin_dirs;
118 int count_plugin_dirs;
120 unsigned int enable_client_ssl:1;
121 unsigned int fresh_mount:1;
125 lwsws_align(struct jpargs *a)
127 if ((unsigned long)(a->p) & 15)
128 a->p += 16 - ((unsigned long)(a->p) & 15);
134 arg_to_bool(const char *s)
136 static const char * const on[] = { "on", "yes", "true" };
142 for (n = 0; n < ARRAY_SIZE(on); n++)
143 if (!strcasecmp(s, on[n]))
150 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
152 struct jpargs *a = (struct jpargs *)ctx->user;
154 /* we only match on the prepared path strings */
155 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
158 switch (ctx->path_match - 1) {
160 a->info->uid = atoi(ctx->buf);
163 a->info->gid = atoi(ctx->buf);
165 case LEJPGP_COUNT_THREADS:
166 a->info->count_threads = atoi(ctx->buf);
168 case LWJPGP_INIT_SSL:
169 if (arg_to_bool(ctx->buf))
170 a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
172 case LEJPGP_SERVER_STRING:
173 a->info->server_string = a->p;
175 case LEJPGP_PLUGIN_DIR:
176 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
177 lwsl_err("Too many plugin dirs\n");
180 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
187 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
193 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
195 struct jpargs *a = (struct jpargs *)ctx->user;
196 struct lws_protocol_vhost_options *pvo, *mp_cgienv;
197 struct lws_http_mount *m;
201 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
202 for (n = 0; n < ctx->wildcount; n++)
203 lwsl_notice(" %d\n", ctx->wild[n]);
206 if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
207 /* set the defaults for this vhost */
212 a->info->iface = NULL;
213 a->info->protocols = a->protocols;
214 a->info->extensions = a->extensions;
215 a->info->ssl_cert_filepath = NULL;
216 a->info->ssl_private_key_filepath = NULL;
217 a->info->ssl_ca_filepath = NULL;
218 a->info->timeout_secs = 5;
219 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
220 "ECDHE-RSA-AES256-GCM-SHA384:"
221 "DHE-RSA-AES256-GCM-SHA384:"
222 "ECDHE-RSA-AES256-SHA384:"
223 "HIGH:!aNULL:!eNULL:!EXPORT:"
224 "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
225 "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
226 "!DHE-RSA-AES128-SHA256:"
227 "!AES128-GCM-SHA256:"
229 "!DHE-RSA-AES256-SHA256:"
230 "!AES256-GCM-SHA384:"
233 a->info->keepalive_timeout = 60;
234 a->info->log_filepath = NULL;
235 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
236 LWS_SERVER_OPTION_STS);
237 a->enable_client_ssl = 0;
240 if (reason == LEJPCB_OBJECT_START &&
241 ctx->path_match == LEJPVP_MOUNTS + 1) {
243 memset(&a->m, 0, sizeof(a->m));
246 /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
247 if (reason == LEJPCB_OBJECT_START &&
248 ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
249 a->pvo = lwsws_align(a);
250 a->p += sizeof(*a->pvo);
252 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
253 /* ie, enable this protocol, no options yet */
254 a->pvo->next = a->info->pvo;
255 a->info->pvo = a->pvo;
257 lwsl_notice(" adding protocol %s\n", a->p);
259 a->pvo->value = a->p;
260 a->pvo->options = NULL;
261 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
265 if (reason == LEJPCB_OBJECT_END &&
266 (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
269 struct lws_vhost *vhost;
271 //lwsl_notice("%s\n", ctx->path);
272 if (!a->info->port) {
273 lwsl_err("Port required (eg, 443)");
277 a->info->mounts = a->head;
279 vhost = lws_create_vhost(a->context, a->info);
281 lwsl_err("Failed to create vhost %s\n",
282 a->info->vhost_name);
286 if (a->enable_client_ssl) {
287 memset(a->info, 0, sizeof(*a->info));
288 a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
289 lws_init_vhost_client_ssl(a->info, vhost);
295 if (reason == LEJPCB_OBJECT_END &&
296 ctx->path_match == LEJPVP_MOUNTS + 1) {
297 static const char * const mount_protocols[] = {
310 if (!a->m.mountpoint || !a->m.origin) {
311 lwsl_err("mountpoint and origin required\n");
314 lwsl_debug("adding mount %s\n", a->m.mountpoint);
316 memcpy(m, &a->m, sizeof(*m));
318 a->last->mount_next = m;
320 for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
321 if (!strncmp(a->m.origin, mount_protocols[n],
322 strlen(mount_protocols[n]))) {
323 m->origin_protocol = n;
324 m->origin = a->m.origin + strlen(mount_protocols[n]);
328 if (n == ARRAY_SIZE(mount_protocols)) {
329 lwsl_err("unsupported protocol:// %s\n", a->m.origin);
341 /* we only match on the prepared path strings */
342 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
345 switch (ctx->path_match - 1) {
347 a->info->vhost_name = a->p;
350 a->info->port = atoi(ctx->buf);
352 case LEJPVP_INTERFACE:
353 a->info->iface = a->p;
356 if (arg_to_bool(ctx->buf))
357 a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
359 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
362 if (arg_to_bool(ctx->buf))
363 a->info->options |= LWS_SERVER_OPTION_STS;
365 a->info->options &= ~(LWS_SERVER_OPTION_STS);
367 case LEJPVP_HOST_SSL_KEY:
368 a->info->ssl_private_key_filepath = a->p;
370 case LEJPVP_HOST_SSL_CERT:
371 a->info->ssl_cert_filepath = a->p;
373 case LEJPVP_HOST_SSL_CA:
374 a->info->ssl_ca_filepath = a->p;
376 case LEJPVP_ACCESS_LOG:
377 a->info->log_filepath = a->p;
379 case LEJPVP_MOUNTPOINT:
380 a->m.mountpoint = a->p;
381 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
389 case LEJPVP_MOUNT_CACHE_MAX_AGE:
390 a->m.cache_max_age = atoi(ctx->buf);
392 case LEJPVP_MOUNT_CACHE_REUSE:
393 a->m.cache_reusable = arg_to_bool(ctx->buf);
395 case LEJPVP_MOUNT_CACHE_REVALIDATE:
396 a->m.cache_revalidate = arg_to_bool(ctx->buf);
398 case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
399 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
401 case LEJPVP_CGI_TIMEOUT:
402 a->m.cgi_timeout = atoi(ctx->buf);
404 case LEJPVP_KEEPALIVE_TIMEOUT:
405 a->info->keepalive_timeout = atoi(ctx->buf);
408 a->info->ssl_cipher_list = a->p;
410 case LEJPVP_ECDH_CURVE:
411 a->info->ecdh_curve = a->p;
414 mp_cgienv = lwsws_align(a);
415 a->p += sizeof(*a->m.cgienv);
417 mp_cgienv->next = a->m.cgienv;
418 a->m.cgienv = mp_cgienv;
420 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
421 mp_cgienv->name = a->p;
423 mp_cgienv->value = a->p;
424 mp_cgienv->options = NULL;
425 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
428 lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
432 case LEJPVP_PROTOCOL_NAME_OPT:
434 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
435 * ie, these are options attached to a protocol with { }
437 pvo = lwsws_align(a);
438 a->p += sizeof(*a->pvo);
440 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
441 /* ie, enable this protocol, no options yet */
442 pvo->next = a->pvo->options;
443 a->pvo->options = pvo;
450 case LEJPVP_MOUNT_EXTRA_MIMETYPES:
451 a->pvo_em = lwsws_align(a);
452 a->p += sizeof(*a->pvo_em);
454 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
455 /* ie, enable this protocol, no options yet */
456 a->pvo_em->next = a->m.extra_mimetypes;
457 a->m.extra_mimetypes = a->pvo_em;
458 a->pvo_em->name = a->p;
459 lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
461 a->pvo_em->value = a->p;
462 a->pvo_em->options = NULL;
465 case LEJPVP_ENABLE_CLIENT_SSL:
466 a->enable_client_ssl = arg_to_bool(ctx->buf);
473 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
480 * returns 0 = OK, 1 = can't open, 2 = parsing error
484 lwsws_get_config(void *user, const char *f, const char * const *paths,
485 int count_paths, lejp_callback cb)
487 unsigned char buf[128];
491 fd = open(f, O_RDONLY);
493 lwsl_err("Cannot open %s\n", f);
496 lwsl_info("%s: %s\n", __func__, f);
497 lejp_construct(&ctx, cb, user, paths, count_paths);
500 n = read(fd, buf, sizeof(buf));
504 m = (int)(signed char)lejp_parse(&ctx, buf, n);
505 } while (m == LEJP_CONTINUE);
512 lwsl_err("%s(%u): parsing error %d\n", f, n, m);
519 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
522 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
523 int count_paths, lejp_callback cb)
533 if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
534 lwsl_err("Scandir on %s failed\n", d);
538 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
539 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
540 ret = lwsws_get_config(user, path, paths, count_paths, cb);
546 uv_fs_req_cleanup(&req);
547 uv_loop_close(&loop);
555 static int filter(const struct dirent *ent)
557 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
565 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
566 int count_paths, lejp_callback cb)
569 struct dirent **namelist;
573 n = scandir(d, &namelist, filter, alphasort);
575 lwsl_err("Scandir on %d failed\n", d);
578 for (i = 0; i < n; i++) {
579 snprintf(path, sizeof(path) - 1, "%s/%s", d,
580 namelist[i]->d_name);
581 ret = lwsws_get_config(user, path, paths, count_paths, cb);
602 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
606 const char * const *old = info->plugin_dirs;
608 memset(&a, 0, sizeof(a));
612 a.end = (a.p + *len) - 1;
616 info->plugin_dirs = (void *)a.p;
617 a.plugin_dirs = (void *)a.p; /* writeable version */
618 a.p += MAX_PLUGIN_DIRS * sizeof(void *);
620 /* copy any default paths */
622 while (old && *old) {
623 a.plugin_dirs[a.count_plugin_dirs++] = *old;
627 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
628 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
630 if (lwsws_get_config_d(&a, d, paths_global,
631 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
634 a.plugin_dirs[a.count_plugin_dirs] = NULL;
643 lwsws_get_config_vhosts(struct lws_context *context,
644 struct lws_context_creation_info *info, const char *d,
649 memset(&a, 0, sizeof(a));
656 a.protocols = info->protocols;
657 a.extensions = info->extensions;
659 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
660 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
662 if (lwsws_get_config_d(&a, d, paths_vhosts,
663 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
669 lws_finalize_startup(context);