Annotation of embedaddon/lighttpd/src/configfile-glue.c, revision 1.1.1.2

1.1.1.2 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       3: #include "base.h"
                      4: #include "buffer.h"
                      5: #include "array.h"
                      6: #include "log.h"
                      7: #include "plugin.h"
                      8: 
                      9: #include "configfile.h"
                     10: 
                     11: #include <string.h>
                     12: #include <stdlib.h>
1.1.1.2 ! misho      13: #ifndef _WIN32
        !            14: #include <arpa/inet.h>
        !            15: #endif
1.1       misho      16: 
                     17: /**
                     18:  * like all glue code this file contains functions which
                     19:  * are the external interface of lighttpd. The functions
                     20:  * are used by the server itself and the plugins.
                     21:  *
                     22:  * The main-goal is to have a small library in the end
                     23:  * which is linked against both and which will define
                     24:  * the interface itself in the end.
                     25:  *
                     26:  */
                     27: 
                     28: 
                     29: /* handle global options */
                     30: 
                     31: /* parse config array */
1.1.1.2 ! misho      32: int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
1.1       misho      33:        size_t i;
                     34:        data_unset *du;
                     35: 
                     36:        for (i = 0; cv[i].key; i++) {
                     37: 
                     38:                if (NULL == (du = array_get_element(ca, cv[i].key))) {
                     39:                        /* no found */
                     40: 
                     41:                        continue;
                     42:                }
                     43: 
1.1.1.2 ! misho      44:                if ((T_CONFIG_SCOPE_SERVER == cv[i].scope)
        !            45:                    && (T_CONFIG_SCOPE_SERVER != scope)) {
        !            46:                        /* server scope options should only be set in server scope, not in conditionals */
        !            47:                        log_error_write(srv, __FILE__, __LINE__, "ss",
        !            48:                                "DEPRECATED: don't set server options in conditionals, variable:",
        !            49:                                cv[i].key);
        !            50:                }
        !            51: 
1.1       misho      52:                switch (cv[i].type) {
                     53:                case T_CONFIG_ARRAY:
                     54:                        if (du->type == TYPE_ARRAY) {
                     55:                                size_t j;
                     56:                                data_array *da = (data_array *)du;
                     57: 
                     58:                                for (j = 0; j < da->value->used; j++) {
1.1.1.2 ! misho      59:                                        data_unset *ds = da->value->data[j];
        !            60:                                        if (ds->type == TYPE_STRING) {
        !            61:                                                array_insert_unique(cv[i].destination, ds->copy(ds));
1.1       misho      62:                                        } else {
1.1.1.2 ! misho      63:                                                log_error_write(srv, __FILE__, __LINE__, "sssbsd",
        !            64:                                                                "the value of an array can only be a string, variable:",
        !            65:                                                                cv[i].key, "[", ds->key, "], type:", ds->type);
1.1       misho      66: 
                     67:                                                return -1;
                     68:                                        }
                     69:                                }
                     70:                        } else {
                     71:                                log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
                     72: 
                     73:                                return -1;
                     74:                        }
                     75:                        break;
                     76:                case T_CONFIG_STRING:
                     77:                        if (du->type == TYPE_STRING) {
                     78:                                data_string *ds = (data_string *)du;
                     79: 
1.1.1.2 ! misho      80:                                buffer_copy_buffer(cv[i].destination, ds->value);
1.1       misho      81:                        } else {
                     82:                                log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
                     83: 
                     84:                                return -1;
                     85:                        }
                     86:                        break;
                     87:                case T_CONFIG_SHORT:
                     88:                        switch(du->type) {
                     89:                        case TYPE_INTEGER: {
                     90:                                data_integer *di = (data_integer *)du;
                     91: 
                     92:                                *((unsigned short *)(cv[i].destination)) = di->value;
                     93:                                break;
                     94:                        }
                     95:                        case TYPE_STRING: {
                     96:                                data_string *ds = (data_string *)du;
                     97: 
                     98:                                /* If the value came from an environment variable, then it is a
                     99:                                 * data_string, although it may contain a number in ASCII
                    100:                                 * decimal format.  We try to interpret the string as a decimal
                    101:                                 * short before giving up, in order to support setting numeric
                    102:                                 * values with environment variables (eg, port number).
                    103:                                 */
                    104:                                if (ds->value->ptr && *ds->value->ptr) {
                    105:                                        char *e;
                    106:                                        long l = strtol(ds->value->ptr, &e, 10);
                    107:                                        if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
                    108:                                                *((unsigned short *)(cv[i].destination)) = l;
                    109:                                                break;
                    110:                                        }
                    111:                                }
                    112: 
                    113:                                log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
                    114: 
                    115:                                return -1;
                    116:                        }
                    117:                        default:
                    118:                                log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
                    119:                                return -1;
                    120:                        }
                    121:                        break;
                    122:                case T_CONFIG_INT:
                    123:                        switch(du->type) {
                    124:                        case TYPE_INTEGER: {
                    125:                                data_integer *di = (data_integer *)du;
                    126: 
                    127:                                *((unsigned int *)(cv[i].destination)) = di->value;
                    128:                                break;
                    129:                        }
                    130:                        case TYPE_STRING: {
                    131:                                data_string *ds = (data_string *)du;
                    132: 
                    133:                                if (ds->value->ptr && *ds->value->ptr) {
                    134:                                        char *e;
                    135:                                        long l = strtol(ds->value->ptr, &e, 10);
                    136:                                        if (e != ds->value->ptr && !*e && l >= 0) {
                    137:                                                *((unsigned int *)(cv[i].destination)) = l;
                    138:                                                break;
                    139:                                        }
                    140:                                }
                    141: 
                    142:                                log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
                    143: 
                    144:                                return -1;
                    145:                        }
                    146:                        default:
                    147:                                log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
                    148:                                return -1;
                    149:                        }
                    150:                        break;
                    151:                case T_CONFIG_BOOLEAN:
                    152:                        if (du->type == TYPE_STRING) {
                    153:                                data_string *ds = (data_string *)du;
                    154: 
                    155:                                if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
                    156:                                        *((unsigned short *)(cv[i].destination)) = 1;
                    157:                                } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
                    158:                                        *((unsigned short *)(cv[i].destination)) = 0;
                    159:                                } else {
                    160:                                        log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
                    161: 
                    162:                                        return -1;
                    163:                                }
                    164:                        } else {
                    165:                                log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
                    166: 
                    167:                                return -1;
                    168:                        }
                    169:                        break;
                    170:                case T_CONFIG_LOCAL:
                    171:                case T_CONFIG_UNSET:
                    172:                        break;
                    173:                case T_CONFIG_UNSUPPORTED:
                    174:                        log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
                    175: 
                    176:                        srv->config_unsupported = 1;
                    177: 
                    178:                        break;
                    179:                case T_CONFIG_DEPRECATED:
                    180:                        log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
                    181: 
                    182:                        srv->config_deprecated = 1;
                    183: 
                    184:                        break;
                    185:                }
                    186:        }
                    187: 
                    188:        return 0;
                    189: }
                    190: 
