From 7970ab8ec60f2d8c21690974d704dd1e27d637e3 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Tue, 23 Nov 2021 12:52:43 +0300 Subject: [PATCH 01/34] 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 bc4af23af..5ad6aff45 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021004 -#define NGINX_VERSION "1.21.4" +#define nginx_version 1021005 +#define NGINX_VERSION "1.21.5" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From 2cf26199a334a552a31dc916f01099b2dc31db18 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Mon, 1 Nov 2021 18:09:34 +0300 Subject: [PATCH 02/34] SSL: $ssl_curve (ticket #2135). The variable contains a negotiated curve used for the handshake key exchange process. Known curves are listed by their names, unknown ones are shown in hex. Note that for resumed sessions in TLSv1.2 and older protocols, $ssl_curve contains the curve used during the initial handshake, while in TLSv1.3 it contains the curve used during the session resumption (see the SSL_get_negotiated_group manual page for details). The variable is only meaningful when using OpenSSL 3.0 and above. With older versions the variable is empty. --- src/event/ngx_event_openssl.c | 36 ++++++++++++++++++++++++++ src/event/ngx_event_openssl.h | 2 ++ src/http/modules/ngx_http_ssl_module.c | 3 +++ src/stream/ngx_stream_ssl_module.c | 3 +++ 4 files changed, 44 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 393ec9d57..f61e3c1c5 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -4772,6 +4772,42 @@ ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_get_negotiated_group + + int nid; + + nid = SSL_get_negotiated_group(c->ssl->connection); + + if (nid != NID_undef) { + + if ((nid & TLSEXT_nid_unknown) == 0) { + s->len = ngx_strlen(OBJ_nid2sn(nid)); + s->data = (u_char *) OBJ_nid2sn(nid); + return NGX_OK; + } + + s->len = sizeof("0x0000") - 1; + + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(s->data, "0x%04xd", nid & 0xffff); + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 80ee48d5f..d46ccde3a 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -269,6 +269,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index e94e11b01..fb9761ed4 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -384,6 +384,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 530fe8b3d..c5308322a 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -269,6 +269,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 }, From b7b4549c7a09983110a68c75204d88a72110053f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 25 Nov 2021 22:02:05 +0300 Subject: [PATCH 03/34] HTTP/2: fixed "task already active" with sendfile in threads. With sendfile in threads, "task already active" alerts might appear in logs if a write event happens on the main HTTP/2 connection, triggering a sendfile in threads while another thread operation is already running. Observed with "aio threads; aio_write on; sendfile on;" and with thread event handlers modified to post a write event to the main HTTP/2 connection (though can happen without any modifications). Similarly, sendfile() with AIO preloading on FreeBSD can trigger duplicate aio operation, resulting in "second aio post" alerts. This is, however, harder to reproduce, especially on modern FreeBSD systems, since sendfile() usually does not return EBUSY. Fix is to avoid starting a sendfile operation if other thread operation is active by checking r->aio in the thread handler (and, similarly, in aio preload handler). The added check also makes duplicate calls protection redundant, so it is removed. --- src/http/ngx_http_copy_filter_module.c | 38 ++++++++++++++++++++++-- src/http/ngx_http_upstream.c | 22 ++++++++++++++ src/os/unix/ngx_freebsd_sendfile_chain.c | 13 -------- src/os/unix/ngx_linux_sendfile_chain.c | 9 ------ 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c8ad5daee..6c93a3bd9 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -219,13 +219,25 @@ ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) ngx_http_request_t *r; ngx_output_chain_ctx_t *ctx; + aio = file->file->aio; + r = aio->data; + + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + return NGX_AGAIN; + } + n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); if (n == NGX_AGAIN) { - aio = file->file->aio; aio->handler = ngx_http_copy_aio_sendfile_event_handler; - r = aio->data; r->main->blocked++; r->aio = 1; @@ -263,6 +275,7 @@ static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_output_chain_ctx_t *ctx; @@ -270,6 +283,27 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 84f4acc1c..308aa0f95 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3860,6 +3860,7 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; ngx_event_pipe_t *p; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; @@ -3867,6 +3868,27 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; p = r->upstream->pipe; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 3d415bd2c..750c12fc3 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -255,19 +255,6 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) #if (NGX_HAVE_AIO_SENDFILE) if (ebusy) { - if (aio->event.active) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - if (sent) { - c->busy_count = 0; - } - - return in; - } - if (sent == 0) { c->busy_count++; diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 91e7f1d93..101d91a9a 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -379,15 +379,6 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) return ctx->sent; } - if (task->event.active && ctx->file == file) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - return NGX_DONE; - } - ctx->file = file; ctx->socket = c->fd; ctx->size = size; From 8d82e08cdbb3fddd0181833c9049357cc4334f9c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 25 Nov 2021 22:02:10 +0300 Subject: [PATCH 04/34] HTTP/2: fixed sendfile() aio handling. With sendfile() in threads ("aio threads; sendfile on;"), client connection can block on writing, waiting for sendfile() to complete. In HTTP/2 this might result in the request hang, since an attempt to continue processing in thread event handler will call request's write event handler, which is usually stopped by ngx_http_v2_send_chain(): it does nothing if there are no additional data and stream->queued is set. Further, HTTP/2 resets stream's c->write->ready to 0 if writing blocks, so just fixing ngx_http_v2_send_chain() is not enough. Can be reproduced with test suite on Linux with: TEST_NGINX_GLOBALS_HTTP="aio threads; sendfile on;" prove h2*.t The following tests currently fail: h2_keepalive.t, h2_priority.t, h2_proxy_max_temp_file_size.t, h2.t, h2_trailers.t. Similarly, sendfile() with AIO preloading on FreeBSD can block as well, with similar results. This is, however, harder to reproduce, especially on modern FreeBSD systems, since sendfile() usually does not return EBUSY. Fix is to modify ngx_http_v2_send_chain() so it actually tries to send data to the main connection when called, and to make sure that c->write->ready is set by the relevant event handlers. --- src/http/ngx_http_copy_filter_module.c | 32 ++++++++++++++++++++++++- src/http/ngx_http_upstream.c | 14 +++++++++++ src/http/v2/ngx_http_v2_filter_module.c | 29 +++++++++++++++------- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index 6c93a3bd9..b47e4afa7 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -253,16 +253,32 @@ static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) { ngx_event_aio_t *aio; + ngx_connection_t *c; ngx_http_request_t *r; aio = ev->data; r = aio->data; + c = r->connection; r->main->blocked--; r->aio = 0; ev->complete = 0; - r->connection->write->handler(r->connection->write); +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() preload + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + + c->write->handler(c->write); } #endif @@ -357,6 +373,20 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 308aa0f95..fd8728c28 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3940,6 +3940,20 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 90993b6d4..77cf03cf9 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1407,6 +1407,9 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size = 0; #endif + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 send chain: %p", in); + while (in) { size = ngx_buf_size(in->buf); @@ -1425,12 +1428,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) return NGX_CHAIN_ERROR; } - if (stream->queued) { - fc->write->active = 1; - fc->write->ready = 0; - - } else { - fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; } return NULL; @@ -1439,9 +1438,16 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) h2c = stream->connection; if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->active = 1; - fc->write->ready = 0; - return in; + + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->active = 1; + fc->write->ready = 0; + return in; + } } if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { @@ -1784,6 +1790,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c, static ngx_inline ngx_int_t ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream) { + if (stream->queued == 0) { + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + return NGX_OK; + } + stream->blocked = 1; if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) { From 7efbe0a4bb348c606fe1003f945a742de2c8048f Mon Sep 17 00:00:00 2001 From: Gena Makhomed Date: Mon, 20 Dec 2021 20:02:48 +0200 Subject: [PATCH 05/34] Contrib: vim syntax, update core and 3rd party module directives. --- contrib/vim/syntax/nginx.vim | 40 +++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 4907e2a54..1b52d4869 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -152,6 +152,7 @@ syn keyword ngxDirective contained auth_jwt_header_set syn keyword ngxDirective contained auth_jwt_key_file syn keyword ngxDirective contained auth_jwt_key_request syn keyword ngxDirective contained auth_jwt_leeway +syn keyword ngxDirective contained auth_jwt_require syn keyword ngxDirective contained auth_jwt_type syn keyword ngxDirective contained auth_request syn keyword ngxDirective contained auth_request_set @@ -335,6 +336,10 @@ syn keyword ngxDirective contained ip_hash syn keyword ngxDirective contained js_access syn keyword ngxDirective contained js_body_filter syn keyword ngxDirective contained js_content +syn keyword ngxDirective contained js_fetch_ciphers +syn keyword ngxDirective contained js_fetch_protocols +syn keyword ngxDirective contained js_fetch_trusted_certificate +syn keyword ngxDirective contained js_fetch_verify_depth syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_header_filter syn keyword ngxDirective contained js_import @@ -402,6 +407,7 @@ syn keyword ngxDirective contained mp4_buffer_size syn keyword ngxDirective contained mp4_limit_rate syn keyword ngxDirective contained mp4_limit_rate_after syn keyword ngxDirective contained mp4_max_buffer_size +syn keyword ngxDirective contained mp4_start_key_frame syn keyword ngxDirective contained msie_padding syn keyword ngxDirective contained msie_refresh syn keyword ngxDirective contained multi_accept @@ -458,6 +464,7 @@ syn keyword ngxDirective contained proxy_cookie_flags syn keyword ngxDirective contained proxy_cookie_path syn keyword ngxDirective contained proxy_download_rate syn keyword ngxDirective contained proxy_force_ranges +syn keyword ngxDirective contained proxy_half_close syn keyword ngxDirective contained proxy_headers_hash_bucket_size syn keyword ngxDirective contained proxy_headers_hash_max_size syn keyword ngxDirective contained proxy_hide_header @@ -597,6 +604,7 @@ syn keyword ngxDirective contained ssi_min_file_chunk syn keyword ngxDirective contained ssi_silent_errors syn keyword ngxDirective contained ssi_types syn keyword ngxDirective contained ssi_value_length +syn keyword ngxDirective contained ssl_alpn syn keyword ngxDirective contained ssl_buffer_size syn keyword ngxDirective contained ssl_certificate syn keyword ngxDirective contained ssl_certificate_key @@ -788,11 +796,15 @@ syn keyword ngxDirectiveThirdParty contained auth_digest_user_file syn keyword ngxDirectiveThirdParty contained auth_gss syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal +syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal_regex +syn keyword ngxDirectiveThirdParty contained auth_gss_constrained_delegation +syn keyword ngxDirectiveThirdParty contained auth_gss_delegate_credentials syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm syn keyword ngxDirectiveThirdParty contained auth_gss_format_full syn keyword ngxDirectiveThirdParty contained auth_gss_keytab syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local syn keyword ngxDirectiveThirdParty contained auth_gss_realm +syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache syn keyword ngxDirectiveThirdParty contained auth_gss_service_name " LDAP Authentication @@ -969,7 +981,6 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_hide_parent_dir syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks syn keyword ngxDirectiveThirdParty contained fancyindex_ignore syn keyword ngxDirectiveThirdParty contained fancyindex_localtime -syn keyword ngxDirectiveThirdParty contained fancyindex_name_length syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles syn keyword ngxDirectiveThirdParty contained fancyindex_show_path syn keyword ngxDirectiveThirdParty contained fancyindex_time_format @@ -1059,7 +1070,9 @@ syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request syn keyword ngxDirectiveThirdParty contained nchan_pubsub syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location +syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_discovered_ip_range_blacklist syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace @@ -1067,12 +1080,29 @@ syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target syn keyword ngxDirectiveThirdParty contained nchan_redis_pass syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable +syn keyword ngxDirectiveThirdParty contained nchan_redis_password syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size syn keyword ngxDirectiveThirdParty contained nchan_redis_server +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_ciphers +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate_key +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_server_name +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate_path +syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_verify_certificate syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode syn keyword ngxDirectiveThirdParty contained nchan_redis_subscribe_weights +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_ciphers +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_client_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_server_name +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate_path +syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_verify_certificate syn keyword ngxDirectiveThirdParty contained nchan_redis_url +syn keyword ngxDirectiveThirdParty contained nchan_redis_username syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting syn keyword ngxDirectiveThirdParty contained nchan_shared_memory_size syn keyword ngxDirectiveThirdParty contained nchan_storage_engine @@ -1385,6 +1415,7 @@ syn keyword ngxDirectiveThirdParty contained lua_socket_read_timeout syn keyword ngxDirectiveThirdParty contained lua_socket_send_lowat syn keyword ngxDirectiveThirdParty contained lua_socket_send_timeout syn keyword ngxDirectiveThirdParty contained lua_ssl_ciphers +syn keyword ngxDirectiveThirdParty contained lua_ssl_conf_command syn keyword ngxDirectiveThirdParty contained lua_ssl_crl syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate @@ -1392,6 +1423,7 @@ syn keyword ngxDirectiveThirdParty contained lua_ssl_verify_depth syn keyword ngxDirectiveThirdParty contained lua_thread_cache_max_entries syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers syn keyword ngxDirectiveThirdParty contained lua_use_default_type +syn keyword ngxDirectiveThirdParty contained lua_worker_thread_vm_pool_size syn keyword ngxDirectiveThirdParty contained rewrite_by_lua syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_block syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_file @@ -1401,6 +1433,8 @@ syn keyword ngxDirectiveThirdParty contained set_by_lua_block syn keyword ngxDirectiveThirdParty contained set_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_block syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_file +syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_block +syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_block syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_file syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_block @@ -1719,15 +1753,18 @@ syn keyword ngxDirectiveThirdParty contained set_base32_alphabet syn keyword ngxDirectiveThirdParty contained set_base32_padding syn keyword ngxDirectiveThirdParty contained set_decode_base32 syn keyword ngxDirectiveThirdParty contained set_decode_base64 +syn keyword ngxDirectiveThirdParty contained set_decode_base64url syn keyword ngxDirectiveThirdParty contained set_decode_hex syn keyword ngxDirectiveThirdParty contained set_encode_base32 syn keyword ngxDirectiveThirdParty contained set_encode_base64 +syn keyword ngxDirectiveThirdParty contained set_encode_base64url syn keyword ngxDirectiveThirdParty contained set_encode_hex syn keyword ngxDirectiveThirdParty contained set_escape_uri syn keyword ngxDirectiveThirdParty contained set_formatted_gmt_time syn keyword ngxDirectiveThirdParty contained set_formatted_local_time syn keyword ngxDirectiveThirdParty contained set_hashed_upstream syn keyword ngxDirectiveThirdParty contained set_hmac_sha1 +syn keyword ngxDirectiveThirdParty contained set_hmac_sha256 syn keyword ngxDirectiveThirdParty contained set_if_empty syn keyword ngxDirectiveThirdParty contained set_local_today syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding @@ -1849,6 +1886,7 @@ syn keyword ngxDirectiveThirdParty contained vod_notification_uri syn keyword ngxDirectiveThirdParty contained vod_open_file_thread_pool syn keyword ngxDirectiveThirdParty contained vod_output_buffer_pool syn keyword ngxDirectiveThirdParty contained vod_parse_hdlr_name +syn keyword ngxDirectiveThirdParty contained vod_parse_udta_name syn keyword ngxDirectiveThirdParty contained vod_path_response_postfix syn keyword ngxDirectiveThirdParty contained vod_path_response_prefix syn keyword ngxDirectiveThirdParty contained vod_performance_counters From 6624ccbe0cfd7259634b0a0f3aa61b1422651c35 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Tue, 21 Dec 2021 07:54:16 +0300 Subject: [PATCH 06/34] Moved Huffman coding out of HTTP/2. ngx_http_v2_huff_decode.c and ngx_http_v2_huff_encode.c are renamed to ngx_http_huff_decode.c and ngx_http_huff_encode.c. --- auto/modules | 7 +++-- auto/sources | 3 ++ src/http/modules/ngx_http_grpc_module.c | 16 +++++----- src/http/ngx_http.h | 8 +++++ ...2_huff_decode.c => ngx_http_huff_decode.c} | 18 +++++------ ...2_huff_encode.c => ngx_http_huff_encode.c} | 30 +++++++++---------- src/http/v2/ngx_http_v2.c | 8 ++--- src/http/v2/ngx_http_v2.h | 6 ---- src/http/v2/ngx_http_v2_encode.c | 2 +- 9 files changed, 53 insertions(+), 45 deletions(-) rename src/http/{v2/ngx_http_v2_huff_decode.c => ngx_http_huff_decode.c} (99%) rename src/http/{v2/ngx_http_v2_huff_encode.c => ngx_http_huff_encode.c} (93%) diff --git a/auto/modules b/auto/modules index 22e1a9586..ff3d13be3 100644 --- a/auto/modules +++ b/auto/modules @@ -102,6 +102,11 @@ if [ $HTTP = YES ]; then fi + if [ $HTTP_V2 = YES ]; then + HTTP_SRCS="$HTTP_SRCS $HTTP_HUFF_SRCS" + fi + + # the module order is important # ngx_http_static_module # ngx_http_gzip_static_module @@ -427,8 +432,6 @@ if [ $HTTP = YES ]; then ngx_module_srcs="src/http/v2/ngx_http_v2.c \ src/http/v2/ngx_http_v2_table.c \ src/http/v2/ngx_http_v2_encode.c \ - src/http/v2/ngx_http_v2_huff_decode.c \ - src/http/v2/ngx_http_v2_huff_encode.c \ src/http/v2/ngx_http_v2_module.c" ngx_module_libs= ngx_module_link=$HTTP_V2 diff --git a/auto/sources b/auto/sources index 3dad11132..156f7979e 100644 --- a/auto/sources +++ b/auto/sources @@ -255,3 +255,6 @@ NGX_WIN32_RC="src/os/win32/nginx.rc" HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c + +HTTP_HUFF_SRCS="src/http/ngx_http_huff_decode.c + src/http/ngx_http_huff_encode.c" diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 6842b7c6e..864fc4fda 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -3180,10 +3180,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3289,10 +3289,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 444f93536..7bb881ec2 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -171,6 +171,14 @@ ngx_uint_t ngx_http_degraded(ngx_http_request_t *); #endif +#if (NGX_HTTP_V2) +ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len, + u_char **dst, ngx_uint_t last, ngx_log_t *log); +size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, + ngx_uint_t lower); +#endif + + extern ngx_module_t ngx_http_module; extern ngx_str_t ngx_http_html_default_types[]; diff --git a/src/http/v2/ngx_http_v2_huff_decode.c b/src/http/ngx_http_huff_decode.c similarity index 99% rename from src/http/v2/ngx_http_v2_huff_decode.c rename to src/http/ngx_http_huff_decode.c index 49ca576f7..14b7b7896 100644 --- a/src/http/v2/ngx_http_v2_huff_decode.c +++ b/src/http/ngx_http_huff_decode.c @@ -15,14 +15,14 @@ typedef struct { u_char emit; u_char sym; u_char ending; -} ngx_http_v2_huff_decode_code_t; +} ngx_http_huff_decode_code_t; -static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state, +static ngx_inline ngx_int_t ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst); -static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = +static ngx_http_huff_decode_code_t ngx_http_huff_decode_codes[256][16] = { /* 0 */ { @@ -2640,7 +2640,7 @@ static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = ngx_int_t -ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, +ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log) { u_char *end, ch, ending; @@ -2653,7 +2653,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, while (src != end) { ch = *src++; - if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch >> 4, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2663,7 +2663,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, return NGX_ERROR; } - if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch & 0xf, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2692,12 +2692,12 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, static ngx_inline ngx_int_t -ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, +ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst) { - ngx_http_v2_huff_decode_code_t code; + ngx_http_huff_decode_code_t code; - code = ngx_http_v2_huff_decode_codes[*state][bits]; + code = ngx_http_huff_decode_codes[*state][bits]; if (code.next == *state) { return NGX_ERROR; diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/ngx_http_huff_encode.c similarity index 93% rename from src/http/v2/ngx_http_v2_huff_encode.c rename to src/http/ngx_http_huff_encode.c index 3f822cd0b..c03b153da 100644 --- a/src/http/v2/ngx_http_v2_huff_encode.c +++ b/src/http/ngx_http_huff_encode.c @@ -14,10 +14,10 @@ typedef struct { uint32_t code; uint32_t len; -} ngx_http_v2_huff_encode_code_t; +} ngx_http_huff_encode_code_t; -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -87,7 +87,7 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = /* same as above, but embeds lowercase transformation */ -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table_lc[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -161,10 +161,10 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #if (NGX_HAVE_LITTLE_ENDIAN) #if (NGX_HAVE_GCC_BSWAP64) -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = __builtin_bswap64(buf)) #else -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ ((dst)[0] = (u_char) ((buf) >> 56), \ (dst)[1] = (u_char) ((buf) >> 48), \ (dst)[2] = (u_char) ((buf) >> 40), \ @@ -176,28 +176,28 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #endif #else /* !NGX_HAVE_LITTLE_ENDIAN */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = (buf)) #endif #else /* NGX_PTR_SIZE == 4 */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint32_t *) (dst) = htonl(buf)) #endif size_t -ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) +ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) { - u_char *end; - size_t hlen; - ngx_uint_t buf, pending, code; - ngx_http_v2_huff_encode_code_t *table, *next; + u_char *end; + size_t hlen; + ngx_uint_t buf, pending, code; + ngx_http_huff_encode_code_t *table, *next; - table = lower ? ngx_http_v2_huff_encode_table_lc - : ngx_http_v2_huff_encode_table; + table = lower ? ngx_http_huff_encode_table_lc + : ngx_http_huff_encode_table; hlen = 0; buf = 0; pending = 0; @@ -224,7 +224,7 @@ ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) buf |= code >> pending; - ngx_http_v2_huff_encode_buf(&dst[hlen], buf); + ngx_http_huff_encode_buf(&dst[hlen], buf); hlen += sizeof(buf); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index fe6416b1d..e11f17acf 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1602,10 +1602,10 @@ ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->state.length -= size; h2c->state.field_rest -= size; - if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, - &h2c->state.field_end, - h2c->state.field_rest == 0, - h2c->connection->log) + if (ngx_http_huff_decode(&h2c->state.field_state, pos, size, + &h2c->state.field_end, + h2c->state.field_rest == 0, + h2c->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 517a48856..49bc31952 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -368,12 +368,6 @@ ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); -ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, - u_char **dst, ngx_uint_t last, ngx_log_t *log); -size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, - ngx_uint_t lower); - - #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c index d1fb7217a..1961c0734 100644 --- a/src/http/v2/ngx_http_v2_encode.c +++ b/src/http/v2/ngx_http_v2_encode.c @@ -20,7 +20,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, { size_t hlen; - hlen = ngx_http_v2_huff_encode(src, len, tmp, lower); + hlen = ngx_http_huff_encode(src, len, tmp, lower); if (hlen > 0) { *dst = NGX_HTTP_V2_ENCODE_HUFF; From 585e5cd09e65d1199d14b1dbf106c9134b9ea97a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:10 +0300 Subject: [PATCH 07/34] Core: fixed ngx_pcre_studies cleanup. If a configuration parsing fails for some reason, ngx_regex_module_init() is not called, and ngx_pcre_studies remained set despite the fact that the pool it was allocated from is already freed. This might result in a segmentation fault during runtime regular expression compilation, such as in SSI, for example, in the single process mode, or if a worker process died and was respawned from a master process in such an inconsistent state. Fix is to clear ngx_pcre_studies from the pool cleanup handler (which is anyway used to free JIT-compiled patterns). --- src/core/ngx_regex.c | 83 +++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 52169f655..1e9a1b59e 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -10,15 +10,14 @@ typedef struct { - ngx_flag_t pcre_jit; + ngx_flag_t pcre_jit; + ngx_list_t *studies; } ngx_regex_conf_t; static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); -#if (NGX_HAVE_PCRE_JIT) -static void ngx_pcre_free_studies(void *data); -#endif +static void ngx_regex_cleanup(void *data); static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); @@ -248,18 +247,17 @@ ngx_regex_free(void *p) } -#if (NGX_HAVE_PCRE_JIT) - static void -ngx_pcre_free_studies(void *data) +ngx_regex_cleanup(void *data) { - ngx_list_t *studies = data; +#if (NGX_HAVE_PCRE_JIT) + ngx_regex_conf_t *rcf = data; ngx_uint_t i; ngx_list_part_t *part; ngx_regex_elt_t *elts; - part = &studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -274,56 +272,50 @@ ngx_pcre_free_studies(void *data) i = 0; } + /* + * The PCRE JIT compiler uses mmap for its executable codes, so we + * have to explicitly call the pcre_free_study() function to free + * this memory. + */ + if (elts[i].regex->extra != NULL) { pcre_free_study(elts[i].regex->extra); } } -} - #endif + /* + * On configuration parsing errors ngx_regex_module_init() will not + * be called. Make sure ngx_pcre_studies is properly cleared anyway. + */ + + ngx_pcre_studies = NULL; +} + static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle) { - int opt; - const char *errstr; - ngx_uint_t i; - ngx_list_part_t *part; - ngx_regex_elt_t *elts; + int opt; + const char *errstr; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_regex_elt_t *elts; + ngx_regex_conf_t *rcf; opt = 0; -#if (NGX_HAVE_PCRE_JIT) - { - ngx_regex_conf_t *rcf; - ngx_pool_cleanup_t *cln; - rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); +#if (NGX_HAVE_PCRE_JIT) if (rcf->pcre_jit) { opt = PCRE_STUDY_JIT_COMPILE; - - /* - * The PCRE JIT compiler uses mmap for its executable codes, so we - * have to explicitly call the pcre_free_study() function to free - * this memory. - */ - - cln = ngx_pool_cleanup_add(cycle->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_pcre_free_studies; - cln->data = ngx_pcre_studies; - } } #endif ngx_regex_malloc_init(cycle->pool); - part = &ngx_pcre_studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -374,7 +366,8 @@ ngx_regex_module_init(ngx_cycle_t *cycle) static void * ngx_regex_create_conf(ngx_cycle_t *cycle) { - ngx_regex_conf_t *rcf; + ngx_regex_conf_t *rcf; + ngx_pool_cleanup_t *cln; rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); if (rcf == NULL) { @@ -383,11 +376,21 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) rcf->pcre_jit = NGX_CONF_UNSET; - ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); - if (ngx_pcre_studies == NULL) { + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { return NULL; } + cln->handler = ngx_regex_cleanup; + cln->data = rcf; + + rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); + if (rcf->studies == NULL) { + return NULL; + } + + ngx_pcre_studies = rcf->studies; + return rcf; } From 2238ae182dfde4a55ed65989d4af479f74c9bc31 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:12 +0300 Subject: [PATCH 08/34] Core: ngx_regex.c style cleanup. Notably, ngx_pcre_pool and ngx_pcre_studies are renamed to ngx_regex_pool and ngx_regex_studies, respectively. --- src/core/ngx_regex.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 1e9a1b59e..461b4be82 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -15,6 +15,9 @@ typedef struct { } ngx_regex_conf_t; +static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool); +static ngx_inline void ngx_regex_malloc_done(void); + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); static void ngx_regex_cleanup(void *data); @@ -64,8 +67,8 @@ ngx_module_t ngx_regex_module = { }; -static ngx_pool_t *ngx_pcre_pool; -static ngx_list_t *ngx_pcre_studies; +static ngx_pool_t *ngx_regex_pool; +static ngx_list_t *ngx_regex_studies; void @@ -79,14 +82,14 @@ ngx_regex_init(void) static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { - ngx_pcre_pool = pool; + ngx_regex_pool = pool; } static ngx_inline void ngx_regex_malloc_done(void) { - ngx_pcre_pool = NULL; + ngx_regex_pool = NULL; } @@ -112,13 +115,13 @@ ngx_regex_compile(ngx_regex_compile_t *rc) rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - - rc->err.data; + - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\" at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - - rc->err.data; + - rc->err.data; } return NGX_ERROR; @@ -133,8 +136,8 @@ ngx_regex_compile(ngx_regex_compile_t *rc) /* do not study at runtime */ - if (ngx_pcre_studies != NULL) { - elt = ngx_list_push(ngx_pcre_studies); + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); if (elt == NULL) { goto nomem; } @@ -229,11 +232,8 @@ ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { - ngx_pool_t *pool; - pool = ngx_pcre_pool; - - if (pool) { - return ngx_palloc(pool, size); + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); } return NULL; @@ -286,10 +286,10 @@ ngx_regex_cleanup(void *data) /* * On configuration parsing errors ngx_regex_module_init() will not - * be called. Make sure ngx_pcre_studies is properly cleared anyway. + * be called. Make sure ngx_regex_studies is properly cleared anyway. */ - ngx_pcre_studies = NULL; + ngx_regex_studies = NULL; } @@ -357,7 +357,7 @@ ngx_regex_module_init(ngx_cycle_t *cycle) ngx_regex_malloc_done(); - ngx_pcre_studies = NULL; + ngx_regex_studies = NULL; return NGX_OK; } @@ -389,7 +389,7 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) return NULL; } - ngx_pcre_studies = rcf->studies; + ngx_regex_studies = rcf->studies; return rcf; } From 222ea1745cdd7c25f53733b1b7379b4f10d34e4d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:14 +0300 Subject: [PATCH 09/34] Configure: simplified PCRE compilation. Removed ICC-specific PCRE optimizations which tried to link with PCRE object files instead of the library. Made compiler-specific code minimal. --- auto/lib/pcre/conf | 73 +++++----------------------------------------- 1 file changed, 8 insertions(+), 65 deletions(-) diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf index 5e3960fea..ab13bf70f 100644 --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -4,81 +4,24 @@ if [ $PCRE != NONE ]; then + + have=NGX_PCRE . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then + have=PCRE_STATIC . auto/have + fi + CORE_INCS="$CORE_INCS $PCRE" + CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" case "$NGX_CC_NAME" in msvc | owc | bcc) - have=NGX_PCRE . auto/have - have=PCRE_STATIC . auto/have - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib" CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" ;; - icc) - have=NGX_PCRE . auto/have - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" - - LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" - - echo $ngx_n "checking for PCRE library ...$ngx_c" - - if [ -f $PCRE/pcre.h ]; then - ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \ - | sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'` - - else if [ -f $PCRE/configure.in ]; then - ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ - | sed -e 's/^.*=\(.*\)$/\1/'` - - else - ngx_pcre_ver=`grep pcre_major, $PCRE/configure.ac \ - | sed -e 's/^.*pcre_major,.*\[\(.*\)\].*$/\1/'` - fi - fi - - echo " $ngx_pcre_ver major version found" - - # to allow -ipo optimization we link with the *.o but not library - - case "$ngx_pcre_ver" in - 4|5) - CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" - ;; - - 6) - CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" - ;; - - *) - CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre_newline.o" - ;; - - esac - ;; - *) - have=NGX_PCRE . auto/have - - if [ "$NGX_PLATFORM" = win32 ]; then - have=PCRE_STATIC . auto/have - fi - - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" ;; From 7b6d4d03d41b021dd3b61f2c357235103c8edb4d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:15 +0300 Subject: [PATCH 10/34] PCRE2 library support. The PCRE2 library is now used by default if found, instead of the original PCRE library. If needed for some reason, this can be disabled with the --without-pcre2 configure option. To make it possible to specify paths to the library and include files via --with-cc-opt / --with-ld-opt, the library is first tested without any additional paths and options. If this fails, the pcre2-config script is used. Similarly to the original PCRE library, it is now possible to build PCRE2 from sources with nginx configure, by using the --with-pcre= option. It automatically detects if PCRE or PCRE2 sources are provided. Note that compiling PCRE2 10.33 and later requires inttypes.h. When compiling on Windows with MSVC, inttypes.h is only available starting with MSVC 2013. In older versions some replacement needs to be provided ("echo '#include ' > pcre2-10.xx/src/inttypes.h" is good enough for MSVC 2010). The interface on nginx side remains unchanged. --- auto/lib/pcre/conf | 107 +++++++++++--- auto/lib/pcre/make | 152 ++++++++++++++++---- auto/options | 3 + auto/summary | 4 +- src/core/ngx_regex.c | 331 ++++++++++++++++++++++++++++++++++++++++++- src/core/ngx_regex.h | 30 +++- 6 files changed, 574 insertions(+), 53 deletions(-) diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf index ab13bf70f..20c1cafbe 100644 --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -5,29 +5,61 @@ if [ $PCRE != NONE ]; then - have=NGX_PCRE . auto/have + if [ -f $PCRE/src/pcre2.h.generic ]; then - if [ "$NGX_PLATFORM" = win32 ]; then - have=PCRE_STATIC . auto/have - fi + PCRE_LIBRARY=PCRE2 + + have=NGX_PCRE . auto/have + have=NGX_PCRE2 . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then + have=PCRE2_STATIC . auto/have + fi + + CORE_INCS="$CORE_INCS $PCRE/src/" + CORE_DEPS="$CORE_DEPS $PCRE/src/pcre2.h" - CORE_INCS="$CORE_INCS $PCRE" - CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" + case "$NGX_CC_NAME" in - case "$NGX_CC_NAME" in + msvc) + LINK_DEPS="$LINK_DEPS $PCRE/src/pcre2-8.lib" + CORE_LIBS="$CORE_LIBS $PCRE/src/pcre2-8.lib" + ;; - msvc | owc | bcc) - LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib" - CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" - ;; + *) + LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre2-8.a" + CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre2-8.a" + ;; - *) - LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" - CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" - ;; + esac + + else + + PCRE_LIBRARY=PCRE + + have=NGX_PCRE . auto/have + + if [ "$NGX_PLATFORM" = win32 ]; then + have=PCRE_STATIC . auto/have + fi - esac + CORE_INCS="$CORE_INCS $PCRE" + CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" + case "$NGX_CC_NAME" in + + msvc | owc | bcc) + LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib" + CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" + ;; + + *) + LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" + CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a" + ;; + + esac + fi if [ $PCRE_JIT = YES ]; then have=NGX_HAVE_PCRE_JIT . auto/have @@ -37,8 +69,48 @@ if [ $PCRE != NONE ]; then else if [ "$NGX_PLATFORM" != win32 ]; then - PCRE=NO + fi + + if [ $PCRE = NO -a $PCRE2 != DISABLED ]; then + + ngx_feature="PCRE2 library" + ngx_feature_name="NGX_PCRE2" + ngx_feature_run=no + ngx_feature_incs="#define PCRE2_CODE_UNIT_WIDTH 8 + #include " + ngx_feature_path= + ngx_feature_libs="-lpcre2-8" + ngx_feature_test="pcre2_code *re; + re = pcre2_compile(NULL, 0, 0, NULL, NULL, NULL); + if (re == NULL) return 1" + . auto/feature + + if [ $ngx_found = no ]; then + + # pcre2-config + + ngx_pcre2_prefix=`pcre2-config --prefix 2>/dev/null` + + if [ -n "$ngx_pcre2_prefix" ]; then + ngx_feature="PCRE2 library in $ngx_pcre2_prefix" + ngx_feature_path=`pcre2-config --cflags \ + | sed -n -e 's/.*-I *\([^ ][^ ]*\).*/\1/p'` + ngx_feature_libs=`pcre2-config --libs8` + . auto/feature + fi + fi + + if [ $ngx_found = yes ]; then + have=NGX_PCRE . auto/have + CORE_INCS="$CORE_INCS $ngx_feature_path" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + PCRE=YES + PCRE_LIBRARY=PCRE2 + fi + fi + + if [ $PCRE = NO ]; then ngx_feature="PCRE library" ngx_feature_name="NGX_PCRE" @@ -114,6 +186,7 @@ else CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" PCRE=YES + PCRE_LIBRARY=PCRE fi if [ $PCRE = YES ]; then diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make index 97c9f3ba0..839ef294b 100644 --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -3,36 +3,138 @@ # Copyright (C) Nginx, Inc. -case "$NGX_CC_NAME" in +if [ $PCRE_LIBRARY = PCRE2 ]; then + + # PCRE2 + + if [ $NGX_CC_NAME = msvc ]; then + + # With PCRE2, it is not possible to compile all sources. + # Since list of source files changes between versions, we + # test files which might not be present. + + ngx_pcre_srcs="pcre2_auto_possess.c \ + pcre2_chartables.c \ + pcre2_compile.c \ + pcre2_config.c \ + pcre2_context.c \ + pcre2_dfa_match.c \ + pcre2_error.c \ + pcre2_jit_compile.c \ + pcre2_maketables.c \ + pcre2_match.c \ + pcre2_match_data.c \ + pcre2_newline.c \ + pcre2_ord2utf.c \ + pcre2_pattern_info.c \ + pcre2_string_utils.c \ + pcre2_study.c \ + pcre2_substitute.c \ + pcre2_substring.c \ + pcre2_tables.c \ + pcre2_ucd.c \ + pcre2_valid_utf.c \ + pcre2_xclass.c" + + ngx_pcre_test="pcre2_convert.c \ + pcre2_extuni.c \ + pcre2_find_bracket.c \ + pcre2_script_run.c \ + pcre2_serialize.c" + + for ngx_src in $ngx_pcre_test + do + if [ -f $PCRE/src/$ngx_src ]; then + ngx_pcre_srcs="$ngx_pcre_srcs $ngx_src" + fi + done + + ngx_pcre_objs=`echo $ngx_pcre_srcs \ + | sed -e "s#\([^ ]*\.\)c#\1$ngx_objext#g"` + + ngx_pcre_srcs=`echo $ngx_pcre_srcs \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"` + ngx_pcre_objs=`echo $ngx_pcre_objs \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g"` + + cat << END >> $NGX_MAKEFILE + +PCRE_CFLAGS = -O2 -Ob1 -Oi -Gs $LIBC $CPU_OPT +PCRE_FLAGS = -DHAVE_CONFIG_H -DPCRE2_STATIC -DPCRE2_CODE_UNIT_WIDTH=8 \\ + -DHAVE_MEMMOVE + +PCRE_SRCS = $ngx_pcre_srcs +PCRE_OBJS = $ngx_pcre_objs + +$PCRE/src/pcre2.h: + cd $PCRE/src \\ + && copy /y config.h.generic config.h \\ + && copy /y pcre2.h.generic pcre2.h \\ + && copy /y pcre2_chartables.c.dist pcre2_chartables.c + +$PCRE/src/pcre2-8.lib: $PCRE/src/pcre2.h $NGX_MAKEFILE + cd $PCRE/src \\ + && cl -nologo -c \$(PCRE_CFLAGS) -I . \$(PCRE_FLAGS) \$(PCRE_SRCS) \\ + && link -lib -out:pcre2-8.lib -verbose:lib \$(PCRE_OBJS) - msvc) - ngx_makefile=makefile.msvc - ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" - ngx_pcre="PCRE=\"$PCRE\"" - ;; +END + + else + + cat << END >> $NGX_MAKEFILE - owc) - ngx_makefile=makefile.owc - ngx_opt="CPU_OPT=\"$CPU_OPT\"" - ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; +$PCRE/src/pcre2.h: $PCRE/Makefile + +$PCRE/Makefile: $NGX_MAKEFILE + cd $PCRE \\ + && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ + && CC="\$(CC)" CFLAGS="$PCRE_OPT" \\ + ./configure --disable-shared $PCRE_CONF_OPT - bcc) - ngx_makefile=makefile.bcc - ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" - ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` - ;; +$PCRE/.libs/libpcre2-8.a: $PCRE/Makefile + cd $PCRE \\ + && \$(MAKE) libpcre2-8.la - *) - ngx_makefile= - ;; +END -esac + fi -if [ -n "$ngx_makefile" ]; then +else - cat << END >> $NGX_MAKEFILE + # PCRE + + case "$NGX_CC_NAME" in + + msvc) + ngx_makefile=makefile.msvc + ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC" + ngx_pcre="PCRE=\"$PCRE\"" + ;; + + owc) + ngx_makefile=makefile.owc + ngx_opt="CPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + + bcc) + ngx_makefile=makefile.bcc + ngx_opt="-DCPU_OPT=\"$CPU_OPT\"" + ngx_pcre=`echo \-DPCRE=\"$PCRE\" \ + | sed -e "s/\//$ngx_regex_dirsep/g"` + ;; + + *) + ngx_makefile= + ;; + + esac + + + if [ -n "$ngx_makefile" ]; then + + cat << END >> $NGX_MAKEFILE `echo "$PCRE/pcre.lib: $PCRE/pcre.h $NGX_MAKEFILE" \ | sed -e "s/\//$ngx_regex_dirsep/g"` @@ -43,9 +145,9 @@ if [ -n "$ngx_makefile" ]; then END -else + else - cat << END >> $NGX_MAKEFILE + cat << END >> $NGX_MAKEFILE $PCRE/pcre.h: $PCRE/Makefile @@ -61,4 +163,6 @@ $PCRE/.libs/libpcre.a: $PCRE/Makefile END + fi + fi diff --git a/auto/options b/auto/options index bb3600557..03bd1411a 100644 --- a/auto/options +++ b/auto/options @@ -148,6 +148,7 @@ PCRE=NONE PCRE_OPT= PCRE_CONF_OPT= PCRE_JIT=YES +PCRE2=YES USE_OPENSSL=NO OPENSSL="modules/quiche/quiche/deps/boringssl" @@ -369,6 +370,7 @@ use the \"--without-mail_ssl_module\" option instead" --with-pcre=*) PCRE="$value" ;; --with-pcre-opt=*) PCRE_OPT="$value" ;; --without-pcre-jit) PCRE_JIT=NO ;; + --without-pcre2) PCRE2=DISABLED ;; --with-openssl=*) OPENSSL="$value" ;; --with-openssl-opt=*) OPENSSL_OPT="$value" ;; @@ -591,6 +593,7 @@ cat << END --with-pcre=DIR set path to PCRE library sources --with-pcre-opt=OPTIONS set additional build options for PCRE --without-pcre-jit don't build PCRE with JIT compilation support + --without-pcre2 do not use PCRE2 library --with-zlib=DIR set path to zlib library sources --with-zlib-opt=OPTIONS set additional build options for zlib diff --git a/auto/summary b/auto/summary index 9aa776edf..b3c07eedc 100644 --- a/auto/summary +++ b/auto/summary @@ -16,9 +16,9 @@ if [ $USE_PCRE = DISABLED ]; then else case $PCRE in - YES) echo " + using system PCRE library" ;; + YES) echo " + using system $PCRE_LIBRARY library" ;; NONE) echo " + PCRE library is not used" ;; - *) echo " + using PCRE library: $PCRE" ;; + *) echo " + using $PCRE_LIBRARY library: $PCRE" ;; esac fi diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 461b4be82..5ae4f780b 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -18,8 +18,13 @@ typedef struct { static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool); static ngx_inline void ngx_regex_malloc_done(void); +#if (NGX_PCRE2) +static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data); +static void ngx_libc_cdecl ngx_regex_free(void *p, void *data); +#else static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); +#endif static void ngx_regex_cleanup(void *data); static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); @@ -67,15 +72,24 @@ ngx_module_t ngx_regex_module = { }; -static ngx_pool_t *ngx_regex_pool; -static ngx_list_t *ngx_regex_studies; +static ngx_pool_t *ngx_regex_pool; +static ngx_list_t *ngx_regex_studies; +static ngx_uint_t ngx_regex_direct_alloc; + +#if (NGX_PCRE2) +static pcre2_compile_context *ngx_regex_compile_context; +static pcre2_match_data *ngx_regex_match_data; +static ngx_uint_t ngx_regex_match_data_size; +#endif void ngx_regex_init(void) { +#if !(NGX_PCRE2) pcre_malloc = ngx_regex_malloc; pcre_free = ngx_regex_free; +#endif } @@ -83,6 +97,7 @@ static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { ngx_regex_pool = pool; + ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0; } @@ -90,9 +105,146 @@ static ngx_inline void ngx_regex_malloc_done(void) { ngx_regex_pool = NULL; + ngx_regex_direct_alloc = 0; } +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_compile(ngx_regex_compile_t *rc) +{ + int n, errcode; + char *p; + u_char errstr[128]; + size_t erroff; + pcre2_code *re; + ngx_regex_elt_t *elt; + pcre2_general_context *gctx; + pcre2_compile_context *cctx; + + if (ngx_regex_compile_context == NULL) { + /* + * Allocate a compile context if not yet allocated. This uses + * direct allocations from heap, so the result can be cached + * even at runtime. + */ + + ngx_regex_malloc_init(NULL); + + gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free, + NULL); + if (gctx == NULL) { + ngx_regex_malloc_done(); + goto nomem; + } + + cctx = pcre2_compile_context_create(gctx); + if (cctx == NULL) { + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + goto nomem; + } + + ngx_regex_compile_context = cctx; + + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + } + + ngx_regex_malloc_init(rc->pool); + + re = pcre2_compile(rc->pattern.data, rc->pattern.len, + (uint32_t) rc->options, &errcode, &erroff, + ngx_regex_compile_context); + + /* ensure that there is no current pool */ + ngx_regex_malloc_done(); + + if (re == NULL) { + pcre2_get_error_message(errcode, errstr, 128); + + if ((size_t) erroff == rc->pattern.len) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; + + } else { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\" at \"%s\"", + errstr, &rc->pattern, rc->pattern.data + erroff) + - rc->err.data; + } + + return NGX_ERROR; + } + + rc->regex = re; + + /* do not study at runtime */ + + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); + if (elt == NULL) { + goto nomem; + } + + elt->regex = rc->regex; + elt->name = rc->pattern.data; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + + if (rc->captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d"; + goto failed; + } + + if (rc->named_captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d"; + goto failed; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d"; + goto failed; + } + + return NGX_OK; + +failed: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) + - rc->err.data; + return NGX_ERROR; + +nomem: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: no memory", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; +} + +#else + ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc) { @@ -195,6 +347,74 @@ ngx_regex_compile(ngx_regex_compile_t *rc) return NGX_ERROR; } +#endif + + +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + size_t *ov; + ngx_int_t rc; + ngx_uint_t n, i; + + /* + * The pcre2_match() function might allocate memory for backtracking + * frames, typical allocations are from 40k and above. So the allocator + * is configured to do direct allocations from heap during matching. + */ + + ngx_regex_malloc_init(NULL); + + if (ngx_regex_match_data == NULL + || size > ngx_regex_match_data_size) + { + /* + * Allocate a match data if not yet allocated or smaller than + * needed. + */ + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + } + + ngx_regex_match_data_size = size; + ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL); + + if (ngx_regex_match_data == NULL) { + rc = PCRE2_ERROR_NOMEMORY; + goto failed; + } + } + + rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL); + + if (rc < 0) { + goto failed; + } + + n = pcre2_get_ovector_count(ngx_regex_match_data); + ov = pcre2_get_ovector_pointer(ngx_regex_match_data); + + if (n > size / 3) { + n = size / 3; + } + + for (i = 0; i < n; i++) { + captures[i * 2] = ov[i * 2]; + captures[i * 2 + 1] = ov[i * 2 + 1]; + } + +failed: + + ngx_regex_malloc_done(); + + return rc; +} + +#endif + ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) @@ -229,6 +449,35 @@ ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) } +#if (NGX_PCRE2) + +static void * ngx_libc_cdecl +ngx_regex_malloc(size_t size, void *data) +{ + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); + } + + if (ngx_regex_direct_alloc) { + return ngx_alloc(size, ngx_cycle->log); + } + + return NULL; +} + + +static void ngx_libc_cdecl +ngx_regex_free(void *p, void *data) +{ + if (ngx_regex_direct_alloc) { + ngx_free(p); + } + + return; +} + +#else + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { @@ -246,11 +495,13 @@ ngx_regex_free(void *p) return; } +#endif + static void ngx_regex_cleanup(void *data) { -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) ngx_regex_conf_t *rcf = data; ngx_uint_t i; @@ -275,12 +526,17 @@ ngx_regex_cleanup(void *data) /* * The PCRE JIT compiler uses mmap for its executable codes, so we * have to explicitly call the pcre_free_study() function to free - * this memory. + * this memory. In PCRE2, we call the pcre2_code_free() function + * for the same reason. */ +#if (NGX_PCRE2) + pcre2_code_free(elts[i].regex); +#else if (elts[i].regex->extra != NULL) { pcre_free_study(elts[i].regex->extra); } +#endif } #endif @@ -290,6 +546,26 @@ ngx_regex_cleanup(void *data) */ ngx_regex_studies = NULL; + +#if (NGX_PCRE2) + + /* + * Free compile context and match data. If needed at runtime by + * the new cycle, these will be re-allocated. + */ + + if (ngx_regex_compile_context) { + pcre2_compile_context_free(ngx_regex_compile_context); + ngx_regex_compile_context = NULL; + } + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + ngx_regex_match_data = NULL; + ngx_regex_match_data_size = 0; + } + +#endif } @@ -297,7 +573,9 @@ static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle) { int opt; +#if !(NGX_PCRE2) const char *errstr; +#endif ngx_uint_t i; ngx_list_part_t *part; ngx_regex_elt_t *elts; @@ -307,10 +585,16 @@ ngx_regex_module_init(ngx_cycle_t *cycle) rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + if (rcf->pcre_jit) { +#if (NGX_PCRE2) + opt = 1; +#else opt = PCRE_STUDY_JIT_COMPILE; +#endif } + #endif ngx_regex_malloc_init(cycle->pool); @@ -330,6 +614,23 @@ ngx_regex_module_init(ngx_cycle_t *cycle) i = 0; } +#if (NGX_PCRE2) + + if (opt) { + int n; + + n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE); + + if (n != 0) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "pcre2_jit_compile() failed: %d in \"%s\", " + "ignored", + n, elts[i].name); + } + } + +#else + elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr); if (errstr != NULL) { @@ -352,12 +653,16 @@ ngx_regex_module_init(ngx_cycle_t *cycle) elts[i].name); } } +#endif #endif } ngx_regex_malloc_done(); ngx_regex_studies = NULL; +#if (NGX_PCRE2) + ngx_regex_compile_context = NULL; +#endif return NGX_OK; } @@ -415,7 +720,21 @@ ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2) + { + int r; + uint32_t jit; + + jit = 0; + r = pcre2_config(PCRE2_CONFIG_JIT, &jit); + + if (r != 0 || jit != 1) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "PCRE2 library does not support JIT"); + *fp = 0; + } + } +#elif (NGX_HAVE_PCRE_JIT) { int jit, r; diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 680486c81..70bd1db9f 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -12,19 +12,31 @@ #include #include -#include +#if (NGX_PCRE2) + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */ +#define NGX_REGEX_CASELESS PCRE2_CASELESS -#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ +typedef pcre2_code ngx_regex_t; -#define NGX_REGEX_CASELESS PCRE_CASELESS +#else + +#include +#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ +#define NGX_REGEX_CASELESS PCRE_CASELESS typedef struct { pcre *code; pcre_extra *extra; } ngx_regex_t; +#endif + typedef struct { ngx_str_t pattern; @@ -49,10 +61,20 @@ typedef struct { void ngx_regex_init(void); ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); +#if (NGX_PCRE2) + +ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, + ngx_uint_t size); +#define ngx_regex_exec_n "pcre2_match()" + +#else + #define ngx_regex_exec(re, s, captures, size) \ pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ captures, size) -#define ngx_regex_exec_n "pcre_exec()" +#define ngx_regex_exec_n "pcre_exec()" + +#endif ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); From 57f347caa003ebe5b1945e3cd086ea3ace9019ad Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:16 +0300 Subject: [PATCH 11/34] PCRE2 and PCRE binary compatibility. With this change, dynamic modules using nginx regex interface can be used regardless of the variant of the PCRE library nginx was compiled with. If a module is compiled with different PCRE library variant, in case of ngx_regex_exec() errors it will report wrong function name in error messages. This is believed to be tolerable, given that fixing this will require interface changes. --- src/core/ngx_regex.c | 46 ++++++++++++++++++++++++++++++++++++++++---- src/core/ngx_regex.h | 17 ++++++---------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 5ae4f780b..991728b27 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -118,6 +118,7 @@ ngx_regex_compile(ngx_regex_compile_t *rc) char *p; u_char errstr[128]; size_t erroff; + uint32_t options; pcre2_code *re; ngx_regex_elt_t *elt; pcre2_general_context *gctx; @@ -152,11 +153,24 @@ ngx_regex_compile(ngx_regex_compile_t *rc) ngx_regex_malloc_done(); } + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE2_CASELESS; + } + + if (rc->options & ~NGX_REGEX_CASELESS) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + ngx_regex_malloc_init(rc->pool); - re = pcre2_compile(rc->pattern.data, rc->pattern.len, - (uint32_t) rc->options, &errcode, &erroff, - ngx_regex_compile_context); + re = pcre2_compile(rc->pattern.data, rc->pattern.len, options, + &errcode, &erroff, ngx_regex_compile_context); /* ensure that there is no current pool */ ngx_regex_malloc_done(); @@ -252,11 +266,26 @@ ngx_regex_compile(ngx_regex_compile_t *rc) char *p; pcre *re; const char *errstr; + ngx_uint_t options; ngx_regex_elt_t *elt; + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE_CASELESS; + } + + if (rc->options & ~NGX_REGEX_CASELESS) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + ngx_regex_malloc_init(rc->pool); - re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, + re = pcre_compile((const char *) rc->pattern.data, (int) options, &errstr, &erroff, NULL); /* ensure that there is no current pool */ @@ -413,6 +442,15 @@ ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) return rc; } +#else + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + return pcre_exec(re->code, re->extra, (const char *) s->data, s->len, + 0, 0, captures, size); +} + #endif diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 70bd1db9f..74e694d2e 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -19,7 +19,6 @@ #include #define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */ -#define NGX_REGEX_CASELESS PCRE2_CASELESS typedef pcre2_code ngx_regex_t; @@ -28,7 +27,6 @@ typedef pcre2_code ngx_regex_t; #include #define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ -#define NGX_REGEX_CASELESS PCRE_CASELESS typedef struct { pcre *code; @@ -38,10 +36,13 @@ typedef struct { #endif +#define NGX_REGEX_CASELESS 0x00000001 + + typedef struct { ngx_str_t pattern; ngx_pool_t *pool; - ngx_int_t options; + ngx_uint_t options; ngx_regex_t *regex; int captures; @@ -61,19 +62,13 @@ typedef struct { void ngx_regex_init(void); ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); -#if (NGX_PCRE2) - ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size); -#define ngx_regex_exec_n "pcre2_match()" +#if (NGX_PCRE2) +#define ngx_regex_exec_n "pcre2_match()" #else - -#define ngx_regex_exec(re, s, captures, size) \ - pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ - captures, size) #define ngx_regex_exec_n "pcre_exec()" - #endif ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); From b72f9653159b4e732f493a2e8e5f9150428b8d7b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 25 Dec 2021 01:07:18 +0300 Subject: [PATCH 12/34] Core: added NGX_REGEX_MULTILINE for 3rd party modules. Notably, NAXSI is known to misuse ngx_regex_compile() with rc.options set to PCRE_CASELESS | PCRE_MULTILINE. With PCRE2 support, and notably binary compatibility changes, it is no longer possible to set PCRE[2]_MULTILINE option without using proper interface. To facilitate correct usage, this change adds the NGX_REGEX_MULTILINE option. --- src/core/ngx_regex.c | 12 ++++++++++-- src/core/ngx_regex.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 991728b27..bebf3b6a8 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -159,7 +159,11 @@ ngx_regex_compile(ngx_regex_compile_t *rc) options |= PCRE2_CASELESS; } - if (rc->options & ~NGX_REGEX_CASELESS) { + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE2_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "regex \"%V\" compilation failed: invalid options", &rc->pattern) @@ -275,7 +279,11 @@ ngx_regex_compile(ngx_regex_compile_t *rc) options |= PCRE_CASELESS; } - if (rc->options & ~NGX_REGEX_CASELESS) { + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "regex \"%V\" compilation failed: invalid options", &rc->pattern) diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 74e694d2e..182373a22 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -37,6 +37,7 @@ typedef struct { #define NGX_REGEX_CASELESS 0x00000001 +#define NGX_REGEX_MULTILINE 0x00000002 typedef struct { From 783e859f28905fd4326f5925bd5c085192f0b9a2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 27 Dec 2021 19:47:05 +0300 Subject: [PATCH 13/34] Removed "aio sendfile", deprecated since 1.7.11. --- src/http/ngx_http_core_module.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index c4ff42044..07c6cc4d4 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4575,19 +4575,6 @@ ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } -#if (NGX_HAVE_AIO_SENDFILE) - - if (ngx_strcmp(value[1].data, "sendfile") == 0) { - clcf->aio = NGX_HTTP_AIO_ON; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"sendfile\" parameter of " - "the \"aio\" directive is deprecated"); - return NGX_CONF_OK; - } - -#endif - if (ngx_strncmp(value[1].data, "threads", 7) == 0 && (value[1].len == 7 || value[1].data[7] == '=')) { From 6796e0e345e23d1559893018c382c8a6ddb33ac5 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 27 Dec 2021 19:48:33 +0300 Subject: [PATCH 14/34] Simplified sendfile(SF_NODISKIO) usage. Starting with FreeBSD 11, there is no need to use AIO operations to preload data into cache for sendfile(SF_NODISKIO) to work. Instead, sendfile() handles non-blocking loading data from disk by itself. It still can, however, return EBUSY if a page is already being loaded (for example, by a different process). If this happens, we now post an event for the next event loop iteration, so sendfile() is retried "after a short period", as manpage recommends. The limit of the number of EBUSY tolerated without any progress is preserved, but now it does not result in an alert, since on an idle system event loop iteration might be very short and EBUSY can happen many times in a row. Instead, SF_NODISKIO is simply disabled for one call once the limit is reached. With this change, sendfile(SF_NODISKIO) is now used automatically as long as sendfile() is enabled, and no longer requires "aio on;". --- auto/os/freebsd | 8 +-- src/core/ngx_buf.h | 3 - src/core/ngx_connection.h | 2 +- src/core/ngx_module.h | 2 +- src/core/ngx_output_chain.c | 32 --------- src/event/ngx_event.h | 4 -- src/http/ngx_http_copy_filter_module.c | 82 ------------------------ src/os/unix/ngx_freebsd_sendfile_chain.c | 74 ++++++++------------- 8 files changed, 33 insertions(+), 174 deletions(-) diff --git a/auto/os/freebsd b/auto/os/freebsd index 937ca204e..870bac4b3 100644 --- a/auto/os/freebsd +++ b/auto/os/freebsd @@ -44,12 +44,10 @@ if [ $osreldate -gt 300007 ]; then CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS" fi -if [ $NGX_FILE_AIO = YES ]; then - if [ $osreldate -gt 502103 ]; then - echo " + sendfile()'s SF_NODISKIO found" +if [ $osreldate -gt 1100093 ]; then + echo " + sendfile()'s SF_NODISKIO found" - have=NGX_HAVE_AIO_SENDFILE . auto/have - fi + have=NGX_HAVE_SENDFILE_NODISKIO . auto/have fi # POSIX semaphores diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index 4b665629c..fdcd0cddf 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -90,9 +90,6 @@ struct ngx_output_chain_ctx_s { #if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_output_chain_aio_pt aio_handler; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*aio_preload)(ngx_buf_t *file); -#endif #endif #if (NGX_THREADS || NGX_COMPAT) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 88c672c39..c957feab1 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -192,7 +192,7 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; #endif diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 8cf3210e8..6fb455426 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -41,7 +41,7 @@ #define NGX_MODULE_SIGNATURE_3 "0" #endif -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_4 "1" #else #define NGX_MODULE_SIGNATURE_4 "0" diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index fd4603b19..41267eeff 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -29,10 +29,6 @@ static ngx_inline ngx_int_t ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); -#if (NGX_HAVE_AIO_SENDFILE) -static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, - ngx_file_t *file); -#endif static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, @@ -283,12 +279,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) buf->in_file = 0; } -#if (NGX_HAVE_AIO_SENDFILE) - if (ctx->aio_preload && buf->in_file) { - (void) ngx_output_chain_aio_setup(ctx, buf->file); - } -#endif - if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { return 0; } @@ -301,28 +291,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } -#if (NGX_HAVE_AIO_SENDFILE) - -static ngx_int_t -ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) -{ - ngx_event_aio_t *aio; - - if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) { - return NGX_ERROR; - } - - aio = file->aio; - - aio->data = ctx->filter_ctx; - aio->preload_handler = ctx->aio_preload; - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index eb17346b2..594b813d7 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -147,10 +147,6 @@ struct ngx_event_aio_s { ngx_fd_t fd; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*preload_handler)(ngx_buf_t *file); -#endif - #if (NGX_HAVE_EVENTFD) int64_t res; #endif diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index b47e4afa7..bd3028bc7 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -19,10 +19,6 @@ typedef struct { static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); -#if (NGX_HAVE_AIO_SENDFILE) -static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); -static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); -#endif #endif #if (NGX_THREADS) static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, @@ -128,9 +124,6 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { ctx->aio_handler = ngx_http_copy_aio_handler; -#if (NGX_HAVE_AIO_SENDFILE) - ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; -#endif } #endif @@ -207,81 +200,6 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) ngx_http_run_posted_requests(c); } - -#if (NGX_HAVE_AIO_SENDFILE) - -static ssize_t -ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) -{ - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; - ngx_output_chain_ctx_t *ctx; - - aio = file->file->aio; - r = aio->data; - - if (r->aio) { - /* - * tolerate sendfile() calls if another operation is already - * running; this can happen due to subrequests, multiple calls - * of the next body filter from a filter, or in HTTP/2 due to - * a write event on the main connection - */ - - return NGX_AGAIN; - } - - n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); - - if (n == NGX_AGAIN) { - aio->handler = ngx_http_copy_aio_sendfile_event_handler; - - r->main->blocked++; - r->aio = 1; - - ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); - ctx->aio = 1; - } - - return n; -} - - -static void -ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) -{ - ngx_event_aio_t *aio; - ngx_connection_t *c; - ngx_http_request_t *r; - - aio = ev->data; - r = aio->data; - c = r->connection; - - r->main->blocked--; - r->aio = 0; - ev->complete = 0; - -#if (NGX_HTTP_V2) - - if (r->stream) { - /* - * for HTTP/2, update write event to make sure processing will - * reach the main connection to handle sendfile() preload - */ - - c->write->ready = 1; - c->write->active = 0; - } - -#endif - - c->write->handler(c->write); -} - -#endif #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 750c12fc3..c939f6ad6 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -32,23 +32,22 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, flags; - off_t send, prev_send, sent; - size_t file_size; - ssize_t n; - ngx_uint_t eintr, eagain; - ngx_err_t err; - ngx_buf_t *file; - ngx_event_t *wev; - ngx_chain_t *cl; - ngx_iovec_t header, trailer; - struct sf_hdtr hdtr; - struct iovec headers[NGX_IOVS_PREALLOCATE]; - struct iovec trailers[NGX_IOVS_PREALLOCATE]; -#if (NGX_HAVE_AIO_SENDFILE) - ngx_uint_t ebusy; - ngx_event_aio_t *aio; + int rc, flags; + off_t send, prev_send, sent; + size_t file_size; + ssize_t n; + ngx_err_t err; + ngx_buf_t *file; + ngx_uint_t eintr, eagain; +#if (NGX_HAVE_SENDFILE_NODISKIO) + ngx_uint_t ebusy; #endif + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header, trailer; + struct sf_hdtr hdtr; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -77,11 +76,6 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eagain = 0; flags = 0; -#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN) - aio = NULL; - file = NULL; -#endif - header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; @@ -90,7 +84,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) for ( ;; ) { eintr = 0; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) ebusy = 0; #endif prev_send = send; @@ -179,9 +173,8 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sent = 0; -#if (NGX_HAVE_AIO_SENDFILE) - aio = file->file->aio; - flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; +#if (NGX_HAVE_SENDFILE_NODISKIO) + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, @@ -199,7 +192,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eintr = 1; break; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) case NGX_EBUSY: ebusy = 1; break; @@ -252,41 +245,30 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) in = ngx_chain_update_sent(in, sent); -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) if (ebusy) { if (sent == 0) { c->busy_count++; - if (c->busy_count > 2) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile(%V) returned busy again", - &file->file->name); - - c->busy_count = 0; - aio->preload_handler = NULL; - - send = prev_send; - continue; - } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile() busy, count:%d", c->busy_count); } else { c->busy_count = 0; } - n = aio->preload_handler(file); - - if (n > 0) { - send = prev_send + sent; - continue; + if (wev->posted) { + ngx_delete_posted_event(wev); } + ngx_post_event(wev, &ngx_posted_next_events); + + wev->ready = 0; return in; } - if (flags == SF_NODISKIO) { - c->busy_count = 0; - } + c->busy_count = 0; #endif From b51e50ec3a44146e33aaba48b4b4a7b2c4dab21e Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 27 Dec 2021 19:48:42 +0300 Subject: [PATCH 15/34] SSL: SSL_sendfile(SF_NODISKIO) support. --- src/event/ngx_event_openssl.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index f61e3c1c5..9db0f17d3 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2981,7 +2981,7 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) { #ifdef BIO_get_ktls_send - int sslerr; + int sslerr, flags; ssize_t n; ngx_err_t err; @@ -2993,8 +2993,14 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) ngx_set_errno(0); +#if (NGX_HAVE_SENDFILE_NODISKIO) + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; +#else + flags = 0; +#endif + n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos, - size, 0); + size, flags); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n); @@ -3013,6 +3019,10 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) ngx_post_event(c->read, &ngx_posted_events); } +#if (NGX_HAVE_SENDFILE_NODISKIO) + c->busy_count = 0; +#endif + c->sent += n; return n; @@ -3077,6 +3087,23 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) ngx_post_event(c->read, &ngx_posted_events); } +#if (NGX_HAVE_SENDFILE_NODISKIO) + + if (ngx_errno == EBUSY) { + c->busy_count++; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile() busy, count:%d", c->busy_count); + + if (c->write->posted) { + ngx_delete_posted_event(c->write); + } + + ngx_post_event(c->write, &ngx_posted_next_events); + } + +#endif + c->write->ready = 0; return NGX_AGAIN; } From 2567afe82d5b82950da73f31d9e2d1331c3c2bf3 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 27 Dec 2021 19:49:26 +0300 Subject: [PATCH 16/34] Support for sendfile(SF_NOCACHE). The SF_NOCACHE flag, introduced in FreeBSD 11 along with the new non-blocking sendfile() implementation by glebius@, makes it possible to use sendfile() along with the "directio" directive. --- src/core/ngx_output_chain.c | 17 +++++++++++++---- src/event/ngx_event_openssl.c | 6 ++++++ src/os/unix/ngx_freebsd_sendfile_chain.c | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 41267eeff..857074253 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -256,10 +256,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } #endif - if (buf->in_file && buf->file->directio) { - return 0; - } - sendfile = ctx->sendfile; #if (NGX_SENDFILE_LIMIT) @@ -268,6 +264,19 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) sendfile = 0; } +#endif + +#if !(NGX_HAVE_SENDFILE_NODISKIO) + + /* + * With DIRECTIO, disable sendfile() unless sendfile(SF_NOCACHE) + * is available. + */ + + if (buf->in_file && buf->file->directio) { + sendfile = 0; + } + #endif if (!sendfile) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 9db0f17d3..ef3ef1352 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2994,7 +2994,13 @@ ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) ngx_set_errno(0); #if (NGX_HAVE_SENDFILE_NODISKIO) + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + #else flags = 0; #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index c939f6ad6..5c6a830d8 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -174,7 +174,13 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sent = 0; #if (NGX_HAVE_SENDFILE_NODISKIO) + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, From 6ac8cd94128e1f359286d99de686720a9e1cc73a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Dec 2021 17:56:16 +0300 Subject: [PATCH 17/34] Updated OpenSSL and PCRE used for win32 builds. --- misc/GNUmakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/GNUmakefile b/misc/GNUmakefile index 36dd63836..58e9f7f00 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,9 +6,9 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.1.1l +OPENSSL = openssl-1.1.1m ZLIB = zlib-1.2.11 -PCRE = pcre-8.44 +PCRE = pcre2-10.39 release: export From b3e3a9be46300c2bd782141e4044fa8084379baf Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Dec 2021 18:28:37 +0300 Subject: [PATCH 18/34] nginx-1.21.5-RELEASE --- docs/xml/nginx/changes.xml | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 0808b5c6e..fd6da38ba 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,58 @@ + + + + +теперь nginx по умолчанию собирается с библиотекой PCRE2. + + +now nginx is built with the PCRE2 library by default. + + + + + +теперь nginx всегда использует sendfile(SF_NODISKIO) на FreeBSD. + + +now nginx always uses sendfile(SF_NODISKIO) on FreeBSD. + + + + + +поддержка sendfile(SF_NOCACHE) на FreeBSD. + + +support for sendfile(SF_NOCACHE) on FreeBSD. + + + + + +переменная $ssl_curve. + + +the $ssl_curve variable. + + + + + +при использовании HTTP/2 без SSL вместе с директивами sendfile и aio +соединения могли зависать. + + +connections might hang +when using HTTP/2 without SSL with the "sendfile" and "aio" directives. + + + + + + From 75c5c873d248665f0c5fdc43221959b75c0eafc5 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Dec 2021 18:28:38 +0300 Subject: [PATCH 19/34] release-1.21.5 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index ef68adcf4..a1e630018 100644 --- a/.hgtags +++ b/.hgtags @@ -465,3 +465,4 @@ a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1 bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2 2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3 39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4 +d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5 From 68654cf0ae34c5cdcd9bb82dd575661c9aaa47d6 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 29 Dec 2021 22:59:53 +0300 Subject: [PATCH 20/34] 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 5ad6aff45..daac21e2c 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021005 -#define NGINX_VERSION "1.21.5" +#define nginx_version 1021006 +#define NGINX_VERSION "1.21.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From 049ad6230643a1aef9b570400ec3f509b731fe56 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 30 Dec 2021 01:08:46 +0300 Subject: [PATCH 21/34] Events: fixed balancing between workers with EPOLLEXCLUSIVE. Linux with EPOLLEXCLUSIVE usually notifies only the process which was first to add the listening socket to the epoll instance. As a result most of the connections are handled by the first worker process (ticket #2285). To fix this, we re-add the socket periodically, so other workers will get a chance to accept connections. --- src/event/ngx_event.c | 5 ++++ src/event/ngx_event.h | 1 + src/event/ngx_event_accept.c | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 0d187ca33..47229b507 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; +ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) @@ -644,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif + ngx_use_exclusive_accept = 0; + ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); @@ -889,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ccf->worker_processes > 1) { + ngx_use_exclusive_accept = 1; + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) == NGX_ERROR) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 594b813d7..f2bd071ed 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -464,6 +464,7 @@ extern ngx_uint_t ngx_accept_events; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; +extern ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index b05666c76..27038799d 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,9 @@ static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); +#if (NGX_HAVE_EPOLLEXCLUSIVE) +static void ngx_reorder_accept_events(ngx_listening_t *ls); +#endif static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev) } } while (ev->available); + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + ngx_reorder_accept_events(ls); +#endif } @@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) } +#if (NGX_HAVE_EPOLLEXCLUSIVE) + +static void +ngx_reorder_accept_events(ngx_listening_t *ls) +{ + ngx_connection_t *c; + + /* + * Linux with EPOLLEXCLUSIVE usually notifies only the process which + * was first to add the listening socket to the epoll instance. As + * a result most of the connections are handled by the first worker + * process. To fix this, we re-add the socket periodically, so other + * workers will get a chance to accept connections. + */ + + if (!ngx_use_exclusive_accept) { + return; + } + +#if (NGX_HAVE_REUSEPORT) + + if (ls->reuseport) { + return; + } + +#endif + + c = ls->connection; + + if (c->requests++ % 16 != 0 + && ngx_accept_disabled <= 0) + { + return; + } + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return; + } + + if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return; + } +} + +#endif + + static void ngx_close_accepted_connection(ngx_connection_t *c) { From 15275b672ce6bdc43bc31d1bc62e58d96d09dd57 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 11 Jan 2022 02:23:49 +0300 Subject: [PATCH 22/34] Avoid sending "Connection: keep-alive" when shutting down. When a worker process is shutting down, keepalive is not used: this is checked before the ngx_http_set_keepalive() call in ngx_http_finalize_connection(). Yet the "Connection: keep-alive" header was still sent, even if we know that the worker process is shutting down, potentially resulting in additional requests being sent to the connection which is going to be closed anyway. While clients are expected to be able to handle asynchronous close events (see ticket #1022), it is certainly possible to send the "Connection: close" header instead, informing the client that the connection is going to be closed and potentially saving some unneeded work. With this change, we additionally check for worker process shutdown just before sending response headers, and disable keepalive accordingly. --- src/http/ngx_http_header_filter_module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9b8940590..76f6e9629 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -197,6 +197,10 @@ ngx_http_header_filter(ngx_http_request_t *r) } } + if (r->keepalive && (ngx_terminate || ngx_exiting)) { + r->keepalive = 0; + } + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; From 415d026a075af46f12fefbc31cfdd5c5663ee636 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Mon, 17 Jan 2022 17:05:12 +0300 Subject: [PATCH 23/34] SSL: free pkey on SSL_CTX_set0_tmp_dh_pkey() failure. The behaviour was changed in OpenSSL 3.0.1: https://git.openssl.org/?p=openssl.git;a=commitdiff;h=bf17b7b --- src/event/ngx_event_openssl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index ef3ef1352..9fd5dd474 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1383,6 +1383,9 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); +#if (OPENSSL_VERSION_NUMBER >= 0x3000001fL) + EVP_PKEY_free(dh); +#endif BIO_free(bio); return NGX_ERROR; } From 7ebead68241280f216f17947733874c1a687b15d Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Wed, 19 Jan 2022 17:37:34 -0800 Subject: [PATCH 24/34] Core: simplify reader lock release. --- src/core/ngx_rwlock.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index ed2b0f810..e7da8a8ec 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -89,22 +89,10 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) void ngx_rwlock_unlock(ngx_atomic_t *lock) { - ngx_atomic_uint_t readers; - - readers = *lock; - - if (readers == NGX_RWLOCK_WLOCK) { + if (*lock == NGX_RWLOCK_WLOCK) { (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); - return; - } - - for ( ;; ) { - - if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { - return; - } - - readers = *lock; + } else { + (void) ngx_atomic_fetch_add(lock, -1); } } From 9fc865bcc40deb644c075311daa807ab6ae1d2aa Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 22 Jan 2022 00:28:51 +0300 Subject: [PATCH 25/34] Contrib: vim syntax adjusted to save cpoptions (ticket #2276). Line continuation as used in the syntax file might be broken if "compatible" is set or "C" is added to cpoptions. Fix is to set the "cpoptions" option to vim default value at script start and restore it later, see ":help use-cpo-save". --- contrib/vim/syntax/nginx.vim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 1b52d4869..6828cd3e5 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -5,6 +5,9 @@ if exists("b:current_syntax") finish end +let s:save_cpo = &cpo +set cpo&vim + " general syntax if has("patch-7.4.1142") @@ -2485,4 +2488,7 @@ hi def link ngxDirectiveThirdPartyDeprecated Error hi def link ngxListenOptions Keyword hi def link ngxListenOptionsDeprecated Error +let &cpo = s:save_cpo +unlet s:save_cpo + let b:current_syntax = "nginx" From a20648cafbed1bf82b5d04d242872e91b1fec03a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 24 Jan 2022 17:18:50 +0300 Subject: [PATCH 26/34] SSL: always renewing tickets with TLSv1.3 (ticket #1892). Chrome only uses TLS session tickets once with TLS 1.3, likely following RFC 8446 Appendix C.4 recommendation. With OpenSSL, this works fine with built-in session tickets, since these are explicitly renewed in case of TLS 1.3 on each session reuse, but results in only two connections being reused after an initial handshake when using ssl_session_ticket_key. Fix is to always renew TLS session tickets in case of TLS 1.3 when using ssl_session_ticket_key, similarly to how it is done by OpenSSL internally. --- src/event/ngx_event_openssl.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 9fd5dd474..1789e5d3a 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -4490,7 +4490,21 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, return -1; } - return (i == 0) ? 1 : 2 /* renew */; + /* renew if TLSv1.3 */ + +#ifdef TLS1_3_VERSION + if (SSL_version(ssl_conn) == TLS1_3_VERSION) { + return 2; + } +#endif + + /* renew if non-default key */ + + if (i != 0) { + return 2; + } + + return 1; } } From 3f71835f9c81eb47ce3c239785a42abcb67d9640 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 25 Jan 2022 18:03:51 +0300 Subject: [PATCH 27/34] nginx-1.21.6-RELEASE --- docs/xml/nginx/changes.xml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index fd6da38ba..2f9c350e1 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,44 @@ + + + + +при использование EPOLLEXCLUSIVE на Linux +распределение клиентских соединений между рабочими процессами +было неравномерным. + + +when using EPOLLEXCLUSIVE on Linux +client connections were unevenly distributed +among worker processes. + + + + + +во время плавного завершения старых рабочих процессов +nginx возвращал в ответах строку заголовка "Connection: keep-alive". + + +nginx returned the "Connection: keep-alive" header line in responses +during graceful shutdown of old worker processes. + + + + + +в директиве ssl_session_ticket_key при использовании TLSv1.3. + + +in the "ssl_session_ticket_key" when using TLSv1.3. + + + + + + From 1670ce4de531414d7577e6f13ec3a247c2c94868 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 25 Jan 2022 18:03:52 +0300 Subject: [PATCH 28/34] release-1.21.6 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index a1e630018..40a72593c 100644 --- a/.hgtags +++ b/.hgtags @@ -466,3 +466,4 @@ bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2 2217a9c1d0b86026f22700b3c089545db1964f55 release-1.21.3 39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4 d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5 +714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6 From 0a7499bf8c760c19666b91100dd7fe7b6e31ff3d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 24 May 2022 02:55:29 +0300 Subject: [PATCH 29/34] Stable branch. --- 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 daac21e2c..329b603e1 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021006 -#define NGINX_VERSION "1.21.6" +#define nginx_version 1022000 +#define NGINX_VERSION "1.22.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From 396c3cf3c1247fe62aec7392183d86cb6f11ae37 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Fri, 4 Feb 2022 13:29:31 +0300 Subject: [PATCH 30/34] Year 2022. --- docs/text/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/text/LICENSE b/docs/text/LICENSE index fd0c72d49..fdedcb746 100644 --- a/docs/text/LICENSE +++ b/docs/text/LICENSE @@ -1,6 +1,6 @@ /* * Copyright (C) 2002-2021 Igor Sysoev - * Copyright (C) 2011-2021 Nginx, Inc. + * Copyright (C) 2011-2022 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without From 1033316ab44e4ed8461f9fbb6463395a2f4459f8 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 24 May 2022 02:51:49 +0300 Subject: [PATCH 31/34] Updated OpenSSL and zlib used for win32 builds. --- misc/GNUmakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/GNUmakefile b/misc/GNUmakefile index 58e9f7f00..8f839b477 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,8 +6,8 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.1.1m -ZLIB = zlib-1.2.11 +OPENSSL = openssl-1.1.1o +ZLIB = zlib-1.2.12 PCRE = pcre2-10.39 From 727319755fca1aae729dae614bb1fdb4f99c8a6c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 24 May 2022 02:59:18 +0300 Subject: [PATCH 32/34] nginx-1.22.0-RELEASE --- docs/xml/nginx/changes.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 2f9c350e1..3f86e4460 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,20 @@ + + + + +Стабильная ветка 1.22.x. + + +1.22.x stable branch. + + + + + + From a00f001a21c101214e4fe616607620274960f95f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 24 May 2022 02:59:19 +0300 Subject: [PATCH 33/34] release-1.22.0 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 40a72593c..517d2151b 100644 --- a/.hgtags +++ b/.hgtags @@ -467,3 +467,4 @@ bfbc52374adcbf2f9060afd62de940f6fab3bba5 release-1.21.2 39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4 d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5 714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6 +f669c9c2a617d80daf753e012265ab5290df0d9b release-1.22.0 From 6a015ad254884b04698e3fb397b3fc361e39132c Mon Sep 17 00:00:00 2001 From: Stefen Wakefield Date: Tue, 7 Jun 2022 01:37:25 -0500 Subject: [PATCH 34/34] Fix build --- auto/cc/clang | 3 +++ auto/cc/gcc | 2 ++ 2 files changed, 5 insertions(+) diff --git a/auto/cc/clang b/auto/cc/clang index a962ee234..8a15a049c 100644 --- a/auto/cc/clang +++ b/auto/cc/clang @@ -88,6 +88,9 @@ if [ "$NGX_SYSTEM" = "Darwin" ]; then CFLAGS="$CFLAGS -Wno-deprecated-declarations" fi +# dont warn on vla-parameter +CFLAGS="$CFLAGS -Wno-vla-parameter" + # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/cc/gcc b/auto/cc/gcc index a5c5c18fb..9fe64398f 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -164,6 +164,8 @@ case "$NGX_GCC_VER" in ;; esac +# dont warn on vla-parameter +CFLAGS="$CFLAGS -Wno-vla-parameter" # stop on warning CFLAGS="$CFLAGS -Werror"