Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_proxy_module.c @ 692:6db6e93f55ee NGINX_1_3_9
nginx 1.3.9
*) Feature: support for chunked transfer encoding while reading client
request body.
*) Feature: the $request_time and $msec variables can now be used not
only in the "log_format" directive.
*) Bugfix: cache manager and cache loader processes might not be able to
start if more than 512 listen sockets were used.
*) Bugfix: in the ngx_http_dav_module.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Tue, 27 Nov 2012 00:00:00 +0400 |
parents | f41d4b305d22 |
children | 88a1b4797f2e |
comparison
equal
deleted
inserted
replaced
691:acfd484db0ca | 692:6db6e93f55ee |
---|---|
79 } ngx_http_proxy_loc_conf_t; | 79 } ngx_http_proxy_loc_conf_t; |
80 | 80 |
81 | 81 |
82 typedef struct { | 82 typedef struct { |
83 ngx_http_status_t status; | 83 ngx_http_status_t status; |
84 ngx_http_chunked_t chunked; | |
84 ngx_http_proxy_vars_t vars; | 85 ngx_http_proxy_vars_t vars; |
85 size_t internal_body_length; | 86 off_t internal_body_length; |
86 | |
87 ngx_uint_t state; | |
88 off_t size; | |
89 off_t length; | |
90 | 87 |
91 ngx_uint_t head; /* unsigned head:1 */ | 88 ngx_uint_t head; /* unsigned head:1 */ |
92 } ngx_http_proxy_ctx_t; | 89 } ngx_http_proxy_ctx_t; |
93 | 90 |
94 | 91 |
556 | 553 |
557 | 554 |
558 static ngx_keyval_t ngx_http_proxy_headers[] = { | 555 static ngx_keyval_t ngx_http_proxy_headers[] = { |
559 { ngx_string("Host"), ngx_string("$proxy_host") }, | 556 { ngx_string("Host"), ngx_string("$proxy_host") }, |
560 { ngx_string("Connection"), ngx_string("close") }, | 557 { ngx_string("Connection"), ngx_string("close") }, |
558 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, | |
559 { ngx_string("Transfer-Encoding"), ngx_string("") }, | |
561 { ngx_string("Keep-Alive"), ngx_string("") }, | 560 { ngx_string("Keep-Alive"), ngx_string("") }, |
562 { ngx_string("Expect"), ngx_string("") }, | 561 { ngx_string("Expect"), ngx_string("") }, |
563 { ngx_string("Upgrade"), ngx_string("") }, | 562 { ngx_string("Upgrade"), ngx_string("") }, |
564 { ngx_null_string, ngx_null_string } | 563 { ngx_null_string, ngx_null_string } |
565 }; | 564 }; |
581 #if (NGX_HTTP_CACHE) | 580 #if (NGX_HTTP_CACHE) |
582 | 581 |
583 static ngx_keyval_t ngx_http_proxy_cache_headers[] = { | 582 static ngx_keyval_t ngx_http_proxy_cache_headers[] = { |
584 { ngx_string("Host"), ngx_string("$proxy_host") }, | 583 { ngx_string("Host"), ngx_string("$proxy_host") }, |
585 { ngx_string("Connection"), ngx_string("close") }, | 584 { ngx_string("Connection"), ngx_string("close") }, |
585 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, | |
586 { ngx_string("Transfer-Encoding"), ngx_string("") }, | |
586 { ngx_string("Keep-Alive"), ngx_string("") }, | 587 { ngx_string("Keep-Alive"), ngx_string("") }, |
587 { ngx_string("Expect"), ngx_string("") }, | 588 { ngx_string("Expect"), ngx_string("") }, |
588 { ngx_string("Upgrade"), ngx_string("") }, | 589 { ngx_string("Upgrade"), ngx_string("") }, |
589 { ngx_string("If-Modified-Since"), ngx_string("") }, | 590 { ngx_string("If-Modified-Since"), ngx_string("") }, |
590 { ngx_string("If-Unmodified-Since"), ngx_string("") }, | 591 { ngx_string("If-Unmodified-Since"), ngx_string("") }, |
1004 body_len += lcode(&le); | 1005 body_len += lcode(&le); |
1005 } | 1006 } |
1006 | 1007 |
1007 ctx->internal_body_length = body_len; | 1008 ctx->internal_body_length = body_len; |
1008 len += body_len; | 1009 len += body_len; |
1010 | |
1011 } else { | |
1012 ctx->internal_body_length = r->headers_in.content_length_n; | |
1009 } | 1013 } |
1010 | 1014 |
1011 le.ip = plcf->headers_set_len->elts; | 1015 le.ip = plcf->headers_set_len->elts; |
1012 le.request = r; | 1016 le.request = r; |
1013 le.flushed = 1; | 1017 le.flushed = 1; |
1250 | 1254 |
1251 ctx->status.code = 0; | 1255 ctx->status.code = 0; |
1252 ctx->status.count = 0; | 1256 ctx->status.count = 0; |
1253 ctx->status.start = NULL; | 1257 ctx->status.start = NULL; |
1254 ctx->status.end = NULL; | 1258 ctx->status.end = NULL; |
1255 ctx->state = 0; | 1259 ctx->chunked.state = 0; |
1256 | 1260 |
1257 r->upstream->process_header = ngx_http_proxy_process_status_line; | 1261 r->upstream->process_header = ngx_http_proxy_process_status_line; |
1258 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter; | 1262 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter; |
1259 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter; | 1263 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter; |
1260 r->state = 0; | 1264 r->state = 0; |
1615 | 1619 |
1616 return NGX_OK; | 1620 return NGX_OK; |
1617 } | 1621 } |
1618 | 1622 |
1619 | 1623 |
1620 static ngx_inline ngx_int_t | |
1621 ngx_http_proxy_parse_chunked(ngx_http_request_t *r, ngx_buf_t *buf) | |
1622 { | |
1623 u_char *pos, ch, c; | |
1624 ngx_int_t rc; | |
1625 ngx_http_proxy_ctx_t *ctx; | |
1626 enum { | |
1627 sw_chunk_start = 0, | |
1628 sw_chunk_size, | |
1629 sw_chunk_extension, | |
1630 sw_chunk_extension_almost_done, | |
1631 sw_chunk_data, | |
1632 sw_after_data, | |
1633 sw_after_data_almost_done, | |
1634 sw_last_chunk_extension, | |
1635 sw_last_chunk_extension_almost_done, | |
1636 sw_trailer, | |
1637 sw_trailer_almost_done, | |
1638 sw_trailer_header, | |
1639 sw_trailer_header_almost_done | |
1640 } state; | |
1641 | |
1642 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
1643 | |
1644 if (ctx == NULL) { | |
1645 return NGX_ERROR; | |
1646 } | |
1647 | |
1648 state = ctx->state; | |
1649 | |
1650 if (state == sw_chunk_data && ctx->size == 0) { | |
1651 state = sw_after_data; | |
1652 } | |
1653 | |
1654 rc = NGX_AGAIN; | |
1655 | |
1656 for (pos = buf->pos; pos < buf->last; pos++) { | |
1657 | |
1658 ch = *pos; | |
1659 | |
1660 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1661 "http proxy chunked byte: %02Xd s:%d", ch, state); | |
1662 | |
1663 switch (state) { | |
1664 | |
1665 case sw_chunk_start: | |
1666 if (ch >= '0' && ch <= '9') { | |
1667 state = sw_chunk_size; | |
1668 ctx->size = ch - '0'; | |
1669 break; | |
1670 } | |
1671 | |
1672 c = (u_char) (ch | 0x20); | |
1673 | |
1674 if (c >= 'a' && c <= 'f') { | |
1675 state = sw_chunk_size; | |
1676 ctx->size = c - 'a' + 10; | |
1677 break; | |
1678 } | |
1679 | |
1680 goto invalid; | |
1681 | |
1682 case sw_chunk_size: | |
1683 if (ch >= '0' && ch <= '9') { | |
1684 ctx->size = ctx->size * 16 + (ch - '0'); | |
1685 break; | |
1686 } | |
1687 | |
1688 c = (u_char) (ch | 0x20); | |
1689 | |
1690 if (c >= 'a' && c <= 'f') { | |
1691 ctx->size = ctx->size * 16 + (c - 'a' + 10); | |
1692 break; | |
1693 } | |
1694 | |
1695 if (ctx->size == 0) { | |
1696 | |
1697 switch (ch) { | |
1698 case CR: | |
1699 state = sw_last_chunk_extension_almost_done; | |
1700 break; | |
1701 case LF: | |
1702 state = sw_trailer; | |
1703 break; | |
1704 case ';': | |
1705 case ' ': | |
1706 case '\t': | |
1707 state = sw_last_chunk_extension; | |
1708 break; | |
1709 default: | |
1710 goto invalid; | |
1711 } | |
1712 | |
1713 break; | |
1714 } | |
1715 | |
1716 switch (ch) { | |
1717 case CR: | |
1718 state = sw_chunk_extension_almost_done; | |
1719 break; | |
1720 case LF: | |
1721 state = sw_chunk_data; | |
1722 break; | |
1723 case ';': | |
1724 case ' ': | |
1725 case '\t': | |
1726 state = sw_chunk_extension; | |
1727 break; | |
1728 default: | |
1729 goto invalid; | |
1730 } | |
1731 | |
1732 break; | |
1733 | |
1734 case sw_chunk_extension: | |
1735 switch (ch) { | |
1736 case CR: | |
1737 state = sw_chunk_extension_almost_done; | |
1738 break; | |
1739 case LF: | |
1740 state = sw_chunk_data; | |
1741 } | |
1742 break; | |
1743 | |
1744 case sw_chunk_extension_almost_done: | |
1745 if (ch == LF) { | |
1746 state = sw_chunk_data; | |
1747 break; | |
1748 } | |
1749 goto invalid; | |
1750 | |
1751 case sw_chunk_data: | |
1752 rc = NGX_OK; | |
1753 goto data; | |
1754 | |
1755 case sw_after_data: | |
1756 switch (ch) { | |
1757 case CR: | |
1758 state = sw_after_data_almost_done; | |
1759 break; | |
1760 case LF: | |
1761 state = sw_chunk_start; | |
1762 } | |
1763 break; | |
1764 | |
1765 case sw_after_data_almost_done: | |
1766 if (ch == LF) { | |
1767 state = sw_chunk_start; | |
1768 break; | |
1769 } | |
1770 goto invalid; | |
1771 | |
1772 case sw_last_chunk_extension: | |
1773 switch (ch) { | |
1774 case CR: | |
1775 state = sw_last_chunk_extension_almost_done; | |
1776 break; | |
1777 case LF: | |
1778 state = sw_trailer; | |
1779 } | |
1780 break; | |
1781 | |
1782 case sw_last_chunk_extension_almost_done: | |
1783 if (ch == LF) { | |
1784 state = sw_trailer; | |
1785 break; | |
1786 } | |
1787 goto invalid; | |
1788 | |
1789 case sw_trailer: | |
1790 switch (ch) { | |
1791 case CR: | |
1792 state = sw_trailer_almost_done; | |
1793 break; | |
1794 case LF: | |
1795 goto done; | |
1796 default: | |
1797 state = sw_trailer_header; | |
1798 } | |
1799 break; | |
1800 | |
1801 case sw_trailer_almost_done: | |
1802 if (ch == LF) { | |
1803 goto done; | |
1804 } | |
1805 goto invalid; | |
1806 | |
1807 case sw_trailer_header: | |
1808 switch (ch) { | |
1809 case CR: | |
1810 state = sw_trailer_header_almost_done; | |
1811 break; | |
1812 case LF: | |
1813 state = sw_trailer; | |
1814 } | |
1815 break; | |
1816 | |
1817 case sw_trailer_header_almost_done: | |
1818 if (ch == LF) { | |
1819 state = sw_trailer; | |
1820 break; | |
1821 } | |
1822 goto invalid; | |
1823 | |
1824 } | |
1825 } | |
1826 | |
1827 data: | |
1828 | |
1829 ctx->state = state; | |
1830 buf->pos = pos; | |
1831 | |
1832 switch (state) { | |
1833 | |
1834 case sw_chunk_start: | |
1835 ctx->length = 3 /* "0" LF LF */; | |
1836 break; | |
1837 case sw_chunk_size: | |
1838 ctx->length = 2 /* LF LF */ | |
1839 + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0); | |
1840 break; | |
1841 case sw_chunk_extension: | |
1842 case sw_chunk_extension_almost_done: | |
1843 ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */; | |
1844 break; | |
1845 case sw_chunk_data: | |
1846 ctx->length = ctx->size + 4 /* LF "0" LF LF */; | |
1847 break; | |
1848 case sw_after_data: | |
1849 case sw_after_data_almost_done: | |
1850 ctx->length = 4 /* LF "0" LF LF */; | |
1851 break; | |
1852 case sw_last_chunk_extension: | |
1853 case sw_last_chunk_extension_almost_done: | |
1854 ctx->length = 2 /* LF LF */; | |
1855 break; | |
1856 case sw_trailer: | |
1857 case sw_trailer_almost_done: | |
1858 ctx->length = 1 /* LF */; | |
1859 break; | |
1860 case sw_trailer_header: | |
1861 case sw_trailer_header_almost_done: | |
1862 ctx->length = 2 /* LF LF */; | |
1863 break; | |
1864 | |
1865 } | |
1866 | |
1867 return rc; | |
1868 | |
1869 done: | |
1870 | |
1871 return NGX_DONE; | |
1872 | |
1873 invalid: | |
1874 | |
1875 return NGX_ERROR; | |
1876 } | |
1877 | |
1878 | |
1879 static ngx_int_t | 1624 static ngx_int_t |
1880 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) | 1625 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) |
1881 { | 1626 { |
1882 ngx_int_t rc; | 1627 ngx_int_t rc; |
1883 ngx_buf_t *b, **prev; | 1628 ngx_buf_t *b, **prev; |
1899 b = NULL; | 1644 b = NULL; |
1900 prev = &buf->shadow; | 1645 prev = &buf->shadow; |
1901 | 1646 |
1902 for ( ;; ) { | 1647 for ( ;; ) { |
1903 | 1648 |
1904 rc = ngx_http_proxy_parse_chunked(r, buf); | 1649 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked); |
1905 | 1650 |
1906 if (rc == NGX_OK) { | 1651 if (rc == NGX_OK) { |
1907 | 1652 |
1908 /* a chunk has been parsed successfully */ | 1653 /* a chunk has been parsed successfully */ |
1909 | 1654 |
1950 /* STUB */ b->num = buf->num; | 1695 /* STUB */ b->num = buf->num; |
1951 | 1696 |
1952 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, | 1697 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, |
1953 "input buf #%d %p", b->num, b->pos); | 1698 "input buf #%d %p", b->num, b->pos); |
1954 | 1699 |
1955 if (buf->last - buf->pos >= ctx->size) { | 1700 if (buf->last - buf->pos >= ctx->chunked.size) { |
1956 | 1701 |
1957 buf->pos += ctx->size; | 1702 buf->pos += ctx->chunked.size; |
1958 b->last = buf->pos; | 1703 b->last = buf->pos; |
1959 ctx->size = 0; | 1704 ctx->chunked.size = 0; |
1960 | 1705 |
1961 continue; | 1706 continue; |
1962 } | 1707 } |
1963 | 1708 |
1964 ctx->size -= buf->last - buf->pos; | 1709 ctx->chunked.size -= buf->last - buf->pos; |
1965 buf->pos = buf->last; | 1710 buf->pos = buf->last; |
1966 b->last = buf->last; | 1711 b->last = buf->last; |
1967 | 1712 |
1968 continue; | 1713 continue; |
1969 } | 1714 } |
1980 | 1725 |
1981 if (rc == NGX_AGAIN) { | 1726 if (rc == NGX_AGAIN) { |
1982 | 1727 |
1983 /* set p->length, minimal amount of data we want to see */ | 1728 /* set p->length, minimal amount of data we want to see */ |
1984 | 1729 |
1985 p->length = ctx->length; | 1730 p->length = ctx->chunked.length; |
1986 | 1731 |
1987 break; | 1732 break; |
1988 } | 1733 } |
1989 | 1734 |
1990 /* invalid response */ | 1735 /* invalid response */ |
1995 return NGX_ERROR; | 1740 return NGX_ERROR; |
1996 } | 1741 } |
1997 | 1742 |
1998 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1743 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1999 "http proxy chunked state %d, length %d", | 1744 "http proxy chunked state %d, length %d", |
2000 ctx->state, p->length); | 1745 ctx->chunked.state, p->length); |
2001 | 1746 |
2002 if (b) { | 1747 if (b) { |
2003 b->shadow = buf; | 1748 b->shadow = buf; |
2004 b->last_shadow = 1; | 1749 b->last_shadow = 1; |
2005 | 1750 |
2092 ll = &cl->next; | 1837 ll = &cl->next; |
2093 } | 1838 } |
2094 | 1839 |
2095 for ( ;; ) { | 1840 for ( ;; ) { |
2096 | 1841 |
2097 rc = ngx_http_proxy_parse_chunked(r, buf); | 1842 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked); |
2098 | 1843 |
2099 if (rc == NGX_OK) { | 1844 if (rc == NGX_OK) { |
2100 | 1845 |
2101 /* a chunk has been parsed successfully */ | 1846 /* a chunk has been parsed successfully */ |
2102 | 1847 |
2114 b->memory = 1; | 1859 b->memory = 1; |
2115 | 1860 |
2116 b->pos = buf->pos; | 1861 b->pos = buf->pos; |
2117 b->tag = u->output.tag; | 1862 b->tag = u->output.tag; |
2118 | 1863 |
2119 if (buf->last - buf->pos >= ctx->size) { | 1864 if (buf->last - buf->pos >= ctx->chunked.size) { |
2120 buf->pos += ctx->size; | 1865 buf->pos += ctx->chunked.size; |
2121 b->last = buf->pos; | 1866 b->last = buf->pos; |
2122 ctx->size = 0; | 1867 ctx->chunked.size = 0; |
2123 | 1868 |
2124 } else { | 1869 } else { |
2125 ctx->size -= buf->last - buf->pos; | 1870 ctx->chunked.size -= buf->last - buf->pos; |
2126 buf->pos = buf->last; | 1871 buf->pos = buf->last; |
2127 b->last = buf->last; | 1872 b->last = buf->last; |
2128 } | 1873 } |
2129 | 1874 |
2130 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1875 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2299 { | 2044 { |
2300 ngx_http_proxy_ctx_t *ctx; | 2045 ngx_http_proxy_ctx_t *ctx; |
2301 | 2046 |
2302 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | 2047 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); |
2303 | 2048 |
2304 if (ctx == NULL) { | 2049 if (ctx == NULL || ctx->internal_body_length < 0) { |
2305 v->not_found = 1; | 2050 v->not_found = 1; |
2306 return NGX_OK; | 2051 return NGX_OK; |
2307 } | 2052 } |
2308 | 2053 |
2309 v->valid = 1; | 2054 v->valid = 1; |
2310 v->no_cacheable = 0; | 2055 v->no_cacheable = 0; |
2311 v->not_found = 0; | 2056 v->not_found = 0; |
2312 | 2057 |
2313 v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN); | 2058 v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN); |
2314 | 2059 |
2315 if (v->data == NULL) { | 2060 if (v->data == NULL) { |
2316 return NGX_ERROR; | 2061 return NGX_ERROR; |
2317 } | 2062 } |
2318 | 2063 |
2319 v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data; | 2064 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data; |
2320 | 2065 |
2321 return NGX_OK; | 2066 return NGX_OK; |
2322 } | 2067 } |
2323 | 2068 |
2324 | 2069 |
3082 conf->headers_set_hash = prev->headers_set_hash; | 2827 conf->headers_set_hash = prev->headers_set_hash; |
3083 conf->headers_source = prev->headers_source; | 2828 conf->headers_source = prev->headers_source; |
3084 } | 2829 } |
3085 | 2830 |
3086 if (conf->headers_set_hash.buckets | 2831 if (conf->headers_set_hash.buckets |
3087 && ((conf->body_source.data == NULL) | |
3088 == (prev->body_source.data == NULL)) | |
3089 #if (NGX_HTTP_CACHE) | 2832 #if (NGX_HTTP_CACHE) |
3090 && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) | 2833 && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) |
3091 #endif | 2834 #endif |
3092 ) | 2835 ) |
3093 { | 2836 { |
3164 *s = *h; | 2907 *s = *h; |
3165 | 2908 |
3166 next: | 2909 next: |
3167 | 2910 |
3168 h++; | 2911 h++; |
3169 } | |
3170 | |
3171 if (conf->body_source.data) { | |
3172 s = ngx_array_push(&headers_merged); | |
3173 if (s == NULL) { | |
3174 return NGX_ERROR; | |
3175 } | |
3176 | |
3177 ngx_str_set(&s->key, "Content-Length"); | |
3178 ngx_str_set(&s->value, "$proxy_internal_body_length"); | |
3179 } | 2912 } |
3180 | 2913 |
3181 | 2914 |
3182 src = headers_merged.elts; | 2915 src = headers_merged.elts; |
3183 for (i = 0; i < headers_merged.nelts; i++) { | 2916 for (i = 0; i < headers_merged.nelts; i++) { |