1.1.1.2 ! misho     191: int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
1.1       misho     192:        size_t i;
                    193:        data_unset *du;
                    194: 
                    195:        for (i = 0; cv[i].key; i++) {
                    196:                data_string *touched;
                    197: 
                    198:                if (NULL == (du = array_get_element(ca, cv[i].key))) {
                    199:                        /* no found */
                    200: 
                    201:                        continue;
                    202:                }
                    203: 
                    204:                /* touched */
                    205:                touched = data_string_init();
                    206: 
                    207:                buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
1.1.1.2 ! misho     208:                buffer_copy_buffer(touched->key, du->key);
1.1       misho     209: 
                    210:                array_insert_unique(srv->config_touched, (data_unset *)touched);
                    211:        }
                    212: 
1.1.1.2 ! misho     213:        return config_insert_values_internal(srv, ca, cv, scope);
1.1       misho     214: }
                    215: 
                    216: static unsigned short sock_addr_get_port(sock_addr *addr) {
                    217: #ifdef HAVE_IPV6
                    218:        return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
                    219: #else
                    220:        return ntohs(addr->ipv4.sin_port);
                    221: #endif
                    222: }
                    223: 
1.1.1.2 ! misho     224: static const char* cond_result_to_string(cond_result_t cond_result) {
        !           225:        switch (cond_result) {
        !           226:        case COND_RESULT_UNSET: return "unset";
        !           227:        case COND_RESULT_SKIP: return "skipped";
        !           228:        case COND_RESULT_FALSE: return "false";
        !           229:        case COND_RESULT_TRUE: return "true";
        !           230:        default: return "invalid cond_result_t";
        !           231:        }
        !           232: }
        !           233: 
        !           234: static int config_addrstr_eq_remote_ip_mask(server *srv, const char *addrstr, int nm_bits, sock_addr *rmt) {
        !           235:        /* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
        !           236:        sock_addr val;
        !           237: #ifdef HAVE_INET_PTON
        !           238:        if (1 == inet_pton(AF_INET, addrstr, &val.ipv4.sin_addr))
        !           239: #else
        !           240:        if (INADDR_NONE != (val.ipv4.sin_addr = inet_addr(addrstr)))
        !           241: #endif
        !           242:        {
        !           243:                /* build netmask */
        !           244:                uint32_t nm;
        !           245:                if (nm_bits > 32) {
        !           246:                        log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits);
        !           247:                        return -1;
        !           248:                }
        !           249:                nm = htonl(~((1u << (32 - (0 != nm_bits ? nm_bits : 32))) - 1));
        !           250: 
        !           251:                if (rmt->plain.sa_family == AF_INET) {
        !           252:                        return ((val.ipv4.sin_addr.s_addr & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
        !           253: #ifdef HAVE_IPV6
        !           254:                } else if (rmt->plain.sa_family == AF_INET6
        !           255:                           && IN6_IS_ADDR_V4MAPPED(&rmt->ipv6.sin6_addr)) {
        !           256:                      #ifdef s6_addr32
        !           257:                        in_addr_t x = rmt->ipv6.sin6_addr.s6_addr32[3];
        !           258:                      #else
        !           259:                        in_addr_t x;
        !           260:                        memcpy(&x, rmt->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
        !           261:                      #endif
        !           262:                        return ((val.ipv4.sin_addr.s_addr & nm) == (x & nm));
        !           263: #endif
        !           264:                } else {
        !           265:                        return 0;
        !           266:                }
        !           267: #if defined(HAVE_INET_PTON) && defined(HAVE_IPV6)
        !           268:        } else if (1 == inet_pton(AF_INET6, addrstr, &val.ipv6.sin6_addr)) {
        !           269:                if (nm_bits > 128) {
        !           270:                        log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits);
        !           271:                        return -1;
        !           272:                }
        !           273:                if (rmt->plain.sa_family == AF_INET6) {
        !           274:                        uint8_t *a = (uint8_t *)&val.ipv6.sin6_addr.s6_addr[0];
        !           275:                        uint8_t *b = (uint8_t *)&rmt->ipv6.sin6_addr.s6_addr[0];
        !           276:                        int match;
        !           277:                        do {
        !           278:                                match = (nm_bits >= 8)
        !           279:                                  ? *a++ == *b++
        !           280:                                  : (*a >> (8 - nm_bits)) == (*b >> (8 - nm_bits));
        !           281:                        } while (match && (nm_bits -= 8) > 0);
        !           282:                        return match;
        !           283:                } else if (rmt->plain.sa_family == AF_INET
        !           284:                           && IN6_IS_ADDR_V4MAPPED(&val.ipv6.sin6_addr)) {
        !           285:                        uint32_t nm =
        !           286:                          nm_bits < 128 ? htonl(~(~0u >> (nm_bits > 96 ? nm_bits - 96 : 0))) : ~0u;
        !           287:                      #ifdef s6_addr32
        !           288:                        in_addr_t x = val.ipv6.sin6_addr.s6_addr32[3];
        !           289:                      #else
        !           290:                        in_addr_t x;
        !           291:                        memcpy(&x, val.ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
        !           292:                      #endif
        !           293:                        return ((x & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
        !           294:                } else {
        !           295:                        return 0;
        !           296:                }
        !           297: #endif
        !           298:        } else {
        !           299:                log_error_write(srv, __FILE__, __LINE__, "ss", "ERROR: ip addr is invalid:", addrstr);
        !           300:                return -1;
        !           301:        }
        !           302: }
        !           303: 
        !           304: static int config_addrbuf_eq_remote_ip_mask(server *srv, buffer *string, char *nm_slash, sock_addr *rmt) {
        !           305:        char *err;
        !           306:        int nm_bits = strtol(nm_slash + 1, &err, 10);
        !           307:        size_t addrstrlen = (size_t)(nm_slash - string->ptr);
        !           308:        char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
        !           309: 
        !           310:        if (*err) {
        !           311:                log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", string, err);
        !           312:                return -1;
        !           313:        }
        !           314: 
        !           315:        if (nm_bits <= 0) {
        !           316:                if (*(nm_slash+1) == '\0') {
        !           317:                        log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", string);
        !           318:                } else {
        !           319:                        log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask <= 0:", string, err);
        !           320:                }
        !           321:                return -1;
        !           322:        }
        !           323: 
        !           324:        if (addrstrlen >= sizeof(addrstr)) {
        !           325:                log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: address string too long:", string);
        !           326:                return -1;
        !           327:        }
        !           328: 
        !           329:        memcpy(addrstr, string->ptr, addrstrlen);
        !           330:        addrstr[addrstrlen] = '\0';
        !           331: 
        !           332:        return config_addrstr_eq_remote_ip_mask(srv, addrstr, nm_bits, rmt);
        !           333: }
        !           334: 
1.1       misho     335: static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
                    336: 
                    337: static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
                    338:        buffer *l;
                    339:        server_socket *srv_sock = con->srv_socket;
1.1.1.2 ! misho     340:        cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
1.1       misho     341: 
                    342:        /* check parent first */
                    343:        if (dc->parent && dc->parent->context_ndx) {
                    344:                /**
                    345:                 * a nested conditional 
                    346:                 *
                    347:                 * if the parent is not decided yet or false, we can't be true either 
                    348:                 */
                    349:                if (con->conf.log_condition_handling) {
                    350:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "go parent", dc->parent->key);
                    351:                }
                    352: 
                    353:                switch (config_check_cond_cached(srv, con, dc->parent)) {
                    354:                case COND_RESULT_UNSET:
1.1.1.2 ! misho     355:                        /* decide later */
1.1       misho     356:                        return COND_RESULT_UNSET;
1.1.1.2 ! misho     357:                case COND_RESULT_SKIP:
        !           358:                case COND_RESULT_FALSE:
        !           359:                        /* failed precondition */
        !           360:                        return COND_RESULT_SKIP;
        !           361:                case COND_RESULT_TRUE:
        !           362:                        /* proceed */
1.1       misho     363:                        break;
                    364:                }
                    365:        }
                    366: 
                    367:        if (dc->prev) {
                    368:                /**
1.1.1.2 ! misho     369:                 * a else branch; can only be executed if the previous branch
        !           370:                 * was evaluated as "false" (not unset/skipped/true)
1.1       misho     371:                 */
                    372:                if (con->conf.log_condition_handling) {
                    373:                        log_error_write(srv, __FILE__, __LINE__,  "sb", "go prev", dc->prev->key);
                    374:                }
                    375: 
                    376:                /* make sure prev is checked first */
1.1.1.2 ! misho     377:                switch (config_check_cond_cached(srv, con, dc->prev)) {
        !           378:                case COND_RESULT_UNSET:
        !           379:                        /* decide later */
        !           380:                        return COND_RESULT_UNSET;
        !           381:                case COND_RESULT_SKIP:
        !           382:                case COND_RESULT_TRUE:
        !           383:                        /* failed precondition */
        !           384:                        return COND_RESULT_SKIP;
1.1       misho     385:                case COND_RESULT_FALSE:
1.1.1.2 ! misho     386:                        /* proceed */
1.1       misho     387:                        break;
                    388:                }
                    389:        }
                    390: 
                    391:        if (!con->conditional_is_valid[dc->comp]) {
                    392:                if (con->conf.log_condition_handling) {
                    393:                        log_error_write(srv, __FILE__, __LINE__,  "dss", 
                    394:                                dc->comp,
                    395:                                dc->key->ptr,
1.1.1.2 ! misho     396:                                "not available yet");
1.1       misho     397:                }
                    398: 
                    399:                return COND_RESULT_UNSET;
                    400:        }
                    401: 
1.1.1.2 ! misho     402:        /* if we had a real result before and weren't cleared just return it */
        !           403:        switch (cache->local_result) {
        !           404:        case COND_RESULT_TRUE:
        !           405:        case COND_RESULT_FALSE:
        !           406:                return cache->local_result;
        !           407:        default:
        !           408:                break;
        !           409:        }
        !           410: 
1.1       misho     411:        /* pass the rules */
                    412: 
                    413:        switch (dc->comp) {
                    414:        case COMP_HTTP_HOST: {
                    415:                char *ck_colon = NULL, *val_colon = NULL;
                    416: 
1.1.1.2 ! misho     417:                if (!buffer_string_is_empty(con->uri.authority)) {
1.1       misho     418: 
                    419:                        /*
                    420:                         * append server-port to the HTTP_POST if necessary
                    421:                         */
                    422: 
                    423:                        l = con->uri.authority;
                    424: 
                    425:                        switch(dc->cond) {
                    426:                        case CONFIG_COND_NE:
                    427:                        case CONFIG_COND_EQ:
                    428:                                ck_colon = strchr(dc->string->ptr, ':');
                    429:                                val_colon = strchr(l->ptr, ':');
                    430: 
                    431:                                if (NULL != ck_colon && NULL == val_colon) {
                    432:                                        /* condition "host:port" but client send "host" */
1.1.1.2 ! misho     433:                                        buffer_copy_buffer(srv->cond_check_buf, l);
1.1       misho     434:                                        buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
1.1.1.2 ! misho     435:                                        buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
1.1       misho     436:                                        l = srv->cond_check_buf;
                    437:                                } else if (NULL != val_colon && NULL == ck_colon) {
                    438:                                        /* condition "host" but client send "host:port" */
                    439:                                        buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
                    440:                                        l = srv->cond_check_buf;
                    441:                                }
                    442:                                break;
                    443:                        default:
                    444:                                break;
                    445:                        }
                    446: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
1.1.1.2 ! misho     447:                } else if (!buffer_string_is_empty(con->tlsext_server_name)) {
1.1       misho     448:                        l = con->tlsext_server_name;
                    449: #endif
                    450:                } else {
                    451:                        l = srv->empty_string;
                    452:                }
                    453:                break;
                    454:        }
                    455:        case COMP_HTTP_REMOTE_IP: {
                    456:                char *nm_slash;
                    457:                /* handle remoteip limitations
                    458:                 *
                    459:                 * "10.0.0.1" is provided for all comparisions
                    460:                 *
                    461:                 * only for == and != we support
                    462:                 *
                    463:                 * "10.0.0.1/24"
                    464:                 */
                    465: 
                    466:                if ((dc->cond == CONFIG_COND_EQ ||
                    467:                     dc->cond == CONFIG_COND_NE) &&
                    468:                    (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
1.1.1.2 ! misho     469:                        switch (config_addrbuf_eq_remote_ip_mask(srv, dc->string, nm_slash, &con->dst_addr)) {
        !           470:                        case  1: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
        !           471:                        case  0: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
        !           472:                        case -1: return COND_RESULT_FALSE; /*(error parsing configfile entry)*/
1.1       misho     473:                        }
                    474:                }
1.1.1.2 ! misho     475:                l = con->dst_addr_buf;
1.1       misho     476:                break;
                    477:        }
                    478:        case COMP_HTTP_SCHEME:
                    479:                l = con->uri.scheme;
                    480:                break;
                    481: 
                    482:        case COMP_HTTP_URL:
                    483:                l = con->uri.path;
                    484:                break;
                    485: 
                    486:        case COMP_HTTP_QUERY_STRING:
                    487:                l = con->uri.query;
                    488:                break;
                    489: 
                    490:        case COMP_SERVER_SOCKET:
                    491:                l = srv_sock->srv_token;
                    492:                break;
                    493: 
                    494:        case COMP_HTTP_REFERER: {
                    495:                data_string *ds;
                    496: 
                    497:                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
                    498:                        l = ds->value;
                    499:                } else {
                    500:                        l = srv->empty_string;
                    501:                }
                    502:                break;
                    503:        }
                    504:        case COMP_HTTP_COOKIE: {
                    505:                data_string *ds;
                    506:                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
                    507:                        l = ds->value;
                    508:                } else {
                    509:                        l = srv->empty_string;
                    510:                }
                    511:                break;
                    512:        }
                    513:        case COMP_HTTP_USER_AGENT: {
                    514:                data_string *ds;
                    515:                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
                    516:                        l = ds->value;
                    517:                } else {
                    518:                        l = srv->empty_string;
                    519:                }
                    520:                break;
                    521:        }
                    522:        case COMP_HTTP_REQUEST_METHOD: {
                    523:                const char *method = get_http_method_name(con->request.http_method);
                    524: 
                    525:                /* we only have the request method as const char but we need a buffer for comparing */
                    526: 
                    527:                buffer_copy_string(srv->tmp_buf, method);
                    528: 
                    529:                l = srv->tmp_buf;
                    530: 
                    531:                break;
                    532:        }
                    533:        case COMP_HTTP_LANGUAGE: {
                    534:                data_string *ds;
                    535:                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
                    536:                        l = ds->value;
                    537:                } else {
                    538:                        l = srv->empty_string;
                    539:                }
                    540:                break;
                    541:        }
                    542:        default:
                    543:                return COND_RESULT_FALSE;
                    544:        }
                    545: 
                    546:        if (NULL == l) {
                    547:                if (con->conf.log_condition_handling) {
                    548:                        log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
                    549:                                        "(", l, ") compare to NULL");
                    550:                }
                    551:                return COND_RESULT_FALSE;
                    552:        }
                    553: 
                    554:        if (con->conf.log_condition_handling) {
                    555:                log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
                    556:                                "(", l, ") compare to ", dc->string);
                    557:        }
                    558:        switch(dc->cond) {
                    559:        case CONFIG_COND_NE:
                    560:        case CONFIG_COND_EQ:
                    561:                if (buffer_is_equal(l, dc->string)) {
                    562:                        return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
                    563:                } else {
                    564:                        return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
                    565:                }
                    566:                break;
                    567: #ifdef HAVE_PCRE_H
                    568:        case CONFIG_COND_NOMATCH:
                    569:        case CONFIG_COND_MATCH: {
                    570:                int n;
                    571: 
                    572: #ifndef elementsof
                    573: #define elementsof(x) (sizeof(x) / sizeof(x[0]))
                    574: #endif
1.1.1.2 ! misho     575:                n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
1.1       misho     576:                                cache->matches, elementsof(cache->matches));
                    577: 
                    578:                cache->patterncount = n;
                    579:                if (n > 0) {
                    580:                        cache->comp_value = l;
                    581:                        return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
                    582:                } else {
                    583:                        /* cache is already cleared */
                    584:                        return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
                    585:                }
                    586:                break;
                    587:        }
                    588: #endif
                    589:        default:
                    590:                /* no way */
                    591:                break;
                    592:        }
                    593: 
                    594:        return COND_RESULT_FALSE;
                    595: }
                    596: 
                    597: static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
                    598:        cond_cache_t *caches = con->cond_cache;
                    599: 
                    600:        if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
