aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2016-04-01 15:56:03 +0300
committerValentin Bartenev <vbart@nginx.com>2016-04-01 15:56:03 +0300
commitcedba685a1eb18ca960b2eab3fafdc2afdbd624a (patch)
tree6a121230ce1687dcb871a5fbfcd2f274652e3a47 /src
parent7cee215f15cf91e40fe5709485e60655292e2c67 (diff)
downloadnginx-cedba685a1eb18ca960b2eab3fafdc2afdbd624a.tar.gz
nginx-cedba685a1eb18ca960b2eab3fafdc2afdbd624a.zip
HTTP/2: sending RST_STREAM with NO_ERROR to discard request body.
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.
Diffstat (limited to 'src')
-rw-r--r--src/http/v2/ngx_http_v2.c38
-rw-r--r--src/http/v2/ngx_http_v2.h1
2 files changed, 25 insertions, 14 deletions
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index d63226596..95c737cdb 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -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;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index 5a791e626..4d1f2c785 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -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;
};