Coverage Report

Created: 2023-11-19 06:50

/src/lwan/src/lib/lwan.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * lwan - web server
3
 * Copyright (c) 2012, 2013 L. A. F. Pereira <l@tia.mat.br>
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
18
 * USA.
19
 */
20
21
#define _GNU_SOURCE
22
#include <assert.h>
23
#include <ctype.h>
24
#include <dlfcn.h>
25
#include <errno.h>
26
#include <fcntl.h>
27
#include <libproc.h>
28
#include <limits.h>
29
#include <signal.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <sys/resource.h>
33
#include <sys/socket.h>
34
#include <sys/types.h>
35
#include <unistd.h>
36
37
#include "lwan-private.h"
38
39
#include "lwan-config.h"
40
#include "lwan-http-authorize.h"
41
42
#if defined(LWAN_HAVE_LUA)
43
#include "lwan-lua.h"
44
#endif
45
46
/* Ideally, this would check if all items in enum lwan_request_flags,
47
 * when bitwise-or'd together, would not have have any bit set that
48
 * is also set in REQUEST_METHOD_MASK. */
49
static_assert(REQUEST_ACCEPT_DEFLATE > REQUEST_METHOD_MASK,
50
              "enough bits to store request methods");
51
52
/* See detect_fastest_monotonic_clock() */
53
clockid_t monotonic_clock_id = CLOCK_MONOTONIC;
54
55
static const struct lwan_config default_config = {
56
    .listener = "localhost:8080",
57
    .keep_alive_timeout = 15,
58
    .quiet = false,
59
    .proxy_protocol = false,
60
    .allow_cors = false,
61
    .expires = 1 * ONE_WEEK,
62
    .n_threads = 0,
63
    .max_post_data_size = 10 * DEFAULT_BUFFER_SIZE,
64
    .allow_post_temp_file = false,
65
    .max_put_data_size = 10 * DEFAULT_BUFFER_SIZE,
66
    .allow_put_temp_file = false,
67
    .use_dynamic_buffer = false,
68
};
69
70
LWAN_HANDLER_ROUTE(brew_coffee, NULL /* do not autodetect this route */)
71
0
{
72
    /* Placeholder handler so that __start_lwan_handler and __stop_lwan_handler
73
     * symbols will get defined.
74
     */
75
0
    return HTTP_I_AM_A_TEAPOT;
76
0
}
77
78
__attribute__((no_sanitize_address))
79
static void *find_handler(const char *name)
80
0
{
81
0
    const struct lwan_handler_info *handler;
82
83
0
    LWAN_SECTION_FOREACH(lwan_handler, handler) {
84
0
        if (streq(handler->name, name))
85
0
            return handler->handler;
86
0
    }
87
88
0
    return NULL;
89
0
}
90
91
__attribute__((no_sanitize_address))
92
static const struct lwan_module *find_module(const char *name)
93
0
{
94
0
    const struct lwan_module_info *module;
95
96
0
    LWAN_SECTION_FOREACH(lwan_module, module) {
97
0
        if (streq(module->name, name))
98
0
            return module->module;
99
0
    }
100
101
0
    return NULL;
102
0
}
103
104
static void destroy_urlmap(void *data)
105
0
{
106
0
    struct lwan_url_map *url_map = data;
107
108
0
    if (url_map->module) {
109
0
        const struct lwan_module *module = url_map->module;
110
111
0
        if (module->destroy)
112
0
            module->destroy(url_map->data);
113
0
    } else if (url_map->data && url_map->flags & HANDLER_DATA_IS_HASH_TABLE) {
114
0
        hash_free(url_map->data);
115
0
    }
116
117
0
    free(url_map->authorization.realm);
118
0
    free(url_map->authorization.password_file);
119
0
    free((char *)url_map->prefix);
120
0
    free(url_map);
121
0
}
122
123
static struct lwan_url_map *add_url_map(struct lwan_trie *t, const char *prefix,
124
                                        const struct lwan_url_map *map)
