Coverage Report

Created: 2024-09-19 07:08

/src/fluent-bit/lib/monkey/mk_server/mk_vhost.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  Monkey HTTP Server
4
 *  ==================
5
 *  Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include <monkey/mk_info.h>
21
#include <monkey/monkey.h>
22
#include <monkey/mk_core.h>
23
#include <monkey/mk_vhost.h>
24
#include <monkey/mk_vhost_tls.h>
25
#include <monkey/mk_utils.h>
26
#include <monkey/mk_http_status.h>
27
#include <monkey/mk_info.h>
28
29
#include <mk_core/mk_dirent.h>
30
31
#include <re.h>
32
#include <sys/stat.h>
33
#include <fcntl.h>
34
35
static int str_to_regex(char *str, regex_t *reg)
36
0
{
37
0
    char *p = str;
38
0
    regex_t *result;
39
40
0
    while (*p) {
41
0
        if (*p == ' ') *p = '|';
42
0
        p++;
43
0
    }
44
45
0
    result = re_compile(str);
46
47
0
    memcpy(reg, result, REGEXP_SIZE);
48
49
0
    return 0;
50
0
}
51
52
/*
53
 * This function is triggered upon thread creation (inside the thread
54
 * context), here we configure per-thread data.
55
 */
56
int mk_vhost_fdt_worker_init(struct mk_server *server)
57
0
{
58
0
    int i;
59
0
    int j;
60
0
    struct mk_vhost *h;
61
0
    struct mk_list *list;
62
0
    struct mk_list *head;
63
0
    struct vhost_fdt_host *fdt;
64
0
    struct vhost_fdt_hash_table *ht;
65
0
    struct vhost_fdt_hash_chain *hc;
66
67
0
    if (server->fdt == MK_FALSE) {
68
0
        return -1;
69
0
    }
70
71
    /*
72
     * We are under a thread context and the main configuration is
73
     * already in place. Now for every existent virtual host we are
74
     * going to create the File Descriptor Table (FDT) which aims to
75
     * hold references of 'open and shared' file descriptors under
76
     * the Virtual Host context.
77
     */
78
79
    /*
80
     * Under an initialization context we need to protect this critical
81
     * section
82
     */
83
0
    pthread_mutex_lock(&server->vhost_fdt_mutex);
84
85
    /*
86
     * Initialize the thread FDT/Hosts list and create an entry per
87
     * existent virtual host
88
     */
89
0
    list = mk_mem_alloc_z(sizeof(struct mk_list));
90
0
    mk_list_init(list);
91
92
0
    mk_list_foreach(head, &server->hosts) {
93
0
        h = mk_list_entry(head, struct mk_vhost, _head);
94
95
0
        fdt = mk_mem_alloc(sizeof(struct vhost_fdt_host));
96
0
        fdt->host = h;
97
98
        /* Initialize hash table */
99
0
        for (i = 0; i < VHOST_FDT_HASHTABLE_SIZE; i++) {
100
0
            ht = &fdt->hash_table[i];
101
0
            ht->av_slots = VHOST_FDT_HASHTABLE_CHAINS;
102
103
            /* for each chain under the hash table, set the fd */
104
0
            for (j = 0; j < VHOST_FDT_HASHTABLE_CHAINS; j++) {
105
0
                hc = &ht->chain[j];
106
0
                hc->fd      = -1;
107
0
                hc->hash    =  0;
108
0
                hc->readers =  0;
109
0
            }
110
0
        }
111
0
        mk_list_add(&fdt->_head, list);
112
0
    }
113
114
0
    MK_TLS_SET(mk_tls_vhost_fdt, list);
115
0
    pthread_mutex_unlock(&server->vhost_fdt_mutex);
116
117
0
    return 0;
118
0
}
119
120
int mk_vhost_fdt_worker_exit(struct mk_server *server)
121
0
{
122
0
    struct mk_list *list;
123
0
    struct mk_list *head;
124
0
    struct mk_list *tmp;
125
0
    struct vhost_fdt_host *fdt;
126
127
0
    if (server->fdt == MK_FALSE) {
128
0
        return -1;
129
0
    }
130
131
0
    list = MK_TLS_GET(mk_tls_vhost_fdt);
132
0
    mk_list_foreach_safe(head, tmp, list) {
133
0
        fdt = mk_list_entry(head, struct vhost_fdt_host, _head);
134
0
        mk_list_del(&fdt->_head);
135
0
        mk_mem_free(fdt);
136
0
    }
137
138
0
    mk_mem_free(list);
139
0
    return 0;
140
0
}
141
142
143
static inline
144
struct vhost_fdt_hash_table *mk_vhost_fdt_table_lookup(int id, struct mk_vhost *host)
145
0
{
146
0
    struct mk_list *head;
147
0
    struct mk_list *list;
148
0
    struct vhost_fdt_host *fdt_host;
149
0
    struct vhost_fdt_hash_table *ht = NULL;
150
151
0
    list = MK_TLS_GET(mk_tls_vhost_fdt);
152
0
    mk_list_foreach(head, list) {
153
0
        fdt_host = mk_list_entry(head, struct vhost_fdt_host, _head);
154
0
        if (fdt_host->host == host) {
155
0
            ht = &fdt_host->hash_table[id];
156
0
            return ht;
157
0
        }
158
0
    }
159
160
0
    return ht;
161
0
}
162
163
static inline
164
struct vhost_fdt_hash_chain
165
*mk_vhost_fdt_chain_lookup(unsigned int hash, struct vhost_fdt_hash_table *ht)
166
0
{
167
0
    int i;
168
0
    struct vhost_fdt_hash_chain *hc = NULL;
169
170
0
    for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) {
171
0
        hc = &ht->chain[i];
172
0
        if (hc->hash == hash) {
173
0
            return hc;
174
0
        }
175
0
    }
