1: #include "first.h"
2:
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>
13: #ifndef _WIN32
14: #include <arpa/inet.h>
15: #endif
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 */
32: int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
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:
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:
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++) {
59: data_unset *ds = da->value->data[j];
60: if (ds->type == TYPE_STRING) {
61: array_insert_unique(cv[i].destination, ds->copy(ds));
62: } else {
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);
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:
80: buffer_copy_buffer(cv[i].destination, ds->value);
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:
191: int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
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(""));
208: buffer_copy_buffer(touched->key, du->key);
209:
210: array_insert_unique(srv->config_touched, (data_unset *)touched);
211: }
212:
213: return config_insert_values_internal(srv, ca, cv, scope);
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:
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:
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;
340: cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
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:
355: /* decide later */
356: return COND_RESULT_UNSET;
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 */
363: break;
364: }
365: }
366:
367: if (dc->prev) {
368: /**
369: * a else branch; can only be executed if the previous branch
370: * was evaluated as "false" (not unset/skipped/true)
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 */
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;
385: case COND_RESULT_FALSE:
386: /* proceed */
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,
396: "not available yet");
397: }
398:
399: return COND_RESULT_UNSET;
400: }
401:
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:
411: /* pass the rules */
412:
413: switch (dc->comp) {
414: case COMP_HTTP_HOST: {
415: char *ck_colon = NULL, *val_colon = NULL;
416:
417: if (!buffer_string_is_empty(con->uri.authority)) {
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" */
433: buffer_copy_buffer(srv->cond_check_buf, l);
434: buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
435: buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
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
447: } else if (!buffer_string_is_empty(con->tlsext_server_name)) {
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, '/')))) {
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)*/
473: }
474: }
475: l = con->dst_addr_buf;
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
575: n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
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) {
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;
610: }
611:
612: if (con->conf.log_condition_handling) {
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));
617: }
618: } else {
619: if (con->conf.log_condition_handling) {
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));
624: }
625: }
626: return caches[dc->context_ndx].result;
627: }
628:
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:
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++) {
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);
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:
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: }
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>