1 %token_prefix TK_ 2 %extra_argument {config_t *ctx} 3 %name configparser 4 5 %include { 6 #include "first.h" 7 #include "base.h" 8 #include "configfile.h" 9 #include "buffer.h" 10 #include "array.h" 11 #include "request.h" /* http_request_host_normalize() */ 12 13 #include <ctype.h> 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <stdio.h> 17 #include <string.h> 18 19 static data_config * configparser_get_data_config(const array *a, const char *k, const size_t klen) { 20 return (data_config *)array_get_data_unset(a, k, klen); 21 } 22 23 static void configparser_push(config_t *ctx, data_config *dc, int isnew) { 24 if (isnew) { 25 dc->context_ndx = ctx->all_configs->used; 26 force_assert(dc->context_ndx > ctx->current->context_ndx); 27 array_insert_unique(ctx->all_configs, (data_unset *)dc); 28 dc->parent = ctx->current; 29 vector_config_weak_push(&dc->parent->children, dc); 30 } 31 if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) { 32 fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n"); 33 exit(-1); 34 } 35 vector_config_weak_push(&ctx->configs_stack, ctx->current); 36 ctx->current = dc; 37 } 38 39 static data_config *configparser_pop(config_t *ctx) { 40 data_config *old = ctx->current; 41 ctx->current = vector_config_weak_pop(&ctx->configs_stack); 42 return old; 43 } 44 45 /* return a copied variable */ 46 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) { 47 const data_unset *du; 48 data_config *dc; 49 50 #if 0 51 fprintf(stderr, "get var %s\n", key->ptr); 52 #endif 53 for (dc = ctx->current; dc; dc = dc->parent) { 54 #if 0 55 fprintf(stderr, "get var on block: %s\n", dc->key.ptr); 56 array_print(dc->value, 0); 57 #endif 58 if (NULL != (du = array_get_element_klen(dc->value, CONST_BUF_LEN(key)))) { 59 data_unset *du_copy = du->fn->copy(du); 60 buffer_clear(&du_copy->key); 61 return du_copy; 62 } 63 } 64 return NULL; 65 } 66 67 /* op1 is to be eat/return by this function if success, op1->key is not cared 68 op2 is left untouch, unreferenced 69 */ 70 static data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { 71 /* type mismatch */ 72 if (op1->type != op2->type) { 73 if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) { 74 data_string *ds = (data_string *)op1; 75 buffer_append_int(&ds->value, ((data_integer*)op2)->value); 76 return op1; 77 } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) { 78 data_string *ds = data_string_init(); 79 buffer_append_int(&ds->value, ((data_integer*)op1)->value); 80 buffer_append_string_buffer(&ds->value, &((data_string*)op2)->value); 81 op1->fn->free(op1); 82 return (data_unset *)ds; 83 } else { 84 fprintf(stderr, "data type mismatch, cannot merge\n"); 85 op1->fn->free(op1); 86 return NULL; 87 } 88 } 89 90 switch (op1->type) { 91 case TYPE_STRING: 92 buffer_append_string_buffer(&((data_string *)op1)->value, &((data_string *)op2)->value); 93 break; 94 case TYPE_INTEGER: 95 ((data_integer *)op1)->value += ((data_integer *)op2)->value; 96 break; 97 case TYPE_ARRAY: { 98 array *dst = &((data_array *)op1)->value; 99 array *src = &((data_array *)op2)->value; 100 data_unset *du; 101 size_t i; 102 103 for (i = 0; i < src->used; i ++) { 104 du = (data_unset *)src->data[i]; 105 if (du) { 106 if (buffer_is_empty(&du->key) || !array_get_element_klen(dst, CONST_BUF_LEN(&du->key))) { 107 array_insert_unique(dst, du->fn->copy(du)); 108 } else { 109 fprintf(stderr, "Duplicate array-key '%s'\n", du->key.ptr); 110 op1->fn->free(op1); 111 return NULL; 112 } 113 } 114 } 115 break; 116 default: 117 force_assert(0); 118 break; 119 } 120 } 121 return op1; 122 } 123 124 static int configparser_remoteip_normalize_compat(buffer *rvalue) { 125 /* $HTTP["remoteip"] IPv6 accepted with or without '[]' for config compat 126 * http_request_host_normalize() expects IPv6 with '[]', 127 * and config processing at runtime expects COMP_HTTP_REMOTE_IP 128 * compared without '[]', so strip '[]' after normalization */ 129 buffer *b = buffer_init(); 130 int rc; 131 132 if (rvalue->ptr[0] != '[') { 133 buffer_append_string_len(b, CONST_STR_LEN("[")); 134 buffer_append_string_buffer(b, rvalue); 135 buffer_append_string_len(b, CONST_STR_LEN("]")); 136 } else { 137 buffer_append_string_buffer(b, rvalue); 138 } 139 140 rc = http_request_host_normalize(b, 0); 141 142 if (0 == rc) { 143 /* remove surrounding '[]' */ 144 size_t blen = buffer_string_length(b); 145 if (blen > 1) buffer_copy_string_len(rvalue, b->ptr+1, blen-2); 146 } 147 148 buffer_free(b); 149 return rc; 150 } 151 152 } 153 154 %parse_failure { 155 ctx->ok = 0; 156 } 157 158 input ::= metalines. 159 metalines ::= metalines metaline. 160 metalines ::= . 161 metaline ::= varline. 162 metaline ::= global. 163 metaline ::= condlines(A) EOL. { A = NULL; } 164 metaline ::= include. 165 metaline ::= include_shell. 166 metaline ::= EOL. 167 168 %type value {data_unset *} 169 %type expression {data_unset *} 170 %type aelement {data_unset *} 171 %type condline {data_config *} 172 %type cond_else {data_config *} 173 %type condlines {data_config *} 174 %type aelements {array *} 175 %type array {array *} 176 %type key {buffer *} 177 %type stringop {buffer *} 178 179 %type cond {config_cond_t } 180 181 %destructor value { if ($$) $$->fn->free($$); } 182 %destructor expression { if ($$) $$->fn->free($$); } 183 %destructor aelement { if ($$) $$->fn->free($$); } 184 %destructor aelements { array_free($$); } 185 %destructor array { array_free($$); } 186 %destructor key { buffer_free($$); } 187 %destructor stringop { buffer_free($$); } 188 189 %token_type {buffer *} 190 %token_destructor { buffer_free($$); } 191 192 varline ::= key(A) ASSIGN expression(B). { 193 if (ctx->ok) { 194 buffer_copy_buffer(&B->key, A); 195 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { 196 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", 197 ctx->current->context_ndx, 198 ctx->current->key.ptr, A->ptr); 199 ctx->ok = 0; 200 } else if (NULL == array_get_element_klen(ctx->current->value, CONST_BUF_LEN(&B->key))) { 201 array_insert_unique(ctx->current->value, B); 202 B = NULL; 203 } else { 204 fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", 205 ctx->current->context_ndx, 206 ctx->current->key.ptr, B->key.ptr); 207 ctx->ok = 0; 208 } 209 } 210 buffer_free(A); 211 A = NULL; 212 if (B) B->fn->free(B); 213 B = NULL; 214 } 215 216 varline ::= key(A) FORCE_ASSIGN expression(B). { 217 if (ctx->ok) { 218 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { 219 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", 220 ctx->current->context_ndx, 221 ctx->current->key.ptr, A->ptr); 222 ctx->ok = 0; 223 } else { 224 buffer_copy_buffer(&B->key, A); 225 array_replace(ctx->current->value, B); 226 B = NULL; 227 } 228 } 229 buffer_free(A); 230 A = NULL; 231 if (B) B->fn->free(B); 232 B = NULL; 233 } 234 235 varline ::= key(A) APPEND expression(B). { 236 if (ctx->ok) { 237 array *vars = ctx->current->value; 238 data_unset *du; 239 240 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { 241 fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n", 242 ctx->current->context_ndx, 243 ctx->current->key.ptr, A->ptr); 244 ctx->ok = 0; 245 } else if (NULL != (du = array_extract_element_klen(vars, CONST_BUF_LEN(A))) || NULL != (du = configparser_get_variable(ctx, A))) { 246 du = configparser_merge_data(du, B); 247 if (NULL == du) { 248 ctx->ok = 0; 249 } 250 else { 251 buffer_copy_buffer(&du->key, A); 252 array_insert_unique(ctx->current->value, du); 253 } 254 } else { 255 buffer_copy_buffer(&B->key, A); 256 array_insert_unique(ctx->current->value, B); 257 B = NULL; 258 } 259 } 260 buffer_free(A); 261 A = NULL; 262 if (B) B->fn->free(B); 263 B = NULL; 264 } 265 266 key(A) ::= LKEY(B). { 267 if (strchr(B->ptr, '.') == NULL) { 268 A = buffer_init_string("var."); 269 buffer_append_string_buffer(A, B); 270 } else { 271 A = B; 272 B = NULL; 273 } 274 buffer_free(B); 275 B = NULL; 276 } 277 278 expression(A) ::= expression(B) PLUS value(C). { 279 A = NULL; 280 if (ctx->ok) { 281 A = configparser_merge_data(B, C); 282 B = NULL; 283 if (NULL == A) { 284 ctx->ok = 0; 285 } 286 } 287 if (B) B->fn->free(B); 288 B = NULL; 289 if (C) C->fn->free(C); 290 C = NULL; 291 } 292 293 expression(A) ::= value(B). { 294 A = B; 295 B = NULL; 296 } 297 298 value(A) ::= key(B). { 299 A = NULL; 300 if (ctx->ok) { 301 if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) { 302 char *env; 303 304 if (NULL != (env = getenv(B->ptr + 4))) { 305 data_string *ds; 306 ds = data_string_init(); 307 buffer_append_string(&ds->value, env); 308 A = (data_unset *)ds; 309 } 310 else { 311 fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4); 312 ctx->ok = 0; 313 } 314 } else if (NULL == (A = configparser_get_variable(ctx, B))) { 315 fprintf(stderr, "Undefined config variable: %s\n", B->ptr); 316 ctx->ok = 0; 317 } 318 } 319 buffer_free(B); 320 B = NULL; 321 } 322 323 value(A) ::= STRING(B). { 324 A = (data_unset *)data_string_init(); 325 buffer_copy_buffer(&((data_string *)A)->value, B); 326 } 327 328 value(A) ::= INTEGER(B). { 329 char *endptr; 330 A = (data_unset *)data_integer_init(); 331 errno = 0; 332 ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10); 333 /* skip trailing whitespace */ 334 if (endptr != B->ptr) while (isspace(*(unsigned char *)endptr)) endptr++; 335 if (0 != errno || *endptr != '\0') { 336 fprintf(stderr, "error parsing number: '%s'\n", B->ptr); 337 ctx->ok = 0; 338 } 339 buffer_free(B); 340 B = NULL; 341 } 342 value(A) ::= array(B). { 343 A = (data_unset *)data_array_init(); 344 array_copy_array(&((data_array *)(A))->value, B); 345 B = NULL; 346 } 347 array(A) ::= LPARAN RPARAN. { 348 A = array_init(8); 349 } 350 array(A) ::= LPARAN aelements(B) RPARAN. { 351 A = B; 352 B = NULL; 353 } 354 355 aelements(A) ::= aelements(C) COMMA aelement(B). { 356 A = NULL; 357 if (ctx->ok) { 358 if (buffer_is_empty(&B->key) || 359 NULL == array_get_element_klen(C, CONST_BUF_LEN(&B->key))) { 360 array_insert_unique(C, B); 361 B = NULL; 362 } else { 363 fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n", 364 B->key.ptr); 365 ctx->ok = 0; 366 } 367 368 A = C; 369 C = NULL; 370 } 371 array_free(C); 372 C = NULL; 373 if (B) B->fn->free(B); 374 B = NULL; 375 } 376 377 aelements(A) ::= aelements(C) COMMA. { 378 A = C; 379 C = NULL; 380 } 381 382 aelements(A) ::= aelement(B). { 383 A = NULL; 384 if (ctx->ok) { 385 A = array_init(4); 386 array_insert_unique(A, B); 387 B = NULL; 388 } 389 if (B) B->fn->free(B); 390 B = NULL; 391 } 392 393 aelement(A) ::= expression(B). { 394 A = B; 395 B = NULL; 396 } 397 aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). { 398 A = NULL; 399 if (ctx->ok) { 400 buffer_copy_buffer(&C->key, B); 401 402 A = C; 403 C = NULL; 404 } 405 if (C) C->fn->free(C); 406 C = NULL; 407 buffer_free(B); 408 B = NULL; 409 } 410 411 eols ::= EOL. 412 eols ::= . 413 414 globalstart ::= GLOBAL. { 415 data_config *dc; 416 dc = configparser_get_data_config(ctx->srv->config_context, CONST_STR_LEN("global")); 417 force_assert(dc); 418 configparser_push(ctx, dc, 0); 419 } 420 421 global ::= globalstart LCURLY metalines RCURLY. { 422 force_assert(ctx->current); 423 configparser_pop(ctx); 424 force_assert(ctx->current); 425 } 426 427 condlines(A) ::= condlines(B) eols ELSE condline(C). { 428 A = NULL; 429 if (ctx->ok) { 430 if (B->context_ndx >= C->context_ndx) { 431 fprintf(stderr, "unreachable else condition\n"); 432 ctx->ok = 0; 433 } 434 if (B->cond == CONFIG_COND_ELSE) { 435 fprintf(stderr, "unreachable condition following else catch-all\n"); 436 ctx->ok = 0; 437 } 438 C->prev = B; 439 B->next = C; 440 A = C; 441 } 442 B = NULL; 443 C = NULL; 444 } 445 446 condlines(A) ::= condlines(B) eols ELSE cond_else(C). { 447 A = NULL; 448 if (ctx->ok) { 449 if (B->context_ndx >= C->context_ndx) { 450 fprintf(stderr, "unreachable else condition\n"); 451 ctx->ok = 0; 452 } 453 if (B->cond == CONFIG_COND_ELSE) { 454 fprintf(stderr, "unreachable condition following else catch-all\n"); 455 ctx->ok = 0; 456 } 457 } 458 if (ctx->ok) { 459 size_t pos; 460 data_config *dc; 461 dc = (data_config *)array_extract_element_klen(ctx->all_configs, CONST_BUF_LEN(&C->key)); 462 force_assert(C == dc); 463 buffer_copy_buffer(&C->key, &B->key); 464 C->comp = B->comp; 465 /*buffer_copy_buffer(C->comp_key, B->comp_key);*/ 466 /*buffer_copy_buffer(&C->string, &B->string);*/ 467 pos = buffer_string_length(&C->key)-buffer_string_length(&B->string)-2; 468 switch(B->cond) { 469 case CONFIG_COND_NE: 470 C->key.ptr[pos] = '='; /* opposite cond */ 471 /*buffer_copy_string_len(C->op, CONST_STR_LEN("=="));*/ 472 break; 473 case CONFIG_COND_EQ: 474 C->key.ptr[pos] = '!'; /* opposite cond */ 475 /*buffer_copy_string_len(C->op, CONST_STR_LEN("!="));*/ 476 break; 477 case CONFIG_COND_NOMATCH: 478 C->key.ptr[pos] = '='; /* opposite cond */ 479 /*buffer_copy_string_len(C->op, CONST_STR_LEN("=~"));*/ 480 break; 481 case CONFIG_COND_MATCH: 482 C->key.ptr[pos] = '!'; /* opposite cond */ 483 /*buffer_copy_string_len(C->op, CONST_STR_LEN("!~"));*/ 484 break; 485 default: /* should not happen; CONFIG_COND_ELSE checked further above */ 486 force_assert(0); 487 } 488 489 if (NULL == (dc = configparser_get_data_config(ctx->all_configs, CONST_BUF_LEN(&C->key)))) { 490 /* re-insert into ctx->all_configs with new C->key */ 491 array_insert_unique(ctx->all_configs, (data_unset *)C); 492 C->prev = B; 493 B->next = C; 494 } else { 495 fprintf(stderr, "unreachable else condition\n"); 496 ctx->ok = 0; 497 C->fn->free((data_unset *)C); 498 C = dc; 499 } 500 501 A = C; 502 } 503 B = NULL; 504 C = NULL; 505 } 506 507 condlines(A) ::= condline(B). { 508 A = B; 509 B = NULL; 510 } 511 512 condline(A) ::= context LCURLY metalines RCURLY. { 513 A = NULL; 514 if (ctx->ok) { 515 data_config *cur; 516 517 cur = ctx->current; 518 configparser_pop(ctx); 519 520 force_assert(cur && ctx->current); 521 522 A = cur; 523 } 524 } 525 526 cond_else(A) ::= context_else LCURLY metalines RCURLY. { 527 A = NULL; 528 if (ctx->ok) { 529 data_config *cur; 530 531 cur = ctx->current; 532 configparser_pop(ctx); 533 534 force_assert(cur && ctx->current); 535 536 A = cur; 537 } 538 } 539 540 context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). { 541 data_config *dc; 542 buffer *b = NULL, *rvalue; 543 const char *op = NULL; 544 545 if (ctx->ok && D->type != TYPE_STRING) { 546 fprintf(stderr, "rvalue must be string"); 547 ctx->ok = 0; 548 } 549 550 if (ctx->ok) { 551 switch(E) { 552 case CONFIG_COND_NE: 553 op = "!="; 554 break; 555 case CONFIG_COND_EQ: 556 op = "=="; 557 break; 558 case CONFIG_COND_NOMATCH: 559 op = "!~"; 560 break; 561 case CONFIG_COND_MATCH: 562 op = "=~"; 563 break; 564 default: 565 force_assert(0); 566 return; /* unreachable */ 567 } 568 569 b = buffer_init(); 570 buffer_copy_buffer(b, &ctx->current->key); 571 buffer_append_string_len(b, CONST_STR_LEN("/")); 572 buffer_append_string_buffer(b, B); 573 buffer_append_string_buffer(b, C); 574 buffer_append_string_len(b, op, 2); 575 rvalue = &((data_string*)D)->value; 576 buffer_append_string_buffer(b, rvalue); 577 578 if (NULL != (dc = configparser_get_data_config(ctx->all_configs, CONST_BUF_LEN(b)))) { 579 configparser_push(ctx, dc, 0); 580 } else { 581 static const struct { 582 comp_key_t comp; 583 char *comp_key; 584 size_t len; 585 } comps[] = { 586 { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) }, 587 { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, 588 { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, 589 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"referer\"]" ) }, 590 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, 591 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, 592 { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) }, 593 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"cookie\"]" ) }, 594 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, 595 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, 596 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, 597 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, 598 { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, 599 { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, 600 { COMP_UNSET, NULL, 0 }, 601 }; 602 size_t i; 603 604 dc = data_config_init(); 605 606 buffer_copy_buffer(&dc->key, b); 607 dc->op = op; 608 buffer_copy_buffer(dc->comp_tag, C); 609 buffer_copy_buffer(dc->comp_key, B); 610 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\"")); 611 buffer_append_string_buffer(dc->comp_key, C); 612 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]")); 613 dc->cond = E; 614 615 for (i = 0; comps[i].comp_key; i ++) { 616 if (buffer_is_equal_string( 617 dc->comp_key, comps[i].comp_key, comps[i].len)) { 618 dc->comp = comps[i].comp; 619 break; 620 } 621 } 622 if (COMP_UNSET == dc->comp) { 623 if (buffer_is_equal_string(B, CONST_STR_LEN("REQUEST_HEADER"))) { 624 dc->comp = COMP_HTTP_REQUEST_HEADER; 625 } 626 else { 627 fprintf(stderr, "error comp_key %s", dc->comp_key->ptr); 628 ctx->ok = 0; 629 } 630 } 631 else if (COMP_HTTP_LANGUAGE == dc->comp) { 632 dc->comp = COMP_HTTP_REQUEST_HEADER; 633 buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("Accept-Language")); 634 } 635 else if (COMP_HTTP_USER_AGENT == dc->comp) { 636 dc->comp = COMP_HTTP_REQUEST_HEADER; 637 buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("User-Agent")); 638 } 639 else if (COMP_HTTP_REMOTE_IP == dc->comp 640 && (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) { 641 char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */ 642 char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */ 643 if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/ 644 } 645 else if (NULL != slash) { 646 char *nptr; 647 const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10); 648 if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) { 649 /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/ 650 fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr); 651 ctx->ok = 0; 652 } 653 else { 654 int rc; 655 buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/ 656 rc = (NULL == colon) 657 ? http_request_host_normalize(rvalue, 0) 658 : configparser_remoteip_normalize_compat(rvalue); 659 buffer_append_string_len(rvalue, CONST_STR_LEN("/")); 660 buffer_append_int(rvalue, (int)nm_bits); 661 if (0 != rc) { 662 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 663 ctx->ok = 0; 664 } 665 } 666 } 667 else { 668 int rc = (NULL == colon) 669 ? http_request_host_normalize(rvalue, 0) 670 : configparser_remoteip_normalize_compat(rvalue); 671 if (0 != rc) { 672 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 673 ctx->ok = 0; 674 } 675 } 676 } 677 else if (COMP_SERVER_SOCKET == dc->comp) { 678 /*(redundant with parsing in network.c; not actually required here)*/ 679 if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/ 680 && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) { 681 if (http_request_host_normalize(rvalue, 0)) { 682 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 683 ctx->ok = 0; 684 } 685 } 686 } 687 else if (COMP_HTTP_HOST == dc->comp) { 688 if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) { 689 if (http_request_host_normalize(rvalue, 0)) { 690 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr); 691 ctx->ok = 0; 692 } 693 } 694 } 695 696 buffer_copy_buffer(&dc->string, rvalue); 697 698 if (ctx->ok) switch(E) { 699 case CONFIG_COND_NE: 700 case CONFIG_COND_EQ: 701 break; 702 case CONFIG_COND_NOMATCH: 703 case CONFIG_COND_MATCH: { 704 if (!data_config_pcre_compile(dc)) { 705 ctx->ok = 0; 706 } 707 break; 708 } 709 710 default: 711 fprintf(stderr, "unknown condition for $%s[%s]\n", 712 B->ptr, C->ptr); 713 ctx->ok = 0; 714 break; 715 } 716 717 if (ctx->ok) { 718 configparser_push(ctx, dc, 1); 719 } else { 720 dc->fn->free((data_unset*) dc); 721 } 722 } 723 } 724 725 buffer_free(b); 726 buffer_free(B); 727 B = NULL; 728 buffer_free(C); 729 C = NULL; 730 if (D) D->fn->free(D); 731 D = NULL; 732 } 733 734 context_else ::= . { 735 if (ctx->ok) { 736 data_config *dc = data_config_init(); 737 buffer_copy_buffer(&dc->key, &ctx->current->key); 738 buffer_append_string_len(&dc->key, CONST_STR_LEN("/")); 739 buffer_append_string_len(&dc->key, CONST_STR_LEN("else_tmp_token")); 740 dc->cond = CONFIG_COND_ELSE; 741 configparser_push(ctx, dc, 1); 742 } 743 } 744 745 cond(A) ::= EQ. { 746 A = CONFIG_COND_EQ; 747 } 748 cond(A) ::= MATCH. { 749 A = CONFIG_COND_MATCH; 750 } 751 cond(A) ::= NE. { 752 A = CONFIG_COND_NE; 753 } 754 cond(A) ::= NOMATCH. { 755 A = CONFIG_COND_NOMATCH; 756 } 757 758 stringop(A) ::= expression(B). { 759 A = NULL; 760 if (ctx->ok) { 761 if (B->type == TYPE_STRING) { 762 A = buffer_init_buffer(&((data_string*)B)->value); 763 } else if (B->type == TYPE_INTEGER) { 764 A = buffer_init(); 765 buffer_append_int(A, ((data_integer *)B)->value); 766 } else { 767 fprintf(stderr, "operand must be string"); 768 ctx->ok = 0; 769 } 770 } 771 if (B) B->fn->free(B); 772 B = NULL; 773 } 774 775 include ::= INCLUDE stringop(A). { 776 if (ctx->ok) { 777 if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) { 778 ctx->ok = 0; 779 } 780 } 781 buffer_free(A); 782 A = NULL; 783 } 784 785 include_shell ::= INCLUDE_SHELL stringop(A). { 786 if (ctx->ok) { 787 if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) { 788 ctx->ok = 0; 789 } 790 } 791 buffer_free(A); 792 A = NULL; 793 } 794