125
0
{
126
0
    struct lwan_url_map *copy = malloc(sizeof(*copy));
127
128
0
    if (!copy)
129
0
        lwan_status_critical_perror("Could not copy URL map");
130
131
0
    memcpy(copy, map, sizeof(*copy));
132
133
0
    copy->prefix = strdup(prefix ? prefix : copy->prefix);
134
0
    if (!copy->prefix)
135
0
        lwan_status_critical_perror("Could not copy URL prefix");
136
137
0
    copy->prefix_len = strlen(copy->prefix);
138
0
    lwan_trie_add(t, copy->prefix, copy);
139
140
0
    return copy;
141
0
}
142
143
static bool can_override_header(const char *name)
144
0
{
145
    /* NOTE: Update lwan_prepare_response_header_full() in lwan-response.c
146
     *       if new headers are added here. */
147
148
0
    if (strcaseequal_neutral(name, "Date"))
149
0
        return false;
150
0
    if (strcaseequal_neutral(name, "Expires"))
151
0
        return false;
152
0
    if (strcaseequal_neutral(name, "WWW-Authenticate"))
153
0
        return false;
154
0
    if (strcaseequal_neutral(name, "Connection"))
155
0
        return false;
156
0
    if (strcaseequal_neutral(name, "Content-Type"))
157
0
        return false;
158
0
    if (strcaseequal_neutral(name, "Transfer-Encoding"))
159
0
        return false;
160
0
    if (strcaseequal_neutral_len(name, "Access-Control-Allow-",
161
0
                     sizeof("Access-Control-Allow-") - 1))
162
0
        return false;
163
164
0
    return true;
165
0
}
166
167
static void build_response_headers(struct lwan *l,
168
                                   const struct lwan_key_value *kv)
169
0
{
170
0
    struct lwan_strbuf strbuf;
171
0
    bool set_server = false;
172
173
0
    assert(l);
174
175
0
    lwan_strbuf_init(&strbuf);
176
177
0
    for (; kv && kv->key; kv++) {
178
0
        if (!can_override_header(kv->key)) {
179
0
            lwan_status_warning("Cannot override header '%s'", kv->key);
180
0
        } else {
181
0
            if (strcaseequal_neutral(kv->key, "Server"))
182
0
                set_server = true;
183
184
0
            lwan_strbuf_append_printf(&strbuf, "\r\n%s: %s", kv->key,
185
0
                                      kv->value);
186
0
        }
187
0
    }
188
189
0
    if (!set_server)
190
0
        lwan_strbuf_append_strz(&strbuf, "\r\nServer: lwan");
191
192
0
    lwan_strbuf_append_strz(&strbuf, "\r\n\r\n");
193
194
0
    l->headers = (struct lwan_value){.value = lwan_strbuf_get_buffer(&strbuf),
195
0
                                     .len = lwan_strbuf_get_length(&strbuf)};
196
0
}
197
198
static void parse_global_headers(struct config *c,
199
                                 struct lwan *lwan)
200
0
{
201
0
    struct lwan_key_value_array hdrs;
202
0
    const struct config_line *l;
203
0
    struct lwan_key_value *kv;
204
205
0
    lwan_key_value_array_init(&hdrs);
206
207
0
    while ((l = config_read_line(c))) {
208
0
        switch (l->type) {
209
0
        case CONFIG_LINE_TYPE_SECTION:
210
0
            config_error(
211
0
                c, "No sections are supported under the 'headers' section");
212
0
            goto cleanup;
213
214
0
        case CONFIG_LINE_TYPE_LINE:
215
0
            kv = lwan_key_value_array_append(&hdrs);
216
0
            if (!kv) {
217
0
                lwan_status_critical_perror(
218
0
                    "Could not allocate memory for custom response header");
219
0
            }
220
221
0
            kv->key = strdup(l->key);
222
0
            if (!kv->key) {
223
0
                lwan_status_critical_perror(
224
0
                    "Could not allocate memory for custom response header");
225
0
            }
226
227
0
            kv->value = strdup(l->value);
228
0
            if (!kv->value) {
229
0
                lwan_status_critical_perror(
230
0
                    "Could not allocate memory for custom response header");
231
0
            }
232
0
            break;
233
234
0
        case CONFIG_LINE_TYPE_SECTION_END:
235
0
            kv = lwan_key_value_array_append(&hdrs);
236
0
            if (!kv) {
237
0
                lwan_status_critical_perror(
238
0
                    "Could not allocate memory for custom response header");
239
0
            }
240
241
0
            kv->key = NULL;
242
0
            kv->value = NULL;
243
244
0
            build_response_headers(lwan, lwan_key_value_array_get_array(&hdrs));
245
0
            goto cleanup;
246
0
        }
247
0
    }
248
249
0
    config_error(c, "EOF while looking for end of 'headers' section");
250
251
0
cleanup:
252
0
    LWAN_ARRAY_FOREACH (&hdrs, kv) {
253
0
        free(kv->key);
254
0
        free(kv->value);
255
0
    }
256
0
    lwan_key_value_array_reset(&hdrs);
257
0
}
258
259
static void parse_listener_prefix_authorization(struct config *c,
260
                                                const struct config_line *l,
261
                                                struct lwan_url_map *url_map)
