/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, §ion_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, §ion_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(¶m->_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 | } |