[nginx] HTTP/2: fixed window updates when buffering in filters.

Maxim Dounin mdounin at mdounin.ru
Mon Sep 6 13:40:58 UTC 2021


details:   https://hg.nginx.org/nginx/rev/e9f402bfe37e
branches:  
changeset: 7922:e9f402bfe37e
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Mon Sep 06 14:54:47 2021 +0300
description:
HTTP/2: fixed window updates when buffering in filters.

In the body read handler, the window was incorrectly calculated
based on the full buffer size instead of the amount of free space
in the buffer.  If the request body is buffered by a filter, and
the buffer is not empty after the read event is generated by the
filter to resume request body processing, this could result in
"http2 negative window update" alerts.

Further, in the body ready handler and in ngx_http_v2_state_read_data()
the buffer wasn't cleared when the data were already written to disk,
so the client might stuck without window updates.

diffstat:

 src/http/v2/ngx_http_v2.c |  20 ++++++++++++++++++--
 1 files changed, 18 insertions(+), 2 deletions(-)

diffs (43 lines):

diff -r 2245324a507a -r e9f402bfe37e src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c	Thu Sep 02 12:25:37 2021 +0300
+++ b/src/http/v2/ngx_http_v2.c	Mon Sep 06 14:54:47 2021 +0300
@@ -1148,10 +1148,18 @@ ngx_http_v2_state_read_data(ngx_http_v2_
             ngx_http_finalize_request(r, rc);
         }
 
-        if (rc == NGX_AGAIN && !stream->no_flow_control) {
+        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) {
@@ -4459,10 +4467,18 @@ ngx_http_v2_read_client_request_body_han
         return;
     }
 
+    if (r->request_body->busy != NULL) {
+        return;
+    }
+
     stream = r->stream;
     h2c = stream->connection;
 
     buf = r->request_body->buf;
+
+    buf->pos = buf->start;
+    buf->last = buf->start;
+
     window = buf->end - buf->start;
 
     if (h2c->state.stream == stream) {


More information about the nginx-devel mailing list