Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_proxy_module.c @ 4126:bba9a5ccc6cd
Proxy: basic HTTP/1.1 support (including keepalive).
By default we still send requests using HTTP/1.0. This may be changed with
new proxy_http_version directive.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 15 Sep 2011 19:23:20 +0000 |
parents | e5df04b05e75 |
children | 7b77428909ed |
comparison
equal
deleted
inserted
replaced
4125:e5df04b05e75 | 4126:bba9a5ccc6cd |
---|---|
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 |
1248 static ngx_int_t | 1301 static ngx_int_t |
1249 ngx_http_proxy_process_header(ngx_http_request_t *r) | 1302 ngx_http_proxy_process_header(ngx_http_request_t *r) |
1250 { | 1303 { |
1251 ngx_int_t rc; | 1304 ngx_int_t rc; |
1252 ngx_table_elt_t *h; | 1305 ngx_table_elt_t *h; |
1306 ngx_http_upstream_t *u; | |
1307 ngx_http_proxy_ctx_t *ctx; | |
1253 ngx_http_upstream_header_t *hh; | 1308 ngx_http_upstream_header_t *hh; |
1254 ngx_http_upstream_main_conf_t *umcf; | 1309 ngx_http_upstream_main_conf_t *umcf; |
1255 | 1310 |
1256 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); |
1257 | 1312 |
1343 ngx_str_set(&h->key, "Date"); | 1398 ngx_str_set(&h->key, "Date"); |
1344 ngx_str_null(&h->value); | 1399 ngx_str_null(&h->value); |
1345 h->lowcase_key = (u_char *) "date"; | 1400 h->lowcase_key = (u_char *) "date"; |
1346 } | 1401 } |
1347 | 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 | |
1348 return NGX_OK; | 1427 return NGX_OK; |
1349 } | 1428 } |
1350 | 1429 |
1351 if (rc == NGX_AGAIN) { | 1430 if (rc == NGX_AGAIN) { |
1352 return NGX_AGAIN; | 1431 return NGX_AGAIN; |
1357 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 1436 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
1358 "upstream sent invalid header"); | 1437 "upstream sent invalid header"); |
1359 | 1438 |
1360 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | 1439 return NGX_HTTP_UPSTREAM_INVALID_HEADER; |
1361 } | 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; | |
1362 } | 2125 } |
1363 | 2126 |
1364 | 2127 |
1365 static void | 2128 static void |
1366 ngx_http_proxy_abort_request(ngx_http_request_t *r) | 2129 ngx_http_proxy_abort_request(ngx_http_request_t *r) |
1708 conf->upstream.cyclic_temp_file = 0; | 2471 conf->upstream.cyclic_temp_file = 0; |
1709 | 2472 |
1710 conf->redirect = NGX_CONF_UNSET; | 2473 conf->redirect = NGX_CONF_UNSET; |
1711 conf->upstream.change_buffering = 1; | 2474 conf->upstream.change_buffering = 1; |
1712 | 2475 |
2476 conf->http_version = NGX_CONF_UNSET_UINT; | |
2477 | |
1713 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; | 2478 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; |
1714 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; | 2479 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; |
1715 | 2480 |
1716 ngx_str_set(&conf->upstream.module, "proxy"); | 2481 ngx_str_set(&conf->upstream.module, "proxy"); |
1717 | 2482 |
2010 #if (NGX_HTTP_SSL) | 2775 #if (NGX_HTTP_SSL) |
2011 if (conf->upstream.ssl == NULL) { | 2776 if (conf->upstream.ssl == NULL) { |
2012 conf->upstream.ssl = prev->upstream.ssl; | 2777 conf->upstream.ssl = prev->upstream.ssl; |
2013 } | 2778 } |
2014 #endif | 2779 #endif |
2780 | |
2781 ngx_conf_merge_uint_value(conf->http_version, prev->http_version, | |
2782 NGX_HTTP_VERSION_10); | |
2015 | 2783 |
2016 ngx_conf_merge_uint_value(conf->headers_hash_max_size, | 2784 ngx_conf_merge_uint_value(conf->headers_hash_max_size, |
2017 prev->headers_hash_max_size, 512); | 2785 prev->headers_hash_max_size, 512); |
2018 | 2786 |
2019 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size, | 2787 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size, |