Mercurial > hg > nginx
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 |