comparison src/http/ngx_http_variables.c @ 6899:d2b2ff157da5

Variables: generic prefix variables.
author Dmitry Volyntsev <xeioex@nginx.com>
date Tue, 31 Jan 2017 21:19:58 +0300
parents 8cd97c14b0e2
children 1b068a4e82d8 0800444254e8
comparison
equal deleted inserted replaced
6885:25203fc377fb 6899:d2b2ff157da5
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 #include <nginx.h> 11 #include <nginx.h>
12 12
13
14 static ngx_http_variable_t *ngx_http_add_prefix_variable(ngx_conf_t *cf,
15 ngx_str_t *name, ngx_uint_t flags);
13 16
14 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, 17 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
15 ngx_http_variable_value_t *v, uintptr_t data); 18 ngx_http_variable_value_t *v, uintptr_t data);
16 #if 0 19 #if 0
17 static void ngx_http_variable_request_set(ngx_http_request_t *r, 20 static void ngx_http_variable_request_set(ngx_http_request_t *r,
354 357
355 { ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo, 358 { ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo,
356 3, NGX_HTTP_VAR_NOCACHEABLE, 0 }, 359 3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
357 #endif 360 #endif
358 361
362 { ngx_string("http_"), NULL, ngx_http_variable_unknown_header_in,
363 0, NGX_HTTP_VAR_PREFIX, 0 },
364
365 { ngx_string("sent_http_"), NULL, ngx_http_variable_unknown_header_out,
366 0, NGX_HTTP_VAR_PREFIX, 0 },
367
368 { ngx_string("cookie_"), NULL, ngx_http_variable_cookie,
369 0, NGX_HTTP_VAR_PREFIX, 0 },
370
371 { ngx_string("arg_"), NULL, ngx_http_variable_argument,
372 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
373
359 { ngx_null_string, NULL, NULL, 0, 0, 0 } 374 { ngx_null_string, NULL, NULL, 0, 0, 0 }
360 }; 375 };
361 376
362 377
363 ngx_http_variable_value_t ngx_http_variable_null_value = 378 ngx_http_variable_value_t ngx_http_variable_null_value =
380 395
381 if (name->len == 0) { 396 if (name->len == 0) {
382 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 397 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
383 "invalid variable name \"$\""); 398 "invalid variable name \"$\"");
384 return NULL; 399 return NULL;
400 }
401
402 if (flags & NGX_HTTP_VAR_PREFIX) {
403 return ngx_http_add_prefix_variable(cf, name, flags);
385 } 404 }
386 405
387 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 406 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
388 407
389 key = cmcf->variables_keys->keys.elts; 408 key = cmcf->variables_keys->keys.elts;
400 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 419 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
401 "the duplicate \"%V\" variable", name); 420 "the duplicate \"%V\" variable", name);
402 return NULL; 421 return NULL;
403 } 422 }
404 423
424 v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
425
405 return v; 426 return v;
406 } 427 }
407 428
408 v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t)); 429 v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
409 if (v == NULL) { 430 if (v == NULL) {
433 if (rc == NGX_BUSY) { 454 if (rc == NGX_BUSY) {
434 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 455 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
435 "conflicting variable name \"%V\"", name); 456 "conflicting variable name \"%V\"", name);
436 return NULL; 457 return NULL;
437 } 458 }
459
460 return v;
461 }
462
463
464 static ngx_http_variable_t *
465 ngx_http_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
466 {
467 ngx_uint_t i;
468 ngx_http_variable_t *v;
469 ngx_http_core_main_conf_t *cmcf;
470
471 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
472
473 v = cmcf->prefix_variables.elts;
474 for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
475 if (name->len != v[i].name.len
476 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
477 {
478 continue;
479 }
480
481 v = &v[i];
482
483 if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
484 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
485 "the duplicate \"%V\" variable", name);
486 return NULL;
487 }
488
489 v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
490
491 return v;
492 }
493
494 v = ngx_array_push(&cmcf->prefix_variables);
495 if (v == NULL) {
496 return NULL;
497 }
498
499 v->name.len = name->len;
500 v->name.data = ngx_pnalloc(cf->pool, name->len);
501 if (v->name.data == NULL) {
502 return NULL;
503 }
504
505 ngx_strlow(v->name.data, name->data, name->len);
506
507 v->set_handler = NULL;
508 v->get_handler = NULL;
509 v->data = 0;
510 v->flags = flags;
511 v->index = 0;
438 512
439 return v; 513 return v;
440 } 514 }
441 515
442 516
571 645
572 646
573 ngx_http_variable_value_t * 647 ngx_http_variable_value_t *
574 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) 648 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
575 { 649 {
650 size_t len;
651 ngx_uint_t i, n;
576 ngx_http_variable_t *v; 652 ngx_http_variable_t *v;
577 ngx_http_variable_value_t *vv; 653 ngx_http_variable_value_t *vv;
578 ngx_http_core_main_conf_t *cmcf; 654 ngx_http_core_main_conf_t *cmcf;
579 655
580 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); 656 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
608 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); 684 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
609 if (vv == NULL) { 685 if (vv == NULL) {
610 return NULL; 686 return NULL;
611 } 687 }
612 688
613 if (name->len >= 5 && ngx_strncmp(name->data, "http_", 5) == 0) { 689 len = 0;
614 690
615 if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name) 691 v = cmcf->prefix_variables.elts;
616 == NGX_OK) 692 n = cmcf->prefix_variables.nelts;
693
694 for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
695 if (name->len >= v[i].name.len && name->len > len
696 && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
617 { 697 {
618 return vv; 698 len = v[i].name.len;
619 } 699 n = i;
620 700 }
621 return NULL; 701 }
622 } 702
623 703 if (n != cmcf->prefix_variables.nelts) {
624 if (name->len >= 10 && ngx_strncmp(name->data, "sent_http_", 10) == 0) { 704 if (v[n].get_handler(r, vv, (uintptr_t) name) == NGX_OK) {
625
626 if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
627 == NGX_OK)
628 {
629 return vv;
630 }
631
632 return NULL;
633 }
634
635 if (name->len >= 14 && ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
636
637 if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
638 == NGX_OK)
639 {
640 return vv;
641 }
642
643 return NULL;
644 }
645
646 if (name->len >= 7 && ngx_strncmp(name->data, "cookie_", 7) == 0) {
647
648 if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
649 return vv;
650 }
651
652 return NULL;
653 }
654
655 if (name->len >= 16
656 && ngx_strncmp(name->data, "upstream_cookie_", 16) == 0)
657 {
658
659 if (ngx_http_upstream_cookie_variable(r, vv, (uintptr_t) name)
660 == NGX_OK)
661 {
662 return vv;
663 }
664
665 return NULL;
666 }
667
668 if (name->len >= 4 && ngx_strncmp(name->data, "arg_", 4) == 0) {
669
670 if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
671 return vv; 705 return vv;
672 } 706 }
673 707
674 return NULL; 708 return NULL;
675 } 709 }
2500 2534
2501 2535
2502 ngx_int_t 2536 ngx_int_t
2503 ngx_http_variables_add_core_vars(ngx_conf_t *cf) 2537 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
2504 { 2538 {
2505 ngx_int_t rc;
2506 ngx_http_variable_t *cv, *v; 2539 ngx_http_variable_t *cv, *v;
2507 ngx_http_core_main_conf_t *cmcf; 2540 ngx_http_core_main_conf_t *cmcf;
2508 2541
2509 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 2542 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
2510 2543
2521 != NGX_OK) 2554 != NGX_OK)
2522 { 2555 {
2523 return NGX_ERROR; 2556 return NGX_ERROR;
2524 } 2557 }
2525 2558
2559 if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,
2560 sizeof(ngx_http_variable_t))
2561 != NGX_OK)
2562 {
2563 return NGX_ERROR;
2564 }
2565
2526 for (cv = ngx_http_core_variables; cv->name.len; cv++) { 2566 for (cv = ngx_http_core_variables; cv->name.len; cv++) {
2527 v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t)); 2567 v = ngx_http_add_variable(cf, &cv->name, cv->flags);
2528 if (v == NULL) { 2568 if (v == NULL) {
2529 return NGX_ERROR; 2569 return NGX_ERROR;
2530 } 2570 }
2531 2571
2532 *v = *cv; 2572 *v = *cv;
2533
2534 rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
2535 NGX_HASH_READONLY_KEY);
2536
2537 if (rc == NGX_OK) {
2538 continue;
2539 }
2540
2541 if (rc == NGX_BUSY) {
2542 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2543 "conflicting variable name \"%V\"", &v->name);
2544 }
2545
2546 return NGX_ERROR;
2547 } 2573 }
2548 2574
2549 return NGX_OK; 2575 return NGX_OK;
2550 } 2576 }
2551 2577
2552 2578
2553 ngx_int_t 2579 ngx_int_t
2554 ngx_http_variables_init_vars(ngx_conf_t *cf) 2580 ngx_http_variables_init_vars(ngx_conf_t *cf)
2555 { 2581 {
2582 size_t len;
2556 ngx_uint_t i, n; 2583 ngx_uint_t i, n;
2557 ngx_hash_key_t *key; 2584 ngx_hash_key_t *key;
2558 ngx_hash_init_t hash; 2585 ngx_hash_init_t hash;
2559 ngx_http_variable_t *v, *av; 2586 ngx_http_variable_t *v, *av, *pv;
2560 ngx_http_core_main_conf_t *cmcf; 2587 ngx_http_core_main_conf_t *cmcf;
2561 2588
2562 /* set the handlers for the indexed http variables */ 2589 /* set the handlers for the indexed http variables */
2563 2590
2564 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 2591 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
2565 2592
2566 v = cmcf->variables.elts; 2593 v = cmcf->variables.elts;
2594 pv = cmcf->prefix_variables.elts;
2567 key = cmcf->variables_keys->keys.elts; 2595 key = cmcf->variables_keys->keys.elts;
2568 2596
2569 for (i = 0; i < cmcf->variables.nelts; i++) { 2597 for (i = 0; i < cmcf->variables.nelts; i++) {
2570 2598
2571 for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) { 2599 for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
2582 av->flags |= NGX_HTTP_VAR_INDEXED; 2610 av->flags |= NGX_HTTP_VAR_INDEXED;
2583 v[i].flags = av->flags; 2611 v[i].flags = av->flags;
2584 2612
2585 av->index = i; 2613 av->index = i;
2586 2614
2587 if (av->get_handler == NULL) { 2615 if (av->get_handler == NULL
2616 || (av->flags & NGX_HTTP_VAR_WEAK))
2617 {
2588 break; 2618 break;
2589 } 2619 }
2590 2620
2591 goto next; 2621 goto next;
2592 } 2622 }
2593 } 2623 }
2594 2624
2595 if (v[i].name.len >= 5 2625 len = 0;
2596 && ngx_strncmp(v[i].name.data, "http_", 5) == 0) 2626 av = NULL;
2597 { 2627
2598 v[i].get_handler = ngx_http_variable_unknown_header_in; 2628 for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
2629 if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
2630 && ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)
2631 == 0)
2632 {
2633 av = &pv[n];
2634 len = pv[n].name.len;
2635 }
2636 }
2637
2638 if (av) {
2639 v[i].get_handler = av->get_handler;
2599 v[i].data = (uintptr_t) &v[i].name; 2640 v[i].data = (uintptr_t) &v[i].name;
2600 2641 v[i].flags = av->flags;
2601 continue; 2642
2602 } 2643 goto next;
2603 2644 }
2604 if (v[i].name.len >= 10 2645
2605 && ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) 2646 if (v[i].get_handler == NULL) {
2606 { 2647 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
2607 v[i].get_handler = ngx_http_variable_unknown_header_out; 2648 "unknown \"%V\" variable", &v[i].name);
2608 v[i].data = (uintptr_t) &v[i].name; 2649
2609 2650 return NGX_ERROR;
2610 continue; 2651 }
2611 }
2612
2613 if (v[i].name.len >= 14
2614 && ngx_strncmp(v[i].name.data, "upstream_http_", 14) == 0)
2615 {
2616 v[i].get_handler = ngx_http_upstream_header_variable;
2617 v[i].data = (uintptr_t) &v[i].name;
2618 v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
2619
2620 continue;
2621 }
2622
2623 if (v[i].name.len >= 7
2624 && ngx_strncmp(v[i].name.data, "cookie_", 7) == 0)
2625 {
2626 v[i].get_handler = ngx_http_variable_cookie;
2627 v[i].data = (uintptr_t) &v[i].name;
2628
2629 continue;
2630 }
2631
2632 if (v[i].name.len >= 16
2633 && ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0)
2634 {
2635 v[i].get_handler = ngx_http_upstream_cookie_variable;
2636 v[i].data = (uintptr_t) &v[i].name;
2637 v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
2638
2639 continue;
2640 }
2641
2642 if (v[i].name.len >= 4
2643 && ngx_strncmp(v[i].name.data, "arg_", 4) == 0)
2644 {
2645 v[i].get_handler = ngx_http_variable_argument;
2646 v[i].data = (uintptr_t) &v[i].name;
2647 v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
2648
2649 continue;
2650 }
2651
2652 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
2653 "unknown \"%V\" variable", &v[i].name);
2654
2655 return NGX_ERROR;
2656 2652
2657 next: 2653 next:
2658 continue; 2654 continue;
2659 } 2655 }
2660 2656