From 3575f44a17cb533e19616a6f730ca077a68e2b0a Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 3 Sep 2021 17:19:33 +0300 Subject: Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/nginx.h b/src/core/nginx.h index 51155410b..6b134945e 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021002 -#define NGINX_VERSION "1.21.2" +#define nginx_version 1021003 +#define NGINX_VERSION "1.21.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- cgit From 16557ff8b611748e463ff951d6931fb60d9b78f1 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 2 Sep 2021 12:25:37 +0300 Subject: Fixed debug logging. --- src/http/v2/ngx_http_v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 79c4f17c2..3d3afaf2d 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -4214,8 +4214,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, /* update chains */ - ngx_log_error(NGX_LOG_DEBUG, fc->log, 0, - "http2 body update chains"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 body update chains"); rc = ngx_http_v2_filter_request_body(r); -- cgit From 27fb6cdb9f7aa9d6258251d565b199e2a15f5286 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:47 +0300 Subject: HTTP/2: fixed window updates when buffering in filters. In the body read handler, the window was incorrectly calculated based on the full buffer size instead of the amount of free space in the buffer. If the request body is buffered by a filter, and the buffer is not empty after the read event is generated by the filter to resume request body processing, this could result in "http2 negative window update" alerts. Further, in the body ready handler and in ngx_http_v2_state_read_data() the buffer wasn't cleared when the data were already written to disk, so the client might stuck without window updates. --- src/http/v2/ngx_http_v2.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3d3afaf2d..615f933cf 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1148,10 +1148,18 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_finalize_request(r, rc); } - if (rc == NGX_AGAIN && !stream->no_flow_control) { + if (rc == NGX_AGAIN + && !stream->no_flow_control + && !r->request_body_no_buffering) + { buf = r->request_body->buf; - window = buf->end - buf->last; + if (r->request_body->busy == NULL) { + buf->pos = buf->start; + buf->last = buf->start; + } + + window = buf->end - buf->last; window -= h2c->state.length - size; if (window < stream->recv_window) { @@ -4459,10 +4467,18 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) return; } + if (r->request_body->busy != NULL) { + return; + } + stream = r->stream; h2c = stream->connection; buf = r->request_body->buf; + + buf->pos = buf->start; + buf->last = buf->start; + window = buf->end - buf->start; if (h2c->state.stream == stream) { -- cgit From 584a30b4d51302755c5600892fc293b1586985f7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:48 +0300 Subject: HTTP/2: fixed timers left after request body reading. Following rb->filter_need_buffering changes, request body reading is only finished after the filter chain is called and rb->last_saved is set. As such, with r->request_body_no_buffering, timer on fc->read is no longer removed when the last part of the body is received, potentially resulting in incorrect behaviour. The fix is to call ngx_http_v2_process_request_body() from the ngx_http_v2_read_unbuffered_request_body() function instead of directly calling ngx_http_v2_filter_request_body(), so the timer is properly removed. --- src/http/v2/ngx_http_v2.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 615f933cf..bbb86aee5 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -4263,7 +4263,7 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, rb->rest = 0; } - if (r->request_body_no_buffering) { + if (r->request_body_no_buffering && !flush) { break; } @@ -4296,7 +4296,10 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, ngx_add_timer(fc->read, clcf->client_body_timeout); if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + return NGX_AGAIN; } @@ -4309,7 +4312,10 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, } if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + return NGX_OK; } @@ -4527,7 +4533,6 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_v2_stream_t *stream; ngx_http_v2_connection_t *h2c; - ngx_http_core_loc_conf_t *clcf; stream = r->stream; fc = r->connection; @@ -4551,14 +4556,14 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - rc = ngx_http_v2_filter_request_body(r); + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } - if (r->request_body->rest == 0 && r->request_body->last_saved) { + if (rc == NGX_OK) { return NGX_OK; } @@ -4606,11 +4611,6 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (stream->recv_window == 0) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - stream->recv_window = window; return NGX_AGAIN; -- cgit From 243469df65fca2a853c6fe32754d1bfe19567cd2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:50 +0300 Subject: HTTP/2: optimized processing of small DATA frames. The request body filter chain is no longer called after processing a DATA frame. Instead, we now post a read event to do this. This ensures that multiple small DATA frames read during the same event loop iteration are coalesced together, resulting in much faster processing. Since rb->buf can now contain unprocessed data, window update is no longer sent in ngx_http_v2_state_read_data() in case of flow control being used due to filter buffering. Instead, window will be updated by ngx_http_v2_read_client_request_body_handler() in the posted read event. --- src/http/v2/ngx_http_v2.c | 66 +++++++++-------------------------------------- 1 file changed, 12 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index bbb86aee5..3afa8b638 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1092,7 +1092,7 @@ static u_char * ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size, window; + size_t size; ngx_buf_t *buf; ngx_int_t rc; ngx_connection_t *fc; @@ -1148,40 +1148,6 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_finalize_request(r, rc); } - if (rc == NGX_AGAIN - && !stream->no_flow_control - && !r->request_body_no_buffering) - { - buf = r->request_body->buf; - - if (r->request_body->busy == NULL) { - buf->pos = buf->start; - buf->last = buf->start; - } - - window = buf->end - buf->last; - window -= h2c->state.length - size; - - if (window < stream->recv_window) { - ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, - "http2 negative window update"); - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } - - if (window > stream->recv_window) { - if (ngx_http_v2_send_window_update(h2c, stream->node->id, - window - stream->recv_window) - == NGX_ERROR) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } - - stream->recv_window = window; - } - } - ngx_http_run_posted_requests(fc); } else if (size) { @@ -4263,30 +4229,22 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, rb->rest = 0; } - if (r->request_body_no_buffering && !flush) { + if (size == 0) { break; } + } - /* pass buffer to request body filter chain */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body rest %O", rb->rest); + if (flush) { rc = ngx_http_v2_filter_request_body(r); if (rc != NGX_OK) { return rc; } - - if (rb->rest == 0) { - break; - } - - if (size == 0) { - break; - } } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 request body rest %O", rb->rest); - if (rb->rest == 0 && rb->last_saved) { break; } @@ -4295,12 +4253,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(fc->read, clcf->client_body_timeout); - if (r->request_body_no_buffering) { - if (!flush) { - ngx_post_event(fc->read, &ngx_posted_events); - } - - return NGX_AGAIN; + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); } return NGX_AGAIN; @@ -4469,6 +4423,10 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) return; } + if (r->stream->no_flow_control) { + return; + } + if (r->request_body->rest == 0) { return; } -- cgit