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>