File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / configfile-glue.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    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>