176
177
0
    return NULL;
178
0
}
179
180
181
static inline int mk_vhost_fdt_open(int id, unsigned int hash,
182
                                    struct mk_http_request *sr,
183
                                    struct mk_server *server)
184
0
{
185
0
    int i;
186
0
    int fd = -1;
187
0
    struct vhost_fdt_hash_table *ht = NULL;
188
0
    struct vhost_fdt_hash_chain *hc;
189
190
0
    if (server->fdt == MK_FALSE) {
191
0
        return open(sr->real_path.data, sr->file_info.flags_read_only);
192
0
    }
193
194
0
    ht = mk_vhost_fdt_table_lookup(id, sr->host_conf);
195
0
    if (mk_unlikely(!ht)) {
196
0
        return open(sr->real_path.data, sr->file_info.flags_read_only);
197
0
    }
198
199
    /* We got the hash table, now look around the chains array */
200
0
    hc = mk_vhost_fdt_chain_lookup(hash, ht);
201
0
    if (hc) {
202
        /* Increment the readers and return the shared FD */
203
0
        hc->readers++;
204
0
        sr->vhost_fdt_id      = id;
205
0
        sr->vhost_fdt_hash    = hash;
206
0
        sr->vhost_fdt_enabled = MK_TRUE;
207
0
        return hc->fd;
208
0
    }
209
210
    /*
211
     * Get here means that no entry exists in the hash table for the
212
     * requested file descriptor and hash, we must try to open the file
213
     * and register the entry in the table.
214
     */
215
0
    fd = open(sr->real_path.data, sr->file_info.flags_read_only);
216
0
    if (fd == -1) {
217
0
        return -1;
218
0
    }
219
220
    /* If chains are full, just return the new FD, bad luck... */
221
0
    if (ht->av_slots <= 0) {
222
0
        return fd;
223
0
    }
224
225
    /* Register the new entry in an available slot */
226
0
    for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) {
227
0
        hc = &ht->chain[i];
228
0
        if (hc->fd == -1) {
229
0
            hc->fd   = fd;
230
0
            hc->hash = hash;
231
0
            hc->readers++;
232
0
            ht->av_slots--;
233
234
0
            sr->vhost_fdt_id      = id;
235
0
            sr->vhost_fdt_hash    = hash;
236
0
            sr->vhost_fdt_enabled = MK_TRUE;
237
238
0
            return fd;
239
0
        }
240
0
    }
241
242
0
    return fd;
243
0
}
244
245
static inline int mk_vhost_fdt_close(struct mk_http_request *sr,
246
                                     struct mk_server *server)
