blob: 1d529a1fd31d8386cb9e3050dccaa63a2f8935e5 [file] [log] [blame]
Andy Greencd0c6962016-03-28 10:12:37 +08001/*
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
Andy Green3358c532016-05-26 21:12:11 +080022#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
Andy Greencd0c6962016-03-28 10:12:37 +080029
30static const char * const paths_global[] = {
31 "global.uid",
32 "global.gid",
Andy Greencd0c6962016-03-28 10:12:37 +080033 "global.count-threads",
34 "global.init-ssl",
Andy Greenb21c20b2016-04-15 13:33:52 +080035 "global.server-string",
Andy Greencae57ad2016-05-02 10:03:25 +080036 "global.plugin-dir"
Andy Greencd0c6962016-03-28 10:12:37 +080037};
38
39enum lejp_global_paths {
40 LEJPGP_UID,
41 LEJPGP_GID,
Andy Greencd0c6962016-03-28 10:12:37 +080042 LEJPGP_COUNT_THREADS,
43 LWJPGP_INIT_SSL,
Andy Greenb21c20b2016-04-15 13:33:52 +080044 LEJPGP_SERVER_STRING,
Andy Greencae57ad2016-05-02 10:03:25 +080045 LEJPGP_PLUGIN_DIR
Andy Greencd0c6962016-03-28 10:12:37 +080046};
47
48static const char * const paths_vhosts[] = {
49 "vhosts[]",
50 "vhosts[].mounts[]",
51 "vhosts[].name",
52 "vhosts[].port",
Andy Green1042b342016-04-14 11:50:05 +080053 "vhosts[].interface",
Andy Greena1ab2012016-04-14 12:18:33 +080054 "vhosts[].unix-socket",
Andy Green868b9f22016-04-14 12:37:21 +080055 "vhosts[].sts",
Andy Greencd0c6962016-03-28 10:12:37 +080056 "vhosts[].host-ssl-key",
57 "vhosts[].host-ssl-cert",
58 "vhosts[].host-ssl-ca",
Andy Green2f0bc932016-04-15 12:00:23 +080059 "vhosts[].access-log",
Andy Greencd0c6962016-03-28 10:12:37 +080060 "vhosts[].mounts[].mountpoint",
61 "vhosts[].mounts[].origin",
Andy Green37098ae2016-04-08 13:25:34 +080062 "vhosts[].mounts[].default",
Andy Greenf5efa742016-04-13 11:42:53 +080063 "vhosts[].mounts[].cgi-timeout",
Andy Greena5e73a12016-04-13 11:49:07 +080064 "vhosts[].mounts[].cgi-env[].*",
Andy Green42e8b182016-04-22 08:53:49 +080065 "vhosts[].mounts[].cache-max-age",
66 "vhosts[].mounts[].cache-reuse",
67 "vhosts[].mounts[].cache-revalidate",
68 "vhosts[].mounts[].cache-intermediaries",
Andy Green8ef14c02016-05-14 10:00:21 +080069 "vhosts[].mounts[].extra-mimetypes.*",
Andy Green37098ae2016-04-08 13:25:34 +080070 "vhosts[].ws-protocols[].*.*",
71 "vhosts[].ws-protocols[].*",
Andy Greend459a6f2016-04-08 18:30:45 +080072 "vhosts[].ws-protocols[]",
Andy Greenb46e4a82016-04-12 16:26:03 +080073 "vhosts[].keepalive_timeout",
Andy Greenfb8be052016-05-12 19:39:29 +080074 "vhosts[].enable-client-ssl",
Andy Green6954daa2016-05-14 09:50:34 +080075 "vhosts[].ciphers",
76 "vhosts[].ecdh-curve",
Andy Green2dc7dde2016-06-03 21:19:40 +080077 "vhosts[].noipv6",
Andy Green011f9152016-06-04 09:01:28 +080078 "vhosts[].ipv6only",
Andy Green1ec8ba82016-06-10 08:37:26 +080079 "vhosts[].ssl-option-set",
80 "vhosts[].ssl-option-clear",
Andy Greencd0c6962016-03-28 10:12:37 +080081};
82
83enum lejp_vhost_paths {
84 LEJPVP,
85 LEJPVP_MOUNTS,
86 LEJPVP_NAME,
87 LEJPVP_PORT,
Andy Green1042b342016-04-14 11:50:05 +080088 LEJPVP_INTERFACE,
Andy Greena1ab2012016-04-14 12:18:33 +080089 LEJPVP_UNIXSKT,
Andy Green868b9f22016-04-14 12:37:21 +080090 LEJPVP_STS,
Andy Greencd0c6962016-03-28 10:12:37 +080091 LEJPVP_HOST_SSL_KEY,
92 LEJPVP_HOST_SSL_CERT,
93 LEJPVP_HOST_SSL_CA,
Andy Green2f0bc932016-04-15 12:00:23 +080094 LEJPVP_ACCESS_LOG,
Andy Greencd0c6962016-03-28 10:12:37 +080095 LEJPVP_MOUNTPOINT,
96 LEJPVP_ORIGIN,
97 LEJPVP_DEFAULT,
Andy Greenf5efa742016-04-13 11:42:53 +080098 LEJPVP_CGI_TIMEOUT,
Andy Greena5e73a12016-04-13 11:49:07 +080099 LEJPVP_CGI_ENV,
Andy Green42e8b182016-04-22 08:53:49 +0800100 LEJPVP_MOUNT_CACHE_MAX_AGE,
101 LEJPVP_MOUNT_CACHE_REUSE,
102 LEJPVP_MOUNT_CACHE_REVALIDATE,
103 LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
Andy Green8ef14c02016-05-14 10:00:21 +0800104 LEJPVP_MOUNT_EXTRA_MIMETYPES,
Andy Green37098ae2016-04-08 13:25:34 +0800105 LEJPVP_PROTOCOL_NAME_OPT,
106 LEJPVP_PROTOCOL_NAME,
107 LEJPVP_PROTOCOL,
Andy Greenb46e4a82016-04-12 16:26:03 +0800108 LEJPVP_KEEPALIVE_TIMEOUT,
Andy Greenfb8be052016-05-12 19:39:29 +0800109 LEJPVP_ENABLE_CLIENT_SSL,
Andy Green6954daa2016-05-14 09:50:34 +0800110 LEJPVP_CIPHERS,
111 LEJPVP_ECDH_CURVE,
Andy Green2dc7dde2016-06-03 21:19:40 +0800112 LEJPVP_NOIPV6,
Andy Green011f9152016-06-04 09:01:28 +0800113 LEJPVP_IPV6ONLY,
Andy Green1ec8ba82016-06-10 08:37:26 +0800114 LEJPVP_SSL_OPTION_SET,
115 LEJPVP_SSL_OPTION_CLEAR,
Andy Greencd0c6962016-03-28 10:12:37 +0800116};
117
Andy Green4bd5b962016-06-18 06:36:37 +0800118static const char * const parser_errs[] = {
119 "",
120 "",
121 "No opening '{'",
122 "Expected closing '}'",
123 "Expected '\"'",
124 "String underrun",
125 "Illegal unescaped control char",
126 "Illegal escape format",
127 "Illegal hex number",
128 "Expected ':'",
129 "Illegal value start",
130 "Digit required after decimal point",
131 "Bad number format",
132 "Bad exponent format",
133 "Unknown token",
134 "Too many ']'",
135 "Mismatched ']'",
136 "Expected ']'",
137 "JSON nesting limit exceeded",
138 "Nesting tracking used up",
139 "Number too long",
140 "Comma or block end expected",
141 "Unknown",
142 "Parser callback errored (see earlier error)",
143};
144
Andy Greencae57ad2016-05-02 10:03:25 +0800145#define MAX_PLUGIN_DIRS 10
146
Andy Greencd0c6962016-03-28 10:12:37 +0800147struct jpargs {
148 struct lws_context_creation_info *info;
149 struct lws_context *context;
150 const struct lws_protocols *protocols;
151 const struct lws_extension *extensions;
152 char *p, *end, valid;
153 struct lws_http_mount *head, *last;
Andy Green42e8b182016-04-22 08:53:49 +0800154
Andy Green37098ae2016-04-08 13:25:34 +0800155 struct lws_protocol_vhost_options *pvo;
Andy Green8ef14c02016-05-14 10:00:21 +0800156 struct lws_protocol_vhost_options *pvo_em;
Andy Green42e8b182016-04-22 08:53:49 +0800157 struct lws_http_mount m;
Andy Greencae57ad2016-05-02 10:03:25 +0800158 const char **plugin_dirs;
159 int count_plugin_dirs;
Andy Greenfb8be052016-05-12 19:39:29 +0800160
161 unsigned int enable_client_ssl:1;
Andy Green8ef14c02016-05-14 10:00:21 +0800162 unsigned int fresh_mount:1;
Andy Green92b0d8a2016-05-22 07:01:35 +0800163 unsigned int any_vhosts:1;
Andy Greencd0c6962016-03-28 10:12:37 +0800164};
165
Andy Green37098ae2016-04-08 13:25:34 +0800166static void *
167lwsws_align(struct jpargs *a)
168{
169 if ((unsigned long)(a->p) & 15)
170 a->p += 16 - ((unsigned long)(a->p) & 15);
171
172 return a->p;
173}
174
Andy Greena1ab2012016-04-14 12:18:33 +0800175static int
176arg_to_bool(const char *s)
Andy Greencd0c6962016-03-28 10:12:37 +0800177{
178 static const char * const on[] = { "on", "yes", "true" };
179 int n = atoi(s);
180
181 if (n)
182 return 1;
183
184 for (n = 0; n < ARRAY_SIZE(on); n++)
185 if (!strcasecmp(s, on[n]))
186 return 1;
187
188 return 0;
189}
190
191static char
192lejp_globals_cb(struct lejp_ctx *ctx, char reason)
193{
194 struct jpargs *a = (struct jpargs *)ctx->user;
195
196 /* we only match on the prepared path strings */
197 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
198 return 0;
199
200 switch (ctx->path_match - 1) {
201 case LEJPGP_UID:
202 a->info->uid = atoi(ctx->buf);
203 return 0;
204 case LEJPGP_GID:
205 a->info->gid = atoi(ctx->buf);
206 return 0;
Andy Greencd0c6962016-03-28 10:12:37 +0800207 case LEJPGP_COUNT_THREADS:
208 a->info->count_threads = atoi(ctx->buf);
209 return 0;
210 case LWJPGP_INIT_SSL:
211 if (arg_to_bool(ctx->buf))
212 a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
213 return 0;
Andy Greenb21c20b2016-04-15 13:33:52 +0800214 case LEJPGP_SERVER_STRING:
215 a->info->server_string = a->p;
216 break;
Andy Greencae57ad2016-05-02 10:03:25 +0800217 case LEJPGP_PLUGIN_DIR:
218 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
219 lwsl_err("Too many plugin dirs\n");
220 return -1;
221 }
222 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
223 break;
Andy Greencd0c6962016-03-28 10:12:37 +0800224
225 default:
226 return 0;
227 }
228
229 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
230
231 return 0;
232}
233
234static char
235lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
236{
237 struct jpargs *a = (struct jpargs *)ctx->user;
Andy Greena5e73a12016-04-13 11:49:07 +0800238 struct lws_protocol_vhost_options *pvo, *mp_cgienv;
Andy Greencd0c6962016-03-28 10:12:37 +0800239 struct lws_http_mount *m;
240 int n;
241
Andy Greena5e73a12016-04-13 11:49:07 +0800242#if 0
243 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
244 for (n = 0; n < ctx->wildcount; n++)
245 lwsl_notice(" %d\n", ctx->wild[n]);
246#endif
Andy Green37098ae2016-04-08 13:25:34 +0800247
Andy Greencd0c6962016-03-28 10:12:37 +0800248 if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
Andy Green37098ae2016-04-08 13:25:34 +0800249 /* set the defaults for this vhost */
Andy Greencd0c6962016-03-28 10:12:37 +0800250 a->valid = 1;
251 a->head = NULL;
252 a->last = NULL;
253 a->info->port = 0;
254 a->info->iface = NULL;
255 a->info->protocols = a->protocols;
256 a->info->extensions = a->extensions;
257 a->info->ssl_cert_filepath = NULL;
258 a->info->ssl_private_key_filepath = NULL;
259 a->info->ssl_ca_filepath = NULL;
260 a->info->timeout_secs = 5;
261 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
262 "ECDHE-RSA-AES256-GCM-SHA384:"
263 "DHE-RSA-AES256-GCM-SHA384:"
264 "ECDHE-RSA-AES256-SHA384:"
265 "HIGH:!aNULL:!eNULL:!EXPORT:"
266 "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
267 "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
268 "!DHE-RSA-AES128-SHA256:"
269 "!AES128-GCM-SHA256:"
270 "!AES128-SHA256:"
271 "!DHE-RSA-AES256-SHA256:"
272 "!AES256-GCM-SHA384:"
273 "!AES256-SHA256";
Andy Green37098ae2016-04-08 13:25:34 +0800274 a->info->pvo = NULL;
Andy Greenb46e4a82016-04-12 16:26:03 +0800275 a->info->keepalive_timeout = 60;
Andy Green2f0bc932016-04-15 12:00:23 +0800276 a->info->log_filepath = NULL;
Andy Green868b9f22016-04-14 12:37:21 +0800277 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
278 LWS_SERVER_OPTION_STS);
Andy Greenfb8be052016-05-12 19:39:29 +0800279 a->enable_client_ssl = 0;
Andy Greencd0c6962016-03-28 10:12:37 +0800280 }
281
282 if (reason == LEJPCB_OBJECT_START &&
Andy Green8ef14c02016-05-14 10:00:21 +0800283 ctx->path_match == LEJPVP_MOUNTS + 1) {
284 a->fresh_mount = 1;
Andy Green42e8b182016-04-22 08:53:49 +0800285 memset(&a->m, 0, sizeof(a->m));
Andy Green8ef14c02016-05-14 10:00:21 +0800286 }
Andy Greencd0c6962016-03-28 10:12:37 +0800287
Andy Green37098ae2016-04-08 13:25:34 +0800288 /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
289 if (reason == LEJPCB_OBJECT_START &&
290 ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
291 a->pvo = lwsws_align(a);
292 a->p += sizeof(*a->pvo);
293
294 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
295 /* ie, enable this protocol, no options yet */
296 a->pvo->next = a->info->pvo;
297 a->info->pvo = a->pvo;
298 a->pvo->name = a->p;
Andy Green8ef14c02016-05-14 10:00:21 +0800299 lwsl_notice(" adding protocol %s\n", a->p);
Andy Green37098ae2016-04-08 13:25:34 +0800300 a->p += n;
301 a->pvo->value = a->p;
302 a->pvo->options = NULL;
303 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
304 *(a->p)++ = '\0';
305 }
306
Andy Greencd0c6962016-03-28 10:12:37 +0800307 if (reason == LEJPCB_OBJECT_END &&
308 (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
309 a->valid) {
310
Andy Greenfb8be052016-05-12 19:39:29 +0800311 struct lws_vhost *vhost;
312
Andy Greencd0c6962016-03-28 10:12:37 +0800313 //lwsl_notice("%s\n", ctx->path);
314 if (!a->info->port) {
315 lwsl_err("Port required (eg, 443)");
316 return 1;
317 }
318 a->valid = 0;
Andy Green4664f712016-05-02 04:59:54 +0800319 a->info->mounts = a->head;
Andy Greencd0c6962016-03-28 10:12:37 +0800320
Andy Greenfb8be052016-05-12 19:39:29 +0800321 vhost = lws_create_vhost(a->context, a->info);
322 if (!vhost) {
Andy Greencd0c6962016-03-28 10:12:37 +0800323 lwsl_err("Failed to create vhost %s\n",
324 a->info->vhost_name);
325 return 1;
326 }
Andy Green92b0d8a2016-05-22 07:01:35 +0800327 a->any_vhosts = 1;
Andy Greencd0c6962016-03-28 10:12:37 +0800328
Andy Greenfb8be052016-05-12 19:39:29 +0800329 if (a->enable_client_ssl) {
330 memset(a->info, 0, sizeof(*a->info));
331 a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
332 lws_init_vhost_client_ssl(a->info, vhost);
333 }
334
Andy Greencd0c6962016-03-28 10:12:37 +0800335 return 0;
336 }
337
338 if (reason == LEJPCB_OBJECT_END &&
339 ctx->path_match == LEJPVP_MOUNTS + 1) {
Andy Green42e8b182016-04-22 08:53:49 +0800340 static const char * const mount_protocols[] = {
341 "http://",
342 "https://",
343 "file://",
344 "cgi://",
345 ">http://",
346 ">https://",
Andy Greenb24aaeb2016-05-09 09:37:01 +0800347 "callback://"
Andy Green42e8b182016-04-22 08:53:49 +0800348 };
349
Andy Green8ef14c02016-05-14 10:00:21 +0800350 if (!a->fresh_mount)
351 return 0;
352
Andy Green42e8b182016-04-22 08:53:49 +0800353 if (!a->m.mountpoint || !a->m.origin) {
Andy Greencd0c6962016-03-28 10:12:37 +0800354 lwsl_err("mountpoint and origin required\n");
355 return 1;
356 }
Andy Green8ef14c02016-05-14 10:00:21 +0800357 lwsl_debug("adding mount %s\n", a->m.mountpoint);
Andy Green42e8b182016-04-22 08:53:49 +0800358 m = lwsws_align(a);
359 memcpy(m, &a->m, sizeof(*m));
360 if (a->last)
361 a->last->mount_next = m;
Andy Greencd0c6962016-03-28 10:12:37 +0800362
Andy Green42e8b182016-04-22 08:53:49 +0800363 for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
364 if (!strncmp(a->m.origin, mount_protocols[n],
365 strlen(mount_protocols[n]))) {
366 m->origin_protocol = n;
367 m->origin = a->m.origin + strlen(mount_protocols[n]);
368 break;
369 }
370
371 if (n == ARRAY_SIZE(mount_protocols)) {
372 lwsl_err("unsupported protocol:// %s\n", a->m.origin);
Andy Greencd0c6962016-03-28 10:12:37 +0800373 return 1;
Andy Green42e8b182016-04-22 08:53:49 +0800374 }
375
376 a->p += sizeof(*m);
Andy Greencd0c6962016-03-28 10:12:37 +0800377 if (!a->head)
378 a->head = m;
379
380 a->last = m;
Andy Green8ef14c02016-05-14 10:00:21 +0800381 a->fresh_mount = 0;
Andy Greencd0c6962016-03-28 10:12:37 +0800382 }
383
384 /* we only match on the prepared path strings */
385 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
386 return 0;
387
388 switch (ctx->path_match - 1) {
389 case LEJPVP_NAME:
390 a->info->vhost_name = a->p;
391 break;
392 case LEJPVP_PORT:
393 a->info->port = atoi(ctx->buf);
394 return 0;
Andy Green1042b342016-04-14 11:50:05 +0800395 case LEJPVP_INTERFACE:
396 a->info->iface = a->p;
397 break;
Andy Greena1ab2012016-04-14 12:18:33 +0800398 case LEJPVP_UNIXSKT:
399 if (arg_to_bool(ctx->buf))
400 a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
401 else
402 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
403 return 0;
Andy Green868b9f22016-04-14 12:37:21 +0800404 case LEJPVP_STS:
405 if (arg_to_bool(ctx->buf))
406 a->info->options |= LWS_SERVER_OPTION_STS;
407 else
408 a->info->options &= ~(LWS_SERVER_OPTION_STS);
409 return 0;
Andy Greencd0c6962016-03-28 10:12:37 +0800410 case LEJPVP_HOST_SSL_KEY:
411 a->info->ssl_private_key_filepath = a->p;
412 break;
413 case LEJPVP_HOST_SSL_CERT:
414 a->info->ssl_cert_filepath = a->p;
415 break;
416 case LEJPVP_HOST_SSL_CA:
417 a->info->ssl_ca_filepath = a->p;
418 break;
Andy Green2f0bc932016-04-15 12:00:23 +0800419 case LEJPVP_ACCESS_LOG:
420 a->info->log_filepath = a->p;
421 break;
Andy Greencd0c6962016-03-28 10:12:37 +0800422 case LEJPVP_MOUNTPOINT:
Andy Green42e8b182016-04-22 08:53:49 +0800423 a->m.mountpoint = a->p;
Andy Green7a9970f2016-05-15 08:29:37 +0800424 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
Andy Greencd0c6962016-03-28 10:12:37 +0800425 break;
426 case LEJPVP_ORIGIN:
Andy Green42e8b182016-04-22 08:53:49 +0800427 a->m.origin = a->p;
Andy Greencd0c6962016-03-28 10:12:37 +0800428 break;
429 case LEJPVP_DEFAULT:
Andy Green42e8b182016-04-22 08:53:49 +0800430 a->m.def = a->p;
Andy Greencd0c6962016-03-28 10:12:37 +0800431 break;
Andy Green42e8b182016-04-22 08:53:49 +0800432 case LEJPVP_MOUNT_CACHE_MAX_AGE:
433 a->m.cache_max_age = atoi(ctx->buf);
434 return 0;
435 case LEJPVP_MOUNT_CACHE_REUSE:
436 a->m.cache_reusable = arg_to_bool(ctx->buf);
437 return 0;
438 case LEJPVP_MOUNT_CACHE_REVALIDATE:
439 a->m.cache_revalidate = arg_to_bool(ctx->buf);
440 return 0;
441 case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
442 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
443 return 0;
Andy Greenf5efa742016-04-13 11:42:53 +0800444 case LEJPVP_CGI_TIMEOUT:
Andy Green42e8b182016-04-22 08:53:49 +0800445 a->m.cgi_timeout = atoi(ctx->buf);
Andy Greenf5efa742016-04-13 11:42:53 +0800446 return 0;
Andy Greenb46e4a82016-04-12 16:26:03 +0800447 case LEJPVP_KEEPALIVE_TIMEOUT:
448 a->info->keepalive_timeout = atoi(ctx->buf);
449 return 0;
Andy Green6954daa2016-05-14 09:50:34 +0800450 case LEJPVP_CIPHERS:
451 a->info->ssl_cipher_list = a->p;
452 break;
453 case LEJPVP_ECDH_CURVE:
454 a->info->ecdh_curve = a->p;
455 break;
Andy Greena5e73a12016-04-13 11:49:07 +0800456 case LEJPVP_CGI_ENV:
457 mp_cgienv = lwsws_align(a);
Andy Green42e8b182016-04-22 08:53:49 +0800458 a->p += sizeof(*a->m.cgienv);
Andy Green37098ae2016-04-08 13:25:34 +0800459
Andy Green42e8b182016-04-22 08:53:49 +0800460 mp_cgienv->next = a->m.cgienv;
461 a->m.cgienv = mp_cgienv;
Andy Greena5e73a12016-04-13 11:49:07 +0800462
463 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
464 mp_cgienv->name = a->p;
465 a->p += n;
466 mp_cgienv->value = a->p;
467 mp_cgienv->options = NULL;
468 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
469 *(a->p)++ = '\0';
470
471 lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
472 mp_cgienv->value);
473
474 break;
Andy Green37098ae2016-04-08 13:25:34 +0800475 case LEJPVP_PROTOCOL_NAME_OPT:
476 /* this catches, eg,
477 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
478 * ie, these are options attached to a protocol with { }
479 */
480 pvo = lwsws_align(a);
481 a->p += sizeof(*a->pvo);
482
483 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
484 /* ie, enable this protocol, no options yet */
485 pvo->next = a->pvo->options;
486 a->pvo->options = pvo;
487 pvo->name = a->p;
488 a->p += n;
489 pvo->value = a->p;
490 pvo->options = NULL;
Andy Green37098ae2016-04-08 13:25:34 +0800491 break;
Andy Green8ef14c02016-05-14 10:00:21 +0800492
493 case LEJPVP_MOUNT_EXTRA_MIMETYPES:
494 a->pvo_em = lwsws_align(a);
495 a->p += sizeof(*a->pvo_em);
496
497 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
498 /* ie, enable this protocol, no options yet */
499 a->pvo_em->next = a->m.extra_mimetypes;
500 a->m.extra_mimetypes = a->pvo_em;
501 a->pvo_em->name = a->p;
502 lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
503 a->p += n;
504 a->pvo_em->value = a->p;
505 a->pvo_em->options = NULL;
506 break;
507
Andy Greenfb8be052016-05-12 19:39:29 +0800508 case LEJPVP_ENABLE_CLIENT_SSL:
509 a->enable_client_ssl = arg_to_bool(ctx->buf);
510 return 0;
Andy Green37098ae2016-04-08 13:25:34 +0800511
Andy Green2dc7dde2016-06-03 21:19:40 +0800512 case LEJPVP_NOIPV6:
513 if (arg_to_bool(ctx->buf))
514 a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
515 else
516 a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
517 return 0;
518
Andy Green011f9152016-06-04 09:01:28 +0800519 case LEJPVP_IPV6ONLY:
520 a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
521 if (arg_to_bool(ctx->buf))
522 a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
523 else
524 a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
525 return 0;
526
Andy Green1ec8ba82016-06-10 08:37:26 +0800527 case LEJPVP_SSL_OPTION_SET:
528 a->info->ssl_options_set |= atol(ctx->buf);
529 return 0;
530 case LEJPVP_SSL_OPTION_CLEAR:
531 a->info->ssl_options_clear |= atol(ctx->buf);
532 return 0;
533
Andy Greencd0c6962016-03-28 10:12:37 +0800534 default:
535 return 0;
536 }
537
538 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
539 *(a->p)++ = '\0';
540
541 return 0;
542}
543
544/*
545 * returns 0 = OK, 1 = can't open, 2 = parsing error
546 */
547
548static int
549lwsws_get_config(void *user, const char *f, const char * const *paths,
550 int count_paths, lejp_callback cb)
551{
552 unsigned char buf[128];
553 struct lejp_ctx ctx;
554 int n, m, fd;
555
556 fd = open(f, O_RDONLY);
557 if (fd < 0) {
558 lwsl_err("Cannot open %s\n", f);
Andy Green92b0d8a2016-05-22 07:01:35 +0800559 return 2;
Andy Greencd0c6962016-03-28 10:12:37 +0800560 }
561 lwsl_info("%s: %s\n", __func__, f);
562 lejp_construct(&ctx, cb, user, paths, count_paths);
563
564 do {
565 n = read(fd, buf, sizeof(buf));
566 if (!n)
567 break;
568
Andy Green6e7b79b2016-04-09 09:32:01 +0800569 m = (int)(signed char)lejp_parse(&ctx, buf, n);
Andy Greencd0c6962016-03-28 10:12:37 +0800570 } while (m == LEJP_CONTINUE);
571
572 close(fd);
573 n = ctx.line;
574 lejp_destruct(&ctx);
575
576 if (m < 0) {
Andy Green4bd5b962016-06-18 06:36:37 +0800577 lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
578 parser_errs[-m]);
Andy Greencd0c6962016-03-28 10:12:37 +0800579 return 2;
580 }
581
582 return 0;
583}
584
Andy Green0a183542016-04-09 07:22:40 +0800585#if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
586
587static int
588lwsws_get_config_d(void *user, const char *d, const char * const *paths,
589 int count_paths, lejp_callback cb)
590{
591 uv_dirent_t dent;
592 uv_fs_t req;
593 char path[256];
594 int ret = 0;
595 uv_loop_t loop;
596
597 uv_loop_init(&loop);
598
599 if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
600 lwsl_err("Scandir on %s failed\n", d);
Andy Green92b0d8a2016-05-22 07:01:35 +0800601 return 2;
Andy Green0a183542016-04-09 07:22:40 +0800602 }
603
604 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
605 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
606 ret = lwsws_get_config(user, path, paths, count_paths, cb);
607 if (ret)
608 goto bail;
609 }
610
611bail:
612 uv_fs_req_cleanup(&req);
613 uv_loop_close(&loop);
614
615 return ret;
616}
617
618#else
619
Andy Greencd0c6962016-03-28 10:12:37 +0800620#ifndef _WIN32
621static int filter(const struct dirent *ent)
622{
623 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
624 return 0;
625
626 return 1;
627}
628#endif
629
630static int
631lwsws_get_config_d(void *user, const char *d, const char * const *paths,
632 int count_paths, lejp_callback cb)
633{
634#ifndef _WIN32
635 struct dirent **namelist;
636 char path[256];
637 int n, i, ret = 0;
638
639 n = scandir(d, &namelist, filter, alphasort);
640 if (n < 0) {
641 lwsl_err("Scandir on %d failed\n", d);
642 }
643
644 for (i = 0; i < n; i++) {
645 snprintf(path, sizeof(path) - 1, "%s/%s", d,
646 namelist[i]->d_name);
647 ret = lwsws_get_config(user, path, paths, count_paths, cb);
648 if (ret) {
649 while (i++ < n)
650 free(namelist[i]);
651 goto bail;
652 }
653 free(namelist[i]);
654 }
655
656bail:
657 free(namelist);
658
659 return ret;
660#else
661 return 0;
662#endif
663}
664
Andy Green0a183542016-04-09 07:22:40 +0800665#endif
666
Andy Greencd0c6962016-03-28 10:12:37 +0800667int
668lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
669 char **cs, int *len)
670{
671 struct jpargs a;
Andy Greencae57ad2016-05-02 10:03:25 +0800672 const char * const *old = info->plugin_dirs;
Andy Green92b0d8a2016-05-22 07:01:35 +0800673 char dd[128];
Andy Greencae57ad2016-05-02 10:03:25 +0800674
675 memset(&a, 0, sizeof(a));
Andy Greencd0c6962016-03-28 10:12:37 +0800676
677 a.info = info;
678 a.p = *cs;
Andy Greena5e73a12016-04-13 11:49:07 +0800679 a.end = (a.p + *len) - 1;
Andy Greencd0c6962016-03-28 10:12:37 +0800680 a.valid = 0;
681
Andy Greencae57ad2016-05-02 10:03:25 +0800682 lwsws_align(&a);
683 info->plugin_dirs = (void *)a.p;
684 a.plugin_dirs = (void *)a.p; /* writeable version */
685 a.p += MAX_PLUGIN_DIRS * sizeof(void *);
686
687 /* copy any default paths */
688
689 while (old && *old) {
690 a.plugin_dirs[a.count_plugin_dirs++] = *old;
691 old++;
692 }
693
Andy Green92b0d8a2016-05-22 07:01:35 +0800694 snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
695 if (lwsws_get_config(&a, dd, paths_global,
Andy Greencd0c6962016-03-28 10:12:37 +0800696 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
697 return 1;
Andy Green92b0d8a2016-05-22 07:01:35 +0800698 snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
699 if (lwsws_get_config_d(&a, dd, paths_global,
Andy Greencd0c6962016-03-28 10:12:37 +0800700 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
701 return 1;
702
Andy Greencae57ad2016-05-02 10:03:25 +0800703 a.plugin_dirs[a.count_plugin_dirs] = NULL;
704
Andy Greencd0c6962016-03-28 10:12:37 +0800705 *cs = a.p;
706 *len = a.end - a.p;
707
708 return 0;
709}
710
711int
712lwsws_get_config_vhosts(struct lws_context *context,
713 struct lws_context_creation_info *info, const char *d,
714 char **cs, int *len)
715{
716 struct jpargs a;
Andy Green92b0d8a2016-05-22 07:01:35 +0800717 char dd[128];
Andy Greencd0c6962016-03-28 10:12:37 +0800718
Andy Greencae57ad2016-05-02 10:03:25 +0800719 memset(&a, 0, sizeof(a));
720
Andy Greencd0c6962016-03-28 10:12:37 +0800721 a.info = info;
722 a.p = *cs;
723 a.end = a.p + *len;
724 a.valid = 0;
725 a.context = context;
726 a.protocols = info->protocols;
727 a.extensions = info->extensions;
728
Andy Green92b0d8a2016-05-22 07:01:35 +0800729 snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
730 if (lwsws_get_config(&a, dd, paths_vhosts,
Andy Greencd0c6962016-03-28 10:12:37 +0800731 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
732 return 1;
Andy Green92b0d8a2016-05-22 07:01:35 +0800733 snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
734 if (lwsws_get_config_d(&a, dd, paths_vhosts,
Andy Greencd0c6962016-03-28 10:12:37 +0800735 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
736 return 1;
737
738 *cs = a.p;
739 *len = a.end - a.p;
740
Andy Green92b0d8a2016-05-22 07:01:35 +0800741 if (!a.any_vhosts) {
742 lwsl_err("Need at least one vhost\n");
743 return 1;
744 }
745
Andy Greencd0c6962016-03-28 10:12:37 +0800746 lws_finalize_startup(context);
747
748 return 0;
749}