1.1.1.2 ! misho     601:                caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc);
        !           602:                switch (caches[dc->context_ndx].result) {
        !           603:                case COND_RESULT_FALSE:
        !           604:                case COND_RESULT_TRUE:
        !           605:                        /* remember result of local condition for a partial reset */
        !           606:                        caches[dc->context_ndx].local_result = caches[dc->context_ndx].result;
        !           607:                        break;
        !           608:                default:
        !           609:                        break;
1.1       misho     610:                }
                    611: 
                    612:                if (con->conf.log_condition_handling) {
1.1.1.2 ! misho     613:                        log_error_write(srv, __FILE__, __LINE__, "dss",
        !           614:                                dc->context_ndx,
        !           615:                                "(uncached) result:",
        !           616:                                cond_result_to_string(caches[dc->context_ndx].result));
1.1       misho     617:                }
                    618:        } else {
                    619:                if (con->conf.log_condition_handling) {
1.1.1.2 ! misho     620:                        log_error_write(srv, __FILE__, __LINE__, "dss",
        !           621:                                dc->context_ndx,
        !           622:                                "(cached) result:",
        !           623:                                cond_result_to_string(caches[dc->context_ndx].result));
1.1       misho     624:                }
                    625:        }
                    626:        return caches[dc->context_ndx].result;
                    627: }
                    628: 