247
0
{
248
0
    int id;
249
0
    unsigned int hash;
250
0
    struct vhost_fdt_hash_table *ht = NULL;
251
0
    struct vhost_fdt_hash_chain *hc;
252
253
0
    if (server->fdt == MK_FALSE || sr->vhost_fdt_enabled == MK_FALSE) {
254
0
        if (sr->in_file.fd > 0) {
255
0
            return close(sr->in_file.fd);
256
0
        }
257
0
        return -1;
258
0
    }
259
260
0
    id   = sr->vhost_fdt_id;
261
0
    hash = sr->vhost_fdt_hash;
262
263
0
    ht = mk_vhost_fdt_table_lookup(id, sr->host_conf);
264
0
    if (mk_unlikely(!ht)) {
265
0
        return close(sr->in_file.fd);
266
0
    }
267
268
    /* We got the hash table, now look around the chains array */
269
0
    hc = mk_vhost_fdt_chain_lookup(hash, ht);
270
0
    if (hc) {
271
        /* Increment the readers and check if we should close */
272
0
        hc->readers--;
273
0
        sr->vhost_fdt_enabled = MK_FALSE;
274
275
0
        if (hc->readers == 0) {
276
0
            hc->fd   = -1;
277
0
            hc->hash = 0;
278
0
            ht->av_slots++;
279
0
            return close(sr->in_file.fd);
280
0
        }
281
0
        else {
282
0
            return 0;
283
0
        }
284
0
    }
285
0
    return close(sr->in_file.fd);
286
0
}
287
288
289
int mk_vhost_open(struct mk_http_request *sr, struct mk_server *server)
290
0
{
291
0
    int id;
292
0
    int off;
293
0
    unsigned int hash;
294
295
0
    off = sr->host_conf->documentroot.len;
296
0
    hash = mk_utils_gen_hash(sr->real_path.data + off,
297
0
                             sr->real_path.len - off);
298
0
    id   = (hash % VHOST_FDT_HASHTABLE_SIZE);
299
300
0
    return mk_vhost_fdt_open(id, hash, sr, server);
301
0
}
302
303
int mk_vhost_close(struct mk_http_request *sr, struct mk_server *server)
304
0
{
305
0
    return mk_vhost_fdt_close(sr, server);
306
0
}
307
308
struct mk_vhost_handler *mk_vhost_handler_match(char *match,
309
                                                void (*cb)(struct mk_http_request *,
310
                                                           void *),
311
                                                void *data)
312
0
{
313
0
    int ret;
314
0
    struct mk_vhost_handler *h;
315
316
0
    h = mk_mem_alloc(sizeof(struct mk_vhost_handler));
317
0
    if (!h) {
318
0
        return NULL;
319
0
    }
320
0
    h->name  = NULL;
321
0
    h->cb    = cb;
322
0
    h->data  = data;
323
0
    h->match = mk_mem_alloc(REGEXP_SIZE);
324
0
    if (!h->match) {
325
0
        mk_mem_free(h);
326
0
        return NULL;
327
0
    }
328
0
    mk_list_init(&h->params);
329
330
0
    ret = str_to_regex(match, h->match);
331
0
    if (ret == -1) {
332
0
        mk_mem_free(h);
333
0
        return NULL;
334
0
    }
335
336
0
    return h;
337
0
}
338
339
/*
340
 * Open a virtual host configuration file and return a structure with
341
 * definitions.
342
 */
343
struct mk_vhost *mk_vhost_read(char *path)
344
0
{
345
0
    int ret;
346
0
    char *tmp;
347
0
    char *host_low;
348
0
    struct stat checkdir;
349
0
    struct mk_vhost *host;
350
0
    struct mk_vhost_alias *new_alias;
351
0
    struct mk_vhost_error_page *err_page;
352
0
    struct mk_rconf *cnf;
353
0
    struct mk_rconf_section *section_host;
354
0
    struct mk_rconf_section *section_ep;
355
0
    struct mk_rconf_section *section_handlers;
356
0
    struct mk_rconf_entry *entry_ep;
357
0
    struct mk_string_line *entry;
358
0
    struct mk_list *head, *list, *line;
359
0
    struct mk_vhost_handler *h_handler;
360
0
    struct mk_vhost_handler_param *h_param;
361
362
    /* Read configuration file */
363
0
    cnf = mk_rconf_open(path);
364
0
    if (!cnf) {
365
0
        mk_err("Configuration error, aborting.");
366
0
        exit(EXIT_FAILURE);
367
0
    }
368
369
    /* Read 'HOST' section */
370
0
    section_host = mk_rconf_section_get(cnf, "HOST");
371
0
    if (!section_host) {
372
0
        mk_err("Invalid config file %s", path);
373
0
        return NULL;
374
0
    }
375
376
    /* Alloc configuration node */
377
0
    host = mk_mem_alloc_z(sizeof(struct mk_vhost));
378
0
    host->config = cnf;
379
0
    host->file = mk_string_dup(path);
380
381
    /* Init list for host name aliases */
382
0
    mk_list_init(&host->server_names);
383
384
    /* Init list for custom error pages */
385
0
    mk_list_init(&host->error_pages);
386
387
    /* Init list for content handlers */
388
0
    mk_list_init(&host->handlers);
389
390
    /* Lookup Servername */
391
0
    list = mk_rconf_section_get_key(section_host, "Servername", MK_RCONF_LIST);
392
0
    if (!list) {
393
0
        mk_err("Hostname does not contain a Servername");
394
0
        exit(EXIT_FAILURE);
395
0
    }
396
397
0
    mk_list_foreach(head, list) {
398
0
        entry = mk_list_entry(head, struct mk_string_line, _head);
399
0
        if (entry->len > MK_HOSTNAME_LEN - 1) {
400
0
            continue;
401
0
        }
402
403
        /* Hostname to lowercase */
404
0
        host_low = mk_string_tolower(entry->val);
405
406
        /* Alloc node */
407
0
        new_alias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias));
