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