Klaus Demo nginx / 756997b
Proxy: proxy_request_buffering chunked support. Maxim Dounin 7 years ago
1 changed file(s) with 216 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
109109 ngx_http_proxy_vars_t vars;
110110 off_t internal_body_length;
111111
112 ngx_uint_t head; /* unsigned head:1 */
112 ngx_chain_t *free;
113 ngx_chain_t *busy;
114
115 unsigned head:1;
116 unsigned internal_chunked:1;
117 unsigned header_sent:1;
113118 } ngx_http_proxy_ctx_t;
114119
115120
120125 #endif
121126 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
122127 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
128 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
123129 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
124130 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
125131 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
144150 ngx_http_variable_value_t *v, uintptr_t data);
145151 static ngx_int_t
146152 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
153 ngx_http_variable_value_t *v, uintptr_t data);
154 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
147155 ngx_http_variable_value_t *v, uintptr_t data);
148156 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
149157 ngx_table_elt_t *h, size_t prefix);
727735 { ngx_string("Host"), ngx_string("$proxy_host") },
728736 { ngx_string("Connection"), ngx_string("close") },
729737 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
738 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
730739 { ngx_string("TE"), ngx_string("") },
731 { ngx_string("Transfer-Encoding"), ngx_string("") },
732740 { ngx_string("Keep-Alive"), ngx_string("") },
733741 { ngx_string("Expect"), ngx_string("") },
734742 { ngx_string("Upgrade"), ngx_string("") },
755763 { ngx_string("Host"), ngx_string("$proxy_host") },
756764 { ngx_string("Connection"), ngx_string("close") },
757765 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
766 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
758767 { ngx_string("TE"), ngx_string("") },
759 { ngx_string("Transfer-Encoding"), ngx_string("") },
760768 { ngx_string("Keep-Alive"), ngx_string("") },
761769 { ngx_string("Expect"), ngx_string("") },
762770 { ngx_string("Upgrade"), ngx_string("") },
792800 ngx_http_proxy_internal_body_length_variable, 0,
793801 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
794802
803 { ngx_string("proxy_internal_chunked"), NULL,
804 ngx_http_proxy_internal_chunked_variable, 0,
805 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
806
795807 { ngx_null_string, NULL, NULL, 0, 0, 0 }
796808 };
797809
884896
885897 if (!plcf->upstream.request_buffering
886898 && plcf->body_values == NULL && plcf->upstream.pass_request_body
887 && !r->headers_in.chunked)
899 && (!r->headers_in.chunked
900 || plcf->http_version == NGX_HTTP_VERSION_11))
888901 {
889 /* TODO: support chunked when using HTTP/1.1 */
890
891902 r->request_body_no_buffering = 1;
892903 }
893904
12091220 ctx->internal_body_length = body_len;
12101221 len += body_len;
12111222
1223 } else if (r->headers_in.chunked && r->reading_body) {
1224 ctx->internal_body_length = -1;
1225 ctx->internal_chunked = 1;
1226
12121227 } else {
12131228 ctx->internal_body_length = r->headers_in.content_length_n;
12141229 }
14111426 if (r->request_body_no_buffering) {
14121427
14131428 u->request_bufs = cl;
1429
1430 if (ctx->internal_chunked) {
1431 u->output.output_filter = ngx_http_proxy_body_output_filter;
1432 u->output.filter_ctx = r;
1433 }
14141434
14151435 } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
14161436
14701490 r->state = 0;
14711491
14721492 return NGX_OK;
1493 }
1494
1495
1496 static ngx_int_t
1497 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
1498 {
1499 ngx_http_request_t *r = data;
1500
1501 off_t size;
1502 u_char *chunk;
1503 ngx_int_t rc;
1504 ngx_buf_t *b;
1505 ngx_chain_t *out, *cl, *tl, **ll;
1506 ngx_http_proxy_ctx_t *ctx;
1507
1508 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1509 "proxy output filter");
1510
1511 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1512
1513 if (in == NULL) {
1514 out = in;
1515 goto out;
1516 }
1517
1518 out = NULL;
1519 ll = &out;
1520
1521 if (!ctx->header_sent) {
1522 /* first buffer contains headers, pass it unmodified */
1523
1524 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1525 "proxy output header");
1526
1527 ctx->header_sent = 1;
1528
1529 tl = ngx_alloc_chain_link(r->pool);
1530 if (tl == NULL) {
1531 return NGX_ERROR;
1532 }
1533
1534 tl->buf = in->buf;
1535 *ll = tl;
1536 ll = &tl->next;
1537
1538 in = in->next;
1539
1540 if (in == NULL) {
1541 tl->next = NULL;
1542 goto out;
1543 }
1544 }
1545
1546 size = 0;
1547 cl = in;
1548
1549 for ( ;; ) {
1550 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1551 "proxy output chunk: %d", ngx_buf_size(cl->buf));
1552
1553 size += ngx_buf_size(cl->buf);
1554
1555 if (cl->buf->flush
1556 || cl->buf->sync
1557 || ngx_buf_in_memory(cl->buf)
1558 || cl->buf->in_file)
1559 {
1560 tl = ngx_alloc_chain_link(r->pool);
1561 if (tl == NULL) {
1562 return NGX_ERROR;
1563 }
1564
1565 tl->buf = cl->buf;
1566 *ll = tl;
1567 ll = &tl->next;
1568 }
1569
1570 if (cl->next == NULL) {
1571 break;
1572 }
1573
1574 cl = cl->next;
1575 }
1576
1577 if (size) {
1578 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1579 if (tl == NULL) {
1580 return NGX_ERROR;
1581 }
1582
1583 b = tl->buf;
1584 chunk = b->start;
1585
1586 if (chunk == NULL) {
1587 /* the "0000000000000000" is 64-bit hexadecimal string */
1588
1589 chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
1590 if (chunk == NULL) {
1591 return NGX_ERROR;
1592 }
1593
1594 b->start = chunk;
1595 b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
1596 }
1597
1598 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1599 b->memory = 0;
1600 b->temporary = 1;
1601 b->pos = chunk;
1602 b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
1603
1604 tl->next = out;
1605 out = tl;
1606 }
1607
1608 if (cl->buf->last_buf) {
1609 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1610 if (tl == NULL) {
1611 return NGX_ERROR;
1612 }
1613
1614 b = tl->buf;
1615
1616 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1617 b->temporary = 0;
1618 b->memory = 1;
1619 b->last_buf = 1;
1620 b->pos = (u_char *) CRLF "0" CRLF CRLF;
1621 b->last = b->pos + 7;
1622
1623 cl->buf->last_buf = 0;
1624
1625 *ll = tl;
1626
1627 if (size == 0) {
1628 b->pos += 2;
1629 }
1630
1631 } else if (size > 0) {
1632 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1633 if (tl == NULL) {
1634 return NGX_ERROR;
1635 }
1636
1637 b = tl->buf;
1638
1639 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1640 b->temporary = 0;
1641 b->memory = 1;
1642 b->pos = (u_char *) CRLF;
1643 b->last = b->pos + 2;
1644
1645 *ll = tl;
1646
1647 } else {
1648 *ll = NULL;
1649 }
1650
1651 out:
1652
1653 rc = ngx_chain_writer(&r->upstream->writer, out);
1654
1655 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1656 (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
1657
1658 return rc;
14731659 }
14741660
14751661
22612447 }
22622448
22632449 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2450
2451 return NGX_OK;
2452 }
2453
2454
2455 static ngx_int_t
2456 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
2457 ngx_http_variable_value_t *v, uintptr_t data)
2458 {
2459 ngx_http_proxy_ctx_t *ctx;
2460
2461 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2462
2463 if (ctx == NULL || !ctx->internal_chunked) {
2464 v->not_found = 1;
2465 return NGX_OK;
2466 }
2467
2468 v->valid = 1;
2469 v->no_cacheable = 0;
2470 v->not_found = 0;
2471
2472 v->data = (u_char *) "chunked";
2473 v->len = sizeof("chunked") - 1;
22642474
22652475 return NGX_OK;
22662476 }