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