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>