[nginx] FastCGI: non-buffered mode support.

Maxim Dounin mdounin at mdounin.ru
Fri Sep 27 12:54:40 UTC 2013


details:   http://hg.nginx.org/nginx/rev/8c827bb1b2b6
branches:  
changeset: 5394:8c827bb1b2b6
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Fri Sep 27 16:50:40 2013 +0400
description:
FastCGI: non-buffered mode support.

diffstat:

 src/http/modules/ngx_http_fastcgi_module.c |  238 ++++++++++++++++++++++++++++-
 1 files changed, 230 insertions(+), 8 deletions(-)

diffs (290 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
@@ -138,6 +138,8 @@ static ngx_int_t ngx_http_fastcgi_proces
 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,
     ngx_buf_t *buf);
+static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
+    ssize_t bytes);
 static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
     ngx_http_fastcgi_ctx_t *f);
 static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
@@ -233,6 +235,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
       NULL },
 
+    { ngx_string("fastcgi_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.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,
@@ -579,13 +588,6 @@ ngx_http_fastcgi_handler(ngx_http_reques
     ngx_http_fastcgi_ctx_t       *f;
     ngx_http_fastcgi_loc_conf_t  *flcf;
 
-    if (r->subrequest_in_memory) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      "ngx_http_fastcgi_module does not support "
-                      "subrequest in memory");
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
     if (ngx_http_upstream_create(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -622,7 +624,7 @@ ngx_http_fastcgi_handler(ngx_http_reques
     u->finalize_request = ngx_http_fastcgi_finalize_request;
     r->state = 0;
 
-    u->buffering = 1;
+    u->buffering = flcf->upstream.buffering;
 
     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
     if (u->pipe == NULL) {
@@ -633,6 +635,8 @@ ngx_http_fastcgi_handler(ngx_http_reques
     u->pipe->input_ctx = r;
 
     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
+    u->input_filter = ngx_http_fastcgi_non_buffered_filter;
+    u->input_filter_ctx = r;
 
     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
 
@@ -1915,6 +1919,222 @@ ngx_http_fastcgi_input_filter(ngx_event_
 
 
 static ngx_int_t
+ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
+{
+    u_char                  *m, *msg;
+    ngx_int_t                rc;
+    ngx_buf_t               *b, *buf;
+    ngx_chain_t             *cl, **ll;
+    ngx_http_request_t      *r;
+    ngx_http_upstream_t     *u;
+    ngx_http_fastcgi_ctx_t  *f;
+
+    r = data;
+    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+    u = r->upstream;
+    buf = &u->buffer;
+
+    buf->pos = buf->last;
+    buf->last += bytes;
+
+    for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
+        ll = &cl->next;
+    }
+
+    f->pos = buf->pos;
+    f->last = buf->last;
+
+    for ( ;; ) {
+        if (f->state < ngx_http_fastcgi_st_data) {
+
+            rc = ngx_http_fastcgi_process_record(r, f);
+
+            if (rc == NGX_AGAIN) {
+                break;
+            }
+
+            if (rc == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
+                f->state = ngx_http_fastcgi_st_padding;
+
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http fastcgi closed stdout");
+
+                continue;
+            }
+        }
+
+        if (f->state == ngx_http_fastcgi_st_padding) {
+
+            if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+
+                if (f->pos + f->padding < f->last) {
+                    u->length = 0;
+                    break;
+                }
+
+                if (f->pos + f->padding == f->last) {
+                    u->length = 0;
+                    u->keepalive = 1;
+                    break;
+                }
+
+                f->padding -= f->last - f->pos;
+
+                break;
+            }
+
+            if (f->pos + f->padding < f->last) {
+                f->state = ngx_http_fastcgi_st_version;
+                f->pos += f->padding;
+
+                continue;
+            }
+
+            if (f->pos + f->padding == f->last) {
+                f->state = ngx_http_fastcgi_st_version;
+
+                break;
+            }
+
+            f->padding -= f->last - f->pos;
+
+            break;
+        }
+
+
+        /* f->state == ngx_http_fastcgi_st_data */
+
+        if (f->type == NGX_HTTP_FASTCGI_STDERR) {
+
+            if (f->length) {
+
+                if (f->pos == f->last) {
+                    break;
+                }
+
+                msg = f->pos;
+
+                if (f->pos + f->length <= f->last) {
+                    f->pos += f->length;
+                    f->length = 0;
+                    f->state = ngx_http_fastcgi_st_padding;
+
+                } else {
+                    f->length -= f->last - f->pos;
+                    f->pos = f->last;
+                }
+
+                for (m = f->pos - 1; msg < m; m--) {
+                    if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
+                        break;
+                    }
+                }
+
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "FastCGI sent in stderr: \"%*s\"",
+                              m + 1 - msg, msg);
+
+            } else {
+                f->state = ngx_http_fastcgi_st_padding;
+            }
+
+            continue;
+        }
+
+        if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+
+            if (f->pos + f->length <= f->last) {
+                f->state = ngx_http_fastcgi_st_padding;
+                f->pos += f->length;
+
+                continue;
+            }
+
+            f->length -= f->last - f->pos;
+
+            break;
+        }
+
+
+        /* f->type == NGX_HTTP_FASTCGI_STDOUT */
+
+        if (f->pos == f->last) {
+            break;
+        }
+
+        cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
+        if (cl == NULL) {
+            return NGX_ERROR;
+        }
+
+        *ll = cl;
+        ll = &cl->next;
+
+        b = cl->buf;
+
+        b->flush = 1;
+        b->memory = 1;
+
+        b->pos = f->pos;
+        b->tag = u->output.tag;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http fastcgi output buf %p", b->pos);
+
+        if (f->pos + f->length <= f->last) {
+            f->state = ngx_http_fastcgi_st_padding;
+            f->pos += f->length;
+            b->last = f->pos;
+
+            continue;
+        }
+
+        f->length -= f->last - f->pos;
+        b->last = f->last;
+
+        break;
+    }
+
+    /* provide continuous buffer for subrequests in memory */
+
+    if (r->subrequest_in_memory) {
+
+        cl = u->out_bufs;
+
+        if (cl) {
+            buf->pos = cl->buf->pos;
+        }
+
+        buf->last = buf->pos;
+
+        for (cl = u->out_bufs; cl; cl = cl->next) {
+            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http fastcgi in memory %p-%p %uz",
+                           cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
+
+            if (buf->last == cl->buf->pos) {
+                buf->last = cl->buf->last;
+                continue;
+            }
+
+            buf->last = ngx_movemem(buf->last, cl->buf->pos,
+                                    cl->buf->last - cl->buf->pos);
+
+            cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
+            cl->buf->last = buf->last;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
     ngx_http_fastcgi_ctx_t *f)
 {
@@ -2126,6 +2346,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
     /* "fastcgi_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
 
+    conf->upstream.change_buffering = 1;
+
     conf->catch_stderr = NGX_CONF_UNSET_PTR;
 
     conf->keep_conn = NGX_CONF_UNSET;



More information about the nginx-devel mailing list