[nginx] FastCGI: fastcgi_request_buffering.
Maxim Dounin
mdounin at mdounin.ru
Mon Mar 23 18:11:36 UTC 2015
details: http://hg.nginx.org/nginx/rev/8ad78808a612
branches:
changeset: 6052:8ad78808a612
user: Maxim Dounin <mdounin at mdounin.ru>
date: Mon Mar 23 21:09:19 2015 +0300
description:
FastCGI: fastcgi_request_buffering.
diffstat:
src/http/modules/ngx_http_fastcgi_module.c | 362 +++++++++++++++++++++++++++-
1 files changed, 343 insertions(+), 19 deletions(-)
diffs (truncated from 463 to 300 lines):
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -81,8 +81,12 @@ typedef struct {
size_t length;
size_t padding;
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+
unsigned fastcgi_stdout:1;
unsigned large_stderr:1;
+ unsigned header_sent:1;
ngx_array_t *split_parts;
@@ -147,6 +151,8 @@ static ngx_int_t ngx_http_fastcgi_create
#endif
static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_body_output_filter(void *data,
+ ngx_chain_t *in);
static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
@@ -257,6 +263,13 @@ static ngx_command_t ngx_http_fastcgi_c
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
NULL },
+ { ngx_string("fastcgi_request_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering),
+ NULL },
+
{ ngx_string("fastcgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -703,6 +716,12 @@ ngx_http_fastcgi_handler(ngx_http_reques
u->input_filter = ngx_http_fastcgi_non_buffered_filter;
u->input_filter_ctx = r;
+ if (!flcf->upstream.request_buffering
+ && flcf->upstream.pass_request_body)
+ {
+ r->request_body_no_buffering = 1;
+ }
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -799,6 +818,7 @@ ngx_http_fastcgi_create_request(ngx_http
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
+ ngx_http_upstream_t *u;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e, le;
ngx_http_fastcgi_header_t *h;
@@ -810,10 +830,12 @@ ngx_http_fastcgi_create_request(ngx_http
header_params = 0;
ignored = NULL;
+ u = r->upstream;
+
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
#if (NGX_HTTP_CACHE)
- params = r->upstream->cacheable ? &flcf->params_cache : &flcf->params;
+ params = u->cacheable ? &flcf->params_cache : &flcf->params;
#else
params = &flcf->params;
#endif
@@ -1134,12 +1156,17 @@ ngx_http_fastcgi_create_request(ngx_http
h->padding_length = 0;
h->reserved = 0;
- h = (ngx_http_fastcgi_header_t *) b->last;
- b->last += sizeof(ngx_http_fastcgi_header_t);
-
- if (flcf->upstream.pass_request_body) {
- body = r->upstream->request_bufs;
- r->upstream->request_bufs = cl;
+ if (r->request_body_no_buffering) {
+
+ u->request_bufs = cl;
+
+ u->output.output_filter = ngx_http_fastcgi_body_output_filter;
+ u->output.filter_ctx = r;
+
+ } else if (flcf->upstream.pass_request_body) {
+
+ body = u->request_bufs;
+ u->request_bufs = cl;
#if (NGX_SUPPRESS_WARN)
file_pos = 0;
@@ -1194,6 +1221,9 @@ ngx_http_fastcgi_create_request(ngx_http
padding = 8 - len % 8;
padding = (padding == 8) ? 0 : padding;
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
h->version = 1;
h->type = NGX_HTTP_FASTCGI_STDIN;
h->request_id_hi = 0;
@@ -1223,9 +1253,6 @@ ngx_http_fastcgi_create_request(ngx_http
b->last += padding;
}
- h = (ngx_http_fastcgi_header_t *) b->last;
- b->last += sizeof(ngx_http_fastcgi_header_t);
-
cl->next = ngx_alloc_chain_link(r->pool);
if (cl->next == NULL) {
return NGX_ERROR;
@@ -1240,17 +1267,22 @@ ngx_http_fastcgi_create_request(ngx_http
}
} else {
- r->upstream->request_bufs = cl;
+ u->request_bufs = cl;
}
- h->version = 1;
- h->type = NGX_HTTP_FASTCGI_STDIN;
- h->request_id_hi = 0;
- h->request_id_lo = 1;
- h->content_length_hi = 0;
- h->content_length_lo = 0;
- h->padding_length = 0;
- h->reserved = 0;
+ if (!r->request_body_no_buffering) {
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
+ h->version = 1;
+ h->type = NGX_HTTP_FASTCGI_STDIN;
+ h->request_id_hi = 0;
+ h->request_id_lo = 1;
+ h->content_length_hi = 0;
+ h->content_length_lo = 0;
+ h->padding_length = 0;
+ h->reserved = 0;
+ }
cl->next = NULL;
@@ -1284,6 +1316,294 @@ ngx_http_fastcgi_reinit_request(ngx_http
static ngx_int_t
+ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
+{
+ ngx_http_request_t *r = data;
+
+ off_t file_pos;
+ u_char *pos, *start;
+ size_t len, padding;
+ ngx_buf_t *b;
+ ngx_int_t rc;
+ ngx_uint_t next, last;
+ ngx_chain_t *cl, *tl, *out, **ll;
+ ngx_http_fastcgi_ctx_t *f;
+ ngx_http_fastcgi_header_t *h;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "fastcgi output filter");
+
+ f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+ if (in == NULL) {
+ out = in;
+ goto out;
+ }
+
+ out = NULL;
+ ll = &out;
+
+ if (!f->header_sent) {
+ /* first buffer contains headers, pass it unmodified */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "fastcgi output header");
+
+ f->header_sent = 1;
+
+ tl = ngx_alloc_chain_link(r->pool);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ tl->buf = in->buf;
+ *ll = tl;
+ ll = &tl->next;
+
+ in = in->next;
+
+ if (in == NULL) {
+ tl->next = NULL;
+ goto out;
+ }
+ }
+
+ cl = ngx_chain_get_free_buf(r->pool, &f->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = cl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
+ b->temporary = 1;
+
+ if (b->start == NULL) {
+ /* reserve space for maximum possible padding, 7 bytes */
+
+ b->start = ngx_palloc(r->pool,
+ sizeof(ngx_http_fastcgi_header_t) + 7);
+ if (b->start == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+
+ b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
+ }
+
+ *ll = cl;
+
+ last = 0;
+ padding = 0;
+
+#if (NGX_SUPPRESS_WARN)
+ file_pos = 0;
+ pos = NULL;
+#endif
+
+ while (in) {
+
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
+ "fastcgi output in l:%d f:%d %p, pos %p, size: %z "
+ "file: %O, size: %O",
+ in->buf->last_buf,
+ in->buf->in_file,
+ in->buf->start, in->buf->pos,
+ in->buf->last - in->buf->pos,
+ in->buf->file_pos,
+ in->buf->file_last - in->buf->file_pos);
+
+ if (in->buf->last_buf) {
+ last = 1;
+ }
+
+ if (ngx_buf_special(in->buf)) {
+ in = in->next;
+ continue;
+ }
+
+ if (in->buf->in_file) {
+ file_pos = in->buf->file_pos;
+
+ } else {
+ pos = in->buf->pos;
+ }
+
+ next = 0;
+
+ do {
+ tl = ngx_chain_get_free_buf(r->pool, &f->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+ start = b->start;
+
+ ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
+
+ /*
+ * restore b->start to preserve memory allocated in the buffer,
+ * to reuse it later for headers and padding
+ */
+
+ b->start = start;
+
+ if (in->buf->in_file) {
+ b->file_pos = file_pos;
+ file_pos += 32 * 1024;
+
+ if (file_pos >= in->buf->file_last) {
+ file_pos = in->buf->file_last;
+ next = 1;
+ }
+
+ b->file_last = file_pos;
+ len = (ngx_uint_t) (file_pos - b->file_pos);
More information about the nginx-devel
mailing list