per-vhost headers and lwsws conf support
[platform/upstream/libwebsockets.git] / lib / lejp-conf.c
1 /*
2  * libwebsockets web server application
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
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.
10  *
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.
15  *
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,
19  * MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23 #include "lejp.h"
24
25 #ifndef _WIN32
26 /* this is needed for Travis CI */
27 #include <dirent.h>
28 #endif
29
30 #define ESC_INSTALL_DATADIR "_lws_ddir_"
31
32 static const char * const paths_global[] = {
33         "global.uid",
34         "global.gid",
35         "global.count-threads",
36         "global.init-ssl",
37         "global.server-string",
38         "global.plugin-dir",
39         "global.ws-pingpong-secs",
40 };
41
42 enum lejp_global_paths {
43         LEJPGP_UID,
44         LEJPGP_GID,
45         LEJPGP_COUNT_THREADS,
46         LWJPGP_INIT_SSL,
47         LEJPGP_SERVER_STRING,
48         LEJPGP_PLUGIN_DIR,
49         LWJPGP_PINGPONG_SECS,
50 };
51
52 static const char * const paths_vhosts[] = {
53         "vhosts[]",
54         "vhosts[].mounts[]",
55         "vhosts[].name",
56         "vhosts[].port",
57         "vhosts[].interface",
58         "vhosts[].unix-socket",
59         "vhosts[].sts",
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",
82         "vhosts[].ciphers",
83         "vhosts[].ecdh-curve",
84         "vhosts[].noipv6",
85         "vhosts[].ipv6only",
86         "vhosts[].ssl-option-set",
87         "vhosts[].ssl-option-clear",
88         "vhosts[].mounts[].pmo[].*",
89         "vhosts[].headers[].*",
90         "vhosts[].headers[]",
91 };
92
93 enum lejp_vhost_paths {
94         LEJPVP,
95         LEJPVP_MOUNTS,
96         LEJPVP_NAME,
97         LEJPVP_PORT,
98         LEJPVP_INTERFACE,
99         LEJPVP_UNIXSKT,
100         LEJPVP_STS,
101         LEJPVP_HOST_SSL_KEY,
102         LEJPVP_HOST_SSL_CERT,
103         LEJPVP_HOST_SSL_CA,
104         LEJPVP_ACCESS_LOG,
105         LEJPVP_MOUNTPOINT,
106         LEJPVP_ORIGIN,
107         LEJPVP_MOUNT_PROTOCOL,
108         LEJPVP_DEFAULT,
109         LEJPVP_DEFAULT_AUTH_MASK,
110         LEJPVP_CGI_TIMEOUT,
111         LEJPVP_CGI_ENV,
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,
120         LEJPVP_PROTOCOL,
121         LEJPVP_KEEPALIVE_TIMEOUT,
122         LEJPVP_ENABLE_CLIENT_SSL,
123         LEJPVP_CIPHERS,
124         LEJPVP_ECDH_CURVE,
125         LEJPVP_NOIPV6,
126         LEJPVP_IPV6ONLY,
127         LEJPVP_SSL_OPTION_SET,
128         LEJPVP_SSL_OPTION_CLEAR,
129         LEJPVP_PMO,
130         LEJPVP_HEADERS_NAME,
131         LEJPVP_HEADERS,
132 };
133
134 static const char * const parser_errs[] = {
135         "",
136         "",
137         "No opening '{'",
138         "Expected closing '}'",
139         "Expected '\"'",
140         "String underrun",
141         "Illegal unescaped control char",
142         "Illegal escape format",
143         "Illegal hex number",
144         "Expected ':'",
145         "Illegal value start",
146         "Digit required after decimal point",
147         "Bad number format",
148         "Bad exponent format",
149         "Unknown token",
150         "Too many ']'",
151         "Mismatched ']'",
152         "Expected ']'",
153         "JSON nesting limit exceeded",
154         "Nesting tracking used up",
155         "Number too long",
156         "Comma or block end expected",
157         "Unknown",
158         "Parser callback errored (see earlier error)",
159 };
160
161 #define MAX_PLUGIN_DIRS 10
162
163 struct jpargs {
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;
170
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;
177
178         unsigned int enable_client_ssl:1;
179         unsigned int fresh_mount:1;
180         unsigned int any_vhosts:1;
181 };
182
183 static void *
184 lwsws_align(struct jpargs *a)
185 {
186         if ((unsigned long)(a->p) & 15)
187                 a->p += 16 - ((unsigned long)(a->p) & 15);
188
189         return a->p;
190 }
191
192 static int
193 arg_to_bool(const char *s)
194 {
195         static const char * const on[] = { "on", "yes", "true" };
196         int n = atoi(s);
197
198         if (n)
199                 return 1;
200
201         for (n = 0; n < ARRAY_SIZE(on); n++)
202                 if (!strcasecmp(s, on[n]))
203                         return 1;
204
205         return 0;
206 }
207
208 static char
209 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
210 {
211         struct jpargs *a = (struct jpargs *)ctx->user;
212
213         /* we only match on the prepared path strings */
214         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
215                 return 0;
216
217         switch (ctx->path_match - 1) {
218         case LEJPGP_UID:
219                 a->info->uid = atoi(ctx->buf);
220                 return 0;
221         case LEJPGP_GID:
222                 a->info->gid = atoi(ctx->buf);
223                 return 0;
224         case LEJPGP_COUNT_THREADS:
225                 a->info->count_threads = atoi(ctx->buf);
226                 return 0;
227         case LWJPGP_INIT_SSL:
228                 if (arg_to_bool(ctx->buf))
229                         a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
230                 return 0;
231         case LEJPGP_SERVER_STRING:
232                 a->info->server_string = a->p;
233                 break;
234         case LEJPGP_PLUGIN_DIR:
235                 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
236                         lwsl_err("Too many plugin dirs\n");
237                         return -1;
238                 }
239                 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
240                 break;
241
242         case LWJPGP_PINGPONG_SECS:
243                 a->info->ws_ping_pong_interval = atoi(ctx->buf);
244                 return 0;
245
246         default:
247                 return 0;
248         }
249
250         a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
251         *(a->p)++ = '\0';
252
253         return 0;
254 }
255
256 static char
257 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
258 {
259         struct jpargs *a = (struct jpargs *)ctx->user;
260         struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
261         struct lws_http_mount *m;
262         char *p, *p1;
263         int n;
264
265 #if 0
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]);
269 #endif
270
271         if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
272                 /* set the defaults for this vhost */
273                 a->valid = 1;
274                 a->head = NULL;
275                 a->last = NULL;
276                 a->info->port = 0;
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:"
293                                        "!AES128-SHA256:"
294                                        "!DHE-RSA-AES256-SHA256:"
295                                        "!AES256-GCM-SHA384:"
296                                        "!AES256-SHA256";
297                 a->info->pvo = NULL;
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;
304         }
305
306         if (reason == LEJPCB_OBJECT_START &&
307             ctx->path_match == LEJPVP_MOUNTS + 1) {
308                 a->fresh_mount = 1;
309                 memset(&a->m, 0, sizeof(a->m));
310         }
311
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);
317
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;
322                 a->pvo->name = a->p;
323                 lwsl_notice("  adding protocol %s\n", a->p);
324                 a->p += n;
325                 a->pvo->value = a->p;
326                 a->pvo->options = NULL;
327                 goto dostring;
328         }
329
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);
335
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);
342                 a->p += n - 1;
343                 *(a->p++) = ':';
344                 if (a->p < a->end)
345                         *(a->p++) = '\0';
346                 else
347                         *(a->p - 1) = '\0';
348                 headers->value = a->p;
349                 headers->options = NULL;
350                 goto dostring;
351         }
352
353         if (reason == LEJPCB_OBJECT_END &&
354             (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
355             a->valid) {
356
357                 struct lws_vhost *vhost;
358
359                 //lwsl_notice("%s\n", ctx->path);
360                 if (!a->info->port) {
361                         lwsl_err("Port required (eg, 443)");
362                         return 1;
363                 }
364                 a->valid = 0;
365                 a->info->mounts = a->head;
366
367                 vhost = lws_create_vhost(a->context, a->info);
368                 if (!vhost) {
369                         lwsl_err("Failed to create vhost %s\n",
370                                  a->info->vhost_name);
371                         return 1;
372                 }
373                 a->any_vhosts = 1;
374
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);
379                 }
380
381                 return 0;
382         }
383
384         if (reason == LEJPCB_OBJECT_END &&
385             ctx->path_match == LEJPVP_MOUNTS + 1) {
386                 static const char * const mount_protocols[] = {
387                         "http://",
388                         "https://",
389                         "file://",
390                         "cgi://",
391                         ">http://",
392                         ">https://",
393                         "callback://"
394                 };
395
396                 if (!a->fresh_mount)
397                         return 0;
398
399                 if (!a->m.mountpoint || !a->m.origin) {
400                         lwsl_err("mountpoint and origin required\n");
401                         return 1;
402                 }
403                 lwsl_debug("adding mount %s\n", a->m.mountpoint);
404                 m = lwsws_align(a);
405                 memcpy(m, &a->m, sizeof(*m));
406                 if (a->last)
407                         a->last->mount_next = m;
408
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]);
416                                 break;
417                         }
418
419                 if (n == ARRAY_SIZE(mount_protocols)) {
420                         lwsl_err("unsupported protocol:// %s\n", a->m.origin);
421                         return 1;
422                 }
423
424                 a->p += sizeof(*m);
425                 if (!a->head)
426                         a->head = m;
427
428                 a->last = m;
429                 a->fresh_mount = 0;
430         }
431
432         /* we only match on the prepared path strings */
433         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
434                 return 0;
435
436         switch (ctx->path_match - 1) {
437         case LEJPVP_NAME:
438                 a->info->vhost_name = a->p;
439                 break;
440         case LEJPVP_PORT:
441                 a->info->port = atoi(ctx->buf);
442                 return 0;
443         case LEJPVP_INTERFACE:
444                 a->info->iface = a->p;
445                 break;
446         case LEJPVP_UNIXSKT:
447                 if (arg_to_bool(ctx->buf))
448                         a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
449                 else
450                         a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
451                 return 0;
452         case LEJPVP_STS:
453                 if (arg_to_bool(ctx->buf))
454                         a->info->options |= LWS_SERVER_OPTION_STS;
455                 else
456                         a->info->options &= ~(LWS_SERVER_OPTION_STS);
457                 return 0;
458         case LEJPVP_HOST_SSL_KEY:
459                 a->info->ssl_private_key_filepath = a->p;
460                 break;
461         case LEJPVP_HOST_SSL_CERT:
462                 a->info->ssl_cert_filepath = a->p;
463                 break;
464         case LEJPVP_HOST_SSL_CA:
465                 a->info->ssl_ca_filepath = a->p;
466                 break;
467         case LEJPVP_ACCESS_LOG:
468                 a->info->log_filepath = a->p;
469                 break;
470         case LEJPVP_MOUNTPOINT:
471                 a->m.mountpoint = a->p;
472                 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
473                 break;
474         case LEJPVP_ORIGIN:
475                 if (!strncmp(ctx->buf, "callback://", 11))
476                         a->m.protocol = a->p + 11;
477
478                 if (!a->m.origin)
479                         a->m.origin = a->p;
480                 break;
481         case LEJPVP_DEFAULT:
482                 a->m.def = a->p;
483                 break;
484         case LEJPVP_DEFAULT_AUTH_MASK:
485                 a->m.auth_mask = atoi(ctx->buf);
486                 return 0;
487         case LEJPVP_MOUNT_CACHE_MAX_AGE:
488                 a->m.cache_max_age = atoi(ctx->buf);
489                 return 0;
490         case LEJPVP_MOUNT_CACHE_REUSE:
491                 a->m.cache_reusable = arg_to_bool(ctx->buf);
492                 return 0;
493         case LEJPVP_MOUNT_CACHE_REVALIDATE:
494                 a->m.cache_revalidate = arg_to_bool(ctx->buf);
495                 return 0;
496         case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
497                 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
498                 return 0;
499         case LEJPVP_CGI_TIMEOUT:
500                 a->m.cgi_timeout = atoi(ctx->buf);
501                 return 0;
502         case LEJPVP_KEEPALIVE_TIMEOUT:
503                 a->info->keepalive_timeout = atoi(ctx->buf);
504                 return 0;
505         case LEJPVP_CIPHERS:
506                 a->info->ssl_cipher_list = a->p;
507                 break;
508         case LEJPVP_ECDH_CURVE:
509                 a->info->ecdh_curve = a->p;
510                 break;
511         case LEJPVP_PMO:
512         case LEJPVP_CGI_ENV:
513                 mp_cgienv = lwsws_align(a);
514                 a->p += sizeof(*a->m.cgienv);
515
516                 mp_cgienv->next = a->m.cgienv;
517                 a->m.cgienv = mp_cgienv;
518
519                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
520                 mp_cgienv->name = a->p;
521                 a->p += n;
522                 mp_cgienv->value = a->p;
523                 mp_cgienv->options = NULL;
524                 lwsl_notice("    adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name,
525                                 mp_cgienv->value);
526                 goto dostring;
527
528         case LEJPVP_PROTOCOL_NAME_OPT:
529                 /* this catches, eg,
530                  * vhosts[].ws-protocols[].xxx-protocol.yyy-option
531                  * ie, these are options attached to a protocol with { }
532                  */
533                 pvo = lwsws_align(a);
534                 a->p += sizeof(*a->pvo);
535
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;
540                 pvo->name = a->p;
541                 a->p += n;
542                 pvo->value = a->p;
543                 pvo->options = NULL;
544                 break;
545
546         case LEJPVP_MOUNT_EXTRA_MIMETYPES:
547                 a->pvo_em = lwsws_align(a);
548                 a->p += sizeof(*a->pvo_em);
549
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);
556                 a->p += n;
557                 a->pvo_em->value = a->p;
558                 a->pvo_em->options = NULL;
559                 break;
560
561         case LEJPVP_MOUNT_INTERPRET:
562                 a->pvo_int = lwsws_align(a);
563                 a->p += sizeof(*a->pvo_int);
564
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,
571                             ctx->buf);
572                 a->p += n;
573                 a->pvo_int->value = a->p;
574                 a->pvo_int->options = NULL;
575                 break;
576
577         case LEJPVP_ENABLE_CLIENT_SSL:
578                 a->enable_client_ssl = arg_to_bool(ctx->buf);
579                 return 0;
580
581         case LEJPVP_NOIPV6:
582                 if (arg_to_bool(ctx->buf))
583                         a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
584                 else
585                         a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
586                 return 0;
587
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;
592                 else
593                         a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
594                 return 0;
595
596         case LEJPVP_SSL_OPTION_SET:
597                 a->info->ssl_options_set |= atol(ctx->buf);
598                 return 0;
599         case LEJPVP_SSL_OPTION_CLEAR:
600                 a->info->ssl_options_clear |= atol(ctx->buf);
601                 return 0;
602
603         default:
604                 return 0;
605         }
606
607 dostring:
608         p = ctx->buf;
609         p1 = strstr(p, ESC_INSTALL_DATADIR);
610         if (p1) {
611                 n = p1 - p;
612                 if (n > a->end - a->p)
613                         n = a->end - a->p;
614                 strncpy(a->p, p, n);
615                 a->p += n;
616                 a->p += snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR);
617                 p += n + strlen(ESC_INSTALL_DATADIR);
618         }
619
620         a->p += snprintf(a->p, a->end - a->p, "%s", p);
621         *(a->p)++ = '\0';
622
623         return 0;
624 }
625
626 /*
627  * returns 0 = OK, 1 = can't open, 2 = parsing error
628  */
629
630 static int
631 lwsws_get_config(void *user, const char *f, const char * const *paths,
632                  int count_paths, lejp_callback cb)
633 {
634         unsigned char buf[128];
635         struct lejp_ctx ctx;
636         int n, m, fd;
637
638         fd = open(f, O_RDONLY);
639         if (fd < 0) {
640                 lwsl_err("Cannot open %s\n", f);
641                 return 2;
642         }
643         lwsl_info("%s: %s\n", __func__, f);
644         lejp_construct(&ctx, cb, user, paths, count_paths);
645
646         do {
647                 n = read(fd, buf, sizeof(buf));
648                 if (!n)
649                         break;
650
651                 m = (int)(signed char)lejp_parse(&ctx, buf, n);
652         } while (m == LEJP_CONTINUE);
653
654         close(fd);
655         n = ctx.line;
656         lejp_destruct(&ctx);
657
658         if (m < 0) {
659                 lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
660                          parser_errs[-m]);
661                 return 2;
662         }
663
664         return 0;
665 }
666
667 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
668
669 static int
670 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
671                    int count_paths, lejp_callback cb)
672 {
673         uv_dirent_t dent;
674         uv_fs_t req;
675         char path[256];
676         int ret = 0;
677         uv_loop_t loop;
678
679         uv_loop_init(&loop);
680
681         if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
682                 lwsl_err("Scandir on %s failed\n", d);
683                 return 2;
684         }
685
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);
689                 if (ret)
690                         goto bail;
691         }
692
693 bail:
694         uv_fs_req_cleanup(&req);
695         uv_loop_close(&loop);
696
697         return ret;
698 }
699
700 #else
701
702 #ifndef _WIN32
703 static int filter(const struct dirent *ent)
704 {
705         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
706                 return 0;
707
708         return 1;
709 }
710 #endif
711
712 static int
713 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
714                    int count_paths, lejp_callback cb)
715 {
716 #ifndef _WIN32
717         struct dirent **namelist;
718         char path[256];
719         int n, i, ret = 0;
720
721         n = scandir(d, &namelist, filter, alphasort);
722         if (n < 0) {
723                 lwsl_err("Scandir on %d failed\n", d);
724         }
725
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);
730                 if (ret) {
731                         while (i++ < n)
732                                 free(namelist[i]);
733                         goto bail;
734                 }
735                 free(namelist[i]);
736         }
737
738 bail:
739         free(namelist);
740
741         return ret;
742 #else
743         return 0;
744 #endif
745 }
746
747 #endif
748
749 int
750 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
751                          char **cs, int *len)
752 {
753         struct jpargs a;
754         const char * const *old = info->plugin_dirs;
755         char dd[128];
756
757         memset(&a, 0, sizeof(a));
758
759         a.info = info;
760         a.p = *cs;
761         a.end = (a.p + *len) - 1;
762         a.valid = 0;
763
764         lwsws_align(&a);
765         info->plugin_dirs = (void *)a.p;
766         a.plugin_dirs = (void *)a.p; /* writeable version */
767         a.p += MAX_PLUGIN_DIRS * sizeof(void *);
768
769         /* copy any default paths */
770
771         while (old && *old) {
772                 a.plugin_dirs[a.count_plugin_dirs++] = *old;
773                 old++;
774         }
775
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)
779                 return 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)
783                 return 1;
784
785         a.plugin_dirs[a.count_plugin_dirs] = NULL;
786
787         *cs = a.p;
788         *len = a.end - a.p;
789
790         return 0;
791 }
792
793 int
794 lwsws_get_config_vhosts(struct lws_context *context,
795                         struct lws_context_creation_info *info, const char *d,
796                         char **cs, int *len)
797 {
798         struct jpargs a;
799         char dd[128];
800
801         memset(&a, 0, sizeof(a));
802
803         a.info = info;
804         a.p = *cs;
805         a.end = a.p + *len;
806         a.valid = 0;
807         a.context = context;
808         a.protocols = info->protocols;
809         a.extensions = info->extensions;
810
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)
814                 return 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)
818                 return 1;
819
820         *cs = a.p;
821         *len = a.end - a.p;
822
823         if (!a.any_vhosts) {
824                 lwsl_err("Need at least one vhost\n");
825                 return 1;
826         }
827
828         lws_finalize_startup(context);
829
830         return 0;
831 }