diff src/http/ngx_http_request_body.c @ 6050:a08fad30aeac

Request body: unbuffered reading. The r->request_body_no_buffering flag was introduced. It instructs client request body reading code to avoid reading the whole body, and to call post_handler early instead. The caller should use the ngx_http_read_unbuffered_request_body() function to read remaining parts of the body. Upstream module is now able to use this mode, if configured with the proxy_request_buffering directive.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 23 Mar 2015 21:09:19 +0300
parents 42d9beeb22db
children 231a5bbd9e9c
line wrap: on
line diff
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -42,12 +42,14 @@ ngx_http_read_client_request_body(ngx_ht
 
 #if (NGX_HTTP_SPDY)
     if (r->spdy_stream && r == r->main) {
+        r->request_body_no_buffering = 0;
         rc = ngx_http_spdy_read_request_body(r, post_handler);
         goto done;
     }
 #endif
 
     if (r != r->main || r->request_body || r->discard_body) {
+        r->request_body_no_buffering = 0;
         post_handler(r);
         return NGX_OK;
     }
@@ -57,6 +59,10 @@ ngx_http_read_client_request_body(ngx_ht
         goto done;
     }
 
+    if (r->request_body_no_buffering) {
+        r->request_body_in_file_only = 0;
+    }
+
     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
     if (rb == NULL) {
         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -79,6 +85,7 @@ ngx_http_read_client_request_body(ngx_ht
     r->request_body = rb;
 
     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
+        r->request_body_no_buffering = 0;
         post_handler(r);
         return NGX_OK;
     }
@@ -171,6 +178,8 @@ ngx_http_read_client_request_body(ngx_ht
             }
         }
 
+        r->request_body_no_buffering = 0;
+
         post_handler(r);
 
         return NGX_OK;
@@ -214,6 +223,21 @@ ngx_http_read_client_request_body(ngx_ht
 
 done:
 
+    if (r->request_body_no_buffering
+        && (rc == NGX_OK || rc == NGX_AGAIN))
+    {
+        if (rc == NGX_OK) {
+            r->request_body_no_buffering = 0;
+
+        } else {
+            /* rc == NGX_AGAIN */
+            r->reading_body = 1;
+        }
+
+        r->read_event_handler = ngx_http_block_reading;
+        post_handler(r);
+    }
+
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
         r->main->count--;
     }
@@ -222,6 +246,26 @@ done:
 }
 
 
+ngx_int_t
+ngx_http_read_unbuffered_request_body(ngx_http_request_t *r)
+{
+    ngx_int_t  rc;
+
+    if (r->connection->read->timedout) {
+        r->connection->timedout = 1;
+        return NGX_HTTP_REQUEST_TIME_OUT;
+    }
+
+    rc = ngx_http_do_read_client_request_body(r);
+
+    if (rc == NGX_OK) {
+        r->reading_body = 0;
+    }
+
+    return rc;
+}
+
+
 static void
 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
 {
@@ -264,18 +308,43 @@ ngx_http_do_read_client_request_body(ngx
         for ( ;; ) {
             if (rb->buf->last == rb->buf->end) {
 
-                /* pass buffer to request body filter chain */
+                if (rb->buf->pos != rb->buf->last) {
+
+                    /* pass buffer to request body filter chain */
 
-                out.buf = rb->buf;
-                out.next = NULL;
+                    out.buf = rb->buf;
+                    out.next = NULL;
+
+                    rc = ngx_http_request_body_filter(r, &out);
 
-                rc = ngx_http_request_body_filter(r, &out);
+                    if (rc != NGX_OK) {
+                        return rc;
+                    }
+
+                } else {
 
-                if (rc != NGX_OK) {
-                    return rc;
+                    /* update chains */
+
+                    rc = ngx_http_request_body_filter(r, NULL);
+
+                    if (rc != NGX_OK) {
+                        return rc;
+                    }
                 }
 
                 if (rb->busy != NULL) {
+                    if (r->request_body_no_buffering) {
+                        if (c->read->timer_set) {
+                            ngx_del_timer(c->read);
+                        }
+
+                        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+                            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                        }
+
+                        return NGX_AGAIN;
+                    }
+
                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                 }
 
@@ -342,6 +411,22 @@ ngx_http_do_read_client_request_body(ngx
         }
 
         if (!c->read->ready) {
+
+            if (r->request_body_no_buffering
+                && rb->buf->pos != rb->buf->last)
+            {
+                /* pass buffer to request body filter chain */
+
+                out.buf = rb->buf;
+                out.next = NULL;
+
+                rc = ngx_http_request_body_filter(r, &out);
+
+                if (rc != NGX_OK) {
+                    return rc;
+                }
+            }
+
             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
             ngx_add_timer(c->read, clcf->client_body_timeout);
 
@@ -387,9 +472,10 @@ ngx_http_do_read_client_request_body(ngx
         }
     }
 
-    r->read_event_handler = ngx_http_block_reading;
-
-    rb->post_handler(r);
+    if (!r->request_body_no_buffering) {
+        r->read_event_handler = ngx_http_block_reading;
+        rb->post_handler(r);
+    }
 
     return NGX_OK;
 }
@@ -1085,7 +1171,8 @@ ngx_http_request_body_save_filter(ngx_ht
     }
 
     if (rb->rest > 0
-        && rb->buf && rb->buf->last == rb->buf->end)
+        && rb->buf && rb->buf->last == rb->buf->end
+        && !r->request_body_no_buffering)
     {
         if (ngx_http_write_request_body(r) != NGX_OK) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;