comparison src/http/modules/ngx_http_proxy_module.c @ 640:eb208e0cf44d NGINX_1_1_4

nginx 1.1.4 *) Feature: the ngx_http_upstream_keepalive module. *) Feature: the "proxy_http_version" directive. *) Feature: the "fastcgi_keep_conn" directive. *) Feature: the "worker_aio_requests" directive. *) Bugfix: if nginx was built --with-file-aio it could not be run on Linux kernel which did not support AIO. *) Bugfix: in Linux AIO error processing. Thanks to Hagai Avrahami. *) Bugfix: reduced memory consumption for long-lived requests. *) Bugfix: the module ngx_http_mp4_module did not support 64-bit MP4 "co64" atom.
author Igor Sysoev <http://sysoev.ru>
date Tue, 20 Sep 2011 00:00:00 +0400
parents 23ef0645ea57
children d3cf6c6b0043
comparison
equal deleted inserted replaced
639:b516b4e38bc9 640:eb208e0cf44d
69 69
70 ngx_http_proxy_vars_t vars; 70 ngx_http_proxy_vars_t vars;
71 71
72 ngx_flag_t redirect; 72 ngx_flag_t redirect;
73 73
74 ngx_uint_t http_version;
75
74 ngx_uint_t headers_hash_max_size; 76 ngx_uint_t headers_hash_max_size;
75 ngx_uint_t headers_hash_bucket_size; 77 ngx_uint_t headers_hash_bucket_size;
76 } ngx_http_proxy_loc_conf_t; 78 } ngx_http_proxy_loc_conf_t;
77 79
78 80
79 typedef struct { 81 typedef struct {
80 ngx_http_status_t status; 82 ngx_http_status_t status;
81 ngx_http_proxy_vars_t vars; 83 ngx_http_proxy_vars_t vars;
82 size_t internal_body_length; 84 size_t internal_body_length;
85
86 ngx_uint_t state;
87 off_t size;
88 off_t length;
89
90 ngx_uint_t head; /* unsigned head:1 */
83 } ngx_http_proxy_ctx_t; 91 } ngx_http_proxy_ctx_t;
84 92
85 93
86 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, 94 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
87 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf); 95 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
90 #endif 98 #endif
91 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); 99 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
92 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); 100 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
93 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); 101 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
94 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); 102 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
103 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
104 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
105 ngx_buf_t *buf);
106 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
107 ngx_buf_t *buf);
108 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
109 ssize_t bytes);
110 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
111 ssize_t bytes);
95 static void ngx_http_proxy_abort_request(ngx_http_request_t *r); 112 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
96 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, 113 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
97 ngx_int_t rc); 114 ngx_int_t rc);
98 115
99 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r, 116 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
155 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, 172 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
156 { ngx_null_string, 0 } 173 { ngx_null_string, 0 }
157 }; 174 };
158 175
159 176
177 static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
178 { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
179 { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
180 { ngx_null_string, 0 }
181 };
182
183
160 ngx_module_t ngx_http_proxy_module; 184 ngx_module_t ngx_http_proxy_module;
161 185
162 186
163 static ngx_command_t ngx_http_proxy_commands[] = { 187 static ngx_command_t ngx_http_proxy_commands[] = {
164 188
429 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 453 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
430 ngx_conf_set_bitmask_slot, 454 ngx_conf_set_bitmask_slot,
431 NGX_HTTP_LOC_CONF_OFFSET, 455 NGX_HTTP_LOC_CONF_OFFSET,
432 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers), 456 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
433 &ngx_http_upstream_ignore_headers_masks }, 457 &ngx_http_upstream_ignore_headers_masks },
458
459 { ngx_string("proxy_http_version"),
460 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
461 ngx_conf_set_enum_slot,
462 NGX_HTTP_LOC_CONF_OFFSET,
463 offsetof(ngx_http_proxy_loc_conf_t, http_version),
464 &ngx_http_proxy_http_version },
434 465
435 #if (NGX_HTTP_SSL) 466 #if (NGX_HTTP_SSL)
436 467
437 { ngx_string("proxy_ssl_session_reuse"), 468 { ngx_string("proxy_ssl_session_reuse"),
438 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 469 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
477 NGX_MODULE_V1_PADDING 508 NGX_MODULE_V1_PADDING
478 }; 509 };
479 510
480 511
481 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; 512 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
513 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
482 514
483 515
484 static ngx_keyval_t ngx_http_proxy_headers[] = { 516 static ngx_keyval_t ngx_http_proxy_headers[] = {
485 { ngx_string("Host"), ngx_string("$proxy_host") }, 517 { ngx_string("Host"), ngx_string("$proxy_host") },
486 { ngx_string("Connection"), ngx_string("close") }, 518 { ngx_string("Connection"), ngx_string("close") },
487 { ngx_string("Keep-Alive"), ngx_string("") }, 519 { ngx_string("Keep-Alive"), ngx_string("") },
488 { ngx_string("Expect"), ngx_string("") }, 520 { ngx_string("Expect"), ngx_string("") },
521 { ngx_string("Upgrade"), ngx_string("") },
489 { ngx_null_string, ngx_null_string } 522 { ngx_null_string, ngx_null_string }
490 }; 523 };
491 524
492 525
493 static ngx_str_t ngx_http_proxy_hide_headers[] = { 526 static ngx_str_t ngx_http_proxy_hide_headers[] = {
608 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); 641 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
609 if (u->pipe == NULL) { 642 if (u->pipe == NULL) {
610 return NGX_HTTP_INTERNAL_SERVER_ERROR; 643 return NGX_HTTP_INTERNAL_SERVER_ERROR;
611 } 644 }
612 645
613 u->pipe->input_filter = ngx_event_pipe_copy_input_filter; 646 u->pipe->input_filter = ngx_http_proxy_copy_filter;
647 u->pipe->input_ctx = r;
648
649 u->input_filter_init = ngx_http_proxy_input_filter_init;
650 u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
651 u->input_filter_ctx = r;
614 652
615 u->accel = 1; 653 u->accel = 1;
616 654
617 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); 655 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
618 656
864 } else { 902 } else {
865 method = r->method_name; 903 method = r->method_name;
866 method.len++; 904 method.len++;
867 } 905 }
868 906
907 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
908
909 if (method.len == 5
910 && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
911 {
912 ctx->head = 1;
913 }
914
869 len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; 915 len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
870 916
871 escape = 0; 917 escape = 0;
872 loc_len = 0; 918 loc_len = 0;
873 unparsed_uri = 0; 919 unparsed_uri = 0;
874
875 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
876 920
877 if (plcf->proxy_lengths) { 921 if (plcf->proxy_lengths) {
878 uri_len = ctx->vars.uri.len; 922 uri_len = ctx->vars.uri.len;
879 923
880 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main) 924 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
1007 } 1051 }
1008 } 1052 }
1009 1053
1010 u->uri.len = b->last - u->uri.data; 1054 u->uri.len = b->last - u->uri.data;
1011 1055
1012 b->last = ngx_cpymem(b->last, ngx_http_proxy_version, 1056 if (plcf->http_version == NGX_HTTP_VERSION_11) {
1013 sizeof(ngx_http_proxy_version) - 1); 1057 b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1058 sizeof(ngx_http_proxy_version_11) - 1);
1059
1060 } else {
1061 b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1062 sizeof(ngx_http_proxy_version) - 1);
1063 }
1014 1064
1015 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); 1065 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1016 1066
1017 e.ip = plcf->headers_set->elts; 1067 e.ip = plcf->headers_set->elts;
1018 e.pos = b->last; 1068 e.pos = b->last;
1156 1206
1157 ctx->status.code = 0; 1207 ctx->status.code = 0;
1158 ctx->status.count = 0; 1208 ctx->status.count = 0;
1159 ctx->status.start = NULL; 1209 ctx->status.start = NULL;
1160 ctx->status.end = NULL; 1210 ctx->status.end = NULL;
1211 ctx->state = 0;
1161 1212
1162 r->upstream->process_header = ngx_http_proxy_process_status_line; 1213 r->upstream->process_header = ngx_http_proxy_process_status_line;
1214 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1215 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1163 r->state = 0; 1216 r->state = 0;
1164 1217
1165 return NGX_OK; 1218 return NGX_OK;
1166 } 1219 }
1167 1220
1208 } 1261 }
1209 #endif 1262 #endif
1210 1263
1211 r->http_version = NGX_HTTP_VERSION_9; 1264 r->http_version = NGX_HTTP_VERSION_9;
1212 u->state->status = NGX_HTTP_OK; 1265 u->state->status = NGX_HTTP_OK;
1266 u->headers_in.connection_close = 1;
1213 1267
1214 return NGX_OK; 1268 return NGX_OK;
1215 } 1269 }
1216 1270
1217 if (u->state) { 1271 if (u->state) {
1231 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len); 1285 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1232 1286
1233 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1287 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1234 "http proxy status %ui \"%V\"", 1288 "http proxy status %ui \"%V\"",
1235 u->headers_in.status_n, &u->headers_in.status_line); 1289 u->headers_in.status_n, &u->headers_in.status_line);
1290
1291 if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1292 u->headers_in.connection_close = 1;
1293 }
1236 1294
1237 u->process_header = ngx_http_proxy_process_header; 1295 u->process_header = ngx_http_proxy_process_header;
1238 1296
1239 return ngx_http_proxy_process_header(r); 1297 return ngx_http_proxy_process_header(r);
1240 } 1298 }
1243 static ngx_int_t 1301 static ngx_int_t
1244 ngx_http_proxy_process_header(ngx_http_request_t *r) 1302 ngx_http_proxy_process_header(ngx_http_request_t *r)
1245 { 1303 {
1246 ngx_int_t rc; 1304 ngx_int_t rc;
1247 ngx_table_elt_t *h; 1305 ngx_table_elt_t *h;
1306 ngx_http_upstream_t *u;
1307 ngx_http_proxy_ctx_t *ctx;
1248 ngx_http_upstream_header_t *hh; 1308 ngx_http_upstream_header_t *hh;
1249 ngx_http_upstream_main_conf_t *umcf; 1309 ngx_http_upstream_main_conf_t *umcf;
1250 1310
1251 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); 1311 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1252 1312
1338 ngx_str_set(&h->key, "Date"); 1398 ngx_str_set(&h->key, "Date");
1339 ngx_str_null(&h->value); 1399 ngx_str_null(&h->value);
1340 h->lowcase_key = (u_char *) "date"; 1400 h->lowcase_key = (u_char *) "date";
1341 } 1401 }
1342 1402
1403 /* clear content length if response is chunked */
1404
1405 u = r->upstream;
1406
1407 if (u->headers_in.chunked) {
1408 u->headers_in.content_length_n = -1;
1409 }
1410
1411 /*
1412 * set u->keepalive if response has no body; this allows to keep
1413 * connections alive in case of r->header_only or X-Accel-Redirect
1414 */
1415
1416 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1417
1418 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1419 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1420 || ctx->head
1421 || (!u->headers_in.chunked
1422 && u->headers_in.content_length_n == 0))
1423 {
1424 u->keepalive = !u->headers_in.connection_close;
1425 }
1426
1343 return NGX_OK; 1427 return NGX_OK;
1344 } 1428 }
1345 1429
1346 if (rc == NGX_AGAIN) { 1430 if (rc == NGX_AGAIN) {
1347 return NGX_AGAIN; 1431 return NGX_AGAIN;
1352 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1436 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1353 "upstream sent invalid header"); 1437 "upstream sent invalid header");
1354 1438
1355 return NGX_HTTP_UPSTREAM_INVALID_HEADER; 1439 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1356 } 1440 }
1441 }
1442
1443
1444 static ngx_int_t
1445 ngx_http_proxy_input_filter_init(void *data)
1446 {
1447 ngx_http_request_t *r = data;
1448 ngx_http_upstream_t *u;
1449 ngx_http_proxy_ctx_t *ctx;
1450
1451 u = r->upstream;
1452 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1453
1454 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1455 "http proxy filter init s:%d h:%d c:%d l:%O",
1456 u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1457 u->headers_in.content_length_n);
1458
1459 /* as per RFC2616, 4.4 Message Length */
1460
1461 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1462 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1463 || ctx->head)
1464 {
1465 /* 1xx, 204, and 304 and replies to HEAD requests */
1466 /* no 1xx since we don't send Expect and Upgrade */
1467
1468 u->pipe->length = 0;
1469 u->length = 0;
1470 u->keepalive = !u->headers_in.connection_close;
1471
1472 } else if (u->headers_in.chunked) {
1473 /* chunked */
1474
1475 u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1476 u->pipe->length = 3; /* "0" LF LF */
1477
1478 u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1479 u->length = -1;
1480
1481 } else if (u->headers_in.content_length_n == 0) {
1482 /* empty body: special case as filter won't be called */
1483
1484 u->pipe->length = 0;
1485 u->length = 0;
1486 u->keepalive = !u->headers_in.connection_close;
1487
1488 } else {
1489 /* content length or connection close */
1490
1491 u->pipe->length = u->headers_in.content_length_n;
1492 u->length = u->headers_in.content_length_n;
1493 }
1494
1495 return NGX_OK;
1496 }
1497
1498
1499 static ngx_int_t
1500 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1501 {
1502 ngx_buf_t *b;
1503 ngx_chain_t *cl;
1504 ngx_http_request_t *r;
1505
1506 if (buf->pos == buf->last) {
1507 return NGX_OK;
1508 }
1509
1510 if (p->free) {
1511 cl = p->free;
1512 b = cl->buf;
1513 p->free = cl->next;
1514 ngx_free_chain(p->pool, cl);
1515
1516 } else {
1517 b = ngx_alloc_buf(p->pool);
1518 if (b == NULL) {
1519 return NGX_ERROR;
1520 }
1521 }
1522
1523 ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1524 b->shadow = buf;
1525 b->tag = p->tag;
1526 b->last_shadow = 1;
1527 b->recycled = 1;
1528 buf->shadow = b;
1529
1530 cl = ngx_alloc_chain_link(p->pool);
1531 if (cl == NULL) {
1532 return NGX_ERROR;
1533 }
1534
1535 cl->buf = b;
1536 cl->next = NULL;
1537
1538 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1539
1540 if (p->in) {
1541 *p->last_in = cl;
1542 } else {
1543 p->in = cl;
1544 }
1545 p->last_in = &cl->next;
1546
1547 if (p->length == -1) {
1548 return NGX_OK;
1549 }
1550
1551 p->length -= b->last - b->pos;
1552
1553 if (p->length == 0) {
1554 r = p->input_ctx;
1555 p->upstream_done = 1;
1556 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1557
1558 } else if (p->length < 0) {
1559 r = p->input_ctx;
1560 p->upstream_done = 1;
1561
1562 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1563 "upstream sent too many data");
1564 }
1565
1566 return NGX_OK;
1567 }
1568
1569
1570 static ngx_inline ngx_int_t
1571 ngx_http_proxy_parse_chunked(ngx_http_request_t *r, ngx_buf_t *buf)
1572 {
1573 u_char *pos, ch, c;
1574 ngx_int_t rc;
1575 ngx_http_proxy_ctx_t *ctx;
1576 enum {
1577 sw_chunk_start = 0,
1578 sw_chunk_size,
1579 sw_chunk_extension,
1580 sw_chunk_extension_almost_done,
1581 sw_chunk_data,
1582 sw_after_data,
1583 sw_after_data_almost_done,
1584 sw_last_chunk_extension,
1585 sw_last_chunk_extension_almost_done,
1586 sw_trailer,
1587 sw_trailer_almost_done,
1588 sw_trailer_header,
1589 sw_trailer_header_almost_done
1590 } state;
1591
1592 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1593 state = ctx->state;
1594
1595 if (state == sw_chunk_data && ctx->size == 0) {
1596 state = sw_after_data;
1597 }
1598
1599 rc = NGX_AGAIN;
1600
1601 for (pos = buf->pos; pos < buf->last; pos++) {
1602
1603 ch = *pos;
1604
1605 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1606 "http proxy chunked byte: %02Xd s:%d", ch, state);
1607
1608 switch (state) {
1609
1610 case sw_chunk_start:
1611 if (ch >= '0' && ch <= '9') {
1612 state = sw_chunk_size;
1613 ctx->size = ch - '0';
1614 break;
1615 }
1616
1617 c = (u_char) (ch | 0x20);
1618
1619 if (c >= 'a' && c <= 'f') {
1620 state = sw_chunk_size;
1621 ctx->size = c - 'a' + 10;
1622 break;
1623 }
1624
1625 goto invalid;
1626
1627 case sw_chunk_size:
1628 if (ch >= '0' && ch <= '9') {
1629 ctx->size = ctx->size * 16 + (ch - '0');
1630 break;
1631 }
1632
1633 c = (u_char) (ch | 0x20);
1634
1635 if (c >= 'a' && c <= 'f') {
1636 ctx->size = ctx->size * 16 + (c - 'a' + 10);
1637 break;
1638 }
1639
1640 if (ctx->size == 0) {
1641
1642 switch (ch) {
1643 case CR:
1644 state = sw_last_chunk_extension_almost_done;
1645 break;
1646 case LF:
1647 state = sw_trailer;
1648 break;
1649 case ';':
1650 state = sw_last_chunk_extension;
1651 break;
1652 default:
1653 goto invalid;
1654 }
1655
1656 break;
1657 }
1658
1659 switch (ch) {
1660 case CR:
1661 state = sw_chunk_extension_almost_done;
1662 break;
1663 case LF:
1664 state = sw_chunk_data;
1665 break;
1666 case ';':
1667 state = sw_chunk_extension;
1668 break;
1669 default:
1670 goto invalid;
1671 }
1672
1673 break;
1674
1675 case sw_chunk_extension:
1676 switch (ch) {
1677 case CR:
1678 state = sw_chunk_extension_almost_done;
1679 break;
1680 case LF:
1681 state = sw_chunk_data;
1682 }
1683 break;
1684
1685 case sw_chunk_extension_almost_done:
1686 if (ch == LF) {
1687 state = sw_chunk_data;
1688 break;
1689 }
1690 goto invalid;
1691
1692 case sw_chunk_data:
1693 rc = NGX_OK;
1694 goto data;
1695
1696 case sw_after_data:
1697 switch (ch) {
1698 case CR:
1699 state = sw_after_data_almost_done;
1700 break;
1701 case LF:
1702 state = sw_chunk_start;
1703 }
1704 break;
1705
1706 case sw_after_data_almost_done:
1707 if (ch == LF) {
1708 state = sw_chunk_start;
1709 break;
1710 }
1711 goto invalid;
1712
1713 case sw_last_chunk_extension:
1714 switch (ch) {
1715 case CR:
1716 state = sw_last_chunk_extension_almost_done;
1717 break;
1718 case LF:
1719 state = sw_trailer;
1720 }
1721 break;
1722
1723 case sw_last_chunk_extension_almost_done:
1724 if (ch == LF) {
1725 state = sw_trailer;
1726 break;
1727 }
1728 goto invalid;
1729
1730 case sw_trailer:
1731 switch (ch) {
1732 case CR:
1733 state = sw_trailer_almost_done;
1734 break;
1735 case LF:
1736 goto done;
1737 default:
1738 state = sw_trailer_header;
1739 }
1740 break;
1741
1742 case sw_trailer_almost_done:
1743 if (ch == LF) {
1744 goto done;
1745 }
1746 goto invalid;
1747
1748 case sw_trailer_header:
1749 switch (ch) {
1750 case CR:
1751 state = sw_trailer_header_almost_done;
1752 break;
1753 case LF:
1754 state = sw_trailer;
1755 }
1756 break;
1757
1758 case sw_trailer_header_almost_done:
1759 if (ch == LF) {
1760 state = sw_trailer;
1761 break;
1762 }
1763 goto invalid;
1764
1765 }
1766 }
1767
1768 data:
1769
1770 ctx->state = state;
1771 buf->pos = pos;
1772
1773 switch (state) {
1774
1775 case sw_chunk_start:
1776 ctx->length = 3 /* "0" LF LF */;
1777 break;
1778 case sw_chunk_size:
1779 ctx->length = 2 /* LF LF */
1780 + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
1781 break;
1782 case sw_chunk_extension:
1783 case sw_chunk_extension_almost_done:
1784 ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
1785 break;
1786 case sw_chunk_data:
1787 ctx->length = ctx->size + 4 /* LF "0" LF LF */;
1788 break;
1789 case sw_after_data:
1790 case sw_after_data_almost_done:
1791 ctx->length = 4 /* LF "0" LF LF */;
1792 break;
1793 case sw_last_chunk_extension:
1794 case sw_last_chunk_extension_almost_done:
1795 ctx->length = 2 /* LF LF */;
1796 break;
1797 case sw_trailer:
1798 case sw_trailer_almost_done:
1799 ctx->length = 1 /* LF */;
1800 break;
1801 case sw_trailer_header:
1802 case sw_trailer_header_almost_done:
1803 ctx->length = 2 /* LF LF */;
1804 break;
1805
1806 }
1807
1808 return rc;
1809
1810 done:
1811
1812 return NGX_DONE;
1813
1814 invalid:
1815
1816 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1817 "upstream sent invalid chunked response");
1818
1819 return NGX_ERROR;
1820 }
1821
1822
1823 static ngx_int_t
1824 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1825 {
1826 ngx_int_t rc;
1827 ngx_buf_t *b, **prev;
1828 ngx_chain_t *cl;
1829 ngx_http_request_t *r;
1830 ngx_http_proxy_ctx_t *ctx;
1831
1832 if (buf->pos == buf->last) {
1833 return NGX_OK;
1834 }
1835
1836 r = p->input_ctx;
1837 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1838
1839 b = NULL;
1840 prev = &buf->shadow;
1841
1842 for ( ;; ) {
1843
1844 rc = ngx_http_proxy_parse_chunked(r, buf);
1845
1846 if (rc == NGX_OK) {
1847
1848 /* a chunk has been parsed successfully */
1849
1850 if (p->free) {
1851 cl = p->free;
1852 b = cl->buf;
1853 p->free = cl->next;
1854 ngx_free_chain(p->pool, cl);
1855
1856 } else {
1857 b = ngx_alloc_buf(p->pool);
1858 if (b == NULL) {
1859 return NGX_ERROR;
1860 }
1861 }
1862
1863 ngx_memzero(b, sizeof(ngx_buf_t));
1864
1865 b->pos = buf->pos;
1866 b->start = buf->start;
1867 b->end = buf->end;
1868 b->tag = p->tag;
1869 b->temporary = 1;
1870 b->recycled = 1;
1871
1872 *prev = b;
1873 prev = &b->shadow;
1874
1875 cl = ngx_alloc_chain_link(p->pool);
1876 if (cl == NULL) {
1877 return NGX_ERROR;
1878 }
1879
1880 cl->buf = b;
1881 cl->next = NULL;
1882
1883 if (p->in) {
1884 *p->last_in = cl;
1885 } else {
1886 p->in = cl;
1887 }
1888 p->last_in = &cl->next;
1889
1890 /* STUB */ b->num = buf->num;
1891
1892 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1893 "input buf #%d %p", b->num, b->pos);
1894
1895 if (buf->last - buf->pos >= ctx->size) {
1896
1897 buf->pos += ctx->size;
1898 b->last = buf->pos;
1899 ctx->size = 0;
1900
1901 continue;
1902 }
1903
1904 ctx->size -= buf->last - buf->pos;
1905 buf->pos = buf->last;
1906 b->last = buf->last;
1907
1908 continue;
1909 }
1910
1911 if (rc == NGX_DONE) {
1912
1913 /* a whole response has been parsed successfully */
1914
1915 p->upstream_done = 1;
1916 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1917
1918 break;
1919 }
1920
1921 if (rc == NGX_AGAIN) {
1922
1923 /* set p->length, minimal amount of data we want to see */
1924
1925 p->length = ctx->length;
1926
1927 break;
1928 }
1929
1930 /* invalid response */
1931
1932 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1933 "upstream sent invalid chunked response");
1934
1935 return NGX_ERROR;
1936 }
1937
1938 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1939 "http proxy chunked state %d, length %d",
1940 ctx->state, p->length);
1941
1942 if (b) {
1943 b->shadow = buf;
1944 b->last_shadow = 1;
1945
1946 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1947 "input buf %p %z", b->pos, b->last - b->pos);
1948
1949 return NGX_OK;
1950 }
1951
1952 /* there is no data record in the buf, add it to free chain */
1953
1954 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1955 return NGX_ERROR;
1956 }
1957
1958 return NGX_OK;
1959 }
1960
1961
1962 static ngx_int_t
1963 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
1964 {
1965 ngx_http_request_t *r = data;
1966
1967 ngx_buf_t *b;
1968 ngx_chain_t *cl, **ll;
1969 ngx_http_upstream_t *u;
1970
1971 u = r->upstream;
1972
1973 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1974 ll = &cl->next;
1975 }
1976
1977 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1978 if (cl == NULL) {
1979 return NGX_ERROR;
1980 }
1981
1982 *ll = cl;
1983
1984 cl->buf->flush = 1;
1985 cl->buf->memory = 1;
1986
1987 b = &u->buffer;
1988
1989 cl->buf->pos = b->last;
1990 b->last += bytes;
1991 cl->buf->last = b->last;
1992 cl->buf->tag = u->output.tag;
1993
1994 if (u->length == -1) {
1995 return NGX_OK;
1996 }
1997
1998 u->length -= bytes;
1999
2000 if (u->length == 0) {
2001 u->keepalive = !u->headers_in.connection_close;
2002 }
2003
2004 return NGX_OK;
2005 }
2006
2007
2008 static ngx_int_t
2009 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
2010 {
2011 ngx_http_request_t *r = data;
2012
2013 ngx_int_t rc;
2014 ngx_buf_t *b, *buf;
2015 ngx_chain_t *cl, **ll;
2016 ngx_http_upstream_t *u;
2017 ngx_http_proxy_ctx_t *ctx;
2018
2019 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2020 u = r->upstream;
2021 buf = &u->buffer;
2022
2023 buf->pos = buf->last;
2024 buf->last += bytes;
2025
2026 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2027 ll = &cl->next;
2028 }
2029
2030 for ( ;; ) {
2031
2032 rc = ngx_http_proxy_parse_chunked(r, buf);
2033
2034 if (rc == NGX_OK) {
2035
2036 /* a chunk has been parsed successfully */
2037
2038 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2039 if (cl == NULL) {
2040 return NGX_ERROR;
2041 }
2042
2043 *ll = cl;
2044 ll = &cl->next;
2045
2046 b = cl->buf;
2047
2048 b->flush = 1;
2049 b->memory = 1;
2050
2051 b->pos = buf->pos;
2052 b->tag = u->output.tag;
2053
2054 if (buf->last - buf->pos >= ctx->size) {
2055 buf->pos += ctx->size;
2056 b->last = buf->pos;
2057 ctx->size = 0;
2058
2059 } else {
2060 ctx->size -= buf->last - buf->pos;
2061 buf->pos = buf->last;
2062 b->last = buf->last;
2063 }
2064
2065 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2066 "http proxy out buf %p %z",
2067 b->pos, b->last - b->pos);
2068
2069 continue;
2070 }
2071
2072 if (rc == NGX_DONE) {
2073
2074 /* a whole response has been parsed successfully */
2075
2076 u->keepalive = !u->headers_in.connection_close;
2077 u->length = 0;
2078
2079 break;
2080 }
2081
2082 if (rc == NGX_AGAIN) {
2083 break;
2084 }
2085
2086 /* invalid response */
2087
2088 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
2089 "upstream sent invalid chunked response");
2090
2091 return NGX_ERROR;
2092 }
2093
2094 /* provide continuous buffer for subrequests in memory */
2095
2096 if (r->subrequest_in_memory) {
2097
2098 cl = u->out_bufs;
2099
2100 if (cl) {
2101 buf->pos = cl->buf->pos;
2102 }
2103
2104 buf->last = buf->pos;
2105
2106 for (cl = u->out_bufs; cl; cl = cl->next) {
2107 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2108 "http proxy in memory %p-%p %uz",
2109 cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2110
2111 if (buf->last == cl->buf->pos) {
2112 buf->last = cl->buf->last;
2113 continue;
2114 }
2115
2116 buf->last = ngx_movemem(buf->last, cl->buf->pos,
2117 cl->buf->last - cl->buf->pos);
2118
2119 cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2120 cl->buf->last = buf->last;
2121 }
2122 }
2123
2124 return NGX_OK;
1357 } 2125 }
1358 2126
1359 2127
1360 static void 2128 static void
1361 ngx_http_proxy_abort_request(ngx_http_request_t *r) 2129 ngx_http_proxy_abort_request(ngx_http_request_t *r)
1703 conf->upstream.cyclic_temp_file = 0; 2471 conf->upstream.cyclic_temp_file = 0;
1704 2472
1705 conf->redirect = NGX_CONF_UNSET; 2473 conf->redirect = NGX_CONF_UNSET;
1706 conf->upstream.change_buffering = 1; 2474 conf->upstream.change_buffering = 1;
1707 2475
2476 conf->http_version = NGX_CONF_UNSET_UINT;
2477
1708 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; 2478 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
1709 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; 2479 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
1710 2480
1711 ngx_str_set(&conf->upstream.module, "proxy"); 2481 ngx_str_set(&conf->upstream.module, "proxy");
1712 2482
2005 #if (NGX_HTTP_SSL) 2775 #if (NGX_HTTP_SSL)
2006 if (conf->upstream.ssl == NULL) { 2776 if (conf->upstream.ssl == NULL) {
2007 conf->upstream.ssl = prev->upstream.ssl; 2777 conf->upstream.ssl = prev->upstream.ssl;
2008 } 2778 }
2009 #endif 2779 #endif
2780
2781 ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
2782 NGX_HTTP_VERSION_10);
2010 2783
2011 ngx_conf_merge_uint_value(conf->headers_hash_max_size, 2784 ngx_conf_merge_uint_value(conf->headers_hash_max_size,
2012 prev->headers_hash_max_size, 512); 2785 prev->headers_hash_max_size, 512);
2013 2786
2014 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size, 2787 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,