[nginx] HTTP/2: send WINDOW_UPDATE instead of RST_STREAM with NO_ERROR.

Valentin Bartenev vbart at nginx.com
Thu Apr 14 12:25:37 UTC 2016


details:   http://hg.nginx.org/nginx/rev/8df664ebe037
branches:  
changeset: 6515:8df664ebe037
user:      Valentin Bartenev <vbart at nginx.com>
date:      Thu Apr 14 15:14:15 2016 +0300
description:
HTTP/2: send WINDOW_UPDATE instead of RST_STREAM with NO_ERROR.

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

diffstat:

 src/http/v2/ngx_http_v2.c |  22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diffs (37 lines):

diff -r 0aa07850922f -r 8df664ebe037 src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c	Thu Apr 14 15:14:15 2016 +0300
+++ b/src/http/v2/ngx_http_v2.c	Thu Apr 14 15:14:15 2016 +0300
@@ -3860,11 +3860,33 @@ ngx_http_v2_close_stream(ngx_http_v2_str
             }
 
         } 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
         }
     }
 



More information about the nginx-devel mailing list