262
0
{
263
0
    if (!streq(l->value, "basic")) {
264
0
        config_error(c, "Only basic authorization supported");
265
0
        return;
266
0
    }
267
268
0
    memset(&url_map->authorization, 0, sizeof(url_map->authorization));
269
270
0
    while ((l = config_read_line(c))) {
271
0
        switch (l->type) {
272
0
        case CONFIG_LINE_TYPE_LINE:
273
0
            if (streq(l->key, "realm")) {
274
0
                free(url_map->authorization.realm);
275
0
                url_map->authorization.realm = strdup(l->value);
276
0
            } else if (streq(l->key, "password_file")) {
277
0
                free(url_map->authorization.password_file);
278
0
                url_map->authorization.password_file = realpath(l->value, NULL);
279
0
                if (!url_map->authorization.password_file)
280
0
                    config_error(c, "Could not determine full path for password file: %s", l->value);
281
0
            }
282
0
            break;
283
284
0
        case CONFIG_LINE_TYPE_SECTION:
285
0
            config_error(c, "Unexpected section: %s", l->key);
286
0
            goto error;
287
288
0
        case CONFIG_LINE_TYPE_SECTION_END:
289
0
            if (!url_map->authorization.realm)
290
0
                url_map->authorization.realm = strdup("Lwan");
291
0
            if (!url_map->authorization.password_file)
292
0
                url_map->authorization.password_file = strdup("htpasswd");
293
294
0
            url_map->flags |= HANDLER_MUST_AUTHORIZE;
295
0
            return;
296
0
        }
297
0
    }
298
299
0
    config_error(c, "Could not find end of authorization section");
300
301
0
error:
302
0
    free(url_map->authorization.realm);
303
0
    free(url_map->authorization.password_file);
304
0
}
305
306
__attribute__((no_sanitize_address))
307
static const char *get_module_name(const struct lwan_module *module)
308
0
{
309
0
    const struct lwan_module_info *iter;
310
311
0
    LWAN_SECTION_FOREACH(lwan_module, iter) {
312
0
        if (iter->module == module)
313
0
            return iter->name;
314
0
    }
315
316
0
    return "<unknown>";
317
0
}
318
319
static void parse_listener_prefix(struct config *c,
320
                                  const struct config_line *l,
321
                                  struct lwan *lwan,
322
                                  const struct lwan_module *module,
323
                                  void *handler)
324
0
{
325
0
    struct lwan_url_map url_map = {};
326
0
    struct hash *hash = hash_str_new(free, free);
327
0
    char *prefix = strdupa(l->value);
328
0
    struct config *isolated;
329
330
0
    if (!hash)
331
0
        lwan_status_critical("Could not allocate hash table");
332
333
0
    isolated = config_isolate_section(c, l);
334
0
    if (!isolated) {
335
0
        config_error(c, "Could not isolate configuration file");
336
0
        goto out;
337
0
    }
338
339
0
    while ((l = config_read_line(c))) {
340
0
        switch (l->type) {
341
0
        case CONFIG_LINE_TYPE_LINE: {
342
0
            char *key_copy = strdup(l->key);
343
0
            char *value_copy = strdup(l->value);
344
345
0
            if (!key_copy)
346
0
                lwan_status_critical("Could not copy key from config file");
347
0
            if (!value_copy)
348
0
                lwan_status_critical("Could not copy value from config file");
349
350
0
            hash_add(hash, key_copy, value_copy);
351
0
            break;
352
0
        }
353
354
0
        case CONFIG_LINE_TYPE_SECTION:
355
0
            if (streq(l->key, "authorization")) {
356
0
                parse_listener_prefix_authorization(c, l, &url_map);
357
0
            } else if (!config_skip_section(c, l)) {
358
0
                config_error(c, "Could not skip section");
359
0
                goto out;
360
0
            }
361
0
            break;
362
363
0
        case CONFIG_LINE_TYPE_SECTION_END:
364
0
            goto add_map;
365
0
        }
366
0
    }
367
368
0
    config_error(c, "Expecting section end while parsing prefix");
369
0
    goto out;
370
371
0
add_map:
372
0
    assert((handler && !module) || (!handler && module));
373
374
0
    if (handler) {
375
0
        url_map.handler = handler;
376
0
        url_map.flags |= HANDLER_PARSE_MASK | HANDLER_DATA_IS_HASH_TABLE;
377
0
        url_map.data = hash;
378
0
        url_map.module = NULL;
379
380
0
        hash = NULL;
381
0
    } else if (module->create_from_hash && module->handle_request) {
382
0
        lwan_status_debug("Initializing module %s from config",
383
0
                          get_module_name(module));
384
385
0
        url_map.data = module->create_from_hash(prefix, hash);
386
0
        if (!url_map.data) {
387
0
            config_error(c, "Could not create module instance");
388
0
            goto out;
389
0
        }
390
391
0
        if (module->parse_conf && !module->parse_conf(url_map.data, isolated)) {
392
0
            const char *msg = config_last_error(isolated);
393
394
0
            config_error(c, "Error from module: %s", msg ? msg : "Unknown");
395
0
            goto out;
396
0
        }
397
398
0
        url_map.handler = module->handle_request;
399
0
        url_map.flags |= module->flags;
400
0
        url_map.module = module;
401
0
    } else if (UNLIKELY(!module->create_from_hash)) {
402
0
        config_error(c, "Module isn't prepared to load settings from a file; "
403
0
                        "create_from_hash() method isn't present");
404
0
        goto out;
405
0
    } else if (UNLIKELY(!module->handle_request)) {
406
0
        config_error(c, "Module does not have handle_request() method");
407
0
        goto out;
408
0
    }
409
410
0
    add_url_map(&lwan->url_map_trie, prefix, &url_map);
411
412
0
out:
413
0
    hash_free(hash);
414
0
    config_close(isolated);
415
0
}
416
417
static void register_url_map(struct lwan *l, const struct lwan_url_map *map)
418
0
{
419
0
    struct lwan_url_map *copy = add_url_map(&l->url_map_trie, NULL, map);
420
421
0
    if (copy->module && copy->module->create) {
422
0
        lwan_status_debug("Initializing module %s from struct",
423
0
                          get_module_name(copy->module));
424
425
0
        copy->data = copy->module->create(map->prefix, copy->args);
426
0
        if (!copy->data) {
427
0
            lwan_status_critical("Could not initialize module %s",
428
0
                                 get_module_name(copy->module));
429
0
        }
430
431
0
        copy->flags = copy->module->flags;
432
0
        copy->handler = copy->module->handle_request;
433
0
    } else {
434
0
        copy->flags = HANDLER_PARSE_MASK;
435
0
    }
436
0
}
437
438
void lwan_set_url_map(struct lwan *l, const struct lwan_url_map *map)
439
0
{
440
0
    lwan_trie_destroy(&l->url_map_trie);
441
0
    if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap)))
