File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / configfile.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    1: #include "first.h"
    2: 
    3: #include "server.h"
    4: #include "log.h"
    5: #include "stream.h"
    6: #include "plugin.h"
    7: 
    8: #include "configparser.h"
    9: #include "configfile.h"
   10: #include "proc_open.h"
   11: #include "request.h"
   12: #include "version.h"
   13: 
   14: #include <sys/stat.h>
   15: 
   16: #include <stdlib.h>
   17: #include <fcntl.h>
   18: #include <unistd.h>
   19: #include <errno.h>
   20: #include <string.h>
   21: #include <stdio.h>
   22: #include <ctype.h>
   23: #include <limits.h>
   24: #include <assert.h>
   25: #include <glob.h>
   26: 
   27: 
   28: static int config_insert(server *srv) {
   29: 	size_t i;
   30: 	int ret = 0;
   31: 	buffer *stat_cache_string;
   32: 
   33: 	config_values_t cv[] = {
   34: 		{ "server.bind",                       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 0 */
   35: 		{ "server.errorlog",                   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 1 */
   36: 		{ "server.errorfile-prefix",           NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 2 */
   37: 		{ "server.chroot",                     NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 3 */
   38: 		{ "server.username",                   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 4 */
   39: 		{ "server.groupname",                  NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 5 */
   40: 		{ "server.port",                       NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER     }, /* 6 */
   41: 		{ "server.tag",                        NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 7 */
   42: 		{ "server.use-ipv6",                   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
   43: 		{ "server.modules",                    NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_SERVER     }, /* 9 */
   44: 
   45: 		{ "server.event-handler",              NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 10 */
   46: 		{ "server.pid-file",                   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 11 */
   47: 		{ "server.max-request-size",           NULL, T_CONFIG_INT,     T_CONFIG_SCOPE_SERVER     }, /* 12 */
   48: 		{ "server.max-worker",                 NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER     }, /* 13 */
   49: 		{ "server.document-root",              NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 14 */
   50: 		{ "server.force-lowercase-filenames",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
   51: 		{ "debug.log-condition-handling",      NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
   52: 		{ "server.max-keep-alive-requests",    NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 17 */
   53: 		{ "server.name",                       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 18 */
   54: 		{ "server.max-keep-alive-idle",        NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 19 */
   55: 
   56: 		{ "server.max-read-idle",              NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 20 */
   57: 		{ "server.max-write-idle",             NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 21 */
   58: 		{ "server.error-handler",              NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 22 */
   59: 		{ "server.max-fds",                    NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER     }, /* 23 */
   60: #ifdef HAVE_LSTAT
   61: 		{ "server.follow-symlink",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
   62: #else
   63: 		{ "server.follow-symlink",
   64: 			"Your system lacks lstat(). We can not differ symlinks from files."
   65: 			"Please remove server.follow-symlinks from your config.",
   66: 			T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET },
   67: #endif
   68: 		{ "server.kbytes-per-second",          NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 25 */
   69: 		{ "connection.kbytes-per-second",      NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 26 */
   70: 		{ "mimetype.use-xattr",                NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
   71: 		{ "mimetype.assign",                   NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_CONNECTION }, /* 28 */
   72: 		{ "ssl.pemfile",                       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 29 */
   73: 
   74: 		{ "ssl.engine",                        NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 30 */
   75: 		{ "debug.log-file-not-found",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 31 */
   76: 		{ "debug.log-request-handling",        NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 32 */
   77: 		{ "debug.log-response-header",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 33 */
   78: 		{ "debug.log-request-header",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 34 */
   79: 		{ "debug.log-ssl-noise",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 35 */
   80: 		{ "server.protocol-http11",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 36 */
   81: 		{ "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 37 */
   82: 		{ "debug.log-state-handling",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 38 */
   83: 		{ "ssl.ca-file",                       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 39 */
   84: 
   85: 		{ "server.errorlog-use-syslog",        NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 40 */
   86: 		{ "server.range-requests",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
   87: 		{ "server.stat-cache-engine",          NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 42 */
   88: 		{ "server.max-connections",            NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER     }, /* 43 */
   89: 		{ "server.network-backend",            NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 44 */
   90: 		{ "server.upload-dirs",                NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_SERVER     }, /* 45 */
   91: 		{ "server.core-files",                 NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 46 */
   92: 		{ "ssl.cipher-list",                   NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 47 */
   93: 		{ "ssl.use-sslv2",                     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 48 */
   94: 		{ "etag.use-inode",                    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 49 */
   95: 
   96: 		{ "etag.use-mtime",                    NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 50 */
   97: 		{ "etag.use-size",                     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 51 */
   98: 		{ "server.reject-expect-100-with-417", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 52 */
   99: 		{ "debug.log-timeouts",                NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 53 */
  100: 		{ "server.defer-accept",               NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 54 */
  101: 		{ "server.breakagelog",                NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 55 */
  102: 		{ "ssl.verifyclient.activate",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 56 */
  103: 		{ "ssl.verifyclient.enforce",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 57 */
  104: 		{ "ssl.verifyclient.depth",            NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 58 */
  105: 		{ "ssl.verifyclient.username",         NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 59 */
  106: 
  107: 		{ "ssl.verifyclient.exportcert",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 60 */
  108: 		{ "server.set-v6only",                 NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 61 */
  109: 		{ "ssl.use-sslv3",                     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 62 */
  110: 		{ "ssl.dh-file",                       NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 63 */
  111: 		{ "ssl.ec-curve",                      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 64 */
  112: 		{ "ssl.disable-client-renegotiation",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 65 */
  113: 		{ "ssl.honor-cipher-order",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 66 */
  114: 		{ "ssl.empty-fragments",               NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 67 */
  115: 		{ "server.upload-temp-file-size",      NULL, T_CONFIG_INT,     T_CONFIG_SCOPE_SERVER     }, /* 68 */
  116: 		{ "mimetype.xattr-name",               NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_SERVER     }, /* 69 */
  117: 		{ "server.listen-backlog",             NULL, T_CONFIG_INT,     T_CONFIG_SCOPE_CONNECTION }, /* 70 */
  118: 		{ "server.error-handler-404",          NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 71 */
  119: 		{ "server.http-parseopt-header-strict",NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 72 */
  120: 		{ "server.http-parseopt-host-strict",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 73 */
  121: 		{ "server.http-parseopt-host-normalize",NULL,T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER     }, /* 74 */
  122: 		{ "server.bsd-accept-filter",          NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION }, /* 75 */
  123: 		{ "server.stream-request-body",        NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 76 */
  124: 		{ "server.stream-response-body",       NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_CONNECTION }, /* 77 */
  125: 
  126: 		{ NULL,                                NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET      }
  127: 	};
  128: 
  129: 	/* all T_CONFIG_SCOPE_SERVER options */
  130: 	cv[0].destination = srv->srvconf.bindhost;
  131: 	cv[1].destination = srv->srvconf.errorlog_file;
  132: 	cv[3].destination = srv->srvconf.changeroot;
  133: 	cv[4].destination = srv->srvconf.username;
  134: 	cv[5].destination = srv->srvconf.groupname;
  135: 	cv[6].destination = &(srv->srvconf.port);
  136: 	cv[9].destination = srv->srvconf.modules;
  137: 
  138: 	cv[10].destination = srv->srvconf.event_handler;
  139: 	cv[11].destination = srv->srvconf.pid_file;
  140: 	cv[13].destination = &(srv->srvconf.max_worker);
  141: 
  142: 	cv[23].destination = &(srv->srvconf.max_fds);
  143: 
  144: 	cv[37].destination = &(srv->srvconf.log_request_header_on_error);
  145: 	cv[38].destination = &(srv->srvconf.log_state_handling);
  146: 
  147: 	cv[40].destination = &(srv->srvconf.errorlog_use_syslog);
  148: 	stat_cache_string = buffer_init();
  149: 	cv[42].destination = stat_cache_string;
  150: 	cv[43].destination = &(srv->srvconf.max_conns);
  151: 	cv[44].destination = srv->srvconf.network_backend;
  152: 	cv[45].destination = srv->srvconf.upload_tempdirs;
  153: 	cv[46].destination = &(srv->srvconf.enable_cores);
  154: 
  155: 	cv[52].destination = &(srv->srvconf.reject_expect_100_with_417);
  156: 	cv[55].destination = srv->srvconf.breakagelog_file;
  157: 
  158: 	cv[68].destination = &(srv->srvconf.upload_temp_file_size);
  159: 	cv[69].destination = srv->srvconf.xattr_name;
  160: 	cv[72].destination = &(srv->srvconf.http_header_strict);
  161: 	cv[73].destination = &(srv->srvconf.http_host_strict);
  162: 	cv[74].destination = &(srv->srvconf.http_host_normalize);
  163: 
  164: 	srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
  165: 
  166: 	force_assert(srv->config_storage);
  167: 
  168: 	for (i = 0; i < srv->config_context->used; i++) {
  169: 		data_config const* config = (data_config const*)srv->config_context->data[i];
  170: 		specific_config *s;
  171: 
  172: 		s = calloc(1, sizeof(specific_config));
  173: 		force_assert(s);
  174: 		s->document_root = buffer_init();
  175: 		s->mimetypes     = array_init();
  176: 		s->server_name   = buffer_init();
  177: 		s->ssl_pemfile   = buffer_init();
  178: 		s->ssl_ca_file   = buffer_init();
  179: 		s->error_handler = buffer_init();
  180: 		s->error_handler_404 = buffer_init();
  181: 		s->server_tag    = buffer_init_string(PACKAGE_DESC);
  182: 		s->ssl_cipher_list = buffer_init();
  183: 		s->ssl_dh_file   = buffer_init();
  184: 		s->ssl_ec_curve  = buffer_init();
  185: 		s->errorfile_prefix = buffer_init();
  186: 	      #if defined(__FreeBSD__) || defined(__NetBSD__) \
  187: 	       || defined(__OpenBSD__) || defined(__DragonflyBSD__)
  188: 		s->bsd_accept_filter = (i == 0)
  189: 		  ? buffer_init()
  190: 		  : buffer_init_buffer(srv->config_storage[0]->bsd_accept_filter);
  191: 	      #endif
  192: 		s->max_keep_alive_requests = 16;
  193: 		s->max_keep_alive_idle = 5;
  194: 		s->max_read_idle = 60;
  195: 		s->max_write_idle = 360;
  196: 		s->max_request_size = 0;
  197: 		s->use_xattr     = 0;
  198: 		s->ssl_enabled   = 0;
  199: 		s->ssl_honor_cipher_order = 1;
  200: 		s->ssl_empty_fragments = 0;
  201: 		s->ssl_use_sslv2 = 0;
  202: 		s->ssl_use_sslv3 = 0;
  203: 		s->use_ipv6      = (i == 0) ? 0 : srv->config_storage[0]->use_ipv6;
  204: 		s->set_v6only    = (i == 0) ? 1 : srv->config_storage[0]->set_v6only;
  205: 		s->defer_accept  = (i == 0) ? 0 : srv->config_storage[0]->defer_accept;
  206: #ifdef HAVE_LSTAT
  207: 		s->follow_symlink = 1;
  208: #endif
  209: 		s->kbytes_per_second = 0;
  210: 		s->allow_http11  = 1;
  211: 		s->etag_use_inode = 1;
  212: 		s->etag_use_mtime = 1;
  213: 		s->etag_use_size  = 1;
  214: 		s->range_requests = 1;
  215: 		s->force_lowercase_filenames = (i == 0) ? 2 : 0; /* we wan't to detect later if user changed this for global section */
  216: 		s->global_kbytes_per_second = 0;
  217: 		s->global_bytes_per_second_cnt = 0;
  218: 		s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
  219: 		s->ssl_verifyclient = 0;
  220: 		s->ssl_verifyclient_enforce = 1;
  221: 		s->ssl_verifyclient_username = buffer_init();
  222: 		s->ssl_verifyclient_depth = 9;
  223: 		s->ssl_verifyclient_export_cert = 0;
  224: 		s->ssl_disable_client_renegotiation = 1;
  225: 		s->listen_backlog = (0 == i ? 1024 : srv->config_storage[0]->listen_backlog);
  226: 		s->stream_request_body = 0;
  227: 		s->stream_response_body = 0;
  228: 
  229: 		/* all T_CONFIG_SCOPE_CONNECTION options */
  230: 		cv[2].destination = s->errorfile_prefix;
  231: 		cv[7].destination = s->server_tag;
  232: 		cv[8].destination = &(s->use_ipv6);
  233: 
  234: 		cv[12].destination = &(s->max_request_size);
  235: 		cv[14].destination = s->document_root;
  236: 		cv[15].destination = &(s->force_lowercase_filenames);
  237: 		cv[16].destination = &(s->log_condition_handling);
  238: 		cv[17].destination = &(s->max_keep_alive_requests);
  239: 		cv[18].destination = s->server_name;
  240: 		cv[19].destination = &(s->max_keep_alive_idle);
  241: 
  242: 		cv[20].destination = &(s->max_read_idle);
  243: 		cv[21].destination = &(s->max_write_idle);
  244: 		cv[22].destination = s->error_handler;
  245: #ifdef HAVE_LSTAT
  246: 		cv[24].destination = &(s->follow_symlink);
  247: #endif
  248: 		cv[25].destination = &(s->global_kbytes_per_second);
  249: 		cv[26].destination = &(s->kbytes_per_second);
  250: 		cv[27].destination = &(s->use_xattr);
  251: 		cv[28].destination = s->mimetypes;
  252: 		cv[29].destination = s->ssl_pemfile;
  253: 
  254: 		cv[30].destination = &(s->ssl_enabled);
  255: 		cv[31].destination = &(s->log_file_not_found);
  256: 		cv[32].destination = &(s->log_request_handling);
  257: 		cv[33].destination = &(s->log_response_header);
  258: 		cv[34].destination = &(s->log_request_header);
  259: 		cv[35].destination = &(s->log_ssl_noise);
  260: 		cv[36].destination = &(s->allow_http11);
  261: 		cv[39].destination = s->ssl_ca_file;
  262: 
  263: 		cv[41].destination = &(s->range_requests);
  264: 		cv[47].destination = s->ssl_cipher_list;
  265: 		cv[48].destination = &(s->ssl_use_sslv2);
  266: 		cv[49].destination = &(s->etag_use_inode);
  267: 
  268: 		cv[50].destination = &(s->etag_use_mtime);
  269: 		cv[51].destination = &(s->etag_use_size);
  270: 		cv[53].destination = &(s->log_timeouts);
  271: 		cv[54].destination = &(s->defer_accept);
  272: 		cv[56].destination = &(s->ssl_verifyclient);
  273: 		cv[57].destination = &(s->ssl_verifyclient_enforce);
  274: 		cv[58].destination = &(s->ssl_verifyclient_depth);
  275: 		cv[59].destination = s->ssl_verifyclient_username;
  276: 
  277: 		cv[60].destination = &(s->ssl_verifyclient_export_cert);
  278: 		cv[61].destination = &(s->set_v6only);
  279: 		cv[62].destination = &(s->ssl_use_sslv3);
  280: 		cv[63].destination = s->ssl_dh_file;
  281: 		cv[64].destination = s->ssl_ec_curve;
  282: 		cv[65].destination = &(s->ssl_disable_client_renegotiation);
  283: 		cv[66].destination = &(s->ssl_honor_cipher_order);
  284: 		cv[67].destination = &(s->ssl_empty_fragments);
  285: 		cv[70].destination = &(s->listen_backlog);
  286: 		cv[71].destination = s->error_handler_404;
  287: 	      #if defined(__FreeBSD__) || defined(__NetBSD__) \
  288: 	       || defined(__OpenBSD__) || defined(__DragonflyBSD__)
  289: 		cv[75].destination = s->bsd_accept_filter;
  290: 	      #endif
  291: 		cv[76].destination = &(s->stream_request_body);
  292: 		cv[77].destination = &(s->stream_response_body);
  293: 
  294: 		srv->config_storage[i] = s;
  295: 
  296: 		if (0 != (ret = config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION))) {
  297: 			break;
  298: 		}
  299: 
  300: 		if (s->stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN) {
  301: 			s->stream_request_body |= FDEVENT_STREAM_REQUEST;
  302: 		}
  303: 		if (s->stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) {
  304: 			s->stream_response_body |= FDEVENT_STREAM_RESPONSE;
  305: 		}
  306: 	}
  307: 
  308: 	{
  309: 		specific_config *s = srv->config_storage[0];
  310: 		s->http_parseopts= /*(global, but stored in con->conf.http_parseopts)*/
  311: 		   (srv->srvconf.http_header_strict  ?(HTTP_PARSEOPT_HEADER_STRICT) :0)
  312: 		  |(srv->srvconf.http_host_strict    ?(HTTP_PARSEOPT_HOST_STRICT
  313: 		                                      |HTTP_PARSEOPT_HOST_NORMALIZE):0)
  314: 		  |(srv->srvconf.http_host_normalize ?(HTTP_PARSEOPT_HOST_NORMALIZE):0);
  315: 	}
  316: 
  317: 	if (buffer_string_is_empty(stat_cache_string)) {
  318: 		srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
  319: 	} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
  320: 		srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
  321: #ifdef HAVE_FAM_H
  322: 	} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
  323: 		srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
  324: #endif
  325: 	} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
  326: 		srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
  327: 	} else {
  328: 		log_error_write(srv, __FILE__, __LINE__, "sb",
  329: 				"server.stat-cache-engine can be one of \"disable\", \"simple\","
  330: #ifdef HAVE_FAM_H
  331: 				" \"fam\","
  332: #endif
  333: 				" but not:", stat_cache_string);
  334: 		ret = HANDLER_ERROR;
  335: 	}
  336: 
  337: 	buffer_free(stat_cache_string);
  338: 
  339: 	{
  340: 		data_string *ds;
  341: 		int prepend_mod_indexfile = 1;
  342: 		int append_mod_dirlisting = 1;
  343: 		int append_mod_staticfile = 1;
  344: 
  345: 		/* prepend default modules */
  346: 		for (i = 0; i < srv->srvconf.modules->used; i++) {
  347: 			ds = (data_string *)srv->srvconf.modules->data[i];
  348: 
  349: 			if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_indexfile"))) {
  350: 				prepend_mod_indexfile = 0;
  351: 			}
  352: 
  353: 			if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_staticfile"))) {
  354: 				append_mod_staticfile = 0;
  355: 			}
  356: 
  357: 			if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_dirlisting"))) {
  358: 				append_mod_dirlisting = 0;
  359: 			}
  360: 
  361: 			if (0 == prepend_mod_indexfile &&
  362: 			    0 == append_mod_dirlisting &&
  363: 			    0 == append_mod_staticfile) {
  364: 				break;
  365: 			}
  366: 		}
  367: 
  368: 		if (prepend_mod_indexfile) {
  369: 			/* mod_indexfile has to be loaded before mod_fastcgi and friends */
  370: 			array *modules = array_init();
  371: 
  372: 			ds = data_string_init();
  373: 			buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
  374: 			array_insert_unique(modules, (data_unset *)ds);
  375: 
  376: 			for (i = 0; i < srv->srvconf.modules->used; i++) {
  377: 				data_unset *du = srv->srvconf.modules->data[i];
  378: 				array_insert_unique(modules, du->copy(du));
  379: 			}
  380: 
  381: 			array_free(srv->srvconf.modules);
  382: 			srv->srvconf.modules = modules;
  383: 		}
  384: 
  385: 		/* append default modules */
  386: 		if (append_mod_dirlisting) {
  387: 			ds = data_string_init();
  388: 			buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
  389: 			array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
  390: 		}
  391: 
  392: 		if (append_mod_staticfile) {
  393: 			ds = data_string_init();
  394: 			buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
  395: 			array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
  396: 		}
  397: 	}
  398: 
  399: 	return ret;
  400: 
  401: }
  402: 
  403: 
  404: #define PATCH(x) con->conf.x = s->x
  405: int config_setup_connection(server *srv, connection *con) {
  406: 	specific_config *s = srv->config_storage[0];
  407: 
  408: 	PATCH(http_parseopts);
  409: 
  410: 	PATCH(allow_http11);
  411: 	PATCH(mimetypes);
  412: 	PATCH(document_root);
  413: 	PATCH(high_precision_timestamps);
  414: 	PATCH(max_keep_alive_requests);
  415: 	PATCH(max_keep_alive_idle);
  416: 	PATCH(max_read_idle);
  417: 	PATCH(max_write_idle);
  418: 	PATCH(max_request_size);
  419: 	PATCH(use_xattr);
  420: 	PATCH(error_handler);
  421: 	PATCH(error_handler_404);
  422: 	PATCH(errorfile_prefix);
  423: #ifdef HAVE_LSTAT
  424: 	PATCH(follow_symlink);
  425: #endif
  426: 	PATCH(server_tag);
  427: 	PATCH(kbytes_per_second);
  428: 	PATCH(global_kbytes_per_second);
  429: 	PATCH(global_bytes_per_second_cnt);
  430: 
  431: 	con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
  432: 	buffer_copy_buffer(con->server_name, s->server_name);
  433: 
  434: 	PATCH(log_request_header);
  435: 	PATCH(log_response_header);
  436: 	PATCH(log_request_handling);
  437: 	PATCH(log_condition_handling);
  438: 	PATCH(log_file_not_found);
  439: 	PATCH(log_ssl_noise);
  440: 	PATCH(log_timeouts);
  441: 
  442: 	PATCH(range_requests);
  443: 	PATCH(force_lowercase_filenames);
  444: 	/*PATCH(listen_backlog);*//*(not necessary; used only at startup)*/
  445: 	PATCH(stream_request_body);
  446: 	PATCH(stream_response_body);
  447: 
  448: 	PATCH(ssl_enabled);
  449: 
  450: 	PATCH(ssl_pemfile);
  451: #ifdef USE_OPENSSL
  452: 	PATCH(ssl_pemfile_x509);
  453: 	PATCH(ssl_pemfile_pkey);
  454: #endif
  455: 	PATCH(ssl_ca_file);
  456: #ifdef USE_OPENSSL
  457: 	PATCH(ssl_ca_file_cert_names);
  458: #endif
  459: 	PATCH(ssl_cipher_list);
  460: 	PATCH(ssl_dh_file);
  461: 	PATCH(ssl_ec_curve);
  462: 	PATCH(ssl_honor_cipher_order);
  463: 	PATCH(ssl_empty_fragments);
  464: 	PATCH(ssl_use_sslv2);
  465: 	PATCH(ssl_use_sslv3);
  466: 	PATCH(etag_use_inode);
  467: 	PATCH(etag_use_mtime);
  468: 	PATCH(etag_use_size);
  469: 
  470: 	PATCH(ssl_verifyclient);
  471: 	PATCH(ssl_verifyclient_enforce);
  472: 	PATCH(ssl_verifyclient_depth);
  473: 	PATCH(ssl_verifyclient_username);
  474: 	PATCH(ssl_verifyclient_export_cert);
  475: 	PATCH(ssl_disable_client_renegotiation);
  476: 
  477: 	return 0;
  478: }
  479: 
  480: int config_patch_connection(server *srv, connection *con) {
  481: 	size_t i, j;
  482: 
  483: 	/* skip the first, the global context */
  484: 	for (i = 1; i < srv->config_context->used; i++) {
  485: 		data_config *dc = (data_config *)srv->config_context->data[i];
  486: 		specific_config *s = srv->config_storage[i];
  487: 
  488: 		/* condition didn't match */
  489: 		if (!config_check_cond(srv, con, dc)) continue;
  490: 
  491: 		/* merge config */
  492: 		for (j = 0; j < dc->value->used; j++) {
  493: 			data_unset *du = dc->value->data[j];
  494: 
  495: 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
  496: 				PATCH(document_root);
  497: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
  498: 				PATCH(range_requests);
  499: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler"))) {
  500: 				PATCH(error_handler);
  501: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
  502: 				PATCH(error_handler_404);
  503: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
  504: 				PATCH(errorfile_prefix);
  505: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {
  506: 				PATCH(mimetypes);
  507: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-requests"))) {
  508: 				PATCH(max_keep_alive_requests);
  509: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-idle"))) {
  510: 				PATCH(max_keep_alive_idle);
  511: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-write-idle"))) {
  512: 				PATCH(max_write_idle);
  513: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-read-idle"))) {
  514: 				PATCH(max_read_idle);
  515: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-request-size"))) {
  516: 				PATCH(max_request_size);
  517: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
  518: 				PATCH(use_xattr);
  519: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-inode"))) {
  520: 				PATCH(etag_use_inode);
  521: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-mtime"))) {
  522: 				PATCH(etag_use_mtime);
  523: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-size"))) {
  524: 				PATCH(etag_use_size);
  525: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
  526: 				PATCH(ssl_pemfile);
  527: #ifdef USE_OPENSSL
  528: 				PATCH(ssl_pemfile_x509);
  529: 				PATCH(ssl_pemfile_pkey);
  530: #endif
  531: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
  532: 				PATCH(ssl_ca_file);
  533: #ifdef USE_OPENSSL
  534: 				PATCH(ssl_ca_file_cert_names);
  535: #endif
  536: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) {
  537: 				PATCH(ssl_honor_cipher_order);
  538: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.empty-fragments"))) {
  539: 				PATCH(ssl_empty_fragments);
  540: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) {
  541: 				PATCH(ssl_use_sslv2);
  542: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) {
  543: 				PATCH(ssl_use_sslv3);
  544: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
  545: 				PATCH(ssl_cipher_list);
  546: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
  547: 				PATCH(ssl_enabled);
  548: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) {
  549: 				PATCH(ssl_dh_file);
  550: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) {
  551: 				PATCH(ssl_ec_curve);
  552: #ifdef HAVE_LSTAT
  553: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
  554: 				PATCH(follow_symlink);
  555: #endif
  556: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
  557: 				buffer_copy_buffer(con->server_name, s->server_name);
  558: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
  559: 				PATCH(server_tag);
  560: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.stream-request-body"))) {
  561: 				PATCH(stream_request_body);
  562: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.stream-response-body"))) {
  563: 				PATCH(stream_response_body);
  564: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
  565: 				PATCH(kbytes_per_second);
  566: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-handling"))) {
  567: 				PATCH(log_request_handling);
  568: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-request-header"))) {
  569: 				PATCH(log_request_header);
  570: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-response-header"))) {
  571: 				PATCH(log_response_header);
  572: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
  573: 				PATCH(log_condition_handling);
  574: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
  575: 				PATCH(log_file_not_found);
  576: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
  577: 				PATCH(log_ssl_noise);
  578: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
  579: 				PATCH(log_timeouts);
  580: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
  581: 				PATCH(allow_http11);
  582: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
  583: 				PATCH(force_lowercase_filenames);
  584: 		      #if 0 /*(not necessary; used only at startup)*/
  585: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.listen-backlog"))) {
  586: 				PATCH(listen_backlog);
  587: 		      #endif
  588: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
  589: 				PATCH(global_kbytes_per_second);
  590: 				PATCH(global_bytes_per_second_cnt);
  591: 				con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
  592: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
  593: 				PATCH(ssl_verifyclient);
  594: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
  595: 				PATCH(ssl_verifyclient_enforce);
  596: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
  597: 				PATCH(ssl_verifyclient_depth);
  598: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
  599: 				PATCH(ssl_verifyclient_username);
  600: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
  601: 				PATCH(ssl_verifyclient_export_cert);
  602: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) {
  603: 				PATCH(ssl_disable_client_renegotiation);
  604: 			}
  605: 		}
  606: 	}
  607: 
  608: 		con->etag_flags = (con->conf.etag_use_mtime ? ETAG_USE_MTIME : 0) |
  609: 				  (con->conf.etag_use_inode ? ETAG_USE_INODE : 0) |
  610: 				  (con->conf.etag_use_size  ? ETAG_USE_SIZE  : 0);
  611: 
  612: 	return 0;
  613: }
  614: #undef PATCH
  615: 
  616: typedef struct {
  617: 	int foo;
  618: 	int bar;
  619: 
  620: 	const buffer *source;
  621: 	const char *input;
  622: 	size_t offset;
  623: 	size_t size;
  624: 
  625: 	int line_pos;
  626: 	int line;
  627: 
  628: 	int in_key;
  629: 	int in_brace;
  630: 	int in_cond;
  631: } tokenizer_t;
  632: 
  633: #if 0
  634: static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
  635: 	if (buffer_string_is_empty(basedir) ||
  636: 			(fn[0] == '/' || fn[0] == '\\') ||
  637: 			(fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
  638: 		t->file = buffer_init_string(fn);
  639: 	} else {
  640: 		t->file = buffer_init_buffer(basedir);
  641: 		buffer_append_string(t->file, fn);
  642: 	}
  643: 
  644: 	if (0 != stream_open(&(t->s), t->file)) {
  645: 		log_error_write(srv, __FILE__, __LINE__, "sbss",
  646: 				"opening configfile ", t->file, "failed:", strerror(errno));
  647: 		buffer_free(t->file);
  648: 		return -1;
  649: 	}
  650: 
  651: 	t->input = t->s.start;
  652: 	t->offset = 0;
  653: 	t->size = t->s.size;
  654: 	t->line = 1;
  655: 	t->line_pos = 1;
  656: 
  657: 	t->in_key = 1;
  658: 	t->in_brace = 0;
  659: 	t->in_cond = 0;
  660: 	return 0;
  661: }
  662: 
  663: static int tokenizer_close(server *srv, tokenizer_t *t) {
  664: 	UNUSED(srv);
  665: 
  666: 	buffer_free(t->file);
  667: 	return stream_close(&(t->s));
  668: }
  669: #endif
  670: static int config_skip_newline(tokenizer_t *t) {
  671: 	int skipped = 1;
  672: 	force_assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
  673: 	if (t->input[t->offset] == '\r' && t->input[t->offset + 1] == '\n') {
  674: 		skipped ++;
  675: 		t->offset ++;
  676: 	}
  677: 	t->offset ++;
  678: 	return skipped;
  679: }
  680: 
  681: static int config_skip_comment(tokenizer_t *t) {
  682: 	int i;
  683: 	force_assert(t->input[t->offset] == '#');
  684: 	for (i = 1; t->input[t->offset + i] &&
  685: 	     (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
  686: 	     i++);
  687: 	t->offset += i;
  688: 	return i;
  689: }
  690: 
  691: static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
  692: 	int tid = 0;
  693: 	size_t i;
  694: 
  695: 	for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
  696: 		char c = t->input[t->offset];
  697: 		const char *start = NULL;
  698: 
  699: 		switch (c) {
  700: 		case '=':
  701: 			if (t->in_brace) {
  702: 				if (t->input[t->offset + 1] == '>') {
  703: 					t->offset += 2;
  704: 
  705: 					buffer_copy_string_len(token, CONST_STR_LEN("=>"));
  706: 
  707: 					tid = TK_ARRAY_ASSIGN;
  708: 				} else {
  709: 					log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  710: 							"source:", t->source,
  711: 							"line:", t->line, "pos:", t->line_pos,
  712: 							"use => for assignments in arrays");
  713: 					return -1;
  714: 				}
  715: 			} else if (t->in_cond) {
  716: 				if (t->input[t->offset + 1] == '=') {
  717: 					t->offset += 2;
  718: 
  719: 					buffer_copy_string_len(token, CONST_STR_LEN("=="));
  720: 
  721: 					tid = TK_EQ;
  722: 				} else if (t->input[t->offset + 1] == '~') {
  723: 					t->offset += 2;
  724: 
  725: 					buffer_copy_string_len(token, CONST_STR_LEN("=~"));
  726: 
  727: 					tid = TK_MATCH;
  728: 				} else {
  729: 					log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  730: 							"source:", t->source,
  731: 							"line:", t->line, "pos:", t->line_pos,
  732: 							"only =~ and == are allowed in the condition");
  733: 					return -1;
  734: 				}
  735: 				t->in_key = 1;
  736: 				t->in_cond = 0;
  737: 			} else if (t->in_key) {
  738: 				tid = TK_ASSIGN;
  739: 
  740: 				buffer_copy_string_len(token, t->input + t->offset, 1);
  741: 
  742: 				t->offset++;
  743: 				t->line_pos++;
  744: 			} else {
  745: 				log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  746: 						"source:", t->source,
  747: 						"line:", t->line, "pos:", t->line_pos,
  748: 						"unexpected equal-sign: =");
  749: 				return -1;
  750: 			}
  751: 
  752: 			break;
  753: 		case '!':
  754: 			if (t->in_cond) {
  755: 				if (t->input[t->offset + 1] == '=') {
  756: 					t->offset += 2;
  757: 
  758: 					buffer_copy_string_len(token, CONST_STR_LEN("!="));
  759: 
  760: 					tid = TK_NE;
  761: 				} else if (t->input[t->offset + 1] == '~') {
  762: 					t->offset += 2;
  763: 
  764: 					buffer_copy_string_len(token, CONST_STR_LEN("!~"));
  765: 
  766: 					tid = TK_NOMATCH;
  767: 				} else {
  768: 					log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  769: 							"source:", t->source,
  770: 							"line:", t->line, "pos:", t->line_pos,
  771: 							"only !~ and != are allowed in the condition");
  772: 					return -1;
  773: 				}
  774: 				t->in_key = 1;
  775: 				t->in_cond = 0;
  776: 			} else {
  777: 				log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  778: 						"source:", t->source,
  779: 						"line:", t->line, "pos:", t->line_pos,
  780: 						"unexpected exclamation-marks: !");
  781: 				return -1;
  782: 			}
  783: 
  784: 			break;
  785: 		case '\t':
  786: 		case ' ':
  787: 			t->offset++;
  788: 			t->line_pos++;
  789: 			break;
  790: 		case '\n':
  791: 		case '\r':
  792: 			if (t->in_brace == 0) {
  793: 				int done = 0;
  794: 				while (!done && t->offset < t->size) {
  795: 					switch (t->input[t->offset]) {
  796: 					case '\r':
  797: 					case '\n':
  798: 						config_skip_newline(t);
  799: 						t->line_pos = 1;
  800: 						t->line++;
  801: 						break;
  802: 
  803: 					case '#':
  804: 						t->line_pos += config_skip_comment(t);
  805: 						break;
  806: 
  807: 					case '\t':
  808: 					case ' ':
  809: 						t->offset++;
  810: 						t->line_pos++;
  811: 						break;
  812: 
  813: 					default:
  814: 						done = 1;
  815: 					}
  816: 				}
  817: 				t->in_key = 1;
  818: 				tid = TK_EOL;
  819: 				buffer_copy_string_len(token, CONST_STR_LEN("(EOL)"));
  820: 			} else {
  821: 				config_skip_newline(t);
  822: 				t->line_pos = 1;
  823: 				t->line++;
  824: 			}
  825: 			break;
  826: 		case ',':
  827: 			if (t->in_brace > 0) {
  828: 				tid = TK_COMMA;
  829: 
  830: 				buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)"));
  831: 			}
  832: 
  833: 			t->offset++;
  834: 			t->line_pos++;
  835: 			break;
  836: 		case '"':
  837: 			/* search for the terminating " */
  838: 			start = t->input + t->offset + 1;
  839: 			buffer_copy_string_len(token, CONST_STR_LEN(""));
  840: 
  841: 			for (i = 1; t->input[t->offset + i]; i++) {
  842: 				if (t->input[t->offset + i] == '\\' &&
  843: 				    t->input[t->offset + i + 1] == '"') {
  844: 
  845: 					buffer_append_string_len(token, start, t->input + t->offset + i - start);
  846: 
  847: 					start = t->input + t->offset + i + 1;
  848: 
  849: 					/* skip the " */
  850: 					i++;
  851: 					continue;
  852: 				}
  853: 
  854: 
  855: 				if (t->input[t->offset + i] == '"') {
  856: 					tid = TK_STRING;
  857: 
  858: 					buffer_append_string_len(token, start, t->input + t->offset + i - start);
  859: 
  860: 					break;
  861: 				}
  862: 			}
  863: 
  864: 			if (t->input[t->offset + i] == '\0') {
  865: 				/* ERROR */
  866: 
  867: 				log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  868: 						"source:", t->source,
  869: 						"line:", t->line, "pos:", t->line_pos,
  870: 						"missing closing quote");
  871: 
  872: 				return -1;
  873: 			}
  874: 
  875: 			t->offset += i + 1;
  876: 			t->line_pos += i + 1;
  877: 
  878: 			break;
  879: 		case '(':
  880: 			t->offset++;
  881: 			t->in_brace++;
  882: 
  883: 			tid = TK_LPARAN;
  884: 
  885: 			buffer_copy_string_len(token, CONST_STR_LEN("("));
  886: 			break;
  887: 		case ')':
  888: 			t->offset++;
  889: 			t->in_brace--;
  890: 
  891: 			tid = TK_RPARAN;
  892: 
  893: 			buffer_copy_string_len(token, CONST_STR_LEN(")"));
  894: 			break;
  895: 		case '$':
  896: 			t->offset++;
  897: 
  898: 			tid = TK_DOLLAR;
  899: 			t->in_cond = 1;
  900: 			t->in_key = 0;
  901: 
  902: 			buffer_copy_string_len(token, CONST_STR_LEN("$"));
  903: 
  904: 			break;
  905: 
  906: 		case '+':
  907: 			if (t->input[t->offset + 1] == '=') {
  908: 				t->offset += 2;
  909: 				buffer_copy_string_len(token, CONST_STR_LEN("+="));
  910: 				tid = TK_APPEND;
  911: 			} else {
  912: 				t->offset++;
  913: 				tid = TK_PLUS;
  914: 				buffer_copy_string_len(token, CONST_STR_LEN("+"));
  915: 			}
  916: 			break;
  917: 
  918: 		case '{':
  919: 			t->offset++;
  920: 
  921: 			tid = TK_LCURLY;
  922: 
  923: 			buffer_copy_string_len(token, CONST_STR_LEN("{"));
  924: 
  925: 			break;
  926: 
  927: 		case '}':
  928: 			t->offset++;
  929: 
  930: 			tid = TK_RCURLY;
  931: 
  932: 			buffer_copy_string_len(token, CONST_STR_LEN("}"));
  933: 
  934: 			break;
  935: 
  936: 		case '[':
  937: 			t->offset++;
  938: 
  939: 			tid = TK_LBRACKET;
  940: 
  941: 			buffer_copy_string_len(token, CONST_STR_LEN("["));
  942: 
  943: 			break;
  944: 
  945: 		case ']':
  946: 			t->offset++;
  947: 
  948: 			tid = TK_RBRACKET;
  949: 
  950: 			buffer_copy_string_len(token, CONST_STR_LEN("]"));
  951: 
  952: 			break;
  953: 		case '#':
  954: 			t->line_pos += config_skip_comment(t);
  955: 
  956: 			break;
  957: 		default:
  958: 			if (t->in_cond) {
  959: 				for (i = 0; t->input[t->offset + i] &&
  960: 				     (isalpha((unsigned char)t->input[t->offset + i])
  961: 				      ); i++);
  962: 
  963: 				if (i && t->input[t->offset + i]) {
  964: 					tid = TK_SRVVARNAME;
  965: 					buffer_copy_string_len(token, t->input + t->offset, i);
  966: 
  967: 					t->offset += i;
  968: 					t->line_pos += i;
  969: 				} else {
  970: 					/* ERROR */
  971: 					log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
  972: 							"source:", t->source,
  973: 							"line:", t->line, "pos:", t->line_pos,
  974: 							"invalid character in condition");
  975: 					return -1;
  976: 				}
  977: 			} else if (isdigit((unsigned char)c)) {
  978: 				/* take all digits */
  979: 				for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]);  i++);
  980: 
  981: 				/* was there it least a digit ? */
  982: 				if (i) {
  983: 					tid = TK_INTEGER;
  984: 
  985: 					buffer_copy_string_len(token, t->input + t->offset, i);
  986: 
  987: 					t->offset += i;
  988: 					t->line_pos += i;
  989: 				}
  990: 			} else {
  991: 				/* the key might consist of [-.0-9a-z] */
  992: 				for (i = 0; t->input[t->offset + i] &&
  993: 				     (isalnum((unsigned char)t->input[t->offset + i]) ||
  994: 				      t->input[t->offset + i] == '.' ||
  995: 				      t->input[t->offset + i] == '_' || /* for env.* */
  996: 				      t->input[t->offset + i] == '-'
  997: 				      ); i++);
  998: 
  999: 				if (i && t->input[t->offset + i]) {
 1000: 					buffer_copy_string_len(token, t->input + t->offset, i);
 1001: 
 1002: 					if (strcmp(token->ptr, "include") == 0) {
 1003: 						tid = TK_INCLUDE;
 1004: 					} else if (strcmp(token->ptr, "include_shell") == 0) {
 1005: 						tid = TK_INCLUDE_SHELL;
 1006: 					} else if (strcmp(token->ptr, "global") == 0) {
 1007: 						tid = TK_GLOBAL;
 1008: 					} else if (strcmp(token->ptr, "else") == 0) {
 1009: 						tid = TK_ELSE;
 1010: 					} else {
 1011: 						tid = TK_LKEY;
 1012: 					}
 1013: 
 1014: 					t->offset += i;
 1015: 					t->line_pos += i;
 1016: 				} else {
 1017: 					/* ERROR */
 1018: 					log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
 1019: 							"source:", t->source,
 1020: 							"line:", t->line, "pos:", t->line_pos,
 1021: 							"invalid character in variable name");
 1022: 					return -1;
 1023: 				}
 1024: 			}
 1025: 			break;
 1026: 		}
 1027: 	}
 1028: 
 1029: 	if (tid) {
 1030: 		*token_id = tid;
 1031: #if 0
 1032: 		log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
 1033: 				"source:", t->source,
 1034: 				"line:", t->line, "pos:", t->line_pos,
 1035: 				token, token->used - 1, tid);
 1036: #endif
 1037: 
 1038: 		return 1;
 1039: 	} else if (t->offset < t->size) {
 1040: 		fprintf(stderr, "%s.%d: %d, %s\n",
 1041: 			__FILE__, __LINE__,
 1042: 			tid, token->ptr);
 1043: 	}
 1044: 	return 0;
 1045: }
 1046: 
 1047: static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
 1048: 	void *pParser;
 1049: 	int token_id;
 1050: 	buffer *token, *lasttoken;
 1051: 	int ret;
 1052: 
 1053: 	pParser = configparserAlloc( malloc );
 1054: 	force_assert(pParser);
 1055: 	lasttoken = buffer_init();
 1056: 	token = buffer_init();
 1057: 	while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
 1058: 		buffer_copy_buffer(lasttoken, token);
 1059: 		configparser(pParser, token_id, token, context);
 1060: 
 1061: 		token = buffer_init();
 1062: 	}
 1063: 	buffer_free(token);
 1064: 
 1065: 	if (ret != -1 && context->ok) {
 1066: 		/* add an EOL at EOF, better than say sorry */
 1067: 		configparser(pParser, TK_EOL, buffer_init_string("(EOL)"), context);
 1068: 		if (context->ok) {
 1069: 			configparser(pParser, 0, NULL, context);
 1070: 		}
 1071: 	}
 1072: 	configparserFree(pParser, free);
 1073: 
 1074: 	if (ret == -1) {
 1075: 		log_error_write(srv, __FILE__, __LINE__, "sb",
 1076: 				"configfile parser failed at:", lasttoken);
 1077: 	} else if (context->ok == 0) {
 1078: 		log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
 1079: 				"source:", t->source,
 1080: 				"line:", t->line, "pos:", t->line_pos,
 1081: 				"parser failed somehow near here:", lasttoken);
 1082: 		ret = -1;
 1083: 	}
 1084: 	buffer_free(lasttoken);
 1085: 
 1086: 	return ret == -1 ? -1 : 0;
 1087: }
 1088: 
 1089: static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
 1090: 
 1091: 	t->source = source;
 1092: 	t->input = input;
 1093: 	t->size = size;
 1094: 	t->offset = 0;
 1095: 	t->line = 1;
 1096: 	t->line_pos = 1;
 1097: 
 1098: 	t->in_key = 1;
 1099: 	t->in_brace = 0;
 1100: 	t->in_cond = 0;
 1101: 	return 0;
 1102: }
 1103: 
 1104: static int config_parse_file_stream(server *srv, config_t *context, const buffer *filename) {
 1105: 	tokenizer_t t;
 1106: 	stream s;
 1107: 	int ret;
 1108: 
 1109: 	if (0 != stream_open(&s, filename)) {
 1110: 		log_error_write(srv, __FILE__, __LINE__, "sbss",
 1111: 				"opening configfile ", filename, "failed:", strerror(errno));
 1112: 		return -1;
 1113: 	} else {
 1114: 		tokenizer_init(&t, filename, s.start, s.size);
 1115: 		ret = config_parse(srv, context, &t);
 1116: 	}
 1117: 
 1118: 	stream_close(&s);
 1119: 	return ret;
 1120: }
 1121: 
 1122: int config_parse_file(server *srv, config_t *context, const char *fn) {
 1123: 	buffer *filename;
 1124: 	size_t i;
 1125: 	int ret = -1;
 1126:       #ifdef GLOB_BRACE
 1127: 	int flags = GLOB_BRACE;
 1128:       #else
 1129: 	int flags = 0;
 1130:       #endif
 1131: 	glob_t gl;
 1132: 
 1133: 	if ((fn[0] == '/' || fn[0] == '\\') ||
 1134: 	    (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\')) ||
 1135: 	    (fn[0] == '.' && fn[1] == '.' && (fn[2] == '/' || fn[2] == '\\'))) {
 1136: 		filename = buffer_init_string(fn);
 1137: 	} else {
 1138: 		filename = buffer_init_buffer(context->basedir);
 1139: 		buffer_append_string(filename, fn);
 1140: 	}
 1141: 
 1142: 	switch (glob(filename->ptr, flags, NULL, &gl)) {
 1143: 	case 0:
 1144: 		for (i = 0; i < gl.gl_pathc; ++i) {
 1145: 			buffer_copy_string(filename, gl.gl_pathv[i]);
 1146: 			ret = config_parse_file_stream(srv, context, filename);
 1147: 			if (0 != ret) break;
 1148: 		}
 1149: 		globfree(&gl);
 1150: 		break;
 1151: 	case GLOB_NOMATCH:
 1152: 		if (filename->ptr[strcspn(filename->ptr, "*?[]{}")] != '\0') { /*(contains glob metachars)*/
 1153: 			ret = 0; /* not an error if no files match glob pattern */
 1154: 		}
 1155: 		else {
 1156: 			log_error_write(srv, __FILE__, __LINE__, "sb", "include file not found: ", filename);
 1157: 		}
 1158: 		break;
 1159: 	case GLOB_ABORTED:
 1160: 	case GLOB_NOSPACE:
 1161: 		log_error_write(srv, __FILE__, __LINE__, "sbss", "glob()", filename, "failed:", strerror(errno));
 1162: 		break;
 1163: 	}
 1164: 
 1165: 	buffer_free(filename);
 1166: 	return ret;
 1167: }
 1168: 
 1169: static char* getCWD(void) {
 1170: 	char *s, *s1;
 1171: 	size_t len;
 1172: #ifdef PATH_MAX
 1173: 	len = PATH_MAX;
 1174: #else
 1175: 	len = 4096;
 1176: #endif
 1177: 
 1178: 	s = malloc(len);
 1179: 	if (!s) return NULL;
 1180: 	while (NULL == getcwd(s, len)) {
 1181: 		if (errno != ERANGE || SSIZE_MAX - len < len) {
 1182: 			free(s);
 1183: 			return NULL;
 1184: 		}
 1185: 		len *= 2;
 1186: 		s1 = realloc(s, len);
 1187: 		if (!s1) {
 1188: 			free(s);
 1189: 			return NULL;
 1190: 		}
 1191: 		s = s1;
 1192: 	}
 1193: 	return s;
 1194: }
 1195: 
 1196: int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
 1197: 	tokenizer_t t;
 1198: 	int ret;
 1199: 	buffer *source;
 1200: 	buffer *out;
 1201: 	char *oldpwd;
 1202: 
 1203: 	if (NULL == (oldpwd = getCWD())) {
 1204: 		log_error_write(srv, __FILE__, __LINE__, "s",
 1205: 			"cannot get cwd", strerror(errno));
 1206: 		return -1;
 1207: 	}
 1208: 
 1209: 	if (!buffer_string_is_empty(context->basedir)) {
 1210: 		if (0 != chdir(context->basedir->ptr)) {
 1211: 			log_error_write(srv, __FILE__, __LINE__, "sbs",
 1212: 				"cannot change directory to", context->basedir, strerror(errno));
 1213: 			free(oldpwd);
 1214: 			return -1;
 1215: 		}
 1216: 	}
 1217: 
 1218: 	source = buffer_init_string(cmd);
 1219: 	out = buffer_init();
 1220: 
 1221: 	if (0 != proc_open_buffer(cmd, NULL, out, NULL)) {
 1222: 		log_error_write(srv, __FILE__, __LINE__, "sbss",
 1223: 			"opening", source, "failed:", strerror(errno));
 1224: 		ret = -1;
 1225: 	} else {
 1226: 		tokenizer_init(&t, source, CONST_BUF_LEN(out));
 1227: 		ret = config_parse(srv, context, &t);
 1228: 	}
 1229: 
 1230: 	buffer_free(source);
 1231: 	buffer_free(out);
 1232: 	if (0 != chdir(oldpwd)) {
 1233: 		log_error_write(srv, __FILE__, __LINE__, "sss",
 1234: 			"cannot change directory to", oldpwd, strerror(errno));
 1235: 		free(oldpwd);
 1236: 		return -1;
 1237: 	}
 1238: 	free(oldpwd);
 1239: 	return ret;
 1240: }
 1241: 
 1242: static void context_init(server *srv, config_t *context) {
 1243: 	context->srv = srv;
 1244: 	context->ok = 1;
 1245: 	vector_config_weak_init(&context->configs_stack);
 1246: 	context->basedir = buffer_init();
 1247: }
 1248: 
 1249: static void context_free(config_t *context) {
 1250: 	vector_config_weak_clear(&context->configs_stack);
 1251: 	buffer_free(context->basedir);
 1252: }
 1253: 
 1254: int config_read(server *srv, const char *fn) {
 1255: 	config_t context;
 1256: 	data_config *dc;
 1257: 	data_integer *dpid;
 1258: 	data_string *dcwd;
 1259: 	int ret;
 1260: 	char *pos;
 1261: 	buffer *filename;
 1262: 
 1263: 	context_init(srv, &context);
 1264: 	context.all_configs = srv->config_context;
 1265: 
 1266: #ifdef __WIN32
 1267: 	pos = strrchr(fn, '\\');
 1268: #else
 1269: 	pos = strrchr(fn, '/');
 1270: #endif
 1271: 	if (pos) {
 1272: 		buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
 1273: 	}
 1274: 
 1275: 	dc = data_config_init();
 1276: 	buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
 1277: 
 1278: 	force_assert(context.all_configs->used == 0);
 1279: 	dc->context_ndx = context.all_configs->used;
 1280: 	array_insert_unique(context.all_configs, (data_unset *)dc);
 1281: 	context.current = dc;
 1282: 
 1283: 	/* default context */
 1284: 	dpid = data_integer_init();
 1285: 	dpid->value = getpid();
 1286: 	buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
 1287: 	array_insert_unique(dc->value, (data_unset *)dpid);
 1288: 
 1289: 	dcwd = data_string_init();
 1290: 	buffer_string_prepare_copy(dcwd->value, 1023);
 1291: 	if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
 1292: 		buffer_commit(dcwd->value, strlen(dcwd->value->ptr));
 1293: 		buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
 1294: 		array_insert_unique(dc->value, (data_unset *)dcwd);
 1295: 	} else {
 1296: 		dcwd->free((data_unset*) dcwd);
 1297: 	}
 1298: 
 1299: 	filename = buffer_init_string(fn);
 1300: 	ret = config_parse_file_stream(srv, &context, filename);
 1301: 	buffer_free(filename);
 1302: 
 1303: 	/* remains nothing if parser is ok */
 1304: 	force_assert(!(0 == ret && context.ok && 0 != context.configs_stack.used));
 1305: 	context_free(&context);
 1306: 
 1307: 	if (0 != ret) {
 1308: 		return ret;
 1309: 	}
 1310: 
 1311: 	if (0 != config_insert(srv)) {
 1312: 		return -1;
 1313: 	}
 1314: 
 1315: 	return 0;
 1316: }
 1317: 
 1318: int config_set_defaults(server *srv) {
 1319: 	size_t i;
 1320: 	specific_config *s = srv->config_storage[0];
 1321: 	struct stat st1, st2;
 1322: 
 1323: 	struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
 1324: 	{
 1325: 		/* - epoll is most reliable
 1326: 		 * - select works everywhere
 1327: 		 */
 1328: #ifdef USE_LINUX_EPOLL
 1329: 		{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
 1330: #endif
 1331: #ifdef USE_POLL
 1332: 		{ FDEVENT_HANDLER_POLL,           "poll" },
 1333: #endif
 1334: #ifdef USE_SELECT
 1335: 		{ FDEVENT_HANDLER_SELECT,         "select" },
 1336: #endif
 1337: #ifdef USE_LIBEV
 1338: 		{ FDEVENT_HANDLER_LIBEV,          "libev" },
 1339: #endif
 1340: #ifdef USE_SOLARIS_DEVPOLL
 1341: 		{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
 1342: #endif
 1343: #ifdef USE_SOLARIS_PORT
 1344: 		{ FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
 1345: #endif
 1346: #ifdef USE_FREEBSD_KQUEUE
 1347: 		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
 1348: 		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
 1349: #endif
 1350: 		{ FDEVENT_HANDLER_UNSET,          NULL }
 1351: 	};
 1352: 
 1353: 	if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
 1354: 		if (-1 == stat(srv->srvconf.changeroot->ptr, &st1)) {
 1355: 			log_error_write(srv, __FILE__, __LINE__, "sb",
 1356: 					"server.chroot doesn't exist:", srv->srvconf.changeroot);
 1357: 			return -1;
 1358: 		}
 1359: 		if (!S_ISDIR(st1.st_mode)) {
 1360: 			log_error_write(srv, __FILE__, __LINE__, "sb",
 1361: 					"server.chroot isn't a directory:", srv->srvconf.changeroot);
 1362: 			return -1;
 1363: 		}
 1364: 	}
 1365: 
 1366: 	if (!srv->srvconf.upload_tempdirs->used) {
 1367: 		data_string *ds = data_string_init();
 1368: 		const char *tmpdir = getenv("TMPDIR");
 1369: 		if (NULL == tmpdir) tmpdir = "/var/tmp";
 1370: 		buffer_copy_string(ds->value, tmpdir);
 1371: 		array_insert_unique(srv->srvconf.upload_tempdirs, (data_unset *)ds);
 1372: 	}
 1373: 
 1374: 	if (srv->srvconf.upload_tempdirs->used) {
 1375: 		buffer * const b = srv->tmp_buf;
 1376: 		size_t len;
 1377: 		if (!buffer_string_is_empty(srv->srvconf.changeroot)) {
 1378: 			buffer_copy_buffer(b, srv->srvconf.changeroot);
 1379: 			buffer_append_slash(b);
 1380: 		} else {
 1381: 			buffer_reset(b);
 1382: 		}
 1383: 		len = buffer_string_length(b);
 1384: 
 1385: 		for (i = 0; i < srv->srvconf.upload_tempdirs->used; ++i) {
 1386: 			const data_string * const ds = (data_string *)srv->srvconf.upload_tempdirs->data[i];
 1387: 			buffer_string_set_length(b, len); /*(truncate)*/
 1388: 			buffer_append_string_buffer(b, ds->value);
 1389: 			if (-1 == stat(b->ptr, &st1)) {
 1390: 				log_error_write(srv, __FILE__, __LINE__, "sb",
 1391: 					"server.upload-dirs doesn't exist:", b);
 1392: 			} else if (!S_ISDIR(st1.st_mode)) {
 1393: 				log_error_write(srv, __FILE__, __LINE__, "sb",
 1394: 					"server.upload-dirs isn't a directory:", b);
 1395: 			}
 1396: 		}
 1397: 	}
 1398: 
 1399: 	chunkqueue_set_tempdirs_default(
 1400: 		srv->srvconf.upload_tempdirs,
 1401: 		srv->srvconf.upload_temp_file_size);
 1402: 
 1403: 	if (buffer_string_is_empty(s->document_root)) {
 1404: 		log_error_write(srv, __FILE__, __LINE__, "s",
 1405: 				"a default document-root has to be set");
 1406: 
 1407: 		return -1;
 1408: 	}
 1409: 
 1410: 	buffer_copy_buffer(srv->tmp_buf, s->document_root);
 1411: 
 1412: 	buffer_to_lower(srv->tmp_buf);
 1413: 
 1414: 	if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */
 1415: 		s->force_lowercase_filenames = 0; /* default to 0 */
 1416: 
 1417: 		if (0 == stat(srv->tmp_buf->ptr, &st1)) {
 1418: 			int is_lower = 0;
 1419: 
 1420: 			is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
 1421: 
 1422: 			/* lower-case existed, check upper-case */
 1423: 			buffer_copy_buffer(srv->tmp_buf, s->document_root);
 1424: 
 1425: 			buffer_to_upper(srv->tmp_buf);
 1426: 
 1427: 			/* we have to handle the special case that upper and lower-casing results in the same filename
 1428: 			 * as in server.document-root = "/" or "/12345/" */
 1429: 
 1430: 			if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
 1431: 				/* lower-casing and upper-casing didn't result in
 1432: 				 * an other filename, no need to stat(),
 1433: 				 * just assume it is case-sensitive. */
 1434: 
 1435: 				s->force_lowercase_filenames = 0;
 1436: 			} else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
 1437: 
 1438: 				/* upper case exists too, doesn't the FS handle this ? */
 1439: 
 1440: 				/* upper and lower have the same inode -> case-insensitve FS */
 1441: 
 1442: 				if (st1.st_ino == st2.st_ino) {
 1443: 					/* upper and lower have the same inode -> case-insensitve FS */
 1444: 
 1445: 					s->force_lowercase_filenames = 1;
 1446: 				}
 1447: 			}
 1448: 		}
 1449: 	}
 1450: 
 1451: 	if (srv->srvconf.port == 0) {
 1452: 		srv->srvconf.port = s->ssl_enabled ? 443 : 80;
 1453: 	}
 1454: 
 1455: 	if (buffer_string_is_empty(srv->srvconf.event_handler)) {
 1456: 		/* choose a good default
 1457: 		 *
 1458: 		 * the event_handler list is sorted by 'goodness'
 1459: 		 * taking the first available should be the best solution
 1460: 		 */
 1461: 		srv->event_handler = event_handlers[0].et;
 1462: 
 1463: 		if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
 1464: 			log_error_write(srv, __FILE__, __LINE__, "s",
 1465: 					"sorry, there is no event handler for this system");
 1466: 
 1467: 			return -1;
 1468: 		}
 1469: 	} else {
 1470: 		/*
 1471: 		 * User override
 1472: 		 */
 1473: 
 1474: 		for (i = 0; event_handlers[i].name; i++) {
 1475: 			if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
 1476: 				srv->event_handler = event_handlers[i].et;
 1477: 				break;
 1478: 			}
 1479: 		}
 1480: 
 1481: 		if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
 1482: 			log_error_write(srv, __FILE__, __LINE__, "sb",
 1483: 					"the selected event-handler in unknown or not supported:",
 1484: 					srv->srvconf.event_handler );
 1485: 
 1486: 			return -1;
 1487: 		}
 1488: 	}
 1489: 
 1490: 	if (s->ssl_enabled) {
 1491: 		if (buffer_string_is_empty(s->ssl_pemfile)) {
 1492: 			/* PEM file is require */
 1493: 
 1494: 			log_error_write(srv, __FILE__, __LINE__, "s",
 1495: 					"ssl.pemfile has to be set");
 1496: 			return -1;
 1497: 		}
 1498: 
 1499: #ifndef USE_OPENSSL
 1500: 		log_error_write(srv, __FILE__, __LINE__, "s",
 1501: 				"ssl support is missing, recompile with --with-openssl");
 1502: 
 1503: 		return -1;
 1504: #endif
 1505: 	}
 1506: 
 1507: 	return 0;
 1508: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>