comparison src/http/modules/ngx_http_fastcgi_module.c @ 6052:8ad78808a612

FastCGI: fastcgi_request_buffering.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 23 Mar 2015 21:09:19 +0300
parents 610832763648
children 2a621245f4cf
comparison
equal deleted inserted replaced
6051:d97e6be2d292 6052:8ad78808a612
79 u_char *last; 79 u_char *last;
80 ngx_uint_t type; 80 ngx_uint_t type;
81 size_t length; 81 size_t length;
82 size_t padding; 82 size_t padding;
83 83
84 ngx_chain_t *free;
85 ngx_chain_t *busy;
86
84 unsigned fastcgi_stdout:1; 87 unsigned fastcgi_stdout:1;
85 unsigned large_stderr:1; 88 unsigned large_stderr:1;
89 unsigned header_sent:1;
86 90
87 ngx_array_t *split_parts; 91 ngx_array_t *split_parts;
88 92
89 ngx_str_t script_name; 93 ngx_str_t script_name;
90 ngx_str_t path_info; 94 ngx_str_t path_info;
145 #if (NGX_HTTP_CACHE) 149 #if (NGX_HTTP_CACHE)
146 static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r); 150 static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
147 #endif 151 #endif
148 static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r); 152 static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
149 static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r); 153 static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
154 static ngx_int_t ngx_http_fastcgi_body_output_filter(void *data,
155 ngx_chain_t *in);
150 static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r); 156 static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
151 static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data); 157 static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
152 static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, 158 static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
153 ngx_buf_t *buf); 159 ngx_buf_t *buf);
154 static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data, 160 static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
253 { ngx_string("fastcgi_buffering"), 259 { ngx_string("fastcgi_buffering"),
254 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 260 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
255 ngx_conf_set_flag_slot, 261 ngx_conf_set_flag_slot,
256 NGX_HTTP_LOC_CONF_OFFSET, 262 NGX_HTTP_LOC_CONF_OFFSET,
257 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering), 263 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
264 NULL },
265
266 { ngx_string("fastcgi_request_buffering"),
267 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
268 ngx_conf_set_flag_slot,
269 NGX_HTTP_LOC_CONF_OFFSET,
270 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering),
258 NULL }, 271 NULL },
259 272
260 { ngx_string("fastcgi_ignore_client_abort"), 273 { ngx_string("fastcgi_ignore_client_abort"),
261 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 274 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
262 ngx_conf_set_flag_slot, 275 ngx_conf_set_flag_slot,
701 714
702 u->input_filter_init = ngx_http_fastcgi_input_filter_init; 715 u->input_filter_init = ngx_http_fastcgi_input_filter_init;
703 u->input_filter = ngx_http_fastcgi_non_buffered_filter; 716 u->input_filter = ngx_http_fastcgi_non_buffered_filter;
704 u->input_filter_ctx = r; 717 u->input_filter_ctx = r;
705 718
719 if (!flcf->upstream.request_buffering
720 && flcf->upstream.pass_request_body)
721 {
722 r->request_body_no_buffering = 1;
723 }
724
706 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); 725 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
707 726
708 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 727 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
709 return rc; 728 return rc;
710 } 729 }
797 ngx_uint_t i, n, next, hash, skip_empty, header_params; 816 ngx_uint_t i, n, next, hash, skip_empty, header_params;
798 ngx_buf_t *b; 817 ngx_buf_t *b;
799 ngx_chain_t *cl, *body; 818 ngx_chain_t *cl, *body;
800 ngx_list_part_t *part; 819 ngx_list_part_t *part;
801 ngx_table_elt_t *header, **ignored; 820 ngx_table_elt_t *header, **ignored;
821 ngx_http_upstream_t *u;
802 ngx_http_script_code_pt code; 822 ngx_http_script_code_pt code;
803 ngx_http_script_engine_t e, le; 823 ngx_http_script_engine_t e, le;
804 ngx_http_fastcgi_header_t *h; 824 ngx_http_fastcgi_header_t *h;
805 ngx_http_fastcgi_params_t *params; 825 ngx_http_fastcgi_params_t *params;
806 ngx_http_fastcgi_loc_conf_t *flcf; 826 ngx_http_fastcgi_loc_conf_t *flcf;
808 828
809 len = 0; 829 len = 0;
810 header_params = 0; 830 header_params = 0;
811 ignored = NULL; 831 ignored = NULL;
812 832
833 u = r->upstream;
834
813 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); 835 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
814 836
815 #if (NGX_HTTP_CACHE) 837 #if (NGX_HTTP_CACHE)
816 params = r->upstream->cacheable ? &flcf->params_cache : &flcf->params; 838 params = u->cacheable ? &flcf->params_cache : &flcf->params;
817 #else 839 #else
818 params = &flcf->params; 840 params = &flcf->params;
819 #endif 841 #endif
820 842
821 if (params->lengths) { 843 if (params->lengths) {
1132 h->content_length_hi = 0; 1154 h->content_length_hi = 0;
1133 h->content_length_lo = 0; 1155 h->content_length_lo = 0;
1134 h->padding_length = 0; 1156 h->padding_length = 0;
1135 h->reserved = 0; 1157 h->reserved = 0;
1136 1158
1137 h = (ngx_http_fastcgi_header_t *) b->last; 1159 if (r->request_body_no_buffering) {
1138 b->last += sizeof(ngx_http_fastcgi_header_t); 1160
1139 1161 u->request_bufs = cl;
1140 if (flcf->upstream.pass_request_body) { 1162
1141 body = r->upstream->request_bufs; 1163 u->output.output_filter = ngx_http_fastcgi_body_output_filter;
1142 r->upstream->request_bufs = cl; 1164 u->output.filter_ctx = r;
1165
1166 } else if (flcf->upstream.pass_request_body) {
1167
1168 body = u->request_bufs;
1169 u->request_bufs = cl;
1143 1170
1144 #if (NGX_SUPPRESS_WARN) 1171 #if (NGX_SUPPRESS_WARN)
1145 file_pos = 0; 1172 file_pos = 0;
1146 pos = NULL; 1173 pos = NULL;
1147 #endif 1174 #endif
1191 len = (ngx_uint_t) (pos - b->pos); 1218 len = (ngx_uint_t) (pos - b->pos);
1192 } 1219 }
1193 1220
1194 padding = 8 - len % 8; 1221 padding = 8 - len % 8;
1195 padding = (padding == 8) ? 0 : padding; 1222 padding = (padding == 8) ? 0 : padding;
1223
1224 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1225 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1196 1226
1197 h->version = 1; 1227 h->version = 1;
1198 h->type = NGX_HTTP_FASTCGI_STDIN; 1228 h->type = NGX_HTTP_FASTCGI_STDIN;
1199 h->request_id_hi = 0; 1229 h->request_id_hi = 0;
1200 h->request_id_lo = 1; 1230 h->request_id_lo = 1;
1221 if (padding) { 1251 if (padding) {
1222 ngx_memzero(b->last, padding); 1252 ngx_memzero(b->last, padding);
1223 b->last += padding; 1253 b->last += padding;
1224 } 1254 }
1225 1255
1226 h = (ngx_http_fastcgi_header_t *) b->last;
1227 b->last += sizeof(ngx_http_fastcgi_header_t);
1228
1229 cl->next = ngx_alloc_chain_link(r->pool); 1256 cl->next = ngx_alloc_chain_link(r->pool);
1230 if (cl->next == NULL) { 1257 if (cl->next == NULL) {
1231 return NGX_ERROR; 1258 return NGX_ERROR;
1232 } 1259 }
1233 1260
1238 1265
1239 body = body->next; 1266 body = body->next;
1240 } 1267 }
1241 1268
1242 } else { 1269 } else {
1243 r->upstream->request_bufs = cl; 1270 u->request_bufs = cl;
1244 } 1271 }
1245 1272
1246 h->version = 1; 1273 if (!r->request_body_no_buffering) {
1247 h->type = NGX_HTTP_FASTCGI_STDIN; 1274 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1248 h->request_id_hi = 0; 1275 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1249 h->request_id_lo = 1; 1276
1250 h->content_length_hi = 0; 1277 h->version = 1;
1251 h->content_length_lo = 0; 1278 h->type = NGX_HTTP_FASTCGI_STDIN;
1252 h->padding_length = 0; 1279 h->request_id_hi = 0;
1253 h->reserved = 0; 1280 h->request_id_lo = 1;
1281 h->content_length_hi = 0;
1282 h->content_length_lo = 0;
1283 h->padding_length = 0;
1284 h->reserved = 0;
1285 }
1254 1286
1255 cl->next = NULL; 1287 cl->next = NULL;
1256 1288
1257 return NGX_OK; 1289 return NGX_OK;
1258 } 1290 }
1278 } 1310 }
1279 1311
1280 r->state = 0; 1312 r->state = 0;
1281 1313
1282 return NGX_OK; 1314 return NGX_OK;
1315 }
1316
1317
1318 static ngx_int_t
1319 ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
1320 {
1321 ngx_http_request_t *r = data;
1322
1323 off_t file_pos;
1324 u_char *pos, *start;
1325 size_t len, padding;
1326 ngx_buf_t *b;
1327 ngx_int_t rc;
1328 ngx_uint_t next, last;
1329 ngx_chain_t *cl, *tl, *out, **ll;
1330 ngx_http_fastcgi_ctx_t *f;
1331 ngx_http_fastcgi_header_t *h;
1332
1333 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1334 "fastcgi output filter");
1335
1336 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1337
1338 if (in == NULL) {
1339 out = in;
1340 goto out;
1341 }
1342
1343 out = NULL;
1344 ll = &out;
1345
1346 if (!f->header_sent) {
1347 /* first buffer contains headers, pass it unmodified */
1348
1349 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1350 "fastcgi output header");
1351
1352 f->header_sent = 1;
1353
1354 tl = ngx_alloc_chain_link(r->pool);
1355 if (tl == NULL) {
1356 return NGX_ERROR;
1357 }
1358
1359 tl->buf = in->buf;
1360 *ll = tl;
1361 ll = &tl->next;
1362
1363 in = in->next;
1364
1365 if (in == NULL) {
1366 tl->next = NULL;
1367 goto out;
1368 }
1369 }
1370
1371 cl = ngx_chain_get_free_buf(r->pool, &f->free);
1372 if (cl == NULL) {
1373 return NGX_ERROR;
1374 }
1375
1376 b = cl->buf;
1377
1378 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1379 b->temporary = 1;
1380
1381 if (b->start == NULL) {
1382 /* reserve space for maximum possible padding, 7 bytes */
1383
1384 b->start = ngx_palloc(r->pool,
1385 sizeof(ngx_http_fastcgi_header_t) + 7);
1386 if (b->start == NULL) {
1387 return NGX_ERROR;
1388 }
1389
1390 b->pos = b->start;
1391 b->last = b->start;
1392
1393 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1394 }
1395
1396 *ll = cl;
1397
1398 last = 0;
1399 padding = 0;
1400
1401 #if (NGX_SUPPRESS_WARN)
1402 file_pos = 0;
1403 pos = NULL;
1404 #endif
1405
1406 while (in) {
1407
1408 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1409 "fastcgi output in l:%d f:%d %p, pos %p, size: %z "
1410 "file: %O, size: %O",
1411 in->buf->last_buf,
1412 in->buf->in_file,
1413 in->buf->start, in->buf->pos,
1414 in->buf->last - in->buf->pos,
1415 in->buf->file_pos,
1416 in->buf->file_last - in->buf->file_pos);
1417
1418 if (in->buf->last_buf) {
1419 last = 1;
1420 }
1421
1422 if (ngx_buf_special(in->buf)) {
1423 in = in->next;
1424 continue;
1425 }
1426
1427 if (in->buf->in_file) {
1428 file_pos = in->buf->file_pos;
1429
1430 } else {
1431 pos = in->buf->pos;
1432 }
1433
1434 next = 0;
1435
1436 do {
1437 tl = ngx_chain_get_free_buf(r->pool, &f->free);
1438 if (tl == NULL) {
1439 return NGX_ERROR;
1440 }
1441
1442 b = tl->buf;
1443 start = b->start;
1444
1445 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1446
1447 /*
1448 * restore b->start to preserve memory allocated in the buffer,
1449 * to reuse it later for headers and padding
1450 */
1451
1452 b->start = start;
1453
1454 if (in->buf->in_file) {
1455 b->file_pos = file_pos;
1456 file_pos += 32 * 1024;
1457
1458 if (file_pos >= in->buf->file_last) {
1459 file_pos = in->buf->file_last;
1460 next = 1;
1461 }
1462
1463 b->file_last = file_pos;
1464 len = (ngx_uint_t) (file_pos - b->file_pos);
1465
1466 } else {
1467 b->pos = pos;
1468 pos += 32 * 1024;
1469
1470 if (pos >= in->buf->last) {
1471 pos = in->buf->last;
1472 next = 1;
1473 }
1474
1475 b->last = pos;
1476 len = (ngx_uint_t) (pos - b->pos);
1477 }
1478
1479 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1480 b->shadow = in->buf;
1481 b->last_shadow = next;
1482
1483 b->last_buf = 0;
1484 b->last_in_chain = 0;
1485
1486 padding = 8 - len % 8;
1487 padding = (padding == 8) ? 0 : padding;
1488
1489 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1490 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1491
1492 h->version = 1;
1493 h->type = NGX_HTTP_FASTCGI_STDIN;
1494 h->request_id_hi = 0;
1495 h->request_id_lo = 1;
1496 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1497 h->content_length_lo = (u_char) (len & 0xff);
1498 h->padding_length = (u_char) padding;
1499 h->reserved = 0;
1500
1501 cl->next = tl;
1502 cl = tl;
1503
1504 tl = ngx_chain_get_free_buf(r->pool, &f->free);
1505 if (tl == NULL) {
1506 return NGX_ERROR;
1507 }
1508
1509 b = tl->buf;
1510
1511 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1512 b->temporary = 1;
1513
1514 if (b->start == NULL) {
1515 /* reserve space for maximum possible padding, 7 bytes */
1516
1517 b->start = ngx_palloc(r->pool,
1518 sizeof(ngx_http_fastcgi_header_t) + 7);
1519 if (b->start == NULL) {
1520 return NGX_ERROR;
1521 }
1522
1523 b->pos = b->start;
1524 b->last = b->start;
1525
1526 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1527 }
1528
1529 if (padding) {
1530 ngx_memzero(b->last, padding);
1531 b->last += padding;
1532 }
1533
1534 cl->next = tl;
1535 cl = tl;
1536
1537 } while (!next);
1538
1539 in = in->next;
1540 }
1541
1542 if (last) {
1543 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1544 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1545
1546 h->version = 1;
1547 h->type = NGX_HTTP_FASTCGI_STDIN;
1548 h->request_id_hi = 0;
1549 h->request_id_lo = 1;
1550 h->content_length_hi = 0;
1551 h->content_length_lo = 0;
1552 h->padding_length = 0;
1553 h->reserved = 0;
1554
1555 cl->buf->last_buf = 1;
1556
1557 } else if (padding == 0) {
1558 /* TODO: do not allocate buffers instead */
1559 cl->buf->temporary = 0;
1560 cl->buf->sync = 1;
1561 }
1562
1563 cl->next = NULL;
1564
1565 out:
1566
1567 #if (NGX_DEBUG)
1568
1569 for (cl = out; cl; cl = cl->next) {
1570 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1571 "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
1572 "file: %O, size: %O",
1573 cl->buf->last_buf,
1574 cl->buf->in_file,
1575 cl->buf->start, cl->buf->pos,
1576 cl->buf->last - cl->buf->pos,
1577 cl->buf->file_pos,
1578 cl->buf->file_last - cl->buf->file_pos);
1579 }
1580
1581 #endif
1582
1583 rc = ngx_chain_writer(&r->upstream->writer, out);
1584
1585 ngx_chain_update_chains(r->pool, &f->free, &f->busy, &out,
1586 (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter);
1587
1588 for (cl = f->free; cl; cl = cl->next) {
1589
1590 /* mark original buffers as sent */
1591
1592 if (cl->buf->shadow) {
1593 if (cl->buf->last_shadow) {
1594 b = cl->buf->shadow;
1595 b->pos = b->last;
1596 }
1597
1598 cl->buf->shadow = NULL;
1599 }
1600 }
1601
1602 return rc;
1283 } 1603 }
1284 1604
1285 1605
1286 static ngx_int_t 1606 static ngx_int_t
1287 ngx_http_fastcgi_process_header(ngx_http_request_t *r) 1607 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
2403 2723
2404 conf->upstream.store = NGX_CONF_UNSET; 2724 conf->upstream.store = NGX_CONF_UNSET;
2405 conf->upstream.store_access = NGX_CONF_UNSET_UINT; 2725 conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2406 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; 2726 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2407 conf->upstream.buffering = NGX_CONF_UNSET; 2727 conf->upstream.buffering = NGX_CONF_UNSET;
2728 conf->upstream.request_buffering = NGX_CONF_UNSET;
2408 conf->upstream.ignore_client_abort = NGX_CONF_UNSET; 2729 conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2409 conf->upstream.force_ranges = NGX_CONF_UNSET; 2730 conf->upstream.force_ranges = NGX_CONF_UNSET;
2410 2731
2411 conf->upstream.local = NGX_CONF_UNSET_PTR; 2732 conf->upstream.local = NGX_CONF_UNSET_PTR;
2412 2733
2495 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, 2816 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2496 prev->upstream.next_upstream_tries, 0); 2817 prev->upstream.next_upstream_tries, 0);
2497 2818
2498 ngx_conf_merge_value(conf->upstream.buffering, 2819 ngx_conf_merge_value(conf->upstream.buffering,
2499 prev->upstream.buffering, 1); 2820 prev->upstream.buffering, 1);
2821
2822 ngx_conf_merge_value(conf->upstream.request_buffering,
2823 prev->upstream.request_buffering, 1);
2500 2824
2501 ngx_conf_merge_value(conf->upstream.ignore_client_abort, 2825 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2502 prev->upstream.ignore_client_abort, 0); 2826 prev->upstream.ignore_client_abort, 0);
2503 2827
2504 ngx_conf_merge_value(conf->upstream.force_ranges, 2828 ngx_conf_merge_value(conf->upstream.force_ranges,