442
0
        lwan_status_critical_perror("Could not initialize trie");
443
444
0
    for (; map->prefix; map++)
445
0
        register_url_map(l, map);
446
0
}
447
448
__attribute__((no_sanitize_address))
449
void lwan_detect_url_map(struct lwan *l)
450
0
{
451
0
    const struct lwan_handler_info *iter;
452
453
0
    lwan_trie_destroy(&l->url_map_trie);
454
0
    if (UNLIKELY(!lwan_trie_init(&l->url_map_trie, destroy_urlmap)))
455
0
        lwan_status_critical_perror("Could not initialize trie");
456
457
0
    LWAN_SECTION_FOREACH(lwan_handler, iter) {
458
0
        if (!iter->route)
459
0
            continue;
460
461
0
        const struct lwan_url_map map = {.prefix = iter->route,
462
0
                                         .handler = iter->handler};
463
0
        register_url_map(l, &map);
464
0
    }
465
0
}
466
467
const char *lwan_get_config_path(char *path_buf, size_t path_buf_len)
468
0
{
469
0
    char buffer[PATH_MAX];
470
471
0
    if (proc_pidpath(getpid(), buffer, sizeof(buffer)) < 0)
472
0
        goto out;
473
474
0
    char *path = strrchr(buffer, '/');
475
0
    if (!path)
476
0
        goto out;
477
0
    int ret = snprintf(path_buf, path_buf_len, "%s.conf", path + 1);
478
0
    if (ret < 0 || ret >= (int)path_buf_len)
479
0
        goto out;
480
481
0
    return path_buf;
482
483
0
out:
484
0
    return "lwan.conf";
485
0
}
486
487
static void parse_tls_listener(struct config *conf, const struct config_line *line, struct lwan *lwan)
488
0
{
489
0
#if !defined(LWAN_HAVE_MBEDTLS)
490
0
    config_error(conf, "Lwan has been built without mbedTLS support");
491
0
    return;
492
0
#endif
493
494
0
    lwan->config.tls_listener = strdup(line->value);
495
0
    if (!lwan->config.tls_listener) {
496
0
        config_error(conf, "Could not allocate memory for tls_listener");
497
0
        return;
498
0
    }
499
500
0
    lwan->config.ssl.cert = NULL;
501
0
    lwan->config.ssl.key = NULL;
502
503
0
    while ((line = config_read_line(conf))) {
504
0
        switch (line->type) {
505
0
        case CONFIG_LINE_TYPE_SECTION_END:
506
0
            if (!lwan->config.ssl.cert)
507
0
                config_error(conf, "Missing path to certificate");
508
0
            if (!lwan->config.ssl.key)
509
0
                config_error(conf, "Missing path to private key");
510
0
            return;
511
0
        case CONFIG_LINE_TYPE_SECTION:
512
0
            config_error(conf, "Unexpected section: %s", line->key);
513
0
            return;
514
0
        case CONFIG_LINE_TYPE_LINE:
515
0
            if (streq(line->key, "cert")) {
516
0
                free(lwan->config.ssl.cert);
517
0
                lwan->config.ssl.cert = strdup(line->value);
518
0
                if (!lwan->config.ssl.cert)
519
0
                    return lwan_status_critical("Could not copy string");
520
0
            } else if (streq(line->key, "key")) {
521
0
                free(lwan->config.ssl.key);
522
0
                lwan->config.ssl.key = strdup(line->value);
523
0
                if (!lwan->config.ssl.key)
524
0
                    return lwan_status_critical("Could not copy string");
525
0
            } else if (streq(line->key, "hsts")) {
526
0
                lwan->config.ssl.send_hsts_header = parse_bool(line->value, false);
527
0
            } else {
528
0
                config_error(conf, "Unexpected key: %s", line->key);
529
0
            }
530
0
        }
531
0
    }
532
533
0
    config_error(conf, "Expecting section end while parsing SSL configuration");
534
0
}
535
536
static void
537
parse_listener(struct config *c, const struct config_line *l, struct lwan *lwan)
538
0
{
539
0
    lwan->config.listener = strdup(l->value);
540
0
    if (!lwan->config.listener)
541
0
        config_error(c, "Could not allocate memory for listener");
542
543
0
    while ((l = config_read_line(c))) {
544
0
        switch (l->type) {
545
0
        case CONFIG_LINE_TYPE_LINE:
546
0
            config_error(c, "Unexpected key %s", l->key);
547
0
            return;
548
0
        case CONFIG_LINE_TYPE_SECTION:
549
0
            config_error(c, "Unexpected section %s", l->key);
550
0
            return;
551
0
        case CONFIG_LINE_TYPE_SECTION_END:
552
0
            return;
553
0
        }
554
0
    }
555
556
0
    config_error(c, "Unexpected EOF while parsing listener");
557
0
}
558
559
static void
560
parse_site(struct config *c, const struct config_line *l, struct lwan *lwan)
561
0
{
562
0
    while ((l = config_read_line(c))) {
563
0
        switch (l->type) {
564
0
        case CONFIG_LINE_TYPE_LINE:
565
0
            config_error(c, "Expecting prefix section");
566
0
            return;
567
0
        case CONFIG_LINE_TYPE_SECTION:
568
            /* FIXME: per-site authorization? */
569
570
0
            if (l->key[0] == '&') {
571
0
                void *handler = find_handler(l->key + 1);
572
0
                if (handler) {
573
0
                    parse_listener_prefix(c, l, lwan, NULL, handler);
574
0
                    continue;
575
0
                }
576
577
0
                config_error(c, "Could not find handler name: %s", l->key + 1);
578
0
                return;
579
0
            }
580
581
0
            const struct lwan_module *module = find_module(l->key);
582
0
            if (module) {
583
0
                parse_listener_prefix(c, l, lwan, module, NULL);
584
0
                continue;
585
0
            }
586
587
0
            config_error(c, "Invalid section or module not found: %s", l->key);
588
0
            return;
589
0
        case CONFIG_LINE_TYPE_SECTION_END:
590
0
            return;
591
0
        }
592
0
    }
593
594
0
    config_error(c, "Expecting section end while parsing listener");
595
0
}
596
597
static bool setup_from_config(struct lwan *lwan, const char *path)
598
0
{
599
0
    const struct config_line *line;
600
0
    struct config *conf;
601
0
    bool has_site = false;
602
0
    bool has_listener = false;
603
0
    bool has_tls_listener = false;
604
0
    char path_buf[PATH_MAX];
605
606
0
    if (!path)
607
0
        path = lwan_get_config_path(path_buf, sizeof(path_buf));
608
0
    lwan_status_info("Loading configuration file: %s", path);
609
610
0
    conf = config_open(path);
611
0
    if (!conf)
612
0
        return false;
613
614
0
    if (!lwan_trie_init(&lwan->url_map_trie, destroy_urlmap))
615
0
        return false;
616
617
0
    while ((line = config_read_line(conf))) {
618
0
        switch (line->type) {
619
0
        case CONFIG_LINE_TYPE_LINE:
620
0
            if (streq(line->key, "keep_alive_timeout")) {
621
0
                lwan->config.keep_alive_timeout = (unsigned int)parse_long(
622
0
                    line->value, default_config.keep_alive_timeout);
623
0
            } else if (streq(line->key, "quiet")) {
624
0
                lwan->config.quiet =
625
0
                    parse_bool(line->value, default_config.quiet);
626
0
            } else if (streq(line->key, "proxy_protocol")) {
627
0
                lwan->config.proxy_protocol =
628
0
                    parse_bool(line->value, default_config.proxy_protocol);
629
0
            } else if (streq(line->key, "allow_cors")) {
630
0
                lwan->config.allow_cors =
631
0
                    parse_bool(line->value, default_config.allow_cors);
632
0
            } else if (streq(line->key, "use_dynamic_buffer")) {
633
0
                lwan->config.use_dynamic_buffer =
634
0
                    parse_bool(line->value, default_config.use_dynamic_buffer);
635
0
            } else if (streq(line->key, "expires")) {
636
0
                lwan->config.expires =
637
0
                    parse_time_period(line->value, default_config.expires);
638
0
            } else if (streq(line->key, "error_template")) {
639
0
                free(lwan->config.error_template);
640
0
                lwan->config.error_template = strdup(line->value);
641
0
            } else if (streq(line->key, "threads")) {
642
0
                long n_threads =
643
0
                    parse_long(line->value, default_config.n_threads);
644
0
                if (n_threads < 0)
645
0
                    config_error(conf, "Invalid number of threads: %ld",
646
0
                                 n_threads);
647
0
                lwan->config.n_threads = (unsigned int)n_threads;
648
0
            } else if (streq(line->key, "max_post_data_size")) {
649
0
                long max_post_data_size = parse_long(
650
0
                    line->value, (long)default_config.max_post_data_size);
651
0
                if (max_post_data_size < 0)
652
0
                    config_error(conf, "Negative maximum post data size");
653
0
                else if (max_post_data_size > 128 * (1 << 20))
654
0
                    config_error(conf,
655
0
                                 "Maximum post data can't be over 128MiB");
656
0
                lwan->config.max_post_data_size = (size_t)max_post_data_size;
657
0
            } else if (streq(line->key, "max_put_data_size")) {
658
0
                long max_put_data_size = parse_long(
659
0
                    line->value, (long)default_config.max_put_data_size);
660
0
                if (max_put_data_size < 0)
661
0
                    config_error(conf, "Negative maximum put data size");
662
0
                else if (max_put_data_size > 128 * (1 << 20))
663
0
                    config_error(conf,
664
0
                                 "Maximum put data can't be over 128MiB");
665
0
                lwan->config.max_put_data_size = (size_t)max_put_data_size;
666
0
            } else if (streq(line->key, "allow_temp_files")) {
667
0
                bool has_post, has_put;
668
669
0
                if (strstr(line->value, "all")) {
670
0
                    has_post = has_put = true;
671
0
                } else {
672
0
                    has_post = !!strstr(line->value, "post");
673
0
                    has_put = !!strstr(line->value, "put");
674
0
                }
675
676
0
                lwan->config.allow_post_temp_file = has_post;
677
0
                lwan->config.allow_put_temp_file = has_put;
678
0
            } else {
679
0
                config_error(conf, "Unknown config key: %s", line->key);
680
0
            }
681
0
            break;
682
0
        case CONFIG_LINE_TYPE_SECTION:
683
0
            if (streq(line->key, "site")) {
684
0
                if (!has_site) {
685
0
                    parse_site(conf, line, lwan);
686
0
                    has_site = true;
687
0
                } else {
688
0
                    config_error(conf, "Only one site may be configured");
689
0
                }
690
0
            } else if (streq(line->key, "straitjacket")) {
691
0
                lwan_straitjacket_enforce_from_config(conf);
692
0
            } else if (streq(line->key, "headers")) {
693
0
                parse_global_headers(conf, lwan);
694
0
            } else if (streq(line->key, "listener")) {
695
0
                if (has_listener) {
696
0
                    config_error(conf, "Listener already set up");
697
0
                } else {
698
0
                    parse_listener(conf, line, lwan);
699
0
                    has_listener = true;
700
0
                }
701
0
            } else if (streq(line->key, "tls_listener")) {
702
0
                if (has_tls_listener) {
703
0
                    config_error(conf, "TLS Listener already set up");
704
0
                } else {
705
0
                    parse_tls_listener(conf, line, lwan);
706
0
                    has_tls_listener = true;
707
0
                }
708
0
            } else {
709
0
                config_error(conf, "Unknown section type: %s", line->key);
710
0
            }
711
0
            break;
712
0
        case CONFIG_LINE_TYPE_SECTION_END:
713
0
            config_error(conf, "Unexpected section end");
714
0
        }
715
0
    }
716
717
0
    if (config_last_error(conf)) {
718
0
        lwan_status_critical("Error on config file \"%s\", line %d: %s", path,
719
0
                             config_cur_line(conf), config_last_error(conf));
720
0
        lwan_trie_destroy(&lwan->url_map_trie);
721
0
    }
722
723
0
    config_close(conf);
724
725
0
    return true;
726
0
}
727
728
static void try_setup_from_config(struct lwan *l,
729
                                  const struct lwan_config *config)
