Add status code 413: Request Entity Too Large
[MonkeyD.git] / src / config.c
blob8feb49261d1bcf231a2ca6a17aee3b01196c09d6
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2010, Eduardo Silva P. <edsiper@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <dirent.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <ctype.h>
34 #include "monkey.h"
35 #include "config.h"
36 #include "str.h"
37 #include "utils.h"
38 #include "mimetype.h"
39 #include "info.h"
40 #include "memory.h"
41 #include "plugin.h"
43 /* Raise a configuration error */
44 void mk_config_error(const char *path, int line, const char *msg)
46 printf("\nReading %s", path);
47 printf("\nError in line %i: %s\n\n", line, msg);
48 fflush(stdout);
49 exit(1);
52 /* Returns a configuration section by [section name] */
53 struct mk_config_section *mk_config_section_get(struct mk_config *conf,
54 const char *section_name)
56 struct mk_config_section *section;
58 section = conf->section;
59 while (section) {
60 if (strcasecmp(section->name, section_name) == 0) {
61 return section;
63 section = section->next;
66 return NULL;
69 /* Register a new section into the configuration struct */
70 void mk_config_section_add(struct mk_config *conf, char *section_name)
72 struct mk_config_section *new, *aux;
74 /* Alloc section node */
75 new = mk_mem_malloc(sizeof(struct mk_config_section));
76 new->name = mk_string_dup(section_name);
77 new->entry = NULL;
78 new->next = NULL;
80 if (!conf->section) {
81 conf->section = new;
82 return;
85 /* go to last section available */
86 aux = conf->section;
87 while (aux->next) {
88 aux = aux->next;
91 aux->next = new;
92 return;
95 /* Register a key/value entry in the last section available of the struct */
96 void mk_config_entry_add(struct mk_config *conf,
97 const char *key, const char *val)
99 struct mk_config_section *section;
100 struct mk_config_entry *aux_entry, *new_entry;
102 if (!conf->section) {
103 puts("Error: there are not sections available!");
104 exit(1);
107 /* Go to last section */
108 section = conf->section;
109 while (section->next) {
110 section = section->next;
113 /* Alloc new entry */
114 new_entry = mk_mem_malloc(sizeof(struct mk_config_entry));
115 new_entry->key = mk_string_dup(key);
116 new_entry->val = mk_string_dup(val);
117 new_entry->next = NULL;
119 /* Add first entry */
120 if (!section->entry) {
121 section->entry = new_entry;
122 return;
125 /* Go to last entry */
126 aux_entry = section->entry;
127 while (aux_entry->next) {
128 aux_entry = aux_entry->next;
131 aux_entry->next = new_entry;
134 struct mk_config *mk_config_create(const char *path)
136 int len;
137 int line = 0;
138 int indent_len = -1;
139 char buf[255];
140 char *section = 0;
141 char *indent = 0;
142 char *key, *val, *last;
143 struct mk_config *conf = 0;
144 FILE *f;
146 /* Open configuration file */
147 if ((f = fopen(path, "r")) == NULL) {
148 fprintf(stderr, "\nConfig Error: I can't open %s file\n\n", path);
149 exit(1);
152 /* Alloc configuration node */
153 conf = mk_mem_malloc(sizeof(struct mk_config));
154 conf->created = time(NULL);
155 conf->file = mk_string_dup(path);
156 conf->section = NULL;
158 /* looking for configuration directives */
159 while (fgets(buf, 255, f)) {
160 len = strlen(buf);
161 if (buf[len - 1] == '\n') {
162 buf[--len] = 0;
163 if (len && buf[len - 1] == '\r') {
164 buf[--len] = 0;
168 /* Line number */
169 line++;
171 if (!buf[0]) {
172 continue;
175 /* Skip commented lines */
176 if (buf[0] == '#') {
177 if (section) {
178 mk_mem_free(section);
179 section = NULL;
181 continue;
184 /* Section definition */
185 if (buf[0] == '[') {
186 int end = -1;
187 end = mk_string_char_search(buf, ']', len);
188 if (end > 0) {
189 section = mk_string_copy_substr(buf, 1, end);
190 mk_config_section_add(conf, section);
191 continue;
193 else {
194 mk_config_error(path, line, "Bad header definition");
197 else {
198 /* No separator defined */
199 if (!indent) {
200 int i = 0;
202 do { i++; } while (i < len && isblank(buf[i]));
204 indent = mk_string_copy_substr(buf, 0, i);
205 indent_len = strlen(indent);
207 /* Blank indented line */
208 if (i == len) {
209 continue;
213 /* Validate indentation level */
214 if (strncmp(buf, indent, indent_len) != 0 || !section ||
215 isblank(buf[indent_len]) != 0) {
216 mk_config_error(path, line, "Invalid indentation level");
219 if (buf[indent_len] == '#' || indent_len == len) {
220 continue;
223 /* get line key and value */
224 key = strtok_r(buf + indent_len, "\"\t ", &last);
225 val = strtok_r(NULL, "\"\t", &last);
227 if (!key || !val) {
228 mk_config_error(path, line, "Each key must have a value");
229 continue;
232 /* Trim strings */
233 mk_string_trim(&key);
234 mk_string_trim(&val);
236 /* Register entry */
237 mk_config_entry_add(conf, key, val);
242 struct mk_config_section *s;
243 struct mk_config_entry *e;
245 s = conf->section;
246 while(s) {
247 printf("\n[%s]", s->name);
248 e = s->entry;
249 while(e) {
250 printf("\n %s = %s", e->key, e->val);
251 e = e->next;
253 s = s->next;
255 fflush(stdout);
258 fclose(f);
259 return conf;
262 void mk_config_free(struct mk_config *conf)
264 struct mk_config_section *prev=0, *section;
266 /* Free sections */
267 section = conf->section;
268 while (section) {
269 while (section->next) {
270 prev = section;
271 section = section->next;
274 /* Free section entries */
275 mk_config_free_entries(section);
277 /* Free section node */
278 mk_mem_free(section->name);
279 mk_mem_free(section);
281 if (section == conf->section) {
282 return;
284 prev->next = NULL;
285 section = conf->section;
289 void mk_config_free_entries(struct mk_config_section *section)
291 struct mk_config_entry *prev = 0, *target;
293 target = section->entry;
294 while (target) {
295 while (target->next) {
296 prev = target;
297 target = target->next;
300 /* Free memory assigned */
301 mk_mem_free(target->key);
302 mk_mem_free(target->val);
304 if (target == section->entry) {
305 section->entry = NULL;
306 return;
309 prev->next = NULL;
310 target = section->entry;
314 void *mk_config_section_getval(struct mk_config_section *section, char *key, int mode)
316 int on, off;
317 struct mk_config_entry *entry;
319 entry = section->entry;
320 while (entry) {
321 if (strcasecmp(entry->key, key) == 0) {
322 switch (mode) {
323 case MK_CONFIG_VAL_STR:
324 return (void *) entry->val;
325 case MK_CONFIG_VAL_NUM:
326 return (void *) atoi(entry->val);
327 case MK_CONFIG_VAL_BOOL:
328 on = strcasecmp(entry->val, VALUE_ON);
329 off = strcasecmp(entry->val, VALUE_OFF);
331 if (on != 0 && off != 0) {
332 return (void *) -1;
334 else if (on >= 0) {
335 return (void *) VAR_ON;
337 else {
338 return (void *) VAR_OFF;
340 case MK_CONFIG_VAL_LIST:
341 return mk_string_split_line(entry->val);
344 else {
345 entry = entry->next;
348 return NULL;
351 /* Read configuration files */
352 void mk_config_read_files(char *path_conf, char *file_conf)
354 unsigned long len;
355 char *path = 0;
356 struct stat checkdir;
357 struct mk_config *cnf;
358 struct mk_config_section *section;
359 struct mk_string_line *line, *line_val;
361 config->serverconf = mk_string_dup(path_conf);
362 config->workers = MK_WORKERS_DEFAULT;
364 if (stat(config->serverconf, &checkdir) == -1) {
365 fprintf(stderr, "\nERROR: Invalid path to configuration files");
366 fprintf(stderr, "\nCannot find/open '%s'\n", config->serverconf);
367 exit(1);
370 mk_string_build(&path, &len, "%s/%s", path_conf, file_conf);
372 cnf = mk_config_create(path);
373 section = mk_config_section_get(cnf, "SERVER");
375 if (!section) {
376 fprintf(stderr, "\nERROR: No 'SERVER' section defined");
377 exit(1);
380 /* Map source configuration */
381 config->config = cnf;
383 /* Listen */
384 config->listen_addr = mk_config_section_getval(section, "Listen",
385 MK_CONFIG_VAL_STR);
386 if (!config->listen_addr) {
387 config->listen_addr = MK_DEFAULT_LISTEN_ADDR;
390 /* Connection port */
391 config->serverport = (int) mk_config_section_getval(section,
392 "Port",
393 MK_CONFIG_VAL_NUM);
394 if (!config->serverport >= 1 && !config->serverport <= 65535) {
395 mk_config_print_error_msg("Port", path);
398 /* Number of thread workers */
399 config->workers = (int) mk_config_section_getval(section,
400 "Workers",
401 MK_CONFIG_VAL_NUM);
402 if (config->workers < 1) {
403 mk_config_print_error_msg("Workers", path);
406 /* Timeout */
407 config->timeout = (int) mk_config_section_getval(section,
408 "Timeout", MK_CONFIG_VAL_NUM);
409 if (config->timeout < 1) {
410 mk_config_print_error_msg("Timeout", path);
413 /* KeepAlive */
414 config->keep_alive = (int) mk_config_section_getval(section,
415 "KeepAlive",
416 MK_CONFIG_VAL_BOOL);
417 if (config->keep_alive == VAR_ERR) {
418 mk_config_print_error_msg("KeepAlive", path);
421 /* MaxKeepAliveRequest */
422 config->max_keep_alive_request = (int)
423 mk_config_section_getval(section,
424 "MaxKeepAliveRequest",
425 MK_CONFIG_VAL_NUM);
427 if (config->max_keep_alive_request == 0) {
428 mk_config_print_error_msg("MaxKeepAliveRequest", path);
431 /* KeepAliveTimeout */
432 config->keep_alive_timeout = (int) mk_config_section_getval(section,
433 "KeepAliveTimeout",
434 MK_CONFIG_VAL_NUM);
435 if (config->keep_alive_timeout == 0) {
436 mk_config_print_error_msg("KeepAliveTimeout", path);
439 /* Pid File */
440 config->pid_file_path = mk_config_section_getval(section,
441 "PidFile", MK_CONFIG_VAL_STR);
443 /* Home user's directory /~ */
444 config->user_dir = mk_config_section_getval(section,
445 "UserDir", MK_CONFIG_VAL_STR);
447 /* Index files */
448 line_val = line = mk_config_section_getval(section,
449 "Indexfile", MK_CONFIG_VAL_LIST);
450 while (line_val != NULL) {
451 mk_config_add_index(line_val->val);
452 line_val = line_val->next;
455 /* HideVersion Variable */
456 config->hideversion = (int) mk_config_section_getval(section,
457 "HideVersion",
458 MK_CONFIG_VAL_BOOL);
459 if (config->hideversion == VAR_ERR) {
460 mk_config_print_error_msg("HideVersion", path);
463 /* User Variable */
464 config->user = mk_config_section_getval(section, "User", MK_CONFIG_VAL_STR);
466 /* Resume */
467 config->resume = (int) mk_config_section_getval(section,
468 "Resume", MK_CONFIG_VAL_BOOL);
469 if (config->resume == VAR_ERR) {
470 mk_config_print_error_msg("Resume", path);
473 /* Symbolic Links */
474 config->symlink = (int) mk_config_section_getval(section,
475 "SymLink", MK_CONFIG_VAL_BOOL);
476 if (config->symlink == VAR_ERR) {
477 mk_config_print_error_msg("SymLink", path);
480 mk_mem_free(path);
481 mk_config_read_hosts(path_conf);
484 void mk_config_read_hosts(char *path)
486 DIR *dir;
487 unsigned long len;
488 char *buf = 0;
489 char *file;
490 struct host *p_host, *new_host; /* debug */
491 struct dirent *ent;
493 mk_string_build(&buf, &len, "%s/sites/default", path);
494 config->hosts = mk_config_get_host(buf);
495 config->nhosts++;
496 mk_mem_free(buf);
498 if (!config->hosts) {
499 printf("\nError parsing main configuration file 'default'\n");
500 exit(1);
503 mk_string_build(&buf, &len, "%s/sites/", path);
504 if (!(dir = opendir(buf)))
505 exit(1);
508 p_host = config->hosts;
510 /* Reading content */
511 while ((ent = readdir(dir)) != NULL) {
512 if (strcmp((char *) ent->d_name, ".") == 0)
513 continue;
514 if (strcmp((char *) ent->d_name, "..") == 0)
515 continue;
516 if (strcasecmp((char *) ent->d_name, "default") == 0)
517 continue;
519 mk_string_build(&file, &len, "%s/sites/%s", path, ent->d_name);
521 new_host = (struct host *) mk_config_get_host(file);
522 mk_mem_free(file);
523 if (!new_host) {
524 continue;
526 else {
527 p_host->next = new_host;
528 p_host = new_host;
529 config->nhosts++;
532 closedir(dir);
535 struct host *mk_config_get_host(char *path)
537 unsigned long len = 0;
538 struct stat checkdir;
539 struct host *host;
540 struct mk_config *cnf;
541 struct mk_config_section *section;
543 /* Read configuration file */
544 cnf = mk_config_create(path);
546 /* Read tag 'HOST' */
547 section = mk_config_section_get(cnf, "HOST");
549 /* Alloc configuration node */
550 host = mk_mem_malloc_z(sizeof(struct host));
551 host->config = cnf;
552 host->file = mk_string_dup(path);
553 host->servername = mk_config_section_getval(section, "Servername",
554 MK_CONFIG_VAL_STR);
556 /* document root handled by a mk_pointer */
557 host->documentroot.data = mk_config_section_getval(section,
558 "DocumentRoot",
559 MK_CONFIG_VAL_STR);
560 host->documentroot.len = strlen(host->documentroot.data);
562 /* validate document root configured */
563 if (stat(host->documentroot.data, &checkdir) == -1) {
564 fprintf(stderr, "ERROR: Invalid path to DocumentRoot in %s\n\n", path);
565 exit(1);
567 else if (!(checkdir.st_mode & S_IFDIR)) {
568 fprintf(stderr,
569 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
570 path);
571 exit(1);
574 if (!host->servername) {
575 mk_config_free(cnf);
576 return NULL;
579 /* Server Signature */
580 if (config->hideversion == VAR_OFF) {
581 mk_string_build(&host->host_signature, &len,
582 "Monkey/%s", VERSION);
584 else {
585 mk_string_build(&host->host_signature, &len, "Monkey");
587 mk_string_build(&host->header_host_signature.data,
588 &host->header_host_signature.len,
589 "Server: %s", host->host_signature);
592 /* Access log */
593 host->access_log_path = mk_config_section_getval(section,
594 "AccessLog",
595 MK_CONFIG_VAL_STR);
596 /* Error log */
597 host->error_log_path = mk_config_section_getval(section,
598 "ErrorLog",
599 MK_CONFIG_VAL_STR);
600 host->next = NULL;
601 return host;
604 /* Imprime error de configuracion y cierra */
605 void mk_config_print_error_msg(char *variable, char *path)
607 fprintf(stderr, "\nError: %s variable in %s has an invalid value.\n",
608 variable, path);
609 fflush(stderr);
610 exit(1);
613 /* Agrega distintos index.xxx */
614 void mk_config_add_index(char *indexname)
616 struct indexfile *new_index = 0, *aux_index;
618 new_index = (struct indexfile *) malloc(sizeof(struct indexfile));
619 strncpy(new_index->indexname, indexname, MAX_INDEX_NAME - 1);
620 new_index->indexname[MAX_INDEX_NAME - 1] = '\0';
621 new_index->next = NULL;
623 if (first_index == NULL) {
624 first_index = new_index;
626 else {
627 aux_index = first_index;
628 while (aux_index->next != NULL)
629 aux_index = aux_index->next;
630 aux_index->next = new_index;
634 void mk_config_set_init_values(void)
636 /* Init values */
637 config->timeout = 15;
638 config->hideversion = VAR_OFF;
639 config->keep_alive = VAR_ON;
640 config->keep_alive_timeout = 15;
641 config->max_keep_alive_request = 50;
642 config->resume = VAR_ON;
643 config->standard_port = 80;
644 config->listen_addr = MK_DEFAULT_LISTEN_ADDR;
645 config->serverport = 2001;
646 config->symlink = VAR_OFF;
647 config->nhosts = 0;
648 config->user = NULL;
649 config->open_flags = O_RDONLY | O_NONBLOCK;
651 /* Plugins */
652 config->plugins = NULL;
655 /* read main configuration from monkey.conf */
656 void mk_config_start_configure(void)
658 unsigned long len;
660 mk_config_set_init_values();
661 mk_config_read_files(config->file_config, M_DEFAULT_CONFIG_FILE);
663 /* if not index names defined, set default */
664 if (first_index == NULL) {
665 mk_config_add_index("index.html");
668 /* Load mimes */
669 mk_mimetype_read_config();
671 /* Basic server information */
672 if (config->hideversion == VAR_OFF) {
673 mk_string_build(&config->server_software.data,
674 &len, "Monkey/%s (%s)", VERSION, OS);
675 config->server_software.len = len;
677 else {
678 mk_string_build(&config->server_software.data, &len, "Monkey Server");
679 config->server_software.len = len;
683 struct host *mk_config_host_find(mk_pointer host)
685 struct host *aux_host;
687 aux_host = config->hosts;
689 while (aux_host) {
690 if (strncasecmp(aux_host->servername, host.data, host.len) == 0) {
691 return aux_host;
693 aux_host = aux_host->next;
696 return NULL;
699 void mk_config_sanity_check()
701 /* Check O_NOATIME for current user, flag will just be used
702 * if running user is allowed to.
704 int fd, flags = config->open_flags;
706 flags |= O_NOATIME;
707 fd = open(config->file_config, flags);
709 if (fd > -1) {
710 config->open_flags = flags;
711 close(fd);