From arut at nginx.com Tue Aug 1 07:45:11 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:11 +0400 Subject: [PATCH 0 of 5] QUIC congestion control fixes Message-ID: Hello, Several fixes in QUIC congestion control found while testing under load. The biggest issue here is probe-congestion deadlock which caused connection hang. -- Roman Arutyunyan From arut at nginx.com Tue Aug 1 07:45:12 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:12 +0400 Subject: [PATCH 1 of 5] QUIC: avoid accessing freed frame In-Reply-To: References: Message-ID: <5b91a40f2dd249000e92.1690875912@plentiful-waterbuck> # HG changeset patch # User Roman Arutyunyan # Date 1690874404 -14400 # Tue Aug 01 11:20:04 2023 +0400 # Node ID 5b91a40f2dd249000e9208a0152dc5cc0c6ea0c4 # Parent 4f078be6e2ed08643371a3956f5f18f2357a38db QUIC: avoid accessing freed frame. Previously the field pnum of a potentially freed frame was accessed. Now the value is copied to a local variable. The old behavior did not cause any problems since the frame memory is not freed, but is moved to a free queue instead. diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -548,6 +548,7 @@ ngx_quic_persistent_congestion(ngx_conne void ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) { + uint64_t pnum; ngx_queue_t *q; ngx_quic_frame_t *f, *start; ngx_quic_stream_t *qs; @@ -556,6 +557,7 @@ ngx_quic_resend_frames(ngx_connection_t qc = ngx_quic_get_connection(c); q = ngx_queue_head(&ctx->sent); start = ngx_queue_data(q, ngx_quic_frame_t, queue); + pnum = start->pnum; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic resend packet pnum:%uL", start->pnum); @@ -565,7 +567,7 @@ ngx_quic_resend_frames(ngx_connection_t do { f = ngx_queue_data(q, ngx_quic_frame_t, queue); - if (f->pnum != start->pnum) { + if (f->pnum != pnum) { break; } From arut at nginx.com Tue Aug 1 07:45:13 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:13 +0400 Subject: [PATCH 2 of 5] QUIC: eliminated spurious recovery period In-Reply-To: References: Message-ID: # HG changeset patch # User Roman Arutyunyan # Date 1690874486 -14400 # Tue Aug 01 11:21:26 2023 +0400 # Node ID a53bbd94a0fa436535ee3bbcb6176befdf47c68a # Parent 5b91a40f2dd249000e9208a0152dc5cc0c6ea0c4 QUIC: eliminated spurious recovery period. The initial value for recovery_start used to be the current time. As a result, the packets sent at the very beginning of a connection belonged to a recovery period and their ACKs were treated accordingly. The issue manifested itself with "quic congestion ack recovery" log messages and slower growth of congestion window. Now the initial value for recovery_start is set to an earlier time, which fixes the spurious recovery period. diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -315,7 +315,7 @@ ngx_quic_new_connection(ngx_connection_t ngx_max(2 * qc->tp.max_udp_payload_size, 14720)); qc->congestion.ssthresh = (size_t) -1; - qc->congestion.recovery_start = ngx_current_msec; + qc->congestion.recovery_start = ngx_current_msec - 1; if (pkt->validated && pkt->retried) { qc->tp.retry_scid.len = pkt->dcid.len; From arut at nginx.com Tue Aug 1 07:45:14 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:14 +0400 Subject: [PATCH 3 of 5] QUIC: fixed PTO expiration condition In-Reply-To: References: Message-ID: <741deb8ff8257914312a.1690875914@plentiful-waterbuck> # HG changeset patch # User Roman Arutyunyan # Date 1690874519 -14400 # Tue Aug 01 11:21:59 2023 +0400 # Node ID 741deb8ff8257914312ab134f3a0b69256c661f4 # Parent a53bbd94a0fa436535ee3bbcb6176befdf47c68a QUIC: fixed PTO expiration condition. Previously, PTO handler analyzed the first packet in the sent queue for the timeout expiration. However, the last sent packet should be analyzed instead. An example is timeout calculation in ngx_quic_set_lost_timer(). diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -840,7 +840,7 @@ ngx_quic_pto_handler(ngx_event_t *ev) continue; } - q = ngx_queue_head(&ctx->sent); + q = ngx_queue_last(&ctx->sent); f = ngx_queue_data(q, ngx_quic_frame_t, queue); if (f->pnum <= ctx->largest_ack From arut at nginx.com Tue Aug 1 07:45:15 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:15 +0400 Subject: [PATCH 4 of 5] QUIC: fixed probe-congestion deadlock In-Reply-To: References: Message-ID: # HG changeset patch # User Roman Arutyunyan # Date 1690873324 -14400 # Tue Aug 01 11:02:04 2023 +0400 # Node ID cd0ef56b0f1afaa54d7d2756dad2182628445e04 # Parent 741deb8ff8257914312ab134f3a0b69256c661f4 QUIC: fixed probe-congestion deadlock. When probe timeout expired while congestion window was exhausted, probe PINGs could not be sent. As a result, lost packets could not be declared lost and congestion window could not be freed for new packets. This deadlock continued until connection idle timeout expiration. Now PINGs are sent separately from the frame queue without congestion control. diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -820,9 +820,9 @@ ngx_quic_pto_handler(ngx_event_t *ev) { ngx_uint_t i; ngx_msec_t now; - ngx_queue_t *q, *next; + ngx_queue_t *q; ngx_connection_t *c; - ngx_quic_frame_t *f; + ngx_quic_frame_t *f, frame; ngx_quic_send_ctx_t *ctx; ngx_quic_connection_t *qc; @@ -859,63 +859,23 @@ ngx_quic_pto_handler(ngx_event_t *ev) "quic pto %s pto_count:%ui", ngx_quic_level_name(ctx->level), qc->pto_count); - for (q = ngx_queue_head(&ctx->frames); - q != ngx_queue_sentinel(&ctx->frames); - /* void */) - { - next = ngx_queue_next(q); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); + ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); - if (f->type == NGX_QUIC_FT_PING) { - ngx_queue_remove(q); - ngx_quic_free_frame(c, f); - } - - q = next; - } - - for (q = ngx_queue_head(&ctx->sent); - q != ngx_queue_sentinel(&ctx->sent); - /* void */) - { - next = ngx_queue_next(q); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); + frame.level = ctx->level; + frame.type = NGX_QUIC_FT_PING; - if (f->type == NGX_QUIC_FT_PING) { - ngx_quic_congestion_lost(c, f); - ngx_queue_remove(q); - ngx_quic_free_frame(c, f); - } - - q = next; - } - - /* enforce 2 udp datagrams */ - - f = ngx_quic_alloc_frame(c); - if (f == NULL) { - break; + if (ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK + || ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK) + { + ngx_quic_close_connection(c, NGX_ERROR); + return; } - - f->level = ctx->level; - f->type = NGX_QUIC_FT_PING; - f->flush = 1; - - ngx_quic_queue_frame(qc, f); - - f = ngx_quic_alloc_frame(c); - if (f == NULL) { - break; - } - - f->level = ctx->level; - f->type = NGX_QUIC_FT_PING; - - ngx_quic_queue_frame(qc, f); } qc->pto_count++; + ngx_quic_set_lost_timer(c); + ngx_quic_connstate_dbg(c); } diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -645,10 +645,6 @@ ngx_quic_output_packet(ngx_connection_t f->plen = 0; nframes++; - - if (f->flush) { - break; - } } if (nframes == 0) { diff --git a/src/event/quic/ngx_event_quic_transport.h b/src/event/quic/ngx_event_quic_transport.h --- a/src/event/quic/ngx_event_quic_transport.h +++ b/src/event/quic/ngx_event_quic_transport.h @@ -271,7 +271,6 @@ struct ngx_quic_frame_s { ssize_t len; unsigned need_ack:1; unsigned pkt_need_ack:1; - unsigned flush:1; ngx_chain_t *data; union { From arut at nginx.com Tue Aug 1 07:45:16 2023 From: arut at nginx.com (=?iso-8859-1?q?Roman_Arutyunyan?=) Date: Tue, 01 Aug 2023 11:45:16 +0400 Subject: [PATCH 5 of 5] QUIC: ignore blocked status in congestion event handlers In-Reply-To: References: Message-ID: <80df0852e7ed58631025.1690875916@plentiful-waterbuck> # HG changeset patch # User Roman Arutyunyan # Date 1690874694 -14400 # Tue Aug 01 11:24:54 2023 +0400 # Node ID 80df0852e7ed58631025398694da6dd4dab42611 # Parent cd0ef56b0f1afaa54d7d2756dad2182628445e04 QUIC: ignore blocked status in congestion event handlers. Sometimes, while congestion window allows to send more bytes, the next frame still cannot be sent since it's too big. When this happens, push event is not triggered from congestion ack/loss event handlers which may delay packet send. Now the blocked status is ignored and push event is always posted when congestion window grows bigger. diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -307,7 +307,6 @@ ngx_quic_handle_ack_frame_range(ngx_conn void ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f) { - ngx_uint_t blocked; ngx_msec_t timer; ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; @@ -319,8 +318,6 @@ ngx_quic_congestion_ack(ngx_connection_t qc = ngx_quic_get_connection(c); cg = &qc->congestion; - blocked = (cg->in_flight >= cg->window) ? 1 : 0; - cg->in_flight -= f->plen; timer = f->last - cg->recovery_start; @@ -358,7 +355,7 @@ ngx_quic_congestion_ack(ngx_connection_t done: - if (blocked && cg->in_flight < cg->window) { + if (cg->in_flight < cg->window) { ngx_post_event(&qc->push, &ngx_posted_events); } } @@ -648,7 +645,6 @@ ngx_quic_resend_frames(ngx_connection_t static void ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f) { - ngx_uint_t blocked; ngx_msec_t timer; ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; @@ -660,8 +656,6 @@ ngx_quic_congestion_lost(ngx_connection_ qc = ngx_quic_get_connection(c); cg = &qc->congestion; - blocked = (cg->in_flight >= cg->window) ? 1 : 0; - cg->in_flight -= f->plen; f->plen = 0; @@ -690,7 +684,7 @@ ngx_quic_congestion_lost(ngx_connection_ done: - if (blocked && cg->in_flight < cg->window) { + if (cg->in_flight < cg->window) { ngx_post_event(&qc->push, &ngx_posted_events); } } From pluknet at nginx.com Wed Aug 2 15:54:45 2023 From: pluknet at nginx.com (Sergey Kandaurov) Date: Wed, 2 Aug 2023 18:54:45 +0300 Subject: [PATCH 1 of 2] SSL: provided "nginx" appname when loading OpenSSL configs In-Reply-To: References: Message-ID: <5767CA14-02F4-4F9B-A7F2-946D6DD4EB11@nginx.com> > On 25 Jul 2023, at 02:10, Maxim Dounin wrote: > > # HG changeset patch > # User Maxim Dounin > # Date 1687300195 -10800 > # Wed Jun 21 01:29:55 2023 +0300 > # Node ID b79ef48b91e45dba4bf850be6b2a2cc3b8834f5d > # Parent 904c99bede1770d92566b56939c5b6ec85f05b55 > SSL: provided "nginx" appname when loading OpenSSL configs. > > Following OpenSSL 0.9.8f, OpenSSL tries to load application-specific > configuration section first, and then falls back to the "openssl_conf" > default section if application-specific section is not found, by using > CONF_modules_load_file(CONF_MFLAGS_DEFAULT_SECTION). Therefore this > change is not expected to introduce any compatibility issues with existing > configurations. It does, however, makes it easier to configure specific typo: s/makes/make/ > OpenSSL settings for nginx in system-wide OpenSSL configuration > (ticket #2449). > > Instead of checking OPENSSL_VERSION_NUMBER when using the OPENSSL_init_ssl() > interface, the code now tests for OPENSSL_INIT_LOAD_CONFIG to be defined and > true, and also explicitly excludes LibreSSL. This ensures that this interface > is not used with BoringSSL and LibreSSL, which do not provide additional > library initialization settings, notably the OPENSSL_INIT_set_config_appname() > call. > > diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c > --- a/src/event/ngx_event_openssl.c > +++ b/src/event/ngx_event_openssl.c > @@ -140,13 +140,31 @@ int ngx_ssl_stapling_index; > ngx_int_t > ngx_ssl_init(ngx_log_t *log) > { > -#if OPENSSL_VERSION_NUMBER >= 0x10100003L > - > - if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) { > +#if (OPENSSL_INIT_LOAD_CONFIG && !defined LIBRESSL_VERSION_NUMBER) > + > + OPENSSL_INIT_SETTINGS *init; > + > + init = OPENSSL_INIT_new(); > + if (init == NULL) { > + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_INIT_new() failed"); > + return NGX_ERROR; > + } > + > +#ifndef OPENSSL_NO_STDIO > + if (OPENSSL_INIT_set_config_appname(init, "nginx") == 0) { > + ngx_ssl_error(NGX_LOG_ALERT, log, 0, > + "OPENSSL_INIT_set_config_appname() failed"); > + return NGX_ERROR; > + } > +#endif > + > + if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, init) == 0) { > ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed"); > return NGX_ERROR; > } > > + OPENSSL_INIT_free(init); > + > /* > * OPENSSL_init_ssl() may leave errors in the error queue > * while returning success > @@ -156,7 +174,7 @@ ngx_ssl_init(ngx_log_t *log) > > #else > > - OPENSSL_config(NULL); > + OPENSSL_config("nginx"); > > SSL_library_init(); > SSL_load_error_strings(); Looks good. -- Sergey Kandaurov From pluknet at nginx.com Wed Aug 2 15:55:04 2023 From: pluknet at nginx.com (Sergey Kandaurov) Date: Wed, 2 Aug 2023 18:55:04 +0300 Subject: [PATCH 2 of 2] SSL: avoid using OpenSSL config in build directory (ticket #2404) In-Reply-To: References: Message-ID: > On 25 Jul 2023, at 02:10, Maxim Dounin wrote: > > # HG changeset patch > # User Maxim Dounin > # Date 1687300193 -10800 > # Wed Jun 21 01:29:53 2023 +0300 > # Node ID bd2cc76ebe2367dc303e2746928b17ca8976b604 > # Parent b79ef48b91e45dba4bf850be6b2a2cc3b8834f5d > SSL: avoid using OpenSSL config in build directory (ticket #2404). > > With this change, the NGX_OPENSSL_NO_CONFIG macro is defined when nginx > is asked to build OpenSSL itself. And with this macro automatic loading > of OpenSSL configuration (from the build directory) is prevented unless > the OPENSSL_CONF environment variable is explicitly set. > > Note that not loading configuration is broken in OpenSSL 1.1.1 and 1.1.1a > (fixed in OpenSSL 1.1.1b, see https://github.com/openssl/openssl/issues/7350). > If nginx is used to compile these OpenSSL versions, configuring nginx with > NGX_OPENSSL_NO_CONFIG explicitly set to 0 might be used as a workaround. Not sure how the last paragraph is relevant as the patch doesn't change the number of OPENSSL_init_ssl() calls. Otherwise looks good. > > diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf > --- a/auto/lib/openssl/conf > +++ b/auto/lib/openssl/conf > @@ -8,6 +8,8 @@ if [ $OPENSSL != NONE ]; then > have=NGX_OPENSSL . auto/have > have=NGX_SSL . auto/have > > + have=NGX_OPENSSL_NO_CONFIG . auto/have > + > if [ $USE_OPENSSL_QUIC = YES ]; then > have=NGX_QUIC . auto/have > have=NGX_QUIC_OPENSSL_COMPAT . auto/have > diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c > --- a/src/event/ngx_event_openssl.c > +++ b/src/event/ngx_event_openssl.c > @@ -142,8 +142,19 @@ ngx_ssl_init(ngx_log_t *log) > { > #if (OPENSSL_INIT_LOAD_CONFIG && !defined LIBRESSL_VERSION_NUMBER) > > + uint64_t opts; > OPENSSL_INIT_SETTINGS *init; > > + opts = OPENSSL_INIT_LOAD_CONFIG; > + > +#if (NGX_OPENSSL_NO_CONFIG) > + > + if (getenv("OPENSSL_CONF") == NULL) { > + opts = OPENSSL_INIT_NO_LOAD_CONFIG; > + } > + > +#endif > + > init = OPENSSL_INIT_new(); > if (init == NULL) { > ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_INIT_new() failed"); > @@ -158,7 +169,7 @@ ngx_ssl_init(ngx_log_t *log) > } > #endif > > - if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, init) == 0) { > + if (OPENSSL_init_ssl(opts, init) == 0) { > ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed"); > return NGX_ERROR; > } > @@ -174,6 +185,14 @@ ngx_ssl_init(ngx_log_t *log) > > #else > > +#if (NGX_OPENSSL_NO_CONFIG) > + > + if (getenv("OPENSSL_CONF") == NULL) { > + OPENSSL_no_config(); > + } > + > +#endif > + > OPENSSL_config("nginx"); > > SSL_library_init(); -- Sergey Kandaurov From arut at nginx.com Wed Aug 2 17:12:25 2023 From: arut at nginx.com (Roman Arutyunyan) Date: Wed, 2 Aug 2023 21:12:25 +0400 Subject: [PATCH] Added debug_random directive In-Reply-To: References: Message-ID: <20230802171225.cbxwdhz5k4f2hcx4@N00W24XTQX> On Mon, Jul 24, 2023 at 05:24:04AM +0100, J Carter wrote: [..] > # HG changeset patch > # User J Carter > # Date 1690171706 -3600 > # Mon Jul 24 05:08:26 2023 +0100 > # Node ID ea91b9aa69d8ce9dc9878209a83b7d538e6bc7e1 > # Parent 77c1418916f7817a0d020f28d8a08f278a12fe43 > Added debug_random directive This line needs a prefix, for example: Events: debug_random directive. See "hg log" for common prefixes used in nginx commits. > More bug fixes and style changes. > > diff -r 77c1418916f7 -r ea91b9aa69d8 src/event/ngx_event.c > --- a/src/event/ngx_event.c Thu Jun 08 14:58:01 2023 +0400 > +++ b/src/event/ngx_event.c Mon Jul 24 05:08:26 2023 +0100 > @@ -30,6 +30,8 @@ > static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); > static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, > void *conf); > +static char *ngx_event_debug_random(ngx_conf_t *cf, ngx_command_t *cmd, > + void *conf); > > static void *ngx_event_core_create_conf(ngx_cycle_t *cycle); > static char *ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf); > @@ -162,6 +164,13 @@ > 0, > NULL }, > > + { ngx_string("debug_random"), > + NGX_EVENT_CONF|NGX_CONF_TAKE1, > + ngx_event_debug_random, > + 0, > + 0, > + NULL }, > + > ngx_null_command > }; > > @@ -496,6 +505,7 @@ > size_t size, cl; > ngx_shm_t shm; > ngx_time_t *tp; > + ngx_cidr_t *cidr; > ngx_core_conf_t *ccf; > ngx_event_conf_t *ecf; > > @@ -507,6 +517,33 @@ > "using the \"%s\" event method", ecf->name); > } > > + if (ecf->debug_connection.nelts == 0 > + && ecf->debug_scaled_pct > 0) > + { > + cidr = ngx_array_push(&ecf->debug_connection); > + if (cidr == NULL) { > + return NGX_ERROR; > + } > + /*0.0.0.0/0*/ > + ngx_memzero(cidr, sizeof(ngx_cidr_t)); > + cidr->family = AF_INET; > + > +#ifdef NGX_HAVE_INET6 > + cidr = ngx_array_push(&ecf->debug_connection); > + if (cidr == NULL) { > + return NGX_ERROR; > + } > + /*::/0*/ > + ngx_memzero(cidr, sizeof(ngx_cidr_t)); > + cidr->family = AF_INET6; > +#endif > + > + } else if (ecf->debug_connection.nelts > 0 > + && ecf->debug_scaled_pct == 0) > + { > + ecf->debug_scaled_pct = NGX_MAX_INT32_VALUE; > + } > + Why do we need this code? It looks to me like everything can be done in ngx_debug_accepted_connection(). > ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); > > ngx_timer_resolution = ccf->timer_resolution; > @@ -1254,6 +1291,55 @@ > } > > > +static char * > +ngx_event_debug_random(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) > +{ > +#if (NGX_DEBUG) > + ngx_event_conf_t *ecf = conf; > + > + u_char *c; > + ngx_int_t pct; > + ngx_uint_t len; > + ngx_str_t *value; > + > + if (ecf->debug_scaled_pct != NGX_CONF_UNSET_UINT) { > + return "is duplicate"; > + } > + > + value = cf->args->elts; > + c = value[1].data; > + len = value[1].len; > + > + if (c[len-1] != '%') { > + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, > + "%V missing '%%'", > + &value[1]); > + return NGX_CONF_ERROR; > + } > + > + pct = ngx_atofp(c, len-1, 2); > + > + if (pct == NGX_ERROR || pct == 0 || pct > 9999) { > + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, > + "%V is an invalid value", > + &value[1]); > + return NGX_CONF_ERROR; > + } > + > + ecf->debug_scaled_pct = NGX_MAX_INT32_VALUE / 10000 * pct; We already have a similar handler that parses percent argument, see ngx_stream_split_clients(). Style-wise it's a good idea to follow the style/naming of existing code. Also, why not store 0-10000 value range in configuration and use ngx_random() % 10000 in runtime? > +#else > + > + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, > + "\"debug_random\" is ignored, you need to rebuild " > + "nginx using --with-debug option to enable it"); > + > +#endif > + > + return NGX_CONF_OK; > +} > + > + > static void * > ngx_event_core_create_conf(ngx_cycle_t *cycle) > { > @@ -1279,6 +1365,8 @@ > return NULL; > } > > + ecf->debug_scaled_pct = NGX_CONF_UNSET_UINT; > + > #endif > > return ecf; > @@ -1369,5 +1457,7 @@ > ngx_conf_init_value(ecf->accept_mutex, 0); > ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500); > > + ngx_conf_init_uint_value(ecf->debug_scaled_pct, 0); > + > return NGX_CONF_OK; > } > diff -r 77c1418916f7 -r ea91b9aa69d8 src/event/ngx_event.h > --- a/src/event/ngx_event.h Thu Jun 08 14:58:01 2023 +0400 > +++ b/src/event/ngx_event.h Mon Jul 24 05:08:26 2023 +0100 > @@ -438,6 +438,7 @@ > u_char *name; > > #if (NGX_DEBUG) > + ngx_uint_t debug_scaled_pct; > ngx_array_t debug_connection; > #endif > } ngx_event_conf_t; > diff -r 77c1418916f7 -r ea91b9aa69d8 src/event/ngx_event_accept.c > --- a/src/event/ngx_event_accept.c Thu Jun 08 14:58:01 2023 +0400 > +++ b/src/event/ngx_event_accept.c Mon Jul 24 05:08:26 2023 +0100 > @@ -523,6 +523,7 @@ > struct sockaddr_in6 *sin6; > ngx_uint_t n; > #endif > + ngx_uint_t r = ngx_random(); Style: we do not initialize non-static local variables like that. Instead, a variable is initialized explicitly in the code after declaration. > > cidr = ecf->debug_connection.elts; > for (i = 0; i < ecf->debug_connection.nelts; i++) { > @@ -548,6 +549,7 @@ > > #if (NGX_HAVE_UNIX_DOMAIN) > case AF_UNIX: > + r = 0; > break; > #endif > > @@ -561,7 +563,10 @@ > break; > } > > - c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; > + if (r <= ecf->debug_scaled_pct) { > + c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; > + } > + > break; > > next: > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan From mdounin at mdounin.ru Wed Aug 2 17:37:10 2023 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 2 Aug 2023 20:37:10 +0300 Subject: [PATCH 1 of 3] CSS as file. In-Reply-To: References: Message-ID: Hello! On Mon, Jul 24, 2023 at 02:23:12PM +0000, Liam Crilly via nginx-devel wrote: > # HG changeset patch > # User Liam Crilly > # Date 1690207197 -3600 > # Mon Jul 24 14:59:57 2023 +0100 > # Node ID df1cf98cf8f50eb1770d966aed583d21e481558b > # Parent 1f672755959a64aec3f0aeceab1dbdc13cb36414 > CSS as file. > > Extracts the inline styles from style.xsls into separate files for > ease of style-development and to take advantage of browser caching. > Hebrew and Chinese variants are preserved. > > Stylesheets are located in a new top-level directory (/css) and are > compressed during the gzip process. Thanks, but no. This change results in 4 distinct static language-specific CSS files, with no obvious way to keep them in sync. At the same time, claimed benefits does not seem to be noticeable, in particular: - Surely styles can be developed in any convenient way, and results merged into xsls/style.xsls; - Styles now are about 800 bytes gzipped, and this is hardly noticeable neither for small pages like index.html (2.7k gzipped original, 1.9k gzipped with patch), nor large pages like ngx_http_core_module.html (24k gzipped), and hardly justifies a separate request. Overall, I think that this change will result in more complex support and the same or worse site performance, and therefore I'm against this change. [...] -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Wed Aug 2 17:37:28 2023 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 2 Aug 2023 20:37:28 +0300 Subject: [PATCH 2 of 3] Responsive menu. In-Reply-To: References: Message-ID: Hello! On Mon, Jul 24, 2023 at 02:25:16PM +0000, Liam Crilly via nginx-devel wrote: > # HG changeset patch > # User Liam Crilly > # Date 1690207285 -3600 > # Mon Jul 24 15:01:25 2023 +0100 > # Node ID c4018ab31dc52632f470298fcc7cece1fd8f57b9 > # Parent df1cf98cf8f50eb1770d966aed583d21e481558b > Responsive menu. > > Nav menu is now hidden on narrow displays, collapsing to a "hamburger" > menu icon in the banner. Menu items are now an unordered list instead of > simple text markup. In no particular order: - It looks like this changeset contains more than one logical change. It is generally a good idea to keep distinct changes in separate changesets as long as it is possible. A useful rule of thumb is to consider using more than one changeset as long as you have to mention more than one item in the commit log. - It looks like there are multiple style issues in the change: it fails to follow the style you've just introduced in the previous changeset, and uses style definitions without spaces and empty lines. - Design-wise, banner is expected to be on top of the site, above anything. That's basically reflects the fact that it was, in fact, added to the site as external element. With the suggested change, this is no longer true, and hamburger interferes with banner. This needs a better solution. Removing the banner might be an option, it clearly meaningless now. - Resulting menu seems to be non-scrollable on small screens, and detaches from the hamburger when the page is scrolled. - This change demonstrates very well that using multiple language-specific styles makes development hard: we are already seeing bit rot for he and cn languages, and duplicate work for en/ru. See below for more comments. > > diff -r df1cf98cf8f5 -r c4018ab31dc5 css/style_en.css > --- a/css/style_en.css Mon Jul 24 14:59:57 2023 +0100 > +++ b/css/style_en.css Mon Jul 24 15:01:25 2023 +0100 > @@ -29,10 +29,22 @@ > > #menu { > float: right; > - width: 11em; > - padding: 0 .5em 1em .5em; > + width: 13em; > + padding: 0; > border-left: 2px solid #DDD; > } > +.nav ul{ > + margin:0; > + padding:20px; > +} > +.nav h1{ > + padding:0 20px; > +} > +.nav ul li{ > + list-style-type:none; > + padding:0; > + margin:0; > +} > > #content { > margin-right: 13.5em; > @@ -43,9 +55,7 @@ > display: block; > font-size: 3em; > text-align: left; > - height: .7em; > - margin: 0; > - margin-bottom: .5em; > + margin: 0.5rem 0 0 0; > } > > h1 img { > @@ -205,3 +215,125 @@ > width:100%; > height:100%; > } > + > + at media screen and (max-width:768px) { Overall, I would expect minimal media-specific changes for already defined elements, such as display changes. > + #main { > + padding: 20px; > + min-width: inherit; > + } > + #main #content { > + width: 100%!important; > + padding: 0; > + border: none; > + } > + > + #banner-content { > + max-width: 70vw; > + } > + > + #menu { > + text-align: left; > + } > + > + /* Menu Mobile */ It might be a good idea to avoid useless comments. > + :root { > + --white: #f9f9f9; > + --black: #000; > + --gray: #85888C; > + --green: #b6d7a8; > + color-scheme: light dark; > + } /* variables*/ > + > + /* Nav menu */ > + .nav { > + width: 15rem; > + height: 100%; > + max-height: 0; > + position: fixed; This uses "position: fixed;", and therefore menu cannot be scrolled when it does not fit on screen. Also, hamburger uses "position: absolute;", and together with fixed menu this results in hamburger and menu being when the page itself is scrolled. > + top: 50px; > + right: 0; > + border-left: 1px solid #909090; > + background-color: var(--white); Using variable colors along with non-variable looks wrong. > + overflow: hidden; > + transition: .5s ease-in-out; > + } > + .nav ul { > + margin: 0; > + padding: 20px; > + } > + .nav h1 { > + padding: 0 20px; > + } > + .nav ul li { > + list-style-type: none; > + padding:0; > + margin:0; > + } > + > + .hamb { > + cursor: pointer; > + float: right; > + position: absolute; > + top: 0; > + right: 20px; > + height: 30px; > + width: 70px; > + padding-left: 20px; > + padding-top: 20px; > + z-index: 1100; > + } > + .hamb-line { > + background: var(--green); > + display: block; > + height: 5px; > + position: relative; > + width: 44px; > + border-radius:3px; > + > + } > + .hamb-line::before,.hamb-line::after { > + background: var(--green); > + content: ''; > + display: block; > + height: 100%; > + position: absolute; > + transition: all .2s ease-in-out; > + width: 100%; > + border-radius:3px; > + } > + .hamb-line::before{ > + top: 10px; > + } > + .hamb-line::after{ > + top: -10px; > + } > + .side-menu { > + display: none; > + } /* Hide checkbox */ > + .side-menu:checked ~ .nav{ > + max-height: 100%; > + top: 50px; > + > + } > + .side-menu:checked ~ .hamb .hamb-line { > + background: transparent; > + } > + .side-menu:checked ~ .hamb .hamb-line::before { > + transform: rotate(-45deg); > + top: 0; > + } > + .side-menu:checked ~ .hamb .hamb-line::after { > + transform: rotate(45deg); > + top: 0; > + } > + > + code { > + white-space: pre-line; > + } > +} > + > + at media screen and (min-width:768px){ > + .side-menu,.hamb-line { > + display: none; > + } > +} > diff -r df1cf98cf8f5 -r c4018ab31dc5 css/style_ru.css > --- a/css/style_ru.css Mon Jul 24 14:59:57 2023 +0100 > +++ b/css/style_ru.css Mon Jul 24 15:01:25 2023 +0100 Skipped style_ru.css, as it is exactly identical to style_en.css. [...] > diff -r df1cf98cf8f5 -r c4018ab31dc5 xsls/banner.xsls > --- a/xsls/banner.xsls Mon Jul 24 14:59:57 2023 +0100 > +++ b/xsls/banner.xsls Mon Jul 24 15:01:25 2023 +0100 > @@ -21,7 +21,7 @@ > fetch("!banner_link ()") > .then((response) => response.text()) > .then((resp) => \{ > - document.getElementById("banner").innerHTML = resp; > + document.getElementById("banner-content").innerHTML = resp; > \}) > .catch((error) => \{ > console.warn(error); > diff -r df1cf98cf8f5 -r c4018ab31dc5 xsls/body.xsls > --- a/xsls/body.xsls Mon Jul 24 14:59:57 2023 +0100 > +++ b/xsls/body.xsls Mon Jul 24 15:01:25 2023 +0100 > @@ -18,20 +18,27 @@ > > > > >
> -