Mercurial > hg > nginx-mail
comparison src/http/ngx_http_variables.c @ 665:0b460e61bdcd default tip
Merge with nginx 1.0.0.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 25 Apr 2011 04:22:17 +0400 |
parents | 8214eaef3530 |
children |
comparison
equal
deleted
inserted
replaced
572:06419a2298a9 | 665:0b460e61bdcd |
---|---|
11 | 11 |
12 | 12 |
13 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, | 13 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, |
14 ngx_http_variable_value_t *v, uintptr_t data); | 14 ngx_http_variable_value_t *v, uintptr_t data); |
15 static void ngx_http_variable_request_set(ngx_http_request_t *r, | 15 static void ngx_http_variable_request_set(ngx_http_request_t *r, |
16 ngx_http_variable_value_t *v, uintptr_t data); | |
17 static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, | |
16 ngx_http_variable_value_t *v, uintptr_t data); | 18 ngx_http_variable_value_t *v, uintptr_t data); |
17 static void ngx_http_variable_request_set_size(ngx_http_request_t *r, | 19 static void ngx_http_variable_request_set_size(ngx_http_request_t *r, |
18 ngx_http_variable_value_t *v, uintptr_t data); | 20 ngx_http_variable_value_t *v, uintptr_t data); |
19 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, | 21 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, |
20 ngx_http_variable_value_t *v, uintptr_t data); | 22 ngx_http_variable_value_t *v, uintptr_t data); |
192 NGX_HTTP_VAR_NOCACHEABLE, 0 }, | 194 NGX_HTTP_VAR_NOCACHEABLE, 0 }, |
193 | 195 |
194 { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 }, | 196 { ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 }, |
195 | 197 |
196 { ngx_string("request_method"), NULL, | 198 { ngx_string("request_method"), NULL, |
197 ngx_http_variable_request_method, 0, 0, 0 }, | 199 ngx_http_variable_request_method, 0, |
200 NGX_HTTP_VAR_NOCACHEABLE, 0 }, | |
198 | 201 |
199 { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 }, | 202 { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 }, |
200 | 203 |
201 { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent, | 204 { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent, |
202 0, 0, 0 }, | 205 0, 0, 0 }, |
236 | 239 |
237 { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers, | 240 { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers, |
238 offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 }, | 241 offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 }, |
239 | 242 |
240 { ngx_string("limit_rate"), ngx_http_variable_request_set_size, | 243 { ngx_string("limit_rate"), ngx_http_variable_request_set_size, |
241 ngx_http_variable_request, | 244 ngx_http_variable_request_get_size, |
242 offsetof(ngx_http_request_t, limit_rate), | 245 offsetof(ngx_http_request_t, limit_rate), |
243 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, | 246 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, |
244 | 247 |
245 { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version, | 248 { ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version, |
246 0, 0, 0 }, | 249 0, 0, 0 }, |
436 return ngx_http_get_indexed_variable(r, index); | 439 return ngx_http_get_indexed_variable(r, index); |
437 } | 440 } |
438 | 441 |
439 | 442 |
440 ngx_http_variable_value_t * | 443 ngx_http_variable_value_t * |
441 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key, | 444 ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key) |
442 ngx_uint_t nowarn) | |
443 { | 445 { |
444 ngx_http_variable_t *v; | 446 ngx_http_variable_t *v; |
445 ngx_http_variable_value_t *vv; | 447 ngx_http_variable_value_t *vv; |
446 ngx_http_core_main_conf_t *cmcf; | 448 ngx_http_core_main_conf_t *cmcf; |
447 | 449 |
449 | 451 |
450 v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); | 452 v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len); |
451 | 453 |
452 if (v) { | 454 if (v) { |
453 if (v->flags & NGX_HTTP_VAR_INDEXED) { | 455 if (v->flags & NGX_HTTP_VAR_INDEXED) { |
454 return ngx_http_get_indexed_variable(r, v->index); | 456 return ngx_http_get_flushed_variable(r, v->index); |
455 | 457 |
456 } else { | 458 } else { |
457 | 459 |
458 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); | 460 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); |
459 | 461 |
490 } | 492 } |
491 | 493 |
492 return NULL; | 494 return NULL; |
493 } | 495 } |
494 | 496 |
495 if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) { | 497 if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) { |
496 | 498 |
497 if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) | 499 if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) |
498 == NGX_OK) | 500 == NGX_OK) |
499 { | 501 { |
500 return vv; | 502 return vv; |
520 | 522 |
521 return NULL; | 523 return NULL; |
522 } | 524 } |
523 | 525 |
524 vv->not_found = 1; | 526 vv->not_found = 1; |
525 | |
526 if (nowarn == 0) { | |
527 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
528 "unknown \"%V\" variable", name); | |
529 } | |
530 | 527 |
531 return vv; | 528 return vv; |
532 } | 529 } |
533 | 530 |
534 | 531 |
566 s->len = v->len; | 563 s->len = v->len; |
567 s->data = v->data; | 564 s->data = v->data; |
568 } | 565 } |
569 | 566 |
570 | 567 |
568 static ngx_int_t | |
569 ngx_http_variable_request_get_size(ngx_http_request_t *r, | |
570 ngx_http_variable_value_t *v, uintptr_t data) | |
571 { | |
572 size_t *sp; | |
573 | |
574 sp = (size_t *) ((char *) r + data); | |
575 | |
576 v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN); | |
577 if (v->data == NULL) { | |
578 return NGX_ERROR; | |
579 } | |
580 | |
581 v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data; | |
582 v->valid = 1; | |
583 v->no_cacheable = 0; | |
584 v->not_found = 0; | |
585 | |
586 return NGX_OK; | |
587 } | |
588 | |
589 | |
571 static void | 590 static void |
572 ngx_http_variable_request_set_size(ngx_http_request_t *r, | 591 ngx_http_variable_request_set_size(ngx_http_request_t *r, |
573 ngx_http_variable_value_t *v, uintptr_t data) | 592 ngx_http_variable_value_t *v, uintptr_t data) |
574 { | 593 { |
575 ssize_t s, *sp; | 594 ssize_t s, *sp; |
885 | 904 |
886 v->len = sizeof(struct in6_addr); | 905 v->len = sizeof(struct in6_addr); |
887 v->valid = 1; | 906 v->valid = 1; |
888 v->no_cacheable = 0; | 907 v->no_cacheable = 0; |
889 v->not_found = 0; | 908 v->not_found = 0; |
890 v->data = (u_char *) &sin6->sin6_addr; | 909 v->data = sin6->sin6_addr.s6_addr; |
891 | 910 |
892 break; | 911 break; |
893 #endif | 912 #endif |
894 | 913 |
895 default: /* AF_INET */ | 914 default: /* AF_INET */ |
1369 v->data = r->headers_out.location->value.data; | 1388 v->data = r->headers_out.location->value.data; |
1370 | 1389 |
1371 return NGX_OK; | 1390 return NGX_OK; |
1372 } | 1391 } |
1373 | 1392 |
1374 name.len = sizeof("sent_http_location") - 1; | 1393 ngx_str_set(&name, "sent_http_location"); |
1375 name.data = (u_char *) "sent_http_location"; | |
1376 | 1394 |
1377 return ngx_http_variable_unknown_header(v, &name, | 1395 return ngx_http_variable_unknown_header(v, &name, |
1378 &r->headers_out.headers.part, | 1396 &r->headers_out.headers.part, |
1379 sizeof("sent_http_") - 1); | 1397 sizeof("sent_http_") - 1); |
1380 } | 1398 } |
1638 v->not_found = 0; | 1656 v->not_found = 0; |
1639 v->data = p; | 1657 v->data = p; |
1640 | 1658 |
1641 return NGX_OK; | 1659 return NGX_OK; |
1642 } | 1660 } |
1661 | |
1662 | |
1663 void * | |
1664 ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, ngx_uint_t key, | |
1665 u_char *text, size_t len, ngx_str_t *match) | |
1666 { | |
1667 void *p; | |
1668 | |
1669 p = ngx_hash_find_combined(&map->hash, key, text, len); | |
1670 if (p) { | |
1671 return p; | |
1672 } | |
1673 | |
1674 #if (NGX_PCRE) | |
1675 | |
1676 if (len && map->nregex) { | |
1677 ngx_int_t n; | |
1678 ngx_uint_t i; | |
1679 ngx_http_map_regex_t *reg; | |
1680 | |
1681 reg = map->regex; | |
1682 | |
1683 for (i = 0; i < map->nregex; i++) { | |
1684 | |
1685 n = ngx_http_regex_exec(r, reg[i].regex, match); | |
1686 | |
1687 if (n == NGX_OK) { | |
1688 return reg[i].value; | |
1689 } | |
1690 | |
1691 if (n == NGX_DECLINED) { | |
1692 continue; | |
1693 } | |
1694 | |
1695 /* NGX_ERROR */ | |
1696 | |
1697 return NULL; | |
1698 } | |
1699 } | |
1700 | |
1701 #endif | |
1702 | |
1703 return NULL; | |
1704 } | |
1705 | |
1706 | |
1707 #if (NGX_PCRE) | |
1708 | |
1709 static ngx_int_t | |
1710 ngx_http_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v, | |
1711 uintptr_t data) | |
1712 { | |
1713 v->not_found = 1; | |
1714 return NGX_OK; | |
1715 } | |
1716 | |
1717 | |
1718 ngx_http_regex_t * | |
1719 ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) | |
1720 { | |
1721 u_char *p; | |
1722 size_t size; | |
1723 ngx_str_t name; | |
1724 ngx_uint_t i, n; | |
1725 ngx_http_variable_t *v; | |
1726 ngx_http_regex_t *re; | |
1727 ngx_http_regex_variable_t *rv; | |
1728 ngx_http_core_main_conf_t *cmcf; | |
1729 | |
1730 rc->pool = cf->pool; | |
1731 | |
1732 if (ngx_regex_compile(rc) != NGX_OK) { | |
1733 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err); | |
1734 return NULL; | |
1735 } | |
1736 | |
1737 re = ngx_pcalloc(cf->pool, sizeof(ngx_http_regex_t)); | |
1738 if (re == NULL) { | |
1739 return NULL; | |
1740 } | |
1741 | |
1742 re->regex = rc->regex; | |
1743 re->ncaptures = rc->captures; | |
1744 | |
1745 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
1746 cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures); | |
1747 | |
1748 n = (ngx_uint_t) rc->named_captures; | |
1749 | |
1750 if (n == 0) { | |
1751 return re; | |
1752 } | |
1753 | |
1754 rv = ngx_palloc(rc->pool, n * sizeof(ngx_http_regex_variable_t)); | |
1755 if (rv == NULL) { | |
1756 return NULL; | |
1757 } | |
1758 | |
1759 re->variables = rv; | |
1760 re->nvariables = n; | |
1761 re->name = rc->pattern; | |
1762 | |
1763 size = rc->name_size; | |
1764 p = rc->names; | |
1765 | |
1766 for (i = 0; i < n; i++) { | |
1767 rv[i].capture = 2 * ((p[0] << 8) + p[1]); | |
1768 | |
1769 name.data = &p[2]; | |
1770 name.len = ngx_strlen(name.data); | |
1771 | |
1772 v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); | |
1773 if (v == NULL) { | |
1774 return NULL; | |
1775 } | |
1776 | |
1777 rv[i].index = ngx_http_get_variable_index(cf, &name); | |
1778 if (rv[i].index == NGX_ERROR) { | |
1779 return NULL; | |
1780 } | |
1781 | |
1782 v->get_handler = ngx_http_variable_not_found; | |
1783 | |
1784 p += size; | |
1785 } | |
1786 | |
1787 return re; | |
1788 } | |
1789 | |
1790 | |
1791 ngx_int_t | |
1792 ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s) | |
1793 { | |
1794 ngx_int_t rc, index; | |
1795 ngx_uint_t i, n, len; | |
1796 ngx_http_variable_value_t *vv; | |
1797 ngx_http_core_main_conf_t *cmcf; | |
1798 | |
1799 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
1800 | |
1801 if (re->ncaptures) { | |
1802 len = cmcf->ncaptures; | |
1803 | |
1804 if (r->captures == NULL) { | |
1805 r->captures = ngx_palloc(r->pool, len * sizeof(int)); | |
1806 if (r->captures == NULL) { | |
1807 return NGX_ERROR; | |
1808 } | |
1809 } | |
1810 | |
1811 } else { | |
1812 len = 0; | |
1813 } | |
1814 | |
1815 rc = ngx_regex_exec(re->regex, s, r->captures, len); | |
1816 | |
1817 if (rc == NGX_REGEX_NO_MATCHED) { | |
1818 return NGX_DECLINED; | |
1819 } | |
1820 | |
1821 if (rc < 0) { | |
1822 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
1823 ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", | |
1824 rc, s, &re->name); | |
1825 return NGX_ERROR; | |
1826 } | |
1827 | |
1828 for (i = 0; i < re->nvariables; i++) { | |
1829 | |
1830 n = re->variables[i].capture; | |
1831 index = re->variables[i].index; | |
1832 vv = &r->variables[index]; | |
1833 | |
1834 vv->len = r->captures[n + 1] - r->captures[n]; | |
1835 vv->valid = 1; | |
1836 vv->no_cacheable = 0; | |
1837 vv->not_found = 0; | |
1838 vv->data = &s->data[r->captures[n]]; | |
1839 | |
1840 #if (NGX_DEBUG) | |
1841 { | |
1842 ngx_http_variable_t *v; | |
1843 | |
1844 v = cmcf->variables.elts; | |
1845 | |
1846 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1847 "http regex set $%V to \"%*s\"", | |
1848 &v[index].name, vv->len, vv->data); | |
1849 } | |
1850 #endif | |
1851 } | |
1852 | |
1853 r->ncaptures = rc * 2; | |
1854 r->captures_data = s->data; | |
1855 | |
1856 return NGX_OK; | |
1857 } | |
1858 | |
1859 #endif | |
1643 | 1860 |
1644 | 1861 |
1645 ngx_int_t | 1862 ngx_int_t |
1646 ngx_http_variables_add_core_vars(ngx_conf_t *cf) | 1863 ngx_http_variables_add_core_vars(ngx_conf_t *cf) |
1647 { | 1864 { |
1755 } | 1972 } |
1756 | 1973 |
1757 if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) { | 1974 if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) { |
1758 v[i].get_handler = ngx_http_variable_argument; | 1975 v[i].get_handler = ngx_http_variable_argument; |
1759 v[i].data = (uintptr_t) &v[i].name; | 1976 v[i].data = (uintptr_t) &v[i].name; |
1977 v[i].flags = NGX_HTTP_VAR_NOCACHEABLE; | |
1760 | 1978 |
1761 continue; | 1979 continue; |
1762 } | 1980 } |
1763 | 1981 |
1764 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | 1982 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, |
1797 | 2015 |
1798 cmcf->variables_keys = NULL; | 2016 cmcf->variables_keys = NULL; |
1799 | 2017 |
1800 return NGX_OK; | 2018 return NGX_OK; |
1801 } | 2019 } |
1802 | |
1803 | |
1804 void | |
1805 ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp, | |
1806 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) | |
1807 { | |
1808 ngx_rbtree_node_t **p; | |
1809 ngx_http_variable_value_node_t *vvn, *vvt; | |
1810 | |
1811 for ( ;; ) { | |
1812 | |
1813 vvn = (ngx_http_variable_value_node_t *) node; | |
1814 vvt = (ngx_http_variable_value_node_t *) temp; | |
1815 | |
1816 if (node->key != temp->key) { | |
1817 | |
1818 p = (node->key < temp->key) ? &temp->left : &temp->right; | |
1819 | |
1820 } else if (vvn->len != vvt->len) { | |
1821 | |
1822 p = (vvn->len < vvt->len) ? &temp->left : &temp->right; | |
1823 | |
1824 } else { | |
1825 p = (ngx_memcmp(vvn->value->data, vvt->value->data, vvn->len) < 0) | |
1826 ? &temp->left : &temp->right; | |
1827 } | |
1828 | |
1829 if (*p == sentinel) { | |
1830 break; | |
1831 } | |
1832 | |
1833 temp = *p; | |
1834 } | |
1835 | |
1836 *p = node; | |
1837 node->parent = temp; | |
1838 node->left = sentinel; | |
1839 node->right = sentinel; | |
1840 ngx_rbt_red(node); | |
1841 } | |
1842 | |
1843 | |
1844 ngx_http_variable_value_t * | |
1845 ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, | |
1846 uint32_t hash) | |
1847 { | |
1848 ngx_int_t rc; | |
1849 ngx_rbtree_node_t *node, *sentinel; | |
1850 ngx_http_variable_value_node_t *vvn; | |
1851 | |
1852 node = rbtree->root; | |
1853 sentinel = rbtree->sentinel; | |
1854 | |
1855 while (node != sentinel) { | |
1856 | |
1857 vvn = (ngx_http_variable_value_node_t *) node; | |
1858 | |
1859 if (hash != node->key) { | |
1860 node = (hash < node->key) ? node->left : node->right; | |
1861 continue; | |
1862 } | |
1863 | |
1864 if (val->len != vvn->len) { | |
1865 node = (val->len < vvn->len) ? node->left : node->right; | |
1866 continue; | |
1867 } | |
1868 | |
1869 rc = ngx_memcmp(val->data, vvn->value->data, val->len); | |
1870 | |
1871 if (rc < 0) { | |
1872 node = node->left; | |
1873 continue; | |
1874 } | |
1875 | |
1876 if (rc > 0) { | |
1877 node = node->right; | |
1878 continue; | |
1879 } | |
1880 | |
1881 return vvn->value; | |
1882 } | |
1883 | |
1884 return NULL; | |
1885 } |