]> git.kaiwu.me - nginx.git/commitdiff
HTTP/2: sending RST_STREAM with NO_ERROR to discard request body.
authorValentin Bartenev <vbart@nginx.com>
Fri, 1 Apr 2016 12:56:03 +0000 (15:56 +0300)
committerValentin Bartenev <vbart@nginx.com>
Fri, 1 Apr 2016 12:56:03 +0000 (15:56 +0300)
RFC 7540 states that "A server can send a complete response prior to the client
sending an entire request if the response does not depend on any portion of the
request that has not been sent and received.  When this is true, a server MAY
request that the client abort transmission of a request without error by sending
a RST_STREAM with an error code of NO_ERROR after sending a complete response
(i.e., a frame with the END_STREAM flag)."

This should prevent a client from blocking on the stream window, since it isn't
maintained for closed streams.  Currently, quite big initial stream windows are
used, so such blocking is very unlikly, but that will be changed in the further
patches.

src/http/v2/ngx_http_v2.c
src/http/v2/ngx_http_v2.h

index d63226596a4222d8c56c80d512a056f2441bdfe8..95c737cdb3d222fc71b799c6f1dfdb8b1b700c91 100644 (file)
@@ -3709,7 +3709,7 @@ ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
         return NGX_ERROR;
     }
 
-    stream->out_closed = 1;
+    stream->rst_sent = 1;
 
     fc = stream->request->connection;
     fc->error = 1;
@@ -3744,13 +3744,23 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
         return;
     }
 
-    if (!stream->out_closed) {
-        if (ngx_http_v2_send_rst_stream(h2c, node->id,
-                                     fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
-                                                  : NGX_HTTP_V2_INTERNAL_ERROR)
-            != NGX_OK)
-        {
-            h2c->connection->error = 1;
+    if (!stream->rst_sent && !h2c->connection->error) {
+
+        if (!stream->out_closed) {
+            if (ngx_http_v2_send_rst_stream(h2c, node->id,
+                                      fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
+                                                   : NGX_HTTP_V2_INTERNAL_ERROR)
+                != NGX_OK)
+            {
+                h2c->connection->error = 1;
+            }
+
+        } else if (!stream->in_closed) {
+            if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
+                != NGX_OK)
+            {
+                h2c->connection->error = 1;
+            }
         }
     }
 
@@ -3942,23 +3952,23 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
 
     c = h2c->connection;
 
-    if (h2c->state.stream) {
-        h2c->state.stream->out_closed = 1;
-        ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST);
-    }
-
     h2c->blocked = 1;
 
     if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
         (void) ngx_http_v2_send_output_queue(h2c);
     }
 
+    c->error = 1;
+
+    if (h2c->state.stream) {
+        ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST);
+    }
+
     if (!h2c->processing) {
         ngx_http_close_connection(c);
         return;
     }
 
-    c->error = 1;
     c->read->handler = ngx_http_empty_handler;
     c->write->handler = ngx_http_empty_handler;
 
index 5a791e62697aa092c66c53a9854117c2a8f38f28..4d1f2c78512407aad90796f38dd70c459867e401 100644 (file)
@@ -194,6 +194,7 @@ struct ngx_http_v2_stream_s {
     unsigned                         exhausted:1;
     unsigned                         in_closed:1;
     unsigned                         out_closed:1;
+    unsigned                         rst_sent:1;
     unsigned                         skip_data:2;
 };