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[] = {
28 "global.count-threads",
32 enum lejp_global_paths {
40 static const char * const paths_vhosts[] = {
45 "vhosts[].host-ssl-key",
46 "vhosts[].host-ssl-cert",
47 "vhosts[].host-ssl-ca",
48 "vhosts[].mounts[].mountpoint",
49 "vhosts[].mounts[].origin",
50 "vhosts[].mounts[].default",
51 "vhosts[].mounts[].cgi-env[].*",
52 "vhosts[].ws-protocols[].*.*",
53 "vhosts[].ws-protocols[].*",
54 "vhosts[].ws-protocols[]",
57 enum lejp_vhost_paths {
69 LEJPVP_PROTOCOL_NAME_OPT,
75 struct lws_context_creation_info *info;
76 struct lws_context *context;
77 const struct lws_protocols *protocols;
78 const struct lws_extension *extensions;
80 struct lws_http_mount *head, *last;
81 char *mountpoint, *origin, *def;
82 struct lws_protocol_vhost_options *pvo;
83 struct lws_protocol_vhost_options *mp_cgienv;
87 lwsws_align(struct jpargs *a)
89 if ((unsigned long)(a->p) & 15)
90 a->p += 16 - ((unsigned long)(a->p) & 15);
95 static int arg_to_bool(const char *s)
97 static const char * const on[] = { "on", "yes", "true" };
103 for (n = 0; n < ARRAY_SIZE(on); n++)
104 if (!strcasecmp(s, on[n]))
111 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
113 struct jpargs *a = (struct jpargs *)ctx->user;
115 /* we only match on the prepared path strings */
116 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
119 switch (ctx->path_match - 1) {
121 a->info->uid = atoi(ctx->buf);
124 a->info->gid = atoi(ctx->buf);
126 case LEJPGP_INTERFACE:
127 a->info->iface = a->p;
129 case LEJPGP_COUNT_THREADS:
130 a->info->count_threads = atoi(ctx->buf);
132 case LWJPGP_INIT_SSL:
133 if (arg_to_bool(ctx->buf))
134 a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
141 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
147 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
149 struct jpargs *a = (struct jpargs *)ctx->user;
150 struct lws_protocol_vhost_options *pvo, *mp_cgienv;
151 struct lws_http_mount *m;
155 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
156 for (n = 0; n < ctx->wildcount; n++)
157 lwsl_notice(" %d\n", ctx->wild[n]);
160 if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
161 /* set the defaults for this vhost */
166 a->info->iface = NULL;
167 a->info->protocols = a->protocols;
168 a->info->extensions = a->extensions;
169 a->info->ssl_cert_filepath = NULL;
170 a->info->ssl_private_key_filepath = NULL;
171 a->info->ssl_ca_filepath = NULL;
172 a->info->timeout_secs = 5;
173 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
174 "ECDHE-RSA-AES256-GCM-SHA384:"
175 "DHE-RSA-AES256-GCM-SHA384:"
176 "ECDHE-RSA-AES256-SHA384:"
177 "HIGH:!aNULL:!eNULL:!EXPORT:"
178 "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
179 "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
180 "!DHE-RSA-AES128-SHA256:"
181 "!AES128-GCM-SHA256:"
183 "!DHE-RSA-AES256-SHA256:"
184 "!AES256-GCM-SHA384:"
189 if (reason == LEJPCB_OBJECT_START &&
190 ctx->path_match == LEJPVP_MOUNTS + 1) {
191 a->mountpoint = NULL;
197 /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
198 if (reason == LEJPCB_OBJECT_START &&
199 ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
200 a->pvo = lwsws_align(a);
201 a->p += sizeof(*a->pvo);
203 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
204 /* ie, enable this protocol, no options yet */
205 a->pvo->next = a->info->pvo;
206 a->info->pvo = a->pvo;
208 lwsl_err("adding %s\n", a->p);
210 a->pvo->value = a->p;
211 a->pvo->options = NULL;
212 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
216 if (reason == LEJPCB_OBJECT_END &&
217 (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
220 //lwsl_notice("%s\n", ctx->path);
221 if (!a->info->port) {
222 lwsl_err("Port required (eg, 443)");
227 if (!lws_create_vhost(a->context, a->info, a->head)) {
228 lwsl_err("Failed to create vhost %s\n",
229 a->info->vhost_name);
236 if (reason == LEJPCB_OBJECT_END &&
237 ctx->path_match == LEJPVP_MOUNTS + 1) {
238 if (!a->mountpoint || !a->origin) {
239 lwsl_err("mountpoint and origin required\n");
243 n = lws_write_http_mount(a->last, &m, a->p, a->mountpoint,
244 a->origin, a->def, a->mp_cgienv);
254 /* we only match on the prepared path strings */
255 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
258 switch (ctx->path_match - 1) {
260 a->info->vhost_name = a->p;
263 a->info->port = atoi(ctx->buf);
265 case LEJPVP_HOST_SSL_KEY:
266 a->info->ssl_private_key_filepath = a->p;
268 case LEJPVP_HOST_SSL_CERT:
269 a->info->ssl_cert_filepath = a->p;
271 case LEJPVP_HOST_SSL_CA:
272 a->info->ssl_ca_filepath = a->p;
274 case LEJPVP_MOUNTPOINT:
275 a->mountpoint = a->p;
284 mp_cgienv = lwsws_align(a);
285 a->p += sizeof(*a->mp_cgienv);
287 mp_cgienv->next = a->mp_cgienv;
288 a->mp_cgienv = mp_cgienv;
290 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
291 mp_cgienv->name = a->p;
293 mp_cgienv->value = a->p;
294 mp_cgienv->options = NULL;
295 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
298 lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
302 case LEJPVP_PROTOCOL_NAME_OPT:
304 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
305 * ie, these are options attached to a protocol with { }
307 pvo = lwsws_align(a);
308 a->p += sizeof(*a->pvo);
310 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
311 /* ie, enable this protocol, no options yet */
312 pvo->next = a->pvo->options;
313 a->pvo->options = pvo;
318 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
326 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
333 * returns 0 = OK, 1 = can't open, 2 = parsing error
337 lwsws_get_config(void *user, const char *f, const char * const *paths,
338 int count_paths, lejp_callback cb)
340 unsigned char buf[128];
344 fd = open(f, O_RDONLY);
346 lwsl_err("Cannot open %s\n", f);
349 lwsl_info("%s: %s\n", __func__, f);
350 lejp_construct(&ctx, cb, user, paths, count_paths);
353 n = read(fd, buf, sizeof(buf));
357 m = (int)(signed char)lejp_parse(&ctx, buf, n);
358 } while (m == LEJP_CONTINUE);
365 lwsl_err("%s(%u): parsing error %d\n", f, n, m);
372 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
375 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
376 int count_paths, lejp_callback cb)
386 if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
387 lwsl_err("Scandir on %s failed\n", d);
391 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
392 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
393 ret = lwsws_get_config(user, path, paths, count_paths, cb);
399 uv_fs_req_cleanup(&req);
400 uv_loop_close(&loop);
408 static int filter(const struct dirent *ent)
410 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
418 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
419 int count_paths, lejp_callback cb)
422 struct dirent **namelist;
426 n = scandir(d, &namelist, filter, alphasort);
428 lwsl_err("Scandir on %d failed\n", d);
431 for (i = 0; i < n; i++) {
432 snprintf(path, sizeof(path) - 1, "%s/%s", d,
433 namelist[i]->d_name);
434 ret = lwsws_get_config(user, path, paths, count_paths, cb);
455 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
462 a.end = (a.p + *len) - 1;
465 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
466 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
468 if (lwsws_get_config_d(&a, d, paths_global,
469 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
479 lwsws_get_config_vhosts(struct lws_context *context,
480 struct lws_context_creation_info *info, const char *d,
490 a.protocols = info->protocols;
491 a.extensions = info->extensions;
493 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
494 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
496 if (lwsws_get_config_d(&a, d, paths_vhosts,
497 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
503 lws_finalize_startup(context);