HTTP/2: optimized processing of small DATA frames.

The request body filter chain is no longer called after processing
a DATA frame.  Instead, we now post a read event to do this.  This
ensures that multiple small DATA frames read during the same event loop
iteration are coalesced together, resulting in much faster processing.

Since rb->buf can now contain unprocessed data, window update is no
longer sent in ngx_http_v2_state_read_data() in case of flow control
being used due to filter buffering.  Instead, window will be updated
by ngx_http_v2_read_client_request_body_handler() in the posted read
event.
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index bbb86ae..3afa8b6 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -1092,7 +1092,7 @@
 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
     u_char *end)
 {
-    size_t                   size, window;
+    size_t                   size;
     ngx_buf_t               *buf;
     ngx_int_t                rc;
     ngx_connection_t        *fc;
@@ -1148,40 +1148,6 @@
             ngx_http_finalize_request(r, rc);
         }
 
-        if (rc == NGX_AGAIN
-            && !stream->no_flow_control
-            && !r->request_body_no_buffering)
-        {
-            buf = r->request_body->buf;
-
-            if (r->request_body->busy == NULL) {
-                buf->pos = buf->start;
-                buf->last = buf->start;
-            }
-
-            window = buf->end - buf->last;
-            window -= h2c->state.length - size;
-
-            if (window < stream->recv_window) {
-                ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
-                              "http2 negative window update");
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-
-            if (window > stream->recv_window) {
-                if (ngx_http_v2_send_window_update(h2c, stream->node->id,
-                                                   window - stream->recv_window)
-                    == NGX_ERROR)
-                {
-                    return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-                }
-
-                stream->recv_window = window;
-            }
-        }
-
         ngx_http_run_posted_requests(fc);
 
     } else if (size) {
@@ -4263,22 +4229,6 @@
                 rb->rest = 0;
             }
 
-            if (r->request_body_no_buffering && !flush) {
-                break;
-            }
-
-            /* pass buffer to request body filter chain */
-
-            rc = ngx_http_v2_filter_request_body(r);
-
-            if (rc != NGX_OK) {
-                return rc;
-            }
-
-            if (rb->rest == 0) {
-                break;
-            }
-
             if (size == 0) {
                 break;
             }
@@ -4287,6 +4237,14 @@
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
                        "http2 request body rest %O", rb->rest);
 
+        if (flush) {
+            rc = ngx_http_v2_filter_request_body(r);
+
+            if (rc != NGX_OK) {
+                return rc;
+            }
+        }
+
         if (rb->rest == 0 && rb->last_saved) {
             break;
         }
@@ -4295,12 +4253,8 @@
             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
             ngx_add_timer(fc->read, clcf->client_body_timeout);
 
-            if (r->request_body_no_buffering) {
-                if (!flush) {
-                    ngx_post_event(fc->read, &ngx_posted_events);
-                }
-
-                return NGX_AGAIN;
+            if (!flush) {
+                ngx_post_event(fc->read, &ngx_posted_events);
             }
 
             return NGX_AGAIN;
@@ -4469,6 +4423,10 @@
         return;
     }
 
+    if (r->stream->no_flow_control) {
+        return;
+    }
+
     if (r->request_body->rest == 0) {
         return;
     }