comparison src/http/modules/ngx_http_proxy_module.c @ 6051:d97e6be2d292

Proxy: proxy_request_buffering chunked support.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 23 Mar 2015 21:09:19 +0300
parents a08fad30aeac
children 24ccec3c4a87
comparison
equal deleted inserted replaced
6050:a08fad30aeac 6051:d97e6be2d292
108 ngx_http_status_t status; 108 ngx_http_status_t status;
109 ngx_http_chunked_t chunked; 109 ngx_http_chunked_t chunked;
110 ngx_http_proxy_vars_t vars; 110 ngx_http_proxy_vars_t vars;
111 off_t internal_body_length; 111 off_t internal_body_length;
112 112
113 ngx_uint_t head; /* unsigned head:1 */ 113 ngx_chain_t *free;
114 ngx_chain_t *busy;
115
116 unsigned head:1;
117 unsigned internal_chunked:1;
118 unsigned header_sent:1;
114 } ngx_http_proxy_ctx_t; 119 } ngx_http_proxy_ctx_t;
115 120
116 121
117 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, 122 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
118 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf); 123 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
119 #if (NGX_HTTP_CACHE) 124 #if (NGX_HTTP_CACHE)
120 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); 125 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
121 #endif 126 #endif
122 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); 127 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
123 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); 128 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
129 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
124 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); 130 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
125 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); 131 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
126 static ngx_int_t ngx_http_proxy_input_filter_init(void *data); 132 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
127 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, 133 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
128 ngx_buf_t *buf); 134 ngx_buf_t *buf);
143 static ngx_int_t 149 static ngx_int_t
144 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, 150 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
145 ngx_http_variable_value_t *v, uintptr_t data); 151 ngx_http_variable_value_t *v, uintptr_t data);
146 static ngx_int_t 152 static ngx_int_t
147 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, 153 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
154 ngx_http_variable_value_t *v, uintptr_t data);
155 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
148 ngx_http_variable_value_t *v, uintptr_t data); 156 ngx_http_variable_value_t *v, uintptr_t data);
149 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, 157 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
150 ngx_table_elt_t *h, size_t prefix); 158 ngx_table_elt_t *h, size_t prefix);
151 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, 159 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
152 ngx_table_elt_t *h); 160 ngx_table_elt_t *h);
726 734
727 static ngx_keyval_t ngx_http_proxy_headers[] = { 735 static ngx_keyval_t ngx_http_proxy_headers[] = {
728 { ngx_string("Host"), ngx_string("$proxy_host") }, 736 { ngx_string("Host"), ngx_string("$proxy_host") },
729 { ngx_string("Connection"), ngx_string("close") }, 737 { ngx_string("Connection"), ngx_string("close") },
730 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, 738 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
739 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
731 { ngx_string("TE"), ngx_string("") }, 740 { ngx_string("TE"), ngx_string("") },
732 { ngx_string("Transfer-Encoding"), ngx_string("") },
733 { ngx_string("Keep-Alive"), ngx_string("") }, 741 { ngx_string("Keep-Alive"), ngx_string("") },
734 { ngx_string("Expect"), ngx_string("") }, 742 { ngx_string("Expect"), ngx_string("") },
735 { ngx_string("Upgrade"), ngx_string("") }, 743 { ngx_string("Upgrade"), ngx_string("") },
736 { ngx_null_string, ngx_null_string } 744 { ngx_null_string, ngx_null_string }
737 }; 745 };
754 762
755 static ngx_keyval_t ngx_http_proxy_cache_headers[] = { 763 static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
756 { ngx_string("Host"), ngx_string("$proxy_host") }, 764 { ngx_string("Host"), ngx_string("$proxy_host") },
757 { ngx_string("Connection"), ngx_string("close") }, 765 { ngx_string("Connection"), ngx_string("close") },
758 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, 766 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
767 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
759 { ngx_string("TE"), ngx_string("") }, 768 { ngx_string("TE"), ngx_string("") },
760 { ngx_string("Transfer-Encoding"), ngx_string("") },
761 { ngx_string("Keep-Alive"), ngx_string("") }, 769 { ngx_string("Keep-Alive"), ngx_string("") },
762 { ngx_string("Expect"), ngx_string("") }, 770 { ngx_string("Expect"), ngx_string("") },
763 { ngx_string("Upgrade"), ngx_string("") }, 771 { ngx_string("Upgrade"), ngx_string("") },
764 { ngx_string("If-Modified-Since"), 772 { ngx_string("If-Modified-Since"),
765 ngx_string("$upstream_cache_last_modified") }, 773 ngx_string("$upstream_cache_last_modified") },
791 799
792 { ngx_string("proxy_internal_body_length"), NULL, 800 { ngx_string("proxy_internal_body_length"), NULL,
793 ngx_http_proxy_internal_body_length_variable, 0, 801 ngx_http_proxy_internal_body_length_variable, 0,
794 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, 802 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
795 803
804 { ngx_string("proxy_internal_chunked"), NULL,
805 ngx_http_proxy_internal_chunked_variable, 0,
806 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
807
796 { ngx_null_string, NULL, NULL, 0, 0, 0 } 808 { ngx_null_string, NULL, NULL, 0, 0, 0 }
797 }; 809 };
798 810
799 811
800 static ngx_path_init_t ngx_http_proxy_temp_path = { 812 static ngx_path_init_t ngx_http_proxy_temp_path = {
883 895
884 u->accel = 1; 896 u->accel = 1;
885 897
886 if (!plcf->upstream.request_buffering 898 if (!plcf->upstream.request_buffering
887 && plcf->body_values == NULL && plcf->upstream.pass_request_body 899 && plcf->body_values == NULL && plcf->upstream.pass_request_body
888 && !r->headers_in.chunked) 900 && (!r->headers_in.chunked
901 || plcf->http_version == NGX_HTTP_VERSION_11))
889 { 902 {
890 /* TODO: support chunked when using HTTP/1.1 */
891
892 r->request_body_no_buffering = 1; 903 r->request_body_no_buffering = 1;
893 } 904 }
894 905
895 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); 906 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
896 907
1208 } 1219 }
1209 1220
1210 ctx->internal_body_length = body_len; 1221 ctx->internal_body_length = body_len;
1211 len += body_len; 1222 len += body_len;
1212 1223
1224 } else if (r->headers_in.chunked && r->reading_body) {
1225 ctx->internal_body_length = -1;
1226 ctx->internal_chunked = 1;
1227
1213 } else { 1228 } else {
1214 ctx->internal_body_length = r->headers_in.content_length_n; 1229 ctx->internal_body_length = r->headers_in.content_length_n;
1215 } 1230 }
1216 1231
1217 le.ip = headers->lengths->elts; 1232 le.ip = headers->lengths->elts;
1410 (size_t) (b->last - b->pos), b->pos); 1425 (size_t) (b->last - b->pos), b->pos);
1411 1426
1412 if (r->request_body_no_buffering) { 1427 if (r->request_body_no_buffering) {
1413 1428
1414 u->request_bufs = cl; 1429 u->request_bufs = cl;
1430
1431 if (ctx->internal_chunked) {
1432 u->output.output_filter = ngx_http_proxy_body_output_filter;
1433 u->output.filter_ctx = r;
1434 }
1415 1435
1416 } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) { 1436 } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
1417 1437
1418 body = u->request_bufs; 1438 body = u->request_bufs;
1419 u->request_bufs = cl; 1439 u->request_bufs = cl;
1469 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter; 1489 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1470 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter; 1490 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1471 r->state = 0; 1491 r->state = 0;
1472 1492
1473 return NGX_OK; 1493 return NGX_OK;
1494 }
1495
1496
1497 static ngx_int_t
1498 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
1499 {
1500 ngx_http_request_t *r = data;
1501
1502 off_t size;
1503 u_char *chunk;
1504 ngx_int_t rc;
1505 ngx_buf_t *b;
1506 ngx_chain_t *out, *cl, *tl, **ll;
1507 ngx_http_proxy_ctx_t *ctx;
1508
1509 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1510 "proxy output filter");
1511
1512 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1513
1514 if (in == NULL) {
1515 out = in;
1516 goto out;
1517 }
1518
1519 out = NULL;
1520 ll = &out;
1521
1522 if (!ctx->header_sent) {
1523 /* first buffer contains headers, pass it unmodified */
1524
1525 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1526 "proxy output header");
1527
1528 ctx->header_sent = 1;
1529
1530 tl = ngx_alloc_chain_link(r->pool);
1531 if (tl == NULL) {
1532 return NGX_ERROR;
1533 }
1534
1535 tl->buf = in->buf;
1536 *ll = tl;
1537 ll = &tl->next;
1538
1539 in = in->next;
1540
1541 if (in == NULL) {
1542 tl->next = NULL;
1543 goto out;
1544 }
1545 }
1546
1547 size = 0;
1548 cl = in;
1549
1550 for ( ;; ) {
1551 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1552 "proxy output chunk: %d", ngx_buf_size(cl->buf));
1553
1554 size += ngx_buf_size(cl->buf);
1555
1556 if (cl->buf->flush
1557 || cl->buf->sync
1558 || ngx_buf_in_memory(cl->buf)
1559 || cl->buf->in_file)
1560 {
1561 tl = ngx_alloc_chain_link(r->pool);
1562 if (tl == NULL) {
1563 return NGX_ERROR;
1564 }
1565
1566 tl->buf = cl->buf;
1567 *ll = tl;
1568 ll = &tl->next;
1569 }
1570
1571 if (cl->next == NULL) {
1572 break;
1573 }
1574
1575 cl = cl->next;
1576 }
1577
1578 if (size) {
1579 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1580 if (tl == NULL) {
1581 return NGX_ERROR;
1582 }
1583
1584 b = tl->buf;
1585 chunk = b->start;
1586
1587 if (chunk == NULL) {
1588 /* the "0000000000000000" is 64-bit hexadecimal string */
1589
1590 chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
1591 if (chunk == NULL) {
1592 return NGX_ERROR;
1593 }
1594
1595 b->start = chunk;
1596 b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
1597 }
1598
1599 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1600 b->memory = 0;
1601 b->temporary = 1;
1602 b->pos = chunk;
1603 b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
1604
1605 tl->next = out;
1606 out = tl;
1607 }
1608
1609 if (cl->buf->last_buf) {
1610 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1611 if (tl == NULL) {
1612 return NGX_ERROR;
1613 }
1614
1615 b = tl->buf;
1616
1617 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1618 b->temporary = 0;
1619 b->memory = 1;
1620 b->last_buf = 1;
1621 b->pos = (u_char *) CRLF "0" CRLF CRLF;
1622 b->last = b->pos + 7;
1623
1624 cl->buf->last_buf = 0;
1625
1626 *ll = tl;
1627
1628 if (size == 0) {
1629 b->pos += 2;
1630 }
1631
1632 } else if (size > 0) {
1633 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1634 if (tl == NULL) {
1635 return NGX_ERROR;
1636 }
1637
1638 b = tl->buf;
1639
1640 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1641 b->temporary = 0;
1642 b->memory = 1;
1643 b->pos = (u_char *) CRLF;
1644 b->last = b->pos + 2;
1645
1646 *ll = tl;
1647
1648 } else {
1649 *ll = NULL;
1650 }
1651
1652 out:
1653
1654 rc = ngx_chain_writer(&r->upstream->writer, out);
1655
1656 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1657 (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
1658
1659 return rc;
1474 } 1660 }
1475 1661
1476 1662
1477 static ngx_int_t 1663 static ngx_int_t
1478 ngx_http_proxy_process_status_line(ngx_http_request_t *r) 1664 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
2260 if (v->data == NULL) { 2446 if (v->data == NULL) {
2261 return NGX_ERROR; 2447 return NGX_ERROR;
2262 } 2448 }
2263 2449
2264 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data; 2450 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2451
2452 return NGX_OK;
2453 }
2454
2455
2456 static ngx_int_t
2457 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
2458 ngx_http_variable_value_t *v, uintptr_t data)
2459 {
2460 ngx_http_proxy_ctx_t *ctx;
2461
2462 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2463
2464 if (ctx == NULL || !ctx->internal_chunked) {
2465 v->not_found = 1;
2466 return NGX_OK;
2467 }
2468
2469 v->valid = 1;
2470 v->no_cacheable = 0;
2471 v->not_found = 0;
2472
2473 v->data = (u_char *) "chunked";
2474 v->len = sizeof("chunked") - 1;
2265 2475
2266 return NGX_OK; 2476 return NGX_OK;
2267 } 2477 }
2268 2478
2269 2479