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++) {