]> git.kaiwu.me - nginx.git/commitdiff
HTTP/2: send WINDOW_UPDATE instead of RST_STREAM with NO_ERROR.
authorValentin Bartenev <vbart@nginx.com>
Thu, 14 Apr 2016 12:14:15 +0000 (15:14 +0300)
committerValentin Bartenev <vbart@nginx.com>
Thu, 14 Apr 2016 12:14:15 +0000 (15:14 +0300)
After the 92464ebace8e change, it has been discovered that not all
clients follow the RFC and handle RST_STREAM with NO_ERROR properly.

Notably, Chrome currently interprets it as INTERNAL_ERROR and discards
the response.

As a workaround, instead of RST_STREAM the maximum stream window update
will be sent, which will let client to send up to 2 GB of a request body
data before getting stuck on flow control.  All the received data will
be silently discarded.

See for details:
http://mailman.nginx.org/pipermail/nginx-devel/2016-April/008143.html
https://bugs.chromium.org/p/chromium/issues/detail?id=603182

src/http/v2/ngx_http_v2.c

index 74754977b661340708a8da530a9d5aad2dce1b42..c88e29728a4e2c693dae0ae135dc72601a8b08e2 100644 (file)
@@ -3860,11 +3860,33 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
             }
 
         } else if (!stream->in_closed) {
+#if 0
             if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
                 != NGX_OK)
             {
                 h2c->connection->error = 1;
             }
+#else
+            /*
+             * At the time of writing at least the latest versions of Chrome
+             * do not properly handle RST_STREAM with NO_ERROR status.
+             *
+             * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182
+             *
+             * As a workaround, the stream window is maximized before closing
+             * the stream.  This allows a client to send up to 2 GB of data
+             * before getting blocked on flow control.
+             */
+
+            if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW
+                && ngx_http_v2_send_window_update(h2c, node->id,
+                                                  NGX_HTTP_V2_MAX_WINDOW
+                                                  - stream->recv_window)
+                   != NGX_OK)
+            {
+                h2c->connection->error = 1;
+            }
+#endif
         }
     }