]> git.kaiwu.me - nginx.git/commitdiff
HTTP/2: fixed window updates when buffering in filters.
authorMaxim Dounin <mdounin@mdounin.ru>
Mon, 6 Sep 2021 11:54:47 +0000 (14:54 +0300)
committerMaxim Dounin <mdounin@mdounin.ru>
Mon, 6 Sep 2021 11:54:47 +0000 (14:54 +0300)
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.

src/http/v2/ngx_http_v2.c

index 3d3afaf2d071af46ae0ba25ba082a1c8d96af563..615f933cf28d91d388f8a3dc54f8f731a01406fd 100644 (file)
@@ -1148,10 +1148,18 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
             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;
-            window = buf->end - buf->last;
 
+            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_handler(ngx_http_request_t *r)
         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) {