730
0
{
731
0
    if (!setup_from_config(l, config->config_file_path)) {
732
0
        if (config->config_file_path) {
733
0
            lwan_status_critical("Could not read config file: %s",
734
0
                                 config->config_file_path);
735
0
        }
736
0
    }
737
738
0
    lwan_status_init(l); /* `quiet` key might have changed value. */
739
740
0
    l->config.request_flags =
741
0
        (l->config.proxy_protocol ? REQUEST_ALLOW_PROXY_REQS : 0) |
742
0
        (l->config.allow_cors ? REQUEST_ALLOW_CORS : 0) |
743
0
        (l->config.ssl.send_hsts_header ? REQUEST_WANTS_HSTS_HEADER : 0);
744
0
}
745
746
static rlim_t setup_open_file_count_limits(void)
747
0
{
748
0
    struct rlimit r;
749
750
0
    if (getrlimit(RLIMIT_NOFILE, &r) < 0) {
751
0
        lwan_status_perror("Could not obtain maximum number of file "
752
0
                           "descriptors. Assuming %d",
753
0
                           OPEN_MAX);
754
0
        return OPEN_MAX;
755
0
    }
756
757
0
    if (r.rlim_max != r.rlim_cur) {
758
0
        const rlim_t current = r.rlim_cur;
759
760
0
        if (r.rlim_max == RLIM_INFINITY && r.rlim_cur < OPEN_MAX) {
761
0
            r.rlim_cur = OPEN_MAX;
762
0
        } else if (r.rlim_cur < r.rlim_max) {
763
0
            r.rlim_cur = r.rlim_max;
764
0
        } else {
765
            /* Shouldn't happen, so just return the current value. */
766
0
            goto out;
767
0
        }
768
769
0
        if (setrlimit(RLIMIT_NOFILE, &r) < 0) {
770
0
            lwan_status_perror("Could not raise maximum number of file "
771
0
                               "descriptors to %" PRIu64 ". Leaving at "
772
0
                               "%" PRIu64, r.rlim_max, current);
773
0
            r.rlim_cur = current;
774
0
        }
775
0
    }
776
777
0
out:
778
0
    return r.rlim_cur;
779
0
}
780
781
static void allocate_connections(struct lwan *l, size_t max_open_files)
782
0
{
783
0
    const size_t sz = max_open_files * sizeof(struct lwan_connection);
784
785
0
    l->conns = lwan_aligned_alloc(sz, 64);
786
0
    if (UNLIKELY(!l->conns))
787
0
        lwan_status_critical_perror("lwan_alloc_aligned");
788
789
0
    memset(l->conns, 0, sz);
790
0
}
791
792
static void get_number_of_cpus(struct lwan *l)
793
0
{
794
0
    long n_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
795
0
    long n_available_cpus = sysconf(_SC_NPROCESSORS_CONF);
796
797
0
    if (n_online_cpus < 0) {
798
0
        lwan_status_warning(
799
0
            "Could not get number of online CPUs, assuming 1 CPU");
800
0
        n_online_cpus = 1;
801
0
    }
802
803
0
    if (n_available_cpus < 0) {
804
0
        lwan_status_warning(
805
0
            "Could not get number of available CPUs, assuming %ld CPUs",
806
0
            n_online_cpus);
807
0
        n_available_cpus = n_online_cpus;
808
0
    }
809
810
0
    l->online_cpus = (unsigned int)n_online_cpus;
811
0
    l->available_cpus = (unsigned int)n_available_cpus;
812
0
}
813
814
0
void lwan_init(struct lwan *l) { lwan_init_with_config(l, &default_config); }
815
816
const struct lwan_config *lwan_get_default_config(void)
817
0
{
818
0
    return &default_config;
819
0
}
820
821
static char *dup_or_null(const char *s)
822
0
{
823
0
    return s ? strdup(s) : NULL;
824
0
}
825
826
void lwan_init_with_config(struct lwan *l, const struct lwan_config *config)
827
0
{
828
    /* Load defaults */
829
0
    memset(l, 0, sizeof(*l));
830
0
    memcpy(&l->config, config, sizeof(*config));
831
0
    l->config.listener = dup_or_null(l->config.listener);
832
0
    l->config.config_file_path = dup_or_null(l->config.config_file_path);
833
0
    l->config.ssl.key = dup_or_null(l->config.ssl.key);
834
0
    l->config.ssl.cert = dup_or_null(l->config.ssl.cert);
835
836
    /* Initialize status first, as it is used by other things during
837
     * their initialization. */
838
0
    lwan_status_init(l);
839
840
    /* These will only print debugging messages. Debug messages are always
841
     * printed if we're on a debug build, so the quiet setting will be
842
     * respected. */
843
0
    lwan_job_thread_init();
844
0
    lwan_tables_init();
845
846
    /* Get the number of CPUs here because straightjacket might be active
847
     * and this will block access to /proc and /sys, which will cause
848
     * get_number_of_cpus() to get incorrect fallback values. */
849
0
    get_number_of_cpus(l);
850
851
0
    try_setup_from_config(l, config);
852
853
0
    if (!l->headers.len)
854
0
        build_response_headers(l, config->global_headers);
855
856
0
    lwan_response_init(l);
857
858
    /* Continue initialization as normal. */
859
0
    lwan_status_debug("Initializing lwan web server");
860
861
0
    if (!l->config.n_threads) {
862
0
        l->thread.count = l->online_cpus;
863
0
        if (l->thread.count == 1)
864
0
            l->thread.count = 2;
865
0
    } else if (l->config.n_threads > 3 * l->online_cpus) {
866
0
        l->thread.count = l->online_cpus * 3;
867
868
0
        lwan_status_warning("%d threads requested, but only %d online CPUs "
869
0
                            "(out of %d configured CPUs); capping to %d threads",
870
0
                            l->config.n_threads, l->online_cpus, l->available_cpus,
871
0
                            3 * l->online_cpus);
872
0
    } else if (l->config.n_threads > 255) {
873
0
        l->thread.count = 256;
874
875
0
        lwan_status_warning("%d threads requested, but max 256 supported",
876
0
            l->config.n_threads);
877
0
    } else {
878
0
        l->thread.count = l->config.n_threads;
879
0
    }
880
881
0
    rlim_t max_open_files = setup_open_file_count_limits();
882
0
    allocate_connections(l, (size_t)max_open_files);
883
884
0
    l->thread.max_fd = (unsigned)max_open_files / (unsigned)l->thread.count;
885
0
    lwan_status_info("Using %d threads, maximum %d sockets per thread",
886
0
                     l->thread.count, l->thread.max_fd);
887
888
0
    signal(SIGPIPE, SIG_IGN);
889
890
0
    lwan_readahead_init();
891
0
    lwan_thread_init(l);
892
0
    lwan_http_authorize_init();
893
0
}
894
895
void lwan_shutdown(struct lwan *l)
896
0
{
897
0
    lwan_status_info("Shutting down");
898
899
0
    free(l->config.listener);
900
0
    free(l->config.error_template);
901
0
    free(l->config.config_file_path);
902
903
0
    lwan_always_bzero(l->config.ssl.cert, strlen(l->config.ssl.cert));
904
0
    free(l->config.ssl.cert);
905
0
    lwan_always_bzero(l->config.ssl.key, strlen(l->config.ssl.key));
906
0
    free(l->config.ssl.key);
907
908
0
    lwan_job_thread_shutdown();
909
0
    lwan_thread_shutdown(l);
910
911
0
    lwan_status_debug("Shutting down URL handlers");
912
0
    lwan_trie_destroy(&l->url_map_trie);
913
914
0
    free(l->headers.value);
915
0
    free(l->conns);
916
917
0
    lwan_response_shutdown(l);
918
0
    lwan_tables_shutdown();
919
0
    lwan_status_shutdown(l);
920
0
    lwan_http_authorize_shutdown();
921
0
    lwan_readahead_shutdown();
922
0
}
923
924
void lwan_main_loop(struct lwan *l)
925
0
{
926
0
    lwan_status_info("Ready to serve");
927
928
0
    lwan_job_thread_main_loop();
929
0
}
930
931
#ifdef CLOCK_MONOTONIC_COARSE
932
__attribute__((constructor)) static void detect_fastest_monotonic_clock(void)
933
10
{
934
10
    struct timespec ts;
935
936
10
    if (!clock_gettime(CLOCK_MONOTONIC_COARSE, &ts))
937
10
        monotonic_clock_id = CLOCK_MONOTONIC_COARSE;
938
10
}
939
#endif
940
941
void lwan_set_thread_name(const char *name)
942
0
{
943
0
    char thread_name[16];
944
0
    char process_name[PATH_MAX];
945
0
    char *tmp;
946
0
    int ret;
947
948
0
    if (proc_pidpath(getpid(), process_name, sizeof(process_name)) < 0)
949
0
        return;
950
951
0
    tmp = strrchr(process_name, '/');
952
0
    if (!tmp)
953
0
        return;
954
955
0
    ret = snprintf(thread_name, sizeof(thread_name), "%s %s", tmp + 1, name);
956
0
    if (ret < 0)
957
0
        return;
958
959
0
    pthread_set_name_np(pthread_self(), thread_name);
960
0
}