1.1.1.2 ! misho     629: /* if we reset the cache result for a node, we also need to clear all
        !           630:  * child nodes and else-branches*/
        !           631: static void config_cond_clear_node(server *srv, connection *con, data_config *dc) {
        !           632:        /* if a node is "unset" all children are unset too */
        !           633:        if (con->cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) {
        !           634:                size_t i;
        !           635: 
        !           636:                con->cond_cache[dc->context_ndx].patterncount = 0;
        !           637:                con->cond_cache[dc->context_ndx].comp_value = NULL;
        !           638:                con->cond_cache[dc->context_ndx].result = COND_RESULT_UNSET;
        !           639: 
        !           640:                for (i = 0; i < dc->children.used; ++i) {
        !           641:                        data_config *dc_child = dc->children.data[i];
        !           642:                        if (NULL == dc_child->prev) {
        !           643:                                /* only call for first node in if-else chain */
        !           644:                                config_cond_clear_node(srv, con, dc_child);
        !           645:                        }
        !           646:                }
        !           647:                if (NULL != dc->next) config_cond_clear_node(srv, con, dc->next);
        !           648:        }
        !           649: }
        !           650: 
1.1       misho     651: /**
                    652:  * reset the config-cache for a named item
                    653:  *
                    654:  * if the item is COND_LAST_ELEMENT we reset all items
                    655:  */
                    656: void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
                    657:        size_t i;
                    658: 
                    659:        for (i = 0; i < srv->config_context->used; i++) {
1.1.1.2 ! misho     660:                data_config *dc = (data_config *)srv->config_context->data[i];
        !           661: 
        !           662:                if (item == dc->comp) {
        !           663:                        /* clear local_result */
        !           664:                        con->cond_cache[i].local_result = COND_RESULT_UNSET;
        !           665:                        /* clear result in subtree (including the node itself) */
        !           666:                        config_cond_clear_node(srv, con, dc);
1.1       misho     667:                }
                    668:        }
                    669: }
                    670: 
                    671: /**
                    672:  * reset the config cache to its initial state at connection start
                    673:  */
                    674: void config_cond_cache_reset(server *srv, connection *con) {
                    675:        size_t i;
                    676: 
1.1.1.2 ! misho     677:        /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */
        !           678:        for (i = 0; i < srv->config_context->used; i++) {
        !           679:                con->cond_cache[i].result = COND_RESULT_UNSET;
        !           680:                con->cond_cache[i].local_result = COND_RESULT_UNSET;
        !           681:                con->cond_cache[i].patterncount = 0;
        !           682:                con->cond_cache[i].comp_value = NULL;
        !           683:        }
1.1       misho     684: 
                    685:        for (i = 0; i < COMP_LAST_ELEMENT; i++) {
                    686:                con->conditional_is_valid[i] = 0;
                    687:        }
                    688: }
                    689: 
                    690: int config_check_cond(server *srv, connection *con, data_config *dc) {
                    691:        if (con->conf.log_condition_handling) {
                    692:                log_error_write(srv, __FILE__, __LINE__,  "s",  "=== start of condition block ===");
                    693:        }
                    694:        return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
                    695: }
                    696: 
                    697: int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
                    698: {
                    699:        cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
                    700:        if (n >= cache->patterncount) {
                    701:                return 0;
                    702:        }
                    703: 
                    704:        n <<= 1; /* n *= 2 */
                    705:        buffer_append_string_len(buf,
                    706:                        cache->comp_value->ptr + cache->matches[n],
                    707:                        cache->matches[n + 1] - cache->matches[n]);
                    708:        return 1;
                    709: }

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