From ee00085f5cc655e362337684bf82dbe926d4b885 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 23 Jan 2023 05:01:01 +0300 Subject: [PATCH 01/38] Configure: removed unneeded header from UDP_SEGMENT test. --- auto/os/linux | 1 - 1 file changed, 1 deletion(-) diff --git a/auto/os/linux b/auto/os/linux index 0ae701fad..eb6702679 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -238,7 +238,6 @@ ngx_feature="UDP_SEGMENT" ngx_feature_name="NGX_HAVE_UDP_SEGMENT" ngx_feature_run=no ngx_feature_incs="#include - #include #include " ngx_feature_path= ngx_feature_libs= From 5c18b5bc3fe14aac969d1fb1e383bc696932e1f5 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 24 Jan 2023 03:01:51 +0300 Subject: [PATCH 02/38] Gzip static: ranges support (ticket #2349). In contrast to on-the-fly gzipping with gzip filter, static gzipped representation as returned by gzip_static is persistent, and therefore the same binary representation is available for future requests, making it possible to use range requests. Further, if a gzipped representation is re-generated with different compression settings, it is expected to result in different ETag and different size reported in the Content-Range header, making it possible to safely use range requests anyway. As such, ranges are now allowed for files returned by gzip_static. --- src/http/modules/ngx_http_gzip_static_module.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c index 66fcc5d1b..0ab14636e 100644 --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -247,6 +247,8 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r) ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; + r->allow_ranges = 1; + /* we need to allocate all before the header would be sent */ b = ngx_calloc_buf(r->pool); From f20c6e0eb5820574417106ca5c0863a1ebbe03a7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 26 Jan 2023 03:34:44 +0300 Subject: [PATCH 03/38] Fixed handling of very long locations (ticket #2435). Previously, location prefix length in ngx_http_location_tree_node_t was stored as "u_char", and therefore location prefixes longer than 255 bytes were handled incorrectly. Fix is to use "u_short" instead. With "u_short", prefixes up to 65535 bytes can be safely used, and this isn't reachable due to NGX_CONF_BUFFER, which is 4096 bytes. --- src/http/ngx_http.c | 2 +- src/http/ngx_http_core_module.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 73c08d593..5c628849f 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1130,7 +1130,7 @@ ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) || (lq->inclusive && lq->inclusive->auto_redirect)); - node->len = (u_char) len; + node->len = (u_short) len; ngx_memcpy(node->name, &lq->name->data[prefix], len); ngx_queue_split(locations, q, &tail); diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 49bbd4aa9..1c56264c6 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -463,8 +463,8 @@ struct ngx_http_location_tree_node_s { ngx_http_core_loc_conf_t *exact; ngx_http_core_loc_conf_t *inclusive; + u_short len; u_char auto_redirect; - u_char len; u_char name[1]; }; From dad65f3e449f215469943628f2b1f12a118fcf7e Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 28 Jan 2023 01:29:45 +0300 Subject: [PATCH 04/38] Added warning about redefinition of listen socket protocol options. The "listen" directive in the http module can be used multiple times in different server blocks. Originally, it was supposed to be specified once with various socket options, and without any parameters in virtual server blocks. For example: server { listen 80 backlog=1024; server_name foo; ... } server { listen 80; server_name bar; ... } server { listen 80; server_name bazz; ... } The address part of the syntax ("address[:port]" / "port" / "unix:path") uniquely identifies the listening socket, and therefore is enough for name-based virtual servers (to let nginx know that the virtual server accepts requests on the listening socket in question). To ensure that listening options do not conflict between virtual servers, they were allowed only once. For example, the following configuration will be rejected ("duplicate listen options for 0.0.0.0:80 in ..."): server { listen 80 backlog=1024; server_name foo; ... } server { listen 80 backlog=512; server_name bar; ... } At some point it was, however, noticed, that it is sometimes convenient to repeat some options for clarity. In nginx 0.8.51 the "ssl" parameter was allowed to be specified multiple times, e.g.: server { listen 443 ssl backlog=1024; server_name foo; ... } server { listen 443 ssl; server_name bar; ... } server { listen 443 ssl; server_name bazz; ... } This approach makes configuration more readable, since SSL sockets are immediately visible in the configuration. If this is not needed, just the address can still be used. Later, additional protocol-specific options similar to "ssl" were introduced, notably "http2" and "proxy_protocol". With these options, one can write: server { listen 443 ssl backlog=1024; server_name foo; ... } server { listen 443 http2; server_name bar; ... } server { listen 443 proxy_protocol; server_name bazz; ... } The resulting socket will use ssl, http2, and proxy_protocol, but this is not really obvious from the configuration. To emphasize such misleading configurations are discouraged, nginx now warns as long as the "listen" directive is used with options different from the options previously used if this is potentially confusing. In particular, the following configurations are allowed: server { listen 8401 ssl backlog=1024; server_name foo; } server { listen 8401 ssl; server_name bar; } server { listen 8401 ssl; server_name bazz; } server { listen 8402 ssl http2 backlog=1024; server_name foo; } server { listen 8402 ssl; server_name bar; } server { listen 8402 ssl; server_name bazz; } server { listen 8403 ssl; server_name bar; } server { listen 8403 ssl; server_name bazz; } server { listen 8403 ssl http2; server_name foo; } server { listen 8404 ssl http2 backlog=1024; server_name foo; } server { listen 8404 http2; server_name bar; } server { listen 8404 http2; server_name bazz; } server { listen 8405 ssl http2 backlog=1024; server_name foo; } server { listen 8405 ssl http2; server_name bar; } server { listen 8405 ssl http2; server_name bazz; } server { listen 8406 ssl; server_name foo; } server { listen 8406; server_name bar; } server { listen 8406; server_name bazz; } And the following configurations will generate warnings: server { listen 8501 ssl http2 backlog=1024; server_name foo; } server { listen 8501 http2; server_name bar; } server { listen 8501 ssl; server_name bazz; } server { listen 8502 backlog=1024; server_name foo; } server { listen 8502 ssl; server_name bar; } server { listen 8503 ssl; server_name foo; } server { listen 8503 http2; server_name bar; } server { listen 8504 ssl; server_name foo; } server { listen 8504 http2; server_name bar; } server { listen 8504 proxy_protocol; server_name bazz; } server { listen 8505 ssl http2 proxy_protocol; server_name foo; } server { listen 8505 ssl http2; server_name bar; } server { listen 8505 ssl; server_name bazz; } server { listen 8506 ssl http2; server_name foo; } server { listen 8506 ssl; server_name bar; } server { listen 8506; server_name bazz; } server { listen 8507 ssl; server_name bar; } server { listen 8507; server_name bazz; } server { listen 8507 ssl http2; server_name foo; } server { listen 8508 ssl; server_name bar; } server { listen 8508; server_name bazz; } server { listen 8508 ssl backlog=1024; server_name foo; } server { listen 8509; server_name bazz; } server { listen 8509 ssl; server_name bar; } server { listen 8509 ssl backlog=1024; server_name foo; } The basic idea is that at most two sets of protocol options are allowed: the main one (with socket options, if any), and a shorter one, with options being a subset of the main options, repeated for clarity. As long as the shorter set of protocol options is used, all listen directives except the main one should use it. --- src/http/ngx_http.c | 63 ++++++++++++++++++++++++++++++++- src/http/ngx_http_core_module.h | 4 +++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 5c628849f..93e1cd435 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1228,7 +1228,8 @@ static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) { - ngx_uint_t i, default_server, proxy_protocol; + ngx_uint_t i, default_server, proxy_protocol, + protocols, protocols_prev; ngx_http_conf_addr_t *addr; #if (NGX_HTTP_SSL) ngx_uint_t ssl; @@ -1264,12 +1265,18 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, default_server = addr[i].opt.default_server; proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol; + protocols = lsopt->proxy_protocol; + protocols_prev = addr[i].opt.proxy_protocol; #if (NGX_HTTP_SSL) ssl = lsopt->ssl || addr[i].opt.ssl; + protocols |= lsopt->ssl << 1; + protocols_prev |= addr[i].opt.ssl << 1; #endif #if (NGX_HTTP_V2) http2 = lsopt->http2 || addr[i].opt.http2; + protocols |= lsopt->http2 << 2; + protocols_prev |= addr[i].opt.http2 << 2; #endif if (lsopt->set) { @@ -1299,6 +1306,57 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, addr[i].default_server = cscf; } + /* check for conflicting protocol options */ + + if ((protocols | protocols_prev) != protocols_prev) { + + /* options added */ + + if ((addr[i].opt.set && !lsopt->set) + || addr[i].protocols_changed + || (protocols | protocols_prev) != protocols) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols_prev; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else if ((protocols_prev | protocols) != protocols) { + + /* options removed */ + + if (lsopt->set + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + addr[i].protocols_changed = 1; + + } else { + + /* the same options */ + + if ((lsopt->set && addr[i].protocols_changed) + || (addr[i].protocols_set && protocols != addr[i].protocols)) + { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "protocol options redefined for %V", + &addr[i].opt.addr_text); + } + + addr[i].protocols = protocols; + addr[i].protocols_set = 1; + } + addr[i].opt.default_server = default_server; addr[i].opt.proxy_protocol = proxy_protocol; #if (NGX_HTTP_SSL) @@ -1355,6 +1413,9 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } addr->opt = *lsopt; + addr->protocols = 0; + addr->protocols_set = 0; + addr->protocols_changed = 0; addr->hash.buckets = NULL; addr->hash.size = 0; addr->wc_head = NULL; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 1c56264c6..e41bc68d5 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -274,6 +274,10 @@ typedef struct { typedef struct { ngx_http_listen_opt_t opt; + unsigned protocols:3; + unsigned protocols_set:1; + unsigned protocols_changed:1; + ngx_hash_t hash; ngx_hash_wildcard_t *wc_head; ngx_hash_wildcard_t *wc_tail; From 856a01860e676bd5fe88d0f7ad7189e47cce04d9 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 28 Jan 2023 05:20:23 +0300 Subject: [PATCH 05/38] Style. --- src/event/ngx_event_connectex.c | 4 ++-- src/http/modules/ngx_http_flv_module.c | 2 +- src/http/modules/ngx_http_static_module.c | 4 ++-- src/http/ngx_http_file_cache.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/event/ngx_event_connectex.c b/src/event/ngx_event_connectex.c index 59ada7480..36b151424 100644 --- a/src/event/ngx_event_connectex.c +++ b/src/event/ngx_event_connectex.c @@ -127,8 +127,8 @@ void ngx_iocp_wait_events(int main) conn[0] = NULL; for ( ;; ) { - offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1: 0; - timeout = (nevents == 1 && !first) ? 60000: INFINITE; + offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1 : 0; + timeout = (nevents == 1 && !first) ? 60000 : INFINITE; n = WSAWaitForMultipleEvents(nevents - offset, events[offset], 0, timeout, 0); diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c index cc06d538a..a7ee53cbb 100644 --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -232,7 +232,7 @@ ngx_http_flv_handler(ngx_http_request_t *r) b->file_pos = start; b->file_last = of.size; - b->in_file = b->file_last ? 1: 0; + b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index e30565d4e..3e65edfdb 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -265,8 +265,8 @@ ngx_http_static_handler(ngx_http_request_t *r) b->file_pos = 0; b->file_last = of.size; - b->in_file = b->file_last ? 1: 0; - b->last_buf = (r == r->main) ? 1: 0; + b->in_file = b->file_last ? 1 : 0; + b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; b->file->fd = of.fd; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 4d2f6c42c..8db24f103 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1600,8 +1600,8 @@ ngx_http_cache_send(ngx_http_request_t *r) b->file_pos = c->body_start; b->file_last = c->length; - b->in_file = (c->length - c->body_start) ? 1: 0; - b->last_buf = (r == r->main) ? 1: 0; + b->in_file = (c->length - c->body_start) ? 1 : 0; + b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; b->file->fd = c->file.fd; From 384a8d8dfbf817b98715e8ed5ec7bf3cb545d501 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 28 Jan 2023 05:23:33 +0300 Subject: [PATCH 06/38] Fixed "zero size buf" alerts with subrequests. Since 4611:2b6cb7528409 responses from the gzip static, flv, and mp4 modules can be used with subrequests, though empty files were not properly handled. Empty gzipped, flv, and mp4 files thus resulted in "zero size buf in output" alerts. While valid corresponding files are not expected to be empty, such files shouldn't result in alerts. Fix is to set b->sync on such empty subrequest responses, similarly to what ngx_http_send_special() does. Additionally, the static module, the ngx_http_send_response() function, and file cache are modified to do the same instead of not sending the response body at all in such cases, since not sending the response body at all is believed to be at least questionable, and might break various filters which do not expect such behaviour. --- src/http/modules/ngx_http_flv_module.c | 1 + src/http/modules/ngx_http_gzip_static_module.c | 1 + src/http/modules/ngx_http_mp4_module.c | 1 + src/http/modules/ngx_http_static_module.c | 5 +---- src/http/ngx_http_core_module.c | 5 +---- src/http/ngx_http_file_cache.c | 5 +---- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c index a7ee53cbb..ef2bff433 100644 --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -235,6 +235,7 @@ ngx_http_flv_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c index 0ab14636e..91b38d17b 100644 --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -273,6 +273,7 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 75a7315f9..03175dea2 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -714,6 +714,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index 3e65edfdb..8b0bb1478 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -238,10 +238,6 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (r != r->main && of.size == 0) { - return ngx_http_send_header(r); - } - r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ @@ -268,6 +264,7 @@ ngx_http_static_handler(ngx_http_request_t *r) b->in_file = b->file_last ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = of.fd; b->file->name = path; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6b1cb4fa4..2140e0627 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1803,10 +1803,6 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, } } - if (r != r->main && val.len == 0) { - return ngx_http_send_header(r); - } - b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1817,6 +1813,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, b->memory = val.len ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->memory) ? 0 : 1; out.buf = b; out.next = NULL; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 8db24f103..aa5fd1917 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1575,10 +1575,6 @@ ngx_http_cache_send(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache send: %s", c->file.name.data); - if (r != r->main && c->length - c->body_start == 0) { - return ngx_http_send_header(r); - } - /* we need to allocate all before the header would be sent */ b = ngx_calloc_buf(r->pool); @@ -1603,6 +1599,7 @@ ngx_http_cache_send(ngx_http_request_t *r) b->in_file = (c->length - c->body_start) ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; + b->sync = (b->last_buf || b->in_file) ? 0 : 1; b->file->fd = c->file.fd; b->file->name = c->file.name; From 2485681308bd8d3108da31546cb91bb97813a3fb Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 2 Feb 2023 23:38:48 +0300 Subject: [PATCH 07/38] Lingering close for connections with pipelined requests. This is expected to help with clients using pipelining with some constant depth, such as apt[1][2]. When downloading many resources, apt uses pipelining with some constant depth, a number of requests in flight. This essentially means that after receiving a response it sends an additional request to the server, and this can result in requests arriving to the server at any time. Further, additional requests are sent one-by-one, and can be easily seen as such (neither as pipelined, nor followed by pipelined requests). The only safe approach to close such connections (for example, when keepalive_requests is reached) is with lingering. To do so, now nginx monitors if pipelining was used on the connection, and if it was, closes the connection with lingering. [1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=973861#10 [2] https://mailman.nginx.org/pipermail/nginx-devel/2023-January/ZA2SP5SJU55LHEBCJMFDB2AZVELRLTHI.html --- src/core/ngx_connection.h | 1 + src/http/ngx_http_request.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 6d3348d9c..36e1be27c 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -172,6 +172,7 @@ struct ngx_connection_s { unsigned timedout:1; unsigned error:1; unsigned destroyed:1; + unsigned pipeline:1; unsigned idle:1; unsigned reusable:1; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 131a2c83c..5e0340b28 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2753,7 +2753,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r) || (clcf->lingering_close == NGX_HTTP_LINGERING_ON && (r->lingering_close || r->header_in->pos < r->header_in->last - || r->connection->read->ready))) + || r->connection->read->ready + || r->connection->pipeline))) { ngx_http_set_lingering_close(r->connection); return; @@ -3123,6 +3124,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) c->sent = 0; c->destroyed = 0; + c->pipeline = 1; if (rev->timer_set) { ngx_del_timer(rev); From 504ca566861dde3d20a558fc02c7066e9bb54bfd Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 18:15:53 +0300 Subject: [PATCH 08/38] Win32: removed unneeded wildcard in NGX_CC_NAME test for msvc. Wildcards for msvc in NGX_CC_NAME tests are not needed since 78f8ac479735. --- auto/cc/conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto/cc/conf b/auto/cc/conf index afbca62bc..ba31cb88c 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -117,7 +117,7 @@ else . auto/cc/acc ;; - msvc*) + msvc) # MSVC++ 6.0 SP2, MSVC++ Toolkit 2003 . auto/cc/msvc From 180be97d3157c6ed81efc0272dea6472241304c3 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 18:15:57 +0300 Subject: [PATCH 09/38] Win32: handling of localized MSVC cl output. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output examples in English, Russian, and Spanish: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86 Оптимизирующий 32-разрядный компилятор Microsoft (R) C/C++ версии 16.00.30319.01 для 80x86 Compilador de optimización de C/C++ de Microsoft (R) versión 16.00.30319.01 para x64 Since most of the words are translated, instead of looking for the words "Compiler Version" we now search for "C/C++" and the version number. --- auto/cc/msvc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/cc/msvc b/auto/cc/msvc index 68435ff48..d4c0be4c3 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -11,8 +11,8 @@ # MSVC 2015 (14.0) cl 19.00 -NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'Compiler Version' 2>&1 \ - | sed -e 's/^.* Version \(.*\)/\1/'` +NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'C/C++.* [0-9][0-9]*\.[0-9]' 2>&1 \ + | sed -e 's/^.* \([0-9][0-9]*\.[0-9].*\)/\1/'` echo " + cl version: $NGX_MSVC_VER" From 62b790c3318a56971e461a1e1f5b79197b604e89 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 18:15:59 +0300 Subject: [PATCH 10/38] Win32: i386 now assumed when crossbuilding (ticket #2416). Previously, NGX_MACHINE was not set when crossbuilding, resulting in NGX_ALIGNMENT=16 being used in 32-bit builds (if not explicitly set to a correct value). This in turn might result in memory corruption in ngx_palloc() (as there are no usable aligned allocator on Windows, and normal malloc() is used instead, which provides 8 byte alignment on 32-bit platforms). To fix this, now i386 machine is set when crossbuilding, so nginx won't assume strict alignment requirements. --- auto/configure | 1 + 1 file changed, 1 insertion(+) diff --git a/auto/configure b/auto/configure index 474d69e84..5b88ebb4c 100755 --- a/auto/configure +++ b/auto/configure @@ -44,6 +44,7 @@ if test -z "$NGX_PLATFORM"; then else echo "building for $NGX_PLATFORM" NGX_SYSTEM=$NGX_PLATFORM + NGX_MACHINE=i386 fi . auto/cc/conf From dad6ec3aa63fbd3b427d74842fa659f7a0b82f3b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 18:16:08 +0300 Subject: [PATCH 11/38] Win32: OpenSSL compilation for x64 targets with MSVC. To ensure proper target selection the NGX_MACHINE variable is now set based on the MSVC compiler output, and the OpenSSL target is set based on it. This is not important as long as "no-asm" is used (as in misc/GNUmakefile and win32 build instructions), but might be beneficial if someone is trying to build OpenSSL with assembler code. --- auto/cc/msvc | 15 +++++++++++++++ auto/lib/openssl/make | 15 ++++++++++++++- auto/lib/openssl/makefile.msvc | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/auto/cc/msvc b/auto/cc/msvc index d4c0be4c3..567bac7bc 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -22,6 +22,21 @@ have=NGX_COMPILER value="\"cl $NGX_MSVC_VER\"" . auto/define ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'` +# detect x64 builds + +case "$NGX_MSVC_VER" in + + *x64) + NGX_MACHINE=amd64 + ;; + + *) + NGX_MACHINE=i386 + ;; + +esac + + # optimizations # maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make index 126a23875..a7e9369e7 100644 --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -7,11 +7,24 @@ case "$CC" in cl) + case "$NGX_MACHINE" in + + amd64) + OPENSSL_TARGET=VC-WIN64A + ;; + + *) + OPENSSL_TARGET=VC-WIN32 + ;; + + esac + cat << END >> $NGX_MAKEFILE $OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE \$(MAKE) -f auto/lib/openssl/makefile.msvc \ - OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT" + OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT" \ + OPENSSL_TARGET="$OPENSSL_TARGET" END diff --git a/auto/lib/openssl/makefile.msvc b/auto/lib/openssl/makefile.msvc index a30b28669..ed17cde08 100644 --- a/auto/lib/openssl/makefile.msvc +++ b/auto/lib/openssl/makefile.msvc @@ -6,7 +6,7 @@ all: cd $(OPENSSL) - perl Configure VC-WIN32 no-shared no-threads \ + perl Configure $(OPENSSL_TARGET) no-shared no-threads \ --prefix="%cd%/openssl" \ --openssldir="%cd%/openssl/ssl" \ $(OPENSSL_OPT) From 1f8a66f1991dac0158642a9ac2d531714078ecc6 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:39 +0300 Subject: [PATCH 12/38] Win32: non-ASCII names support in autoindex (ticket #458). Notably, ngx_open_dir() now supports opening directories with non-ASCII characters, and directory entries returned by ngx_read_dir() are properly converted to UTF-8. --- src/os/win32/ngx_files.c | 273 +++++++++++++++++++++++++++++++++++---- src/os/win32/ngx_files.h | 10 +- 2 files changed, 253 insertions(+), 30 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 3017b45fe..cef677e5d 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -13,7 +13,11 @@ static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, size_t len); -static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len); +static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, + size_t reserved); +static u_char *ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, + size_t *allocated); +uint32_t ngx_utf16_decode(u_short **u, size_t n); /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */ @@ -28,7 +32,7 @@ ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) u_short utf16[NGX_UTF16_BUFLEN]; len = NGX_UTF16_BUFLEN; - u = ngx_utf8_to_utf16(utf16, name, &len); + u = ngx_utf8_to_utf16(utf16, name, &len, 0); if (u == NULL) { return INVALID_HANDLE_VALUE; @@ -269,7 +273,7 @@ ngx_file_info(u_char *file, ngx_file_info_t *sb) len = NGX_UTF16_BUFLEN; - u = ngx_utf8_to_utf16(utf16, file, &len); + u = ngx_utf8_to_utf16(utf16, file, &len, 0); if (u == NULL) { return NGX_FILE_ERROR; @@ -427,58 +431,109 @@ ngx_realpath(u_char *path, u_char *resolved) ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) { - u_char *pattern, *p; + size_t len; + u_short *u, *p; ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; - pattern = malloc(name->len + 3); - if (pattern == NULL) { + len = NGX_UTF16_BUFLEN - 2; + u = ngx_utf8_to_utf16(utf16, name->data, &len, 2); + + if (u == NULL) { return NGX_ERROR; } - p = ngx_cpymem(pattern, name->data, name->len); + if (ngx_win32_check_filename(name->data, u, len) != NGX_OK) { + goto failed; + } + + p = &u[len - 1]; *p++ = '/'; *p++ = '*'; *p = '\0'; - dir->dir = FindFirstFile((const char *) pattern, &dir->finddata); + dir->dir = FindFirstFileW(u, &dir->finddata); if (dir->dir == INVALID_HANDLE_VALUE) { - err = ngx_errno; - ngx_free(pattern); - ngx_set_errno(err); - return NGX_ERROR; + goto failed; } - ngx_free(pattern); + if (u != utf16) { + ngx_free(u); + } dir->valid_info = 1; dir->ready = 1; + dir->name = NULL; + dir->allocated = 0; return NGX_OK; -} +failed: -ngx_int_t -ngx_read_dir(ngx_dir_t *dir) -{ - if (dir->ready) { - dir->ready = 0; - return NGX_OK; - } - - if (FindNextFile(dir->dir, &dir->finddata) != 0) { - dir->type = 1; - return NGX_OK; + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); } return NGX_ERROR; } +ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + u_char *name; + size_t len, allocated; + + if (dir->ready) { + dir->ready = 0; + goto convert; + } + + if (FindNextFileW(dir->dir, &dir->finddata) != 0) { + dir->type = 1; + goto convert; + } + + return NGX_ERROR; + +convert: + + name = dir->name; + len = dir->allocated; + + name = ngx_utf16_to_utf8(name, dir->finddata.cFileName, &len, &allocated); + + if (name == NULL) { + return NGX_ERROR; + } + + if (name != dir->name) { + + if (dir->name) { + ngx_free(dir->name); + } + + dir->name = name; + dir->allocated = allocated; + } + + dir->namelen = len - 1; + + return NGX_OK; +} + + ngx_int_t ngx_close_dir(ngx_dir_t *dir) { + if (dir->name) { + ngx_free(dir->name); + } + if (FindClose(dir->dir) == 0) { return NGX_ERROR; } @@ -816,7 +871,7 @@ failed: static u_short * -ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len) +ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, size_t reserved) { u_char *p; u_short *u, *last; @@ -865,7 +920,7 @@ ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len) /* the given buffer is not enough, allocate a new one */ - u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short)); + u = malloc(((p - utf8) + ngx_strlen(p) + 1 + reserved) * sizeof(u_short)); if (u == NULL) { return NULL; } @@ -910,3 +965,167 @@ ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len) /* unreachable */ } + + +static u_char * +ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, size_t *allocated) +{ + u_char *p, *last; + u_short *u, *j; + uint32_t n; + + u = utf16; + p = utf8; + last = utf8 + *len; + + while (p < last) { + + if (*u < 0x80) { + *p++ = (u_char) *u; + + if (*u == 0) { + *len = p - utf8; + return utf8; + } + + u++; + + continue; + } + + if (p >= last - 4) { + *len = p - utf8; + break; + } + + n = ngx_utf16_decode(&u, 2); + + if (n > 0x10ffff) { + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n >= 0x10000) { + *p++ = (u_char) (0xf0 + (n >> 18)); + *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + if (n >= 0x0800) { + *p++ = (u_char) (0xe0 + (n >> 12)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + *p++ = (u_char) (0xc0 + (n >> 6)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + } + + /* the given buffer is not enough, allocate a new one */ + + for (j = u; *j; j++) { /* void */ } + + p = malloc((j - utf16) * 4 + 1); + if (p == NULL) { + return NULL; + } + + if (allocated) { + *allocated = (j - utf16) * 4 + 1; + } + + ngx_memcpy(p, utf8, *len); + + utf8 = p; + p += *len; + + for ( ;; ) { + + if (*u < 0x80) { + *p++ = (u_char) *u; + + if (*u == 0) { + *len = p - utf8; + return utf8; + } + + u++; + + continue; + } + + n = ngx_utf16_decode(&u, 2); + + if (n > 0x10ffff) { + ngx_free(utf8); + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n >= 0x10000) { + *p++ = (u_char) (0xf0 + (n >> 18)); + *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + if (n >= 0x0800) { + *p++ = (u_char) (0xe0 + (n >> 12)); + *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + continue; + } + + *p++ = (u_char) (0xc0 + (n >> 6)); + *p++ = (u_char) (0x80 + (n & 0x3f)); + } + + /* unreachable */ +} + + +/* + * ngx_utf16_decode() decodes one or two UTF-16 code units + * the return values: + * 0x80 - 0x10ffff valid character + * 0x110000 - 0xfffffffd invalid sequence + * 0xfffffffe incomplete sequence + * 0xffffffff error + */ + +uint32_t +ngx_utf16_decode(u_short **u, size_t n) +{ + uint32_t k, m; + + k = **u; + + if (k < 0xd800 || k > 0xdfff) { + (*u)++; + return k; + } + + if (k > 0xdbff) { + (*u)++; + return 0xffffffff; + } + + if (n < 2) { + return 0xfffffffe; + } + + (*u)++; + + m = *(*u)++; + + if (m < 0xdc00 || m > 0xdfff) { + return 0xffffffff; + + } + + return 0x10000 + ((k - 0xd800) << 10) + (m - 0xdc00); +} diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index a10839ba4..fd197fc9f 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -30,7 +30,11 @@ typedef struct { typedef struct { HANDLE dir; - WIN32_FIND_DATA finddata; + WIN32_FIND_DATAW finddata; + + u_char *name; + size_t namelen; + size_t allocated; unsigned valid_info:1; unsigned type:1; @@ -205,8 +209,8 @@ ngx_int_t ngx_close_dir(ngx_dir_t *dir); #define ngx_dir_access(a) (a) -#define ngx_de_name(dir) ((u_char *) (dir)->finddata.cFileName) -#define ngx_de_namelen(dir) ngx_strlen((dir)->finddata.cFileName) +#define ngx_de_name(dir) (dir)->name +#define ngx_de_namelen(dir) (dir)->namelen ngx_int_t ngx_de_info(u_char *name, ngx_dir_t *dir); #define ngx_de_info_n "dummy()" From 99d5ad72a48811c3939a74a54330d7fd5517a5ab Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:41 +0300 Subject: [PATCH 13/38] Win32: non-ASCII names support in "include" with wildcards. Notably, ngx_open_glob() now supports opening directories with non-ASCII characters, and pathnames returned by ngx_read_glob() are converted to UTF-8. --- src/os/win32/ngx_files.c | 96 ++++++++++++++++++++++++++-------------- src/os/win32/ngx_files.h | 2 +- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index cef677e5d..360f14f04 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -10,6 +10,7 @@ #define NGX_UTF16_BUFLEN 256 +#define NGX_UTF8_BUFLEN 512 static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, size_t len); @@ -547,14 +548,27 @@ ngx_open_glob(ngx_glob_t *gl) { u_char *p; size_t len; + u_short *u; ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; - gl->dir = FindFirstFile((const char *) gl->pattern, &gl->finddata); + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, gl->pattern, &len, 0); + + if (u == NULL) { + return NGX_ERROR; + } + + gl->dir = FindFirstFileW(u, &gl->finddata); if (gl->dir == INVALID_HANDLE_VALUE) { err = ngx_errno; + if (u != utf16) { + ngx_free(u); + } + if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) && gl->test) { @@ -562,6 +576,8 @@ ngx_open_glob(ngx_glob_t *gl) return NGX_OK; } + ngx_set_errno(err); + return NGX_ERROR; } @@ -571,18 +587,10 @@ ngx_open_glob(ngx_glob_t *gl) } } - len = ngx_strlen(gl->finddata.cFileName); - gl->name.len = gl->last + len; - - gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); - if (gl->name.data == NULL) { - return NGX_ERROR; + if (u != utf16) { + ngx_free(u); } - ngx_memcpy(gl->name.data, gl->pattern, gl->last); - ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName, - len + 1); - gl->ready = 1; return NGX_OK; @@ -592,40 +600,25 @@ ngx_open_glob(ngx_glob_t *gl) ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) { - size_t len; - ngx_err_t err; + u_char *p; + size_t len; + ngx_err_t err; + u_char utf8[NGX_UTF8_BUFLEN]; if (gl->no_match) { return NGX_DONE; } if (gl->ready) { - *name = gl->name; - gl->ready = 0; - return NGX_OK; + goto convert; } ngx_free(gl->name.data); gl->name.data = NULL; - if (FindNextFile(gl->dir, &gl->finddata) != 0) { - - len = ngx_strlen(gl->finddata.cFileName); - gl->name.len = gl->last + len; - - gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); - if (gl->name.data == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(gl->name.data, gl->pattern, gl->last); - ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName, - len + 1); - - *name = gl->name; - - return NGX_OK; + if (FindNextFileW(gl->dir, &gl->finddata) != 0) { + goto convert; } err = ngx_errno; @@ -638,6 +631,43 @@ ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) "FindNextFile(%s) failed", gl->pattern); return NGX_ERROR; + +convert: + + len = NGX_UTF8_BUFLEN; + p = ngx_utf16_to_utf8(utf8, gl->finddata.cFileName, &len, NULL); + + if (p == NULL) { + return NGX_ERROR; + } + + gl->name.len = gl->last + len - 1; + + gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); + if (gl->name.data == NULL) { + goto failed; + } + + ngx_memcpy(gl->name.data, gl->pattern, gl->last); + ngx_cpystrn(gl->name.data + gl->last, p, len); + + if (p != utf8) { + ngx_free(p); + } + + *name = gl->name; + + return NGX_OK; + +failed: + + if (p != utf8) { + err = ngx_errno; + ngx_free(p); + ngx_set_errno(err); + } + + return NGX_ERROR; } diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index fd197fc9f..a8918e0fd 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -44,7 +44,7 @@ typedef struct { typedef struct { HANDLE dir; - WIN32_FIND_DATA finddata; + WIN32_FIND_DATAW finddata; unsigned ready:1; unsigned test:1; From 1edc23cc84a62afdec2286235286a47e1259ef11 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:44 +0300 Subject: [PATCH 14/38] Win32: non-ASCII directory names support in ngx_getcwd(). This makes it possible to start nginx without a prefix explicitly set in a directory with non-ASCII characters in it. --- src/os/win32/ngx_files.c | 34 ++++++++++++++++++++++++++++++++++ src/os/win32/ngx_files.h | 6 +++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 360f14f04..c09600643 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -429,6 +429,40 @@ ngx_realpath(u_char *path, u_char *resolved) } +size_t +ngx_getcwd(u_char *buf, size_t size) +{ + u_char *p; + size_t n; + u_short utf16[NGX_MAX_PATH]; + + n = GetCurrentDirectoryW(NGX_MAX_PATH, utf16); + + if (n == 0) { + return 0; + } + + if (n > NGX_MAX_PATH) { + ngx_set_errno(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + p = ngx_utf16_to_utf8(buf, utf16, &size, NULL); + + if (p == NULL) { + return 0; + } + + if (p != buf) { + ngx_free(p); + ngx_set_errno(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + return size - 1; +} + + ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index a8918e0fd..bc648e4c9 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -178,8 +178,12 @@ void ngx_close_file_mapping(ngx_file_mapping_t *fm); u_char *ngx_realpath(u_char *path, u_char *resolved); #define ngx_realpath_n "" -#define ngx_getcwd(buf, size) GetCurrentDirectory(size, (char *) buf) + + +size_t ngx_getcwd(u_char *buf, size_t size); #define ngx_getcwd_n "GetCurrentDirectory()" + + #define ngx_path_separator(c) ((c) == '/' || (c) == '\\') #define NGX_HAVE_MAX_PATH 1 From 89719dc5c1163a90b789cbac87845f7393655b70 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:45 +0300 Subject: [PATCH 15/38] Win32: non-ASCII directory names support in ngx_create_dir(). This makes it possible to create directories under prefix with non-ASCII characters, as well as makes it possible to create directories with non-ASCII characters when using the dav module (ticket #1433). To ensure that the dav module operations are restricted similarly to other file operations (in particular, short names are not allowed), the ngx_win32_check_filename() function is used. It improved to support checking of just dirname, and now can be used to check paths when creating files or directories. --- src/os/win32/ngx_files.c | 80 +++++++++++++++++++++++++++++++++++----- src/os/win32/ngx_files.h | 2 +- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index c09600643..641b65c87 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -12,8 +12,8 @@ #define NGX_UTF16_BUFLEN 256 #define NGX_UTF8_BUFLEN 512 -static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, - size_t len); +static ngx_int_t ngx_win32_check_filename(u_short *u, size_t len, + ngx_uint_t dirname); static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, size_t reserved); static u_char *ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, @@ -42,7 +42,7 @@ ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) fd = INVALID_HANDLE_VALUE; if (create == NGX_FILE_OPEN - && ngx_win32_check_filename(name, u, len) != NGX_OK) + && ngx_win32_check_filename(u, len, 0) != NGX_OK) { goto failed; } @@ -282,7 +282,7 @@ ngx_file_info(u_char *file, ngx_file_info_t *sb) rc = NGX_FILE_ERROR; - if (ngx_win32_check_filename(file, u, len) != NGX_OK) { + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { goto failed; } @@ -478,7 +478,7 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) return NGX_ERROR; } - if (ngx_win32_check_filename(name->data, u, len) != NGX_OK) { + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { goto failed; } @@ -577,6 +577,42 @@ ngx_close_dir(ngx_dir_t *dir) } +ngx_int_t +ngx_create_dir(u_char *name, ngx_uint_t access) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 1) != NGX_OK) { + goto failed; + } + + rc = CreateDirectoryW(u, NULL); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + ngx_int_t ngx_open_glob(ngx_glob_t *gl) { @@ -791,11 +827,10 @@ ngx_fs_available(u_char *name) static ngx_int_t -ngx_win32_check_filename(u_char *name, u_short *u, size_t len) +ngx_win32_check_filename(u_short *u, size_t len, ngx_uint_t dirname) { - u_char *p, ch; u_long n; - u_short *lu; + u_short *lu, *p, *slash, ch; ngx_err_t err; enum { sw_start = 0, @@ -808,9 +843,14 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) /* check for NTFS streams (":"), trailing dots and spaces */ lu = NULL; + slash = NULL; state = sw_start; - for (p = name; *p; p++) { +#if (NGX_SUPPRESS_WARN) + ch = 0; +#endif + + for (p = u; *p; p++) { ch = *p; switch (state) { @@ -824,6 +864,7 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) if (ch == '/' || ch == '\\') { state = sw_after_slash; + slash = p; } break; @@ -842,6 +883,7 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) if (ch == '/' || ch == '\\') { state = sw_after_slash; + slash = p; break; } @@ -869,6 +911,7 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) if (ch == '/' || ch == '\\') { state = sw_after_slash; + slash = p; break; } @@ -897,6 +940,12 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) goto invalid; } + if (dirname && slash) { + ch = *slash; + *slash = '\0'; + len = slash - u + 1; + } + /* check if long name match */ lu = malloc(len * 2); @@ -907,6 +956,11 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) n = GetLongPathNameW(u, lu, len); if (n == 0) { + + if (dirname && slash && ngx_errno == NGX_ENOENT) { + ngx_set_errno(NGX_ENOPATH); + } + goto failed; } @@ -914,6 +968,10 @@ ngx_win32_check_filename(u_char *name, u_short *u, size_t len) goto invalid; } + if (dirname && slash) { + *slash = ch; + } + ngx_free(lu); return NGX_OK; @@ -924,6 +982,10 @@ invalid: failed: + if (dirname && slash) { + *slash = ch; + } + if (lu) { err = ngx_errno; ngx_free(lu); diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index bc648e4c9..10a388942 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -202,7 +202,7 @@ ngx_int_t ngx_close_dir(ngx_dir_t *dir); #define ngx_close_dir_n "FindClose()" -#define ngx_create_dir(name, access) CreateDirectory((const char *) name, NULL) +ngx_int_t ngx_create_dir(u_char *name, ngx_uint_t access); #define ngx_create_dir_n "CreateDirectory()" From f8075f1ef5106c9f0d894f83cfa81dbb9f5ce2da Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:47 +0300 Subject: [PATCH 16/38] Win32: non-ASCII directory names support in ngx_delete_dir(). This makes it possible to delete directories with non-ASCII characters when using the dav module (ticket #1433). --- src/os/win32/ngx_files.c | 36 ++++++++++++++++++++++++++++++++++++ src/os/win32/ngx_files.h | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 641b65c87..2e0e5faa9 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -613,6 +613,42 @@ failed: } +ngx_int_t +ngx_delete_dir(u_char *name) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + rc = RemoveDirectoryW(u); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + ngx_int_t ngx_open_glob(ngx_glob_t *gl) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index 10a388942..0ea5f7969 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -206,7 +206,7 @@ ngx_int_t ngx_create_dir(u_char *name, ngx_uint_t access); #define ngx_create_dir_n "CreateDirectory()" -#define ngx_delete_dir(name) RemoveDirectory((const char *) name) +ngx_int_t ngx_delete_dir(u_char *name); #define ngx_delete_dir_n "RemoveDirectory()" From 94d8cea620e0abc67f4d0fe9aaf6170f39529c8c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:50 +0300 Subject: [PATCH 17/38] Win32: reworked ngx_win32_rename_file() to check errors. Previously, ngx_win32_rename_file() retried on all errors returned by MoveFile() to a temporary name. It only make sense, however, to retry when the destination file already exists, similarly to the condition when ngx_win32_rename_file() is called. Retrying on other errors is meaningless and might result in an infinite loop. --- src/os/win32/ngx_files.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 2e0e5faa9..48075b4c9 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -236,10 +236,16 @@ ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) break; } - collision = 1; + err = ngx_errno; - ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) { + collision = 1; + continue; + } + + ngx_log_error(NGX_LOG_CRIT, log, err, "MoveFile() \"%s\" to \"%s\" failed", to->data, name); + goto failed; } if (MoveFile((const char *) from->data, (const char *) to->data) == 0) { @@ -254,6 +260,8 @@ ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) "DeleteFile() \"%s\" failed", name); } +failed: + /* mutex_unlock() */ ngx_free(name); From dc4957485e151ed11026ab827c8e5348b3d3ae01 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:52 +0300 Subject: [PATCH 18/38] Win32: reworked ngx_win32_rename_file() to use nginx wrappers. This ensures that ngx_win32_rename_file() will support non-ASCII names when supported by the wrappers. Notably, this is used by PUT requests in the dav module when overwriting existing files with non-ASCII names (ticket #1433). --- src/os/win32/ngx_files.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 48075b4c9..5bd08e1a9 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -232,7 +232,7 @@ ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num); - if (MoveFile((const char *) to->data, (const char *) name) != 0) { + if (ngx_rename_file(to->data, name) != NGX_FILE_ERROR) { break; } @@ -248,14 +248,14 @@ ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) goto failed; } - if (MoveFile((const char *) from->data, (const char *) to->data) == 0) { + if (ngx_rename_file(from->data, to->data) == NGX_FILE_ERROR) { err = ngx_errno; } else { err = 0; } - if (DeleteFile((const char *) name) == 0) { + if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, "DeleteFile() \"%s\" failed", name); } From 1a9e5c83769128eefb5ee81147b0a350efc7cd68 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:54 +0300 Subject: [PATCH 19/38] Win32: non-ASCII names support in ngx_delete_file(). This makes it possible to delete files with non-ASCII characters when using the dav module (ticket #1433). --- src/os/win32/ngx_files.c | 36 ++++++++++++++++++++++++++++++++++++ src/os/win32/ngx_files.h | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 5bd08e1a9..5eb976d3d 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -207,6 +207,42 @@ ngx_write_console(ngx_fd_t fd, void *buf, size_t size) } +ngx_int_t +ngx_delete_file(u_char *name) +{ + long rc; + size_t len; + u_short *u; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(u, len, 0) != NGX_OK) { + goto failed; + } + + rc = DeleteFileW(u); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index 0ea5f7969..77d586332 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -123,7 +123,7 @@ ssize_t ngx_write_console(ngx_fd_t fd, void *buf, size_t size); #define NGX_LINEFEED CRLF -#define ngx_delete_file(name) DeleteFile((const char *) name) +ngx_int_t ngx_delete_file(u_char *name); #define ngx_delete_file_n "DeleteFile()" From 4d84bc492936cd047d5f589ef4bc4736093ec176 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:55 +0300 Subject: [PATCH 20/38] Win32: non-ASCII names support in ngx_rename_file(). This makes it possible to upload files with non-ASCII characters when using the dav module (ticket #1433). --- src/os/win32/ngx_files.c | 55 ++++++++++++++++++++++++++++++++++++++++ src/os/win32/ngx_files.h | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 5eb976d3d..3a30f51dd 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -243,6 +243,61 @@ failed: } +ngx_int_t +ngx_rename_file(u_char *from, u_char *to) +{ + long rc; + size_t len; + u_short *fu, *tu; + ngx_err_t err; + u_short utf16f[NGX_UTF16_BUFLEN]; + u_short utf16t[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + fu = ngx_utf8_to_utf16(utf16f, from, &len, 0); + + if (fu == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + tu = NULL; + + if (ngx_win32_check_filename(fu, len, 0) != NGX_OK) { + goto failed; + } + + len = NGX_UTF16_BUFLEN; + tu = ngx_utf8_to_utf16(utf16t, to, &len, 0); + + if (tu == NULL) { + goto failed; + } + + if (ngx_win32_check_filename(tu, len, 1) != NGX_OK) { + goto failed; + } + + rc = MoveFileW(fu, tu); + +failed: + + if (fu != utf16f) { + err = ngx_errno; + ngx_free(fu); + ngx_set_errno(err); + } + + if (tu && tu != utf16t) { + err = ngx_errno; + ngx_free(tu); + ngx_set_errno(err); + } + + return rc; +} + + ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index 77d586332..143120647 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -127,7 +127,7 @@ ngx_int_t ngx_delete_file(u_char *name); #define ngx_delete_file_n "DeleteFile()" -#define ngx_rename_file(o, n) MoveFile((const char *) o, (const char *) n) +ngx_int_t ngx_rename_file(u_char *from, u_char *to); #define ngx_rename_file_n "MoveFile()" ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log); From 2062ddef3989525e22445b1965220ffaf8e161c9 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:49:57 +0300 Subject: [PATCH 21/38] Win32: non-ASCII names support in ngx_open_tempfile(). This makes it possible to use temporary directories with non-ASCII characters, either explicitly or via a prefix with non-ASCII characters in it. --- src/os/win32/ngx_files.c | 35 +++++++++++++++++++++++++++++++++++ src/os/win32/ngx_files.h | 12 ++---------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 3a30f51dd..6f57a1775 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -63,6 +63,41 @@ failed: } +ngx_fd_t +ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access) +{ + size_t len; + u_short *u; + ngx_fd_t fd; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { + return INVALID_HANDLE_VALUE; + } + + fd = CreateFileW(u, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, + CREATE_NEW, + persistent ? 0: + FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return fd; +} + + ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h index 143120647..6e59a6fc9 100644 --- a/src/os/win32/ngx_files.h +++ b/src/os/win32/ngx_files.h @@ -90,16 +90,8 @@ ngx_fd_t ngx_open_file(u_char *name, u_long mode, u_long create, u_long access); #define NGX_FILE_OWNER_ACCESS 0 -#define ngx_open_tempfile(name, persistent, access) \ - CreateFile((const char *) name, \ - GENERIC_READ|GENERIC_WRITE, \ - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, \ - NULL, \ - CREATE_NEW, \ - persistent ? 0: \ - FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, \ - NULL); - +ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent, + ngx_uint_t access); #define ngx_open_tempfile_n "CreateFile()" From 6c5fe80bc69b12cc2bd0e8ed7bc67b240795f66b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:50:00 +0300 Subject: [PATCH 22/38] Win32: removed attempt to use a drive letter in ngx_fs_bsize(). Just a drive letter might not correctly represent file system being used, notably when using symlinks (as created by "mklink /d"). As such, instead of trying to call GetDiskFreeSpace() with just a drive letter, we now always use GetDiskFreeSpace() with full path. Further, it looks like the code to use just a drive letter never worked, since it tried to test name[2] instead of name[1] to be ':'. --- src/os/win32/ngx_files.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 6f57a1775..3e0037859 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -967,14 +967,8 @@ ngx_directio_off(ngx_fd_t fd) size_t ngx_fs_bsize(u_char *name) { - u_char root[4]; u_long sc, bs, nfree, ncl; - if (name[2] == ':') { - ngx_cpystrn(root, name, 4); - name = root; - } - if (GetDiskFreeSpace((const char *) name, &sc, &bs, &nfree, &ncl) == 0) { return 512; } From 4ace957c4e08bcbf9ef5e9f83b8e43458bead77f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 23 Feb 2023 20:50:03 +0300 Subject: [PATCH 23/38] Win32: non-ASCII names in ngx_fs_bsize(), ngx_fs_available(). This fixes potentially incorrect cache size calculations and non-working "min_free" when using cache in directories with non-ASCII names. --- src/os/win32/ngx_files.c | 46 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c index 3e0037859..90644ad9c 100644 --- a/src/os/win32/ngx_files.c +++ b/src/os/win32/ngx_files.c @@ -967,12 +967,31 @@ ngx_directio_off(ngx_fd_t fd) size_t ngx_fs_bsize(u_char *name) { - u_long sc, bs, nfree, ncl; + u_long sc, bs, nfree, ncl; + size_t len; + u_short *u; + u_short utf16[NGX_UTF16_BUFLEN]; - if (GetDiskFreeSpace((const char *) name, &sc, &bs, &nfree, &ncl) == 0) { + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { return 512; } + if (GetDiskFreeSpaceW(u, &sc, &bs, &nfree, &ncl) == 0) { + + if (u != utf16) { + ngx_free(u); + } + + return 512; + } + + if (u != utf16) { + ngx_free(u); + } + return sc * bs; } @@ -980,12 +999,31 @@ ngx_fs_bsize(u_char *name) off_t ngx_fs_available(u_char *name) { - ULARGE_INTEGER navail; + size_t len; + u_short *u; + ULARGE_INTEGER navail; + u_short utf16[NGX_UTF16_BUFLEN]; - if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) { + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len, 0); + + if (u == NULL) { return NGX_MAX_OFF_T_VALUE; } + if (GetDiskFreeSpaceExW(u, &navail, NULL, NULL) == 0) { + + if (u != utf16) { + ngx_free(u); + } + + return NGX_MAX_OFF_T_VALUE; + } + + if (u != utf16) { + ngx_free(u); + } + return (off_t) navail.QuadPart; } From 2c5fccd4693c0a68e1c72d65e016ba83e861120e Mon Sep 17 00:00:00 2001 From: Yugo Horie Date: Thu, 23 Feb 2023 08:09:50 +0900 Subject: [PATCH 24/38] Core: stricter UTF-8 handling in ngx_utf8_decode(). An UTF-8 octet sequence cannot start with a 11111xxx byte (above 0xf8), see https://datatracker.ietf.org/doc/html/rfc3629#section-3. Previously, such bytes were accepted by ngx_utf8_decode() and misinterpreted as 11110xxx bytes (as in a 4-byte sequence). While unlikely, this can potentially cause issues. Fix is to explicitly reject such bytes in ngx_utf8_decode(). --- src/core/ngx_string.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 98f270aca..f8f738472 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1364,7 +1364,12 @@ ngx_utf8_decode(u_char **p, size_t n) u = **p; - if (u >= 0xf0) { + if (u >= 0xf8) { + + (*p)++; + return 0xffffffff; + + } else if (u >= 0xf0) { u &= 0x07; valid = 0xffff; From a976e6b9effab65ccf989a1563c602c991964af2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 8 Mar 2023 22:21:53 +0300 Subject: [PATCH 25/38] SSL: switched to detect log level based on the last error. In some cases there might be multiple errors in the OpenSSL error queue, notably when a libcrypto call fails, and then the SSL layer generates an error itself. For example, the following errors were observed with OpenSSL 3.0.8 with TLSv1.3 enabled: SSL_do_handshake() failed (SSL: error:02800066:Diffie-Hellman routines::invalid public key error:0A000132:SSL routines::bad ecpoint) SSL_do_handshake() failed (SSL: error:08000066:elliptic curve routines::invalid encoding error:0A000132:SSL routines::bad ecpoint) SSL_do_handshake() failed (SSL: error:0800006B:elliptic curve routines::point is not on curve error:0A000132:SSL routines::bad ecpoint) In such cases it seems to be better to determine logging level based on the last error in the error queue (the one added by the SSL layer, SSL_R_BAD_ECPOINT in all of the above example example errors). To do so, the ngx_ssl_connection_error() function was changed to use ERR_peek_last_error(). --- src/event/ngx_event_openssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 5f9ff5f0f..3e6e8e5dd 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3389,7 +3389,7 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, } else if (sslerr == SSL_ERROR_SSL) { - n = ERR_GET_REASON(ERR_peek_error()); + n = ERR_GET_REASON(ERR_peek_last_error()); /* handshake failures */ if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC /* 103 */ From a3a94f7534f4cc0c29e059f639a949c30353ef71 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 8 Mar 2023 22:21:59 +0300 Subject: [PATCH 26/38] SSL: logging levels of various errors reported with tlsfuzzer. To further differentiate client-related errors and adjust logging levels of various SSL errors, nginx was tested with tlsfuzzer with multiple OpenSSL versions (3.1.0-beta1, 3.0.8, 1.1.1t, 1.1.0l, 1.0.2u, 1.0.1u, 1.0.0s, 0.9.8zh). The following errors were observed during tlsfuzzer runs with OpenSSL 3.0.8, and are clearly client-related: SSL_do_handshake() failed (SSL: error:0A000092:SSL routines::data length too long) SSL_do_handshake() failed (SSL: error:0A0000A0:SSL routines::length too short) SSL_do_handshake() failed (SSL: error:0A000124:SSL routines::bad legacy version) SSL_do_handshake() failed (SSL: error:0A000178:SSL routines::no shared signature algorithms) Accordingly, the SSL_R_DATA_LENGTH_TOO_LONG ("data length too long"), SSL_R_LENGTH_TOO_SHORT ("length too short"), SSL_R_BAD_LEGACY_VERSION ("bad legacy version"), and SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS ("no shared signature algorithms", misspelled as "sigature" in OpenSSL 1.0.2) errors are now logged at the "info" level. Additionally, the following errors were observed with OpenSSL 3.0.8 and with TLSv1.3 enabled: SSL_do_handshake() failed (SSL: error:0A00006F:SSL routines::bad digest length) SSL_do_handshake() failed (SSL: error:0A000070:SSL routines::missing sigalgs extension) SSL_do_handshake() failed (SSL: error:0A000096:SSL routines::encrypted length too long) SSL_do_handshake() failed (SSL: error:0A00010F:SSL routines::bad length) SSL_read() failed (SSL: error:0A00007A:SSL routines::bad key update) SSL_read() failed (SSL: error:0A000125:SSL routines::mixed handshake and non handshake data) Accordingly, the SSL_R_BAD_DIGEST_LENGTH ("bad digest length"), SSL_R_MISSING_SIGALGS_EXTENSION ("missing sigalgs extension"), SSL_R_ENCRYPTED_LENGTH_TOO_LONG ("encrypted length too long"), SSL_R_BAD_LENGTH ("bad length"), SSL_R_BAD_KEY_UPDATE ("bad key update"), and SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA ("mixed handshake and non handshake data") errors are now logged at the "info" level. Additionally, the following errors were observed with OpenSSL 1.1.1t: SSL_do_handshake() failed (SSL: error:14094091:SSL routines:ssl3_read_bytes:data between ccs and finished) SSL_do_handshake() failed (SSL: error:14094199:SSL routines:ssl3_read_bytes:too many warn alerts) SSL_read() failed (SSL: error:1408F0C6:SSL routines:ssl3_get_record:packet length too long) SSL_read() failed (SSL: error:14094085:SSL routines:ssl3_read_bytes:ccs received early) Accordingly, the SSL_R_CCS_RECEIVED_EARLY ("ccs received early"), SSL_R_DATA_BETWEEN_CCS_AND_FINISHED ("data between ccs and finished"), SSL_R_PACKET_LENGTH_TOO_LONG ("packet length too long"), and SSL_R_TOO_MANY_WARN_ALERTS ("too many warn alerts") errors are now logged at the "info" level. Additionally, the following errors were observed with OpenSSL 1.0.2u: SSL_do_handshake() failed (SSL: error:1407612A:SSL routines:SSL23_GET_CLIENT_HELLO:record too small) SSL_do_handshake() failed (SSL: error:1408C09A:SSL routines:ssl3_get_finished:got a fin before a ccs) Accordingly, the SSL_R_RECORD_TOO_SMALL ("record too small") and SSL_R_GOT_A_FIN_BEFORE_A_CCS ("got a fin before a ccs") errors are now logged at the "info" level. No additional client-related errors were observed while testing with OpenSSL 3.1.0-beta1, OpenSSL 1.1.0l, OpenSSL 1.0.1u, OpenSSL 1.0.0s, and OpenSSL 0.9.8zh. --- src/event/ngx_event_openssl.c | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 3e6e8e5dd..84cdef5a8 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3401,17 +3401,36 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif #ifdef SSL_R_BAD_EXTENSION || n == SSL_R_BAD_EXTENSION /* 110 */ +#endif + || n == SSL_R_BAD_DIGEST_LENGTH /* 111 */ +#ifdef SSL_R_MISSING_SIGALGS_EXTENSION + || n == SSL_R_MISSING_SIGALGS_EXTENSION /* 112 */ #endif #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM || n == SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM /* 118 */ +#endif +#ifdef SSL_R_BAD_KEY_UPDATE + || n == SSL_R_BAD_KEY_UPDATE /* 122 */ #endif || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */ + || n == SSL_R_CCS_RECEIVED_EARLY /* 133 */ +#ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED + || n == SSL_R_DATA_BETWEEN_CCS_AND_FINISHED /* 145 */ +#endif + || n == SSL_R_DATA_LENGTH_TOO_LONG /* 146 */ || n == SSL_R_DIGEST_CHECK_FAILED /* 149 */ + || n == SSL_R_ENCRYPTED_LENGTH_TOO_LONG /* 150 */ || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ +#ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS + || n == SSL_R_GOT_A_FIN_BEFORE_A_CCS /* 154 */ +#endif || n == SSL_R_HTTPS_PROXY_REQUEST /* 155 */ || n == SSL_R_HTTP_REQUEST /* 156 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ +#ifdef SSL_R_LENGTH_TOO_SHORT + || n == SSL_R_LENGTH_TOO_SHORT /* 160 */ +#endif #ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ #endif @@ -3421,6 +3440,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ +#ifdef SSL_R_PACKET_LENGTH_TOO_LONG + || n == SSL_R_PACKET_LENGTH_TOO_LONG /* 198 */ +#endif || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */ #ifdef SSL_R_CLIENTHELLO_TLSEXT || n == SSL_R_CLIENTHELLO_TLSEXT /* 226 */ @@ -3446,6 +3468,7 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_NO_SHARED_GROUP /* 266 */ #endif || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ + || n == SSL_R_BAD_LENGTH /* 271 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY || n == SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY /* 291 */ @@ -3453,6 +3476,15 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_APPLICATION_DATA_ON_SHUTDOWN || n == SSL_R_APPLICATION_DATA_ON_SHUTDOWN /* 291 */ #endif +#ifdef SSL_R_BAD_LEGACY_VERSION + || n == SSL_R_BAD_LEGACY_VERSION /* 292 */ +#endif +#ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA + || n == SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA /* 293 */ +#endif +#ifdef SSL_R_RECORD_TOO_SMALL + || n == SSL_R_RECORD_TOO_SMALL /* 298 */ +#endif #ifdef SSL_R_BAD_ECPOINT || n == SSL_R_BAD_ECPOINT /* 306 */ #endif @@ -3470,12 +3502,21 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_INAPPROPRIATE_FALLBACK || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif +#ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS + || n == SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS /* 376 */ +#endif +#ifdef SSL_R_NO_SHARED_SIGATURE_ALGORITHMS + || n == SSL_R_NO_SHARED_SIGATURE_ALGORITHMS /* 376 */ +#endif #ifdef SSL_R_CERT_CB_ERROR || n == SSL_R_CERT_CB_ERROR /* 377 */ #endif #ifdef SSL_R_VERSION_TOO_LOW || n == SSL_R_VERSION_TOO_LOW /* 396 */ #endif +#ifdef SSL_R_TOO_MANY_WARN_ALERTS + || n == SSL_R_TOO_MANY_WARN_ALERTS /* 409 */ +#endif #ifdef SSL_R_BAD_RECORD_TYPE || n == SSL_R_BAD_RECORD_TYPE /* 443 */ #endif From 13987c88c354cfafa5334f8ed9b478517b71ce9d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 8 Mar 2023 22:22:34 +0300 Subject: [PATCH 27/38] SSL: logging levels of errors observed with tlsfuzzer and LibreSSL. As tested with tlsfuzzer with LibreSSL 3.7.0, the following errors are certainly client-related: SSL_do_handshake() failed (SSL: error:14026073:SSL routines:ACCEPT_SR_CLNT_HELLO:bad packet length) SSL_do_handshake() failed (SSL: error:1402612C:SSL routines:ACCEPT_SR_CLNT_HELLO:ssl3 session id too long) SSL_do_handshake() failed (SSL: error:140380EA:SSL routines:ACCEPT_SR_KEY_EXCH:tls rsa encrypted value length is wrong) Accordingly, the SSL_R_BAD_PACKET_LENGTH ("bad packet length"), SSL_R_SSL3_SESSION_ID_TOO_LONG ("ssl3 session id too long"), SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG ("tls rsa encrypted value length is wrong") errors are now logged at the "info" level. --- src/event/ngx_event_openssl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 84cdef5a8..b400ca6ee 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3406,6 +3406,7 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_MISSING_SIGALGS_EXTENSION || n == SSL_R_MISSING_SIGALGS_EXTENSION /* 112 */ #endif + || n == SSL_R_BAD_PACKET_LENGTH /* 115 */ #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM || n == SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM /* 118 */ #endif @@ -3453,6 +3454,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_CALLBACK_FAILED || n == SSL_R_CALLBACK_FAILED /* 234 */ #endif +#ifdef SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG + || n == SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG /* 234 */ +#endif #ifdef SSL_R_NO_APPLICATION_PROTOCOL || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif @@ -3485,6 +3489,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_RECORD_TOO_SMALL || n == SSL_R_RECORD_TOO_SMALL /* 298 */ #endif +#ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG + || n == SSL_R_SSL3_SESSION_ID_TOO_LONG /* 300 */ +#endif #ifdef SSL_R_BAD_ECPOINT || n == SSL_R_BAD_ECPOINT /* 306 */ #endif From 5c480f917300f8b7252e76928c12585d8d89afed Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 8 Mar 2023 22:22:47 +0300 Subject: [PATCH 28/38] SSL: logging levels of errors observed with BoringSSL. As tested with tlsfuzzer with BoringSSL, the following errors are certainly client-related: SSL_do_handshake() failed (SSL: error:10000066:SSL routines:OPENSSL_internal:BAD_ALERT) SSL_do_handshake() failed (SSL: error:10000089:SSL routines:OPENSSL_internal:DECODE_ERROR) SSL_do_handshake() failed (SSL: error:100000dc:SSL routines:OPENSSL_internal:TOO_MANY_WARNING_ALERTS) SSL_do_handshake() failed (SSL: error:10000100:SSL routines:OPENSSL_internal:INVALID_COMPRESSION_LIST) SSL_do_handshake() failed (SSL: error:10000102:SSL routines:OPENSSL_internal:MISSING_KEY_SHARE) SSL_do_handshake() failed (SSL: error:1000010e:SSL routines:OPENSSL_internal:TOO_MUCH_SKIPPED_EARLY_DATA) SSL_read() failed (SSL: error:100000b6:SSL routines:OPENSSL_internal:NO_RENEGOTIATION) Accordingly, the SSL_R_BAD_ALERT, SSL_R_DECODE_ERROR, SSL_R_TOO_MANY_WARNING_ALERTS, SSL_R_INVALID_COMPRESSION_LIST, SSL_R_MISSING_KEY_SHARE, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA, and SSL_R_NO_RENEGOTIATION errors are now logged at the "info" level. --- src/event/ngx_event_openssl.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index b400ca6ee..104e8daf7 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3396,6 +3396,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_NO_SUITABLE_KEY_SHARE || n == SSL_R_NO_SUITABLE_KEY_SHARE /* 101 */ #endif +#ifdef SSL_R_BAD_ALERT + || n == SSL_R_BAD_ALERT /* 102 */ +#endif #ifdef SSL_R_BAD_KEY_SHARE || n == SSL_R_BAD_KEY_SHARE /* 108 */ #endif @@ -3415,6 +3418,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */ || n == SSL_R_CCS_RECEIVED_EARLY /* 133 */ +#ifdef SSL_R_DECODE_ERROR + || n == SSL_R_DECODE_ERROR /* 137 */ +#endif #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED || n == SSL_R_DATA_BETWEEN_CCS_AND_FINISHED /* 145 */ #endif @@ -3432,6 +3438,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #ifdef SSL_R_LENGTH_TOO_SHORT || n == SSL_R_LENGTH_TOO_SHORT /* 160 */ #endif +#ifdef SSL_R_NO_RENEGOTIATION + || n == SSL_R_NO_RENEGOTIATION /* 182 */ +#endif #ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ #endif @@ -3445,6 +3454,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_PACKET_LENGTH_TOO_LONG /* 198 */ #endif || n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */ +#ifdef SSL_R_TOO_MANY_WARNING_ALERTS + || n == SSL_R_TOO_MANY_WARNING_ALERTS /* 220 */ +#endif #ifdef SSL_R_CLIENTHELLO_TLSEXT || n == SSL_R_CLIENTHELLO_TLSEXT /* 226 */ #endif @@ -3466,12 +3478,21 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, || n == SSL_R_UNKNOWN_PROTOCOL /* 252 */ #ifdef SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS || n == SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS /* 253 */ +#endif +#ifdef SSL_R_INVALID_COMPRESSION_LIST + || n == SSL_R_INVALID_COMPRESSION_LIST /* 256 */ +#endif +#ifdef SSL_R_MISSING_KEY_SHARE + || n == SSL_R_MISSING_KEY_SHARE /* 258 */ #endif || n == SSL_R_UNSUPPORTED_PROTOCOL /* 258 */ #ifdef SSL_R_NO_SHARED_GROUP || n == SSL_R_NO_SHARED_GROUP /* 266 */ #endif || n == SSL_R_WRONG_VERSION_NUMBER /* 267 */ +#ifdef SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA + || n == SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA /* 270 */ +#endif || n == SSL_R_BAD_LENGTH /* 271 */ || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */ #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY From 3c949f7c409e41a7c6fd6edb096281a3e82f85e4 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 10 Mar 2023 06:47:48 +0300 Subject: [PATCH 29/38] HTTP/2: socket leak with "return 444" in error_page (ticket #2455). Similarly to ticket #274 (7354:1812f1d79d84), early request finalization without calling ngx_http_run_posted_requests() resulted in a connection hang (a socket leak) if the 400 (Bad Request) error was generated in ngx_http_v2_state_process_header() due to invalid request headers and "return 444" was used in error_page 400. --- src/http/v2/ngx_http_v2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 0e45a7b27..d32c03f10 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1730,6 +1730,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, size_t len; ngx_int_t rc; ngx_table_elt_t *h; + ngx_connection_t *fc; ngx_http_header_t *hh; ngx_http_request_t *r; ngx_http_v2_header_t *header; @@ -1789,6 +1790,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, } r = h2c->state.stream->request; + fc = r->connection; /* TODO Optimization: validate headers while parsing. */ if (ngx_http_v2_validate_header(r, header) != NGX_OK) { @@ -1886,6 +1888,8 @@ error: h2c->state.stream = NULL; + ngx_http_run_posted_requests(fc); + return ngx_http_v2_state_header_complete(h2c, pos, end); } From ff9e426337b84ed1d9ff3bbd17e7d7632c7ba19d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 10 Mar 2023 06:47:53 +0300 Subject: [PATCH 30/38] HTTP/2: finalize request as bad if header validation fails. Similarly to 7192:d5a535774861, this avoids spurious zero statuses in access.log, and in line with other header-related errors. --- src/http/v2/ngx_http_v2.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index d32c03f10..ea3f27c07 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1794,14 +1794,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, /* TODO Optimization: validate headers while parsing. */ if (ngx_http_v2_validate_header(r, header) != NGX_OK) { - if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, - NGX_HTTP_V2_PROTOCOL_ERROR) - == NGX_ERROR) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } - + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); goto error; } From 853912986d9568b049ecb5499b6af987cb13cb14 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 10 Mar 2023 07:43:40 +0300 Subject: [PATCH 31/38] Syslog: removed usage of ngx_cycle->log and ngx_cycle->hostname. During initial startup the ngx_cycle->hostname is not available, and previously this resulted in incorrect logging. Instead, hostname from the configuration being parsed is now preserved in the syslog peer structure and then used during logging. Similarly, ngx_cycle->log might not match the configuration where the syslog peer is defined if the configuration is not yet fully applied, and previously this resulted in unexpected logging of syslog errors and debug information. Instead, cf->cycle->new_log is now referenced in the syslog peer structure and used for logging, similarly to how it is done in other modules. --- src/core/ngx_syslog.c | 21 +++++++++++---------- src/core/ngx_syslog.h | 19 ++++++++++++------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index 3c7b63a62..0a64e10b8 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -66,6 +66,9 @@ ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) ngx_str_set(&peer->tag, "nginx"); } + peer->hostname = &cf->cycle->hostname; + peer->log = &cf->cycle->new_log; + peer->conn.fd = (ngx_socket_t) -1; peer->conn.read = &ngx_syslog_dummy_event; @@ -243,7 +246,7 @@ ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) } return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, - &ngx_cycle->hostname, &peer->tag); + peer->hostname, &peer->tag); } @@ -292,9 +295,6 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) } } - /* log syslog socket events with valid log */ - peer->conn.log = ngx_cycle->log; - if (ngx_send) { n = ngx_send(&peer->conn, buf, len); @@ -306,7 +306,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) if (n == NGX_ERROR) { if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -324,24 +324,25 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); if (fd == (ngx_socket_t) -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } if (ngx_nonblocking(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, "connect() failed"); goto failed; } peer->conn.fd = fd; + peer->conn.log = peer->log; /* UDP sockets are always ready to write */ peer->conn.write->ready = 1; @@ -351,7 +352,7 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) failed: if (ngx_close_socket(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -372,7 +373,7 @@ ngx_syslog_cleanup(void *data) } if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } } diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h index 50dcd3511..181ebe7b3 100644 --- a/src/core/ngx_syslog.h +++ b/src/core/ngx_syslog.h @@ -9,14 +9,19 @@ typedef struct { - ngx_uint_t facility; - ngx_uint_t severity; - ngx_str_t tag; + ngx_uint_t facility; + ngx_uint_t severity; + ngx_str_t tag; - ngx_addr_t server; - ngx_connection_t conn; - unsigned busy:1; - unsigned nohostname:1; + ngx_str_t *hostname; + + ngx_addr_t server; + ngx_connection_t conn; + + ngx_log_t *log; + + unsigned busy:1; + unsigned nohostname:1; } ngx_syslog_peer_t; From 11ed95bb53210c322c16bb0897f0cb3b5726ed57 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 10 Mar 2023 07:43:50 +0300 Subject: [PATCH 32/38] Syslog: introduced error log handler. This ensures that errors which happen during logging to syslog are logged with proper context, such as "while logging to syslog" and the server name. Prodded by Safar Safarly. --- src/core/ngx_syslog.c | 47 +++++++++++++++++++++++++++++++++++-------- src/core/ngx_syslog.h | 3 ++- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c index 0a64e10b8..bad45bd16 100644 --- a/src/core/ngx_syslog.c +++ b/src/core/ngx_syslog.c @@ -18,6 +18,7 @@ static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer); static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer); static void ngx_syslog_cleanup(void *data); +static u_char *ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len); static char *facilities[] = { @@ -67,7 +68,7 @@ ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) } peer->hostname = &cf->cycle->hostname; - peer->log = &cf->cycle->new_log; + peer->logp = &cf->cycle->new_log; peer->conn.fd = (ngx_socket_t) -1; @@ -289,6 +290,13 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) { ssize_t n; + if (peer->log.handler == NULL) { + peer->log = *peer->logp; + peer->log.handler = ngx_syslog_log_error; + peer->log.data = peer; + peer->log.action = "logging to syslog"; + } + if (peer->conn.fd == (ngx_socket_t) -1) { if (ngx_syslog_init_peer(peer) != NGX_OK) { return NGX_ERROR; @@ -306,7 +314,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) if (n == NGX_ERROR) { if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -324,25 +332,25 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); if (fd == (ngx_socket_t) -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } if (ngx_nonblocking(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_nonblocking_n " failed"); goto failed; } if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, "connect() failed"); goto failed; } peer->conn.fd = fd; - peer->conn.log = peer->log; + peer->conn.log = &peer->log; /* UDP sockets are always ready to write */ peer->conn.write->ready = 1; @@ -352,7 +360,7 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *peer) failed: if (ngx_close_socket(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -373,7 +381,30 @@ ngx_syslog_cleanup(void *data) } if (ngx_close_socket(peer->conn.fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, peer->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno, ngx_close_socket_n " failed"); } } + + +static u_char * +ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_syslog_peer_t *peer; + + p = buf; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + } + + peer = log->data; + + if (peer) { + p = ngx_snprintf(p, len, ", server: %V", &peer->server.name); + } + + return p; +} diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h index 181ebe7b3..e2d54acdb 100644 --- a/src/core/ngx_syslog.h +++ b/src/core/ngx_syslog.h @@ -18,7 +18,8 @@ typedef struct { ngx_addr_t server; ngx_connection_t conn; - ngx_log_t *log; + ngx_log_t log; + ngx_log_t *logp; unsigned busy:1; unsigned nohostname:1; From 2ca4355bf02ab454d6f216dab142816a626d7547 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 24 Mar 2023 02:53:21 +0300 Subject: [PATCH 33/38] Mail: fixed handling of blocked client read events in proxy. When establishing a connection to the backend, nginx blocks reading from the client with ngx_mail_proxy_block_read(). Previously, such events were lost, and in some cases this resulted in connection hangs. Notably, this affected mail_imap_ssl.t on Windows, since the test closes connections after requesting authentication, but without waiting for any responses (so the connection close events might be lost). Fix is to post an event to read from the client after connecting to the backend if there were blocked events. --- src/mail/ngx_mail_proxy_module.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 06679d4e0..efed9ab3e 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,7 +327,9 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } @@ -486,7 +488,9 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } @@ -821,7 +825,9 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos < s->buffer->last) { + if (s->buffer->pos < s->buffer->last + || s->connection->read->ready) + { ngx_post_event(c->write, &ngx_posted_events); } From 7b24b93d67daa9c16d665129fd5d3e7dbc583e4f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 24 Mar 2023 02:57:43 +0300 Subject: [PATCH 34/38] SSL: enabled TLSv1.3 by default. --- src/http/modules/ngx_http_grpc_module.c | 5 +++-- src/http/modules/ngx_http_proxy_module.c | 5 +++-- src/http/modules/ngx_http_ssl_module.c | 5 +++-- src/http/modules/ngx_http_uwsgi_module.c | 5 +++-- src/mail/ngx_mail_ssl_module.c | 5 +++-- src/stream/ngx_stream_proxy_module.c | 5 +++-- src/stream/ngx_stream_ssl_module.c | 5 +++-- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 58332866c..dfe49c586 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -4473,8 +4473,9 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 54e2a3964..9cc202c9d 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -3734,8 +3734,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 6fe5463df..4c4a598b1 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -632,8 +632,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, NGX_SSL_BUFSIZE); diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 4fc663d0b..e4f721bb0 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1875,8 +1875,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index b80a0ca80..28737ac4e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -360,8 +360,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index eb2097621..ed275c009 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -2163,8 +2163,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 105aa1178..1ba1825ce 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -703,8 +703,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + (NGX_CONF_BITMASK_SET + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3)); ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); From 87471918b20957694cb7a7503d2f868c8813c68b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 27 Mar 2023 21:25:05 +0300 Subject: [PATCH 35/38] Gzip: compatibility with recent zlib-ng versions. It now uses custom alloc_aligned() wrapper for all allocations, therefore all allocations are larger than expected by (64 + sizeof(void*)). Further, they are seen as allocations of 1 element. Relevant calculations were adjusted to reflect this, and state allocation is now protected with a flag to avoid misinterpreting other allocations as the zlib deflate_state allocation. Further, it no longer forces window bits to 13 on compression level 1, so the comment was adjusted to reflect this. --- src/http/modules/ngx_http_gzip_filter_module.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index b7758690f..ed0de609a 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -57,6 +57,7 @@ typedef struct { unsigned nomem:1; unsigned buffering:1; unsigned zlib_ng:1; + unsigned state_allocated:1; size_t zin; size_t zout; @@ -514,9 +515,10 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } else { /* * Another zlib variant, https://github.com/zlib-ng/zlib-ng. - * It forces window bits to 13 for fast compression level, - * uses 16-byte padding in one of window-sized buffers, and - * uses 128K hash. + * It used to force window bits to 13 for fast compression level, + * uses (64 + sizeof(void*)) additional space on all allocations + * for alignment, 16-byte padding in one of window-sized buffers, + * and 128K hash. */ if (conf->level == 1) { @@ -524,7 +526,8 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) - + 131072 + (1 << (memlevel + 8)); + + 131072 + (1 << (memlevel + 8)) + + 4 * (64 + sizeof(void*)); ctx->zlib_ng = 1; } } @@ -926,13 +929,16 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) alloc = items * size; - if (items == 1 && alloc % 512 != 0 && alloc < 8192) { - + if (items == 1 && alloc % 512 != 0 && alloc < 8192 + && !ctx->state_allocated) + { /* * The zlib deflate_state allocation, it takes about 6K, * we allocate 8K. Other allocations are divisible by 512. */ + ctx->state_allocated = 1; + alloc = 8192; } From 3fe687f477b8e1f66158eced4456145acb8d00c4 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Mar 2023 02:25:55 +0300 Subject: [PATCH 36/38] Updated OpenSSL used for win32 builds. --- misc/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/GNUmakefile b/misc/GNUmakefile index 8323e07b9..a5c4a1953 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.1.1s +OPENSSL = openssl-1.1.1t ZLIB = zlib-1.2.13 PCRE = pcre2-10.39 From f5a7f1033d55b81ab7f554e4307ca060136f8e9d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Mar 2023 18:01:53 +0300 Subject: [PATCH 37/38] nginx-1.23.4-RELEASE --- docs/xml/nginx/changes.xml | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index c3963fe7b..f304ee44e 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,163 @@ + + + + +теперь протокол TLSv1.3 разрешён по умолчанию. + + +now TLSv1.3 protocol is enabled by default. + + + + + +теперь nginx выдаёт предупреждение +при переопределении параметров listen-сокета, задающих используемые протоколы. + + +now nginx issues a warning +if protocol parameters of a listening socket are redefined. + + + + + +теперь, если клиент использует pipelining, +nginx закрывает соединения с ожиданием дополнительных данных (lingering close). + + +now nginx closes connections with lingering +if pipelining was used by the client. + + + + + +поддержка byte ranges для ответов модуля ngx_http_gzip_static_module. + + +byte ranges support in the ngx_http_gzip_static_module. + + + + + +диапазоны портов в директиве listen не работали; +ошибка появилась в 1.23.3.
+Спасибо Валентину Бартеневу. +
+ +port ranges in the "listen" directive did not work; +the bug had appeared in 1.23.3.
+Thanks to Valentin Bartenev. +
+
+ + + +для обработки запроса мог быть выбран неверный location, +если в конфигурации использовался +префиксный location длиннее 255 символов. + + +incorrect location might be chosen to process a request +if a prefix location longer than 255 characters +was used in the configuration. + + + + + +не-ASCII символы в именах файлов на Windows +не поддерживались модулями ngx_http_autoindex_module и +ngx_http_dav_module, а также директивой include. + + +non-ASCII characters in file names on Windows were not supported +by the ngx_http_autoindex_module, the ngx_http_dav_module, +and the "include" directive. + + + + + +уровень логгирования ошибок SSL +"data length too long", "length too short", "bad legacy version", +"no shared signature algorithms", "bad digest length", +"missing sigalgs extension", "encrypted length too long", +"bad length", "bad key update", "mixed handshake and non handshake data", +"ccs received early", "data between ccs and finished", +"packet length too long", "too many warn alerts", "record too small", +и "got a fin before a ccs" +понижен с уровня crit до info. + + +the logging level of the +"data length too long", "length too short", "bad legacy version", +"no shared signature algorithms", "bad digest length", +"missing sigalgs extension", "encrypted length too long", +"bad length", "bad key update", "mixed handshake and non handshake data", +"ccs received early", "data between ccs and finished", +"packet length too long", "too many warn alerts", "record too small", +and "got a fin before a ccs" SSL errors +has been lowered from "crit" to "info". + + + + + +при использовании HTTP/2 и директивы error_page +для перенаправления ошибок с кодом 400 +могла происходить утечка сокетов. + + +a socket leak might occur +when using HTTP/2 and the "error_page" directive +to redirect errors with code 400. + + + + + +сообщения об ошибках записи в syslog +не содержали информации о том, что +ошибки происходили в процессе записи в syslog.
+Спасибо Safar Safarly. +
+ +messages about logging to syslog errors +did not contain information +that the errors happened while logging to syslog.
+Thanks to Safar Safarly. +
+
+ + + +при использовании zlib-ng +в логах появлялись сообщения "gzip filter failed to use preallocated memory". + + +"gzip filter failed to use preallocated memory" alerts appeared in logs +when using zlib-ng. + + + + + +в почтовом прокси-сервере. + + +in the mail proxy server. + + + +
+ + From dfe70f74a3558f05142fb552cea239add123d414 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 28 Mar 2023 18:01:54 +0300 Subject: [PATCH 38/38] release-1.23.4 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 79d46d2de..e50ceb9cf 100644 --- a/.hgtags +++ b/.hgtags @@ -471,3 +471,4 @@ d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5 a63d0a70afea96813ba6667997bc7d68b5863f0d release-1.23.1 aa901551a7ebad1e8b0f8c11cb44e3424ba29707 release-1.23.2 ff3afd1ce6a6b65057741df442adfaa71a0e2588 release-1.23.3 +ac779115ed6ee4f3039e9aea414a54e560450ee2 release-1.23.4