408
0
        new_alias->name = mk_mem_alloc_z(entry->len + 1);
409
0
        strncpy(new_alias->name, host_low, entry->len);
410
0
        mk_mem_free(host_low);
411
412
0
        new_alias->len = entry->len;
413
414
0
        mk_list_add(&new_alias->_head, &host->server_names);
415
0
    }
416
0
    mk_string_split_free(list);
417
418
    /* Lookup document root handled by a mk_ptr_t */
419
0
    host->documentroot.data = mk_rconf_section_get_key(section_host,
420
0
                                                       "DocumentRoot",
421
0
                                                       MK_RCONF_STR);
422
0
    if (!host->documentroot.data) {
423
0
        mk_err("Missing DocumentRoot entry on %s file", path);
424
0
        mk_rconf_free(cnf);
425
0
        mk_mem_free(host->file);
426
0
        mk_mem_free(host);
427
0
        return NULL;
428
0
    }
429
430
0
    host->documentroot.len = strlen(host->documentroot.data);
431
432
    /* Validate document root configured */
433
0
    if (stat(host->documentroot.data, &checkdir) == -1) {
434
0
        mk_err("Invalid path to DocumentRoot in %s", path);
435
0
    }
436
0
    else if (!(checkdir.st_mode & S_IFDIR)) {
437
0
        mk_err("DocumentRoot variable in %s has an invalid directory path", path);
438
0
    }
439
440
0
    if (mk_list_is_empty(&host->server_names) == 0) {
441
0
        mk_rconf_free(cnf);
442
0
        mk_mem_free(host->file);
443
0
        mk_mem_free(host);
444
0
        return NULL;
445
0
    }
446
447
    /* Check Virtual Host redirection */
448
0
    host->header_redirect.data = NULL;
449
0
    host->header_redirect.len  = 0;
450
451
0
    tmp = mk_rconf_section_get_key(section_host,
452
0
                                   "Redirect",
453
0
                                   MK_RCONF_STR);
454
0
    if (tmp) {
455
0
        host->header_redirect.data = mk_string_dup(tmp);
456
0
        host->header_redirect.len  = strlen(tmp);
457
0
        mk_mem_free(tmp);
458
0
    }
459
460
    /* Error Pages */
461
0
    section_ep = mk_rconf_section_get(cnf, "ERROR_PAGES");
462
0
    if (section_ep) {
463
0
        mk_list_foreach(head, &section_ep->entries) {
464
0
            entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head);
465
466
0
            int ep_status = -1;
467
0
            char *ep_file = NULL;
468
0
            unsigned long len;
469
470
0
            ep_status = atoi(entry_ep->key);
471
0
            ep_file   = entry_ep->val;
472
473
            /* Validate input values */
474
0
            if (ep_status < MK_CLIENT_BAD_REQUEST ||
475
0
                ep_status > MK_SERVER_HTTP_VERSION_UNSUP ||
476
0
                ep_file == NULL) {
477
0
                continue;
478
0
            }
479
480
            /* Alloc error page node */
481
0
            err_page = mk_mem_alloc_z(sizeof(struct mk_vhost_error_page));
482
0
            err_page->status = ep_status;
483
0
            err_page->file   = mk_string_dup(ep_file);
484
0
            err_page->real_path = NULL;
485
0
            mk_string_build(&err_page->real_path, &len, "%s/%s",
486
0
                            host->documentroot.data, err_page->file);
487
488
0
            MK_TRACE("Map error page: status %i -> %s", err_page->status, err_page->file);
489
490
            /* Link page to the error page list */
491
0
            mk_list_add(&err_page->_head, &host->error_pages);
492
0
        }
493
0
    }
494
495
    /* Handlers */
496
0
    int i;
497
0
    int params;
498
0
    struct mk_list *head_line;
499
500
0
    section_handlers = mk_rconf_section_get(cnf, "HANDLERS");
501
0
    if (!section_handlers) {
502
0
        return host;
503
0
    }
504
0
    mk_list_foreach(head, &section_handlers->entries) {
505
0
        entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head);
506
0
        if (strncasecmp(entry_ep->key, "Match", strlen(entry_ep->key)) == 0) {
507
0
            line = mk_string_split_line(entry_ep->val);
508
0
            if (!line) {
509
0
                continue;
510
0
            }
511
0
            h_handler = mk_mem_alloc(sizeof(struct mk_vhost_handler));
512
0
            if (!h_handler) {
513
0
                exit(EXIT_FAILURE);
514
0
            }
515
0
            h_handler->match = mk_mem_alloc(REGEXP_SIZE);
516
0
            if (!h_handler->match) {
517
0
                mk_mem_free(h_handler);
518
0
                exit(EXIT_FAILURE);
519
0
            }
520
0
            h_handler->cb = NULL;
521
0
            mk_list_init(&h_handler->params);
522
523
0
            i = 0;
524
0
            params = 0;
525
0
            mk_list_foreach(head_line, line) {
526
0
                entry = mk_list_entry(head_line, struct mk_string_line, _head);
527
0
                switch (i) {
528
0
                case 0:
529
0
                    ret = str_to_regex(entry->val, h_handler->match);
530
0
                    if (ret == -1) {
531
0
                        return NULL;
532
0
                    }
533
0
                    break;
534
0
                case 1:
535
0
                    h_handler->name = mk_string_dup(entry->val);
536
0
                    break;
537
0
                default:
538
                    /* link parameters */
539
0
                    h_param = mk_mem_alloc(sizeof(struct mk_vhost_handler_param));
540
0
                    h_param->p.data = mk_string_dup(entry->val);
541
0
                    h_param->p.len  = entry->len;
542
0
                    mk_list_add(&h_param->_head, &h_handler->params);
543
0
                    params++;
544
0
                };
545
0
                i++;
546
0
            }
547
0
            h_handler->n_params = params;
548
0
            mk_string_split_free(line);
549
550
0
            if (i < 2) {
551
0
                mk_err("[Host Handlers] invalid Match value\n");
552
0
                exit(EXIT_FAILURE);
553
0
            }
554
0
            mk_list_add(&h_handler->_head, &host->handlers);
555
0
        }
556
0
    }
557
558
559
0
    return host;
560
0
}
561
562
int mk_vhost_map_handlers(struct mk_server *server)
563
0
{
564
0
    int n = 0;
565
0
    struct mk_list *head;
566
0
    struct mk_list *head_handler;
567
0
    struct mk_vhost *host;
568
0
    struct mk_vhost_handler *h_handler;
569
0
    struct mk_plugin *p;
570
571
0
    mk_list_foreach(head, &server->hosts) {
572
0
        host = mk_list_entry(head, struct mk_vhost, _head);
573
0
        mk_list_foreach(head_handler, &host->handlers) {
574
0
            h_handler = mk_list_entry(head_handler,
575
0
                                      struct mk_vhost_handler, _head);
576
577
            /* Lookup plugin by name */
578
0
            p = mk_plugin_lookup(h_handler->name, server);
579
0
            if (!p) {
580
0
                mk_err("Plugin '%s' was not loaded", h_handler->name);
581
0
                continue;
582
0
            }
583
584
0
            if (p->hooks != MK_PLUGIN_STAGE) {
585
0
                mk_err("Plugin '%s' is not a handler", h_handler->name);
586
0
                continue;
587
0
            }
588
589
0
            h_handler->handler = p;
590
0
            n++;
591
0
        }
592
0
    }
593
594
0
    return n;
595
0
}
596
597
void mk_vhost_set_single(char *path, struct mk_server *server)
598
0
{
599
0
    struct mk_vhost *host;
600
0
    struct mk_vhost_alias *halias;
601
0
    struct stat checkdir;
602
603
    /* Set the default host */
604
0
    host = mk_mem_alloc_z(sizeof(struct mk_vhost));
605
0
    mk_list_init(&host->error_pages);
606
0
    mk_list_init(&host->server_names);
607
608
    /* Prepare the unique alias */
609
0
    halias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias));
610
0
    halias->name = mk_string_dup("127.0.0.1");
611
0
    mk_list_add(&halias->_head, &host->server_names);
612
613
0
    host->documentroot.data = mk_string_dup(path);
614
0
    host->documentroot.len = strlen(path);
615
0
    host->header_redirect.data = NULL;
616
617
    /* Validate document root configured */
618
0
    if (stat(host->documentroot.data, &checkdir) == -1) {
619
0
        mk_err("Invalid path to DocumentRoot in %s", path);
620
0
        exit(EXIT_FAILURE);
621
0
    }
622
0
    else if (!(checkdir.st_mode & S_IFDIR)) {
623
0
        mk_err("DocumentRoot variable in %s has an invalid directory path", path);
624
0
        exit(EXIT_FAILURE);
625
0
    }
626
0
    mk_list_add(&host->_head, &server->hosts);
627
0
    mk_list_init(&host->handlers);
628
0
}
629
630
/* Given a configuration directory, start reading the virtual host entries */
631
void mk_vhost_init(char *path, struct mk_server *server)
632
0
{
633
0
    DIR *dir;
634
0
    unsigned long len;
635
0
    char *buf = 0;
636
0
    char *sites = 0;
637
0
    char *file;
638
0
    struct mk_vhost *p_host;     /* debug */
639
0
    struct dirent *ent;
640
0
    struct file_info f_info;
641
0
    int ret;
642
643
0
    if (!server->conf_sites) {
644
0
        mk_warn("[vhost] skipping default site");
645
0
        return;
646
0
    }
647
648
    /* Read default virtual host file */
649
0
    mk_string_build(&sites, &len, "%s/%s/",
650
0
                    path, server->conf_sites);
651
0
    ret = mk_file_get_info(sites, &f_info, MK_FILE_EXISTS);
652
0
    if (ret == -1 || f_info.is_directory == MK_FALSE) {
653
0
        mk_mem_free(sites);
654
0
        sites = server->conf_sites;
655
0
    }
656
657
0
    mk_string_build(&buf, &len, "%s/default", sites);
658
659
0
    p_host = mk_vhost_read(buf);
660
0
    if (!p_host) {
661
0
        mk_err("Error parsing main configuration file 'default'");
662
0
    }
663
0
    mk_list_add(&p_host->_head, &server->hosts);
664
0
    server->nhosts++;
665
0
    mk_mem_free(buf);
666
0
    buf = NULL;
667
668
669
    /* Read all virtual hosts defined in sites/ */
670
0
    if (!(dir = opendir(sites))) {
671
0
        mk_mem_free(sites);
672
0
        mk_err("Could not open %s", sites);
673
0
        exit(EXIT_FAILURE);
674
0
    }
675
676
    /* Reading content */
677
0
    while ((ent = readdir(dir)) != NULL) {
678
0
        if (ent->d_name[0] == '.') {
679
0
            continue;
680
0
        }
681
0
        if (strcmp((char *) ent->d_name, "..") == 0) {
682
0
            continue;
683
0
        }
684
0
        if (ent->d_name[strlen(ent->d_name) - 1] ==  '~') {
685
0
            continue;
686
0
        }
687
0
        if (strcasecmp((char *) ent->d_name, "default") == 0) {
688
0
            continue;
689
0
        }
690
0
        file = NULL;
691
0
        mk_string_build(&file, &len, "%s/%s", sites, ent->d_name);
692
693
0
        p_host = mk_vhost_read(file);
694
0
        mk_mem_free(file);
695
0
        if (!p_host) {
696
0
            continue;
697
0
        }
698
0
        else {
699
0
            mk_list_add(&p_host->_head, &server->hosts);
700
0
            server->nhosts++;
701
0
        }
702
0
    }
703
0
    closedir(dir);
704
0
    mk_mem_free(sites);
705
0
}
706
707
708
/* Lookup a registered virtual host based on the given 'host' input */
709
int mk_vhost_get(mk_ptr_t host, struct mk_vhost **vhost,
710
                 struct mk_vhost_alias **alias,
711
                 struct mk_server *server)
712
0
{
713
0
    struct mk_vhost *entry_host;
714
0
    struct mk_vhost_alias *entry_alias;
715
0
    struct mk_list *head_vhost, *head_alias;
716
717
0
    mk_list_foreach(head_vhost, &server->hosts) {
718
0
        entry_host = mk_list_entry(head_vhost, struct mk_vhost, _head);
719
0
        mk_list_foreach(head_alias, &entry_host->server_names) {
720
0
            entry_alias = mk_list_entry(head_alias, struct mk_vhost_alias, _head);
721
0
            if (entry_alias->len == host.len &&
722
0
                strncmp(entry_alias->name, host.data, host.len) == 0) {
723
0
                *vhost = entry_host;
724
0
                *alias = entry_alias;
725
0
                return 0;
726
0
            }
727
0
        }
728
0
    }
729
730
0
    return -1;
731
0
}
732
733
static void mk_vhost_handler_free(struct mk_vhost_handler *h)
734
0
{
735
0
    struct mk_list *tmp;
736
0
    struct mk_list *head;
737
0
    struct mk_vhost_handler_param *param;
738
739
    /* Release Params */
740
0
    mk_list_foreach_safe(head, tmp, &h->params) {
741
0
        param = mk_list_entry(head, struct mk_vhost_handler_param, _head);
742
0
        mk_list_del(&param->_head);
743
0
        mk_mem_free(param->p.data);
744
0
        mk_mem_free(param);
745
0
    }
746
747
0
    mk_mem_free(h->match);
748
0
    mk_mem_free(h->name);
749
0
    mk_mem_free(h);
750
0
}
751
752
int mk_vhost_destroy(struct mk_vhost *vh)
753
0
{
754
0
    struct mk_vhost_alias *halias = NULL;
755
0
    struct mk_vhost_handler *hhandler;
756
0
    struct mk_vhost_error_page *ep;
757
0
    struct mk_list *head;
758
0
    struct mk_list *tmp;
759
760
0
    if (vh) {
761
        /* Free aliases or servernames */
762
0
        mk_list_foreach_safe(head, tmp, &vh->server_names) {
763
0
            halias = mk_list_entry(head, struct mk_vhost_alias, _head);
764
0
            if (halias) {
765
0
                mk_list_del(&halias->_head);
766
0
                if (halias->name) {
767
0
                    mk_mem_free(halias->name);
768
0
                }
769
0
                mk_mem_free(halias);
770
0
            }
771
0
        }
772
773
        /* Handlers */
774
0
        mk_list_foreach_safe(head, tmp, &vh->handlers) {
775
0
            hhandler = mk_list_entry(head, struct mk_vhost_handler, _head);
776
0
            if (hhandler) {
777
0
                mk_vhost_handler_free(hhandler);
778
0
            }
779
0
        }
780
781
        /* Free error pages */
782
0
        mk_list_foreach_safe(head, tmp, &vh->error_pages) {
783
0
            ep = mk_list_entry(head, struct mk_vhost_error_page, _head);
784
0
            if (ep) {
785
0
                mk_list_del(&ep->_head);
786
0
                if (ep->file) {
787
0
                    mk_mem_free(ep->file);
788
0
                }
789
0
                if (ep->real_path) {
790
0
                    mk_mem_free(ep->real_path);
791
0
                }
792
0
                mk_mem_free(ep);
793
0
            }
794
0
        }
795
0
        mk_ptr_free(&vh->documentroot);
796
797
        /* Free source configuration */
798
0
        if (vh->config) {
799
0
            mk_rconf_free(vh->config);
800
0
        }
801
0
        mk_list_del(&vh->_head);
802
0
        if (vh->file) {
803
0
            mk_mem_free(vh->file);
804
0
        }
805
806
0
        mk_mem_free(vh);
807
0
    }
808
0
    return 0;
809
0
}
810
811
void mk_vhost_free_all(struct mk_server *server)
812
0
{
813
0
    struct mk_vhost *host;
814
0
    struct mk_list *head;
815
0
    struct mk_list *tmp;
816
817
0
    mk_list_foreach_safe(head, tmp, &server->hosts) {
818
0
        host = mk_list_entry(head, struct mk_vhost, _head);
819
0
        mk_vhost_destroy(host);
820
0
    }
821
0
}