[PATCH] HTTP/2: fix flow control with padded DATA frames
Valentin V. Bartenev
vbart at nginx.com
Mon Mar 27 17:44:21 UTC 2017
On Sunday 26 March 2017 01:41:11 Piotr Sikora via nginx-devel wrote:
> # HG changeset patch
> # User Piotr Sikora <piotrsikora at google.com>
> # Date 1490516704 25200
> # Sun Mar 26 01:25:04 2017 -0700
> # Node ID 899a53d2789b8c6bafdd5e40d78b4e92dd32dd10
> # Parent 22be63bf21edaa1b8ea916c7d8cd4e5fe4892061
> HTTP/2: fix flow control with padded DATA frames.
>
> Previously, flow control didn't account for padding in DATA frames,
> which meant that its view of the world could drift from peer's view
> by up to 256 bytes per received padded DATA frame, which could lead
> to a deadlock.
>
> Signed-off-by: Piotr Sikora <piotrsikora at google.com>
>
> diff -r 22be63bf21ed -r 899a53d2789b src/http/v2/ngx_http_v2.c
> --- a/src/http/v2/ngx_http_v2.c
> +++ b/src/http/v2/ngx_http_v2.c
> @@ -783,9 +783,12 @@ ngx_http_v2_state_head(ngx_http_v2_conne
> static u_char *
> ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
> {
> + size_t size;
> ngx_http_v2_node_t *node;
> ngx_http_v2_stream_t *stream;
>
> + size = h2c->state.length;
> +
> if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
>
> if (h2c->state.length == 0) {
> @@ -802,33 +805,32 @@ ngx_http_v2_state_data(ngx_http_v2_conne
> }
>
> h2c->state.padding = *pos++;
> - h2c->state.length--;
> -
> - if (h2c->state.padding > h2c->state.length) {
> +
> + if (h2c->state.padding >= size) {
> ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> "client sent padded DATA frame "
> "with incorrect length: %uz, padding: %uz",
> - h2c->state.length, h2c->state.padding);
> + size, h2c->state.padding);
>
> return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
> }
>
> - h2c->state.length -= h2c->state.padding;
> + h2c->state.length -= 1 + h2c->state.padding;
> }
IMHO, the previous version of this fragment with explicit h2c->state.length
decrement right after reading the padding size and "> h2c->state.length"
condition is more readable.
YMMV.
>
> ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
> "http2 DATA frame");
>
> - if (h2c->state.length > h2c->recv_window) {
> + if (size > h2c->recv_window) {
> ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> "client violated connection flow control: "
> "received DATA frame length %uz, available window %uz",
> - h2c->state.length, h2c->recv_window);
> + size, h2c->recv_window);
>
> return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
> }
>
> - h2c->recv_window -= h2c->state.length;
> + h2c->recv_window -= size;
>
> if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
>
> @@ -854,11 +856,11 @@ ngx_http_v2_state_data(ngx_http_v2_conne
>
> stream = node->stream;
>
> - if (h2c->state.length > stream->recv_window) {
> + if (size > stream->recv_window) {
> ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
> "client violated flow control for stream %ui: "
> "received DATA frame length %uz, available window %uz",
> - node->id, h2c->state.length, stream->recv_window);
> + node->id, size, stream->recv_window);
>
> if (ngx_http_v2_terminate_stream(h2c, stream,
> NGX_HTTP_V2_FLOW_CTRL_ERROR)
> @@ -871,7 +873,7 @@ ngx_http_v2_state_data(ngx_http_v2_conne
> return ngx_http_v2_state_skip_padded(h2c, pos, end);
> }
>
> - stream->recv_window -= h2c->state.length;
> + stream->recv_window -= size;
>
> if (stream->no_flow_control
> && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
>
Everything else looks good to me.
wbr, Valentin V. Bartenev
More information about the nginx-devel
mailing list