From 3575f44a17cb533e19616a6f730ca077a68e2b0a Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 3 Sep 2021 17:19:33 +0300 Subject: [PATCH 1/7] Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 16557ff8b611748e463ff951d6931fb60d9b78f1 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 2 Sep 2021 12:25:37 +0300 Subject: [PATCH 2/7] Fixed debug logging. --- src/http/v2/ngx_http_v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 27fb6cdb9f7aa9d6258251d565b199e2a15f5286 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:47 +0300 Subject: [PATCH 3/7] 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(-) 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) { From 584a30b4d51302755c5600892fc293b1586985f7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:48 +0300 Subject: [PATCH 4/7] 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(-) 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; From 243469df65fca2a853c6fe32754d1bfe19567cd2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 6 Sep 2021 14:54:50 +0300 Subject: [PATCH 5/7] 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 | 72 ++++++++------------------------------- 1 file changed, 15 insertions(+), 57 deletions(-) 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,22 +4229,6 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, rb->rest = 0; } - if (r->request_body_no_buffering && !flush) { - break; - } - - /* pass buffer to request body filter chain */ - - rc = ngx_http_v2_filter_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - if (rb->rest == 0) { - break; - } - if (size == 0) { break; } @@ -4287,6 +4237,14 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, 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 && 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; } From 0b65f34ef072c18ed688babe3c36781dda4c717d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 7 Sep 2021 18:21:02 +0300 Subject: [PATCH 6/7] nginx-1.21.3-RELEASE --- docs/xml/nginx/changes.xml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index fb64a4732..65772d028 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,33 @@ + + + + +оптимизация чтения тела запроса +при использовании HTTP/2. + + +optimization of client request body reading +when using HTTP/2. + + + + + +во внутреннем API для обработки тела запроса +при использовании HTTP/2 и буферизации обрабатываемых данных. + + +in request body filters internal API +when using HTTP/2 and buffering of the data being processed. + + + + + + From 97a5029ef441ffbe123c59669c18ab2c72ad3d09 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 7 Sep 2021 18:21:03 +0300 Subject: [PATCH 7/7] release-1.21.3 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index e9aa48d74..34b2f18af 100644 --- a/.hgtags +++ b/.hgtags @@ -463,3 +463,4 @@ ffcbb9980ee2bad27b4d7b1cd680b14ff47b29aa release-1.19.10 df34dcc9ac072ffd0945e5a1f3eb7987e8275375 release-1.21.0 a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1 bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2 +2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3