Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package haproxy for openSUSE:Factory checked in at 2026-01-30 18:22:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/haproxy (Old) and /work/SRC/openSUSE:Factory/.haproxy.new.1995 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "haproxy" Fri Jan 30 18:22:20 2026 rev:174 rq:1329868 version:3.3.2+git0.72df9192b Changes: -------- --- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes 2025-12-19 17:41:30.593746580 +0100 +++ /work/SRC/openSUSE:Factory/.haproxy.new.1995/haproxy.changes 2026-01-30 18:22:40.222494976 +0100 @@ -1,0 +2,63 @@ +Thu Jan 29 18:46:02 UTC 2026 - Marcus Rueckert <[email protected]> + +- Update to version 3.3.2+git0.72df9192b: + * [RELEASE] Released version 3.3.2 + * BUG/MEDIUM: debug: only dump Lua state when panicking + * BUG/MEDIUM: ssl: fix msg callbacks on QUIC connections + * BUG/MINOR: config/ssl: fix spelling of "expose-experimental-directives" + * BUG/MINOR: config: check capture pool creations for failures + * BUG/MINOR: stick-tables: abort startup on stk_ctr pool creation failure + * DOC: config: mention some possible TLS versions restrictions for kTLS + * BUG/MAJOR: applet: Don't call I/O handler if the applet was shut + * BUG/MINOR: ssl: Encrypted keys could not be loaded when given alongside certificate + * BUG/MINOR: ssl: Properly manage alloc failures in SSL passphrase callback + * DOC: reg-tests: update VTest upstream link in the starting guide + * MINOR: hlua: Add support for lua 5.5 + * BUG/MINOR: ssl: fix error message of tune.ssl.certificate-compression + * MINOR: ssl: allow to disable certificate compression + * BUG/MINOR: proto_tcp: Properly report support for HAVE_TCP_MD5SIG feature + * BUG/MEDIUM: mux-h1: Skip UNUSED htx block when formating the start line + * BUG/MINOR: promex: Detach promex from the server on error dump its metrics dump + * BUG/MINOR: hlua: consume error object if ignored after a failing lua_pcall() + * BUG/MEDIUM: hlua: fix invalid lua_pcall() usage in hlua_traceback() + * BUG/MINOR: proxy: fix deinit crash on defaults with duplicate name + * REGTESTS: ssl: fix generate-certificates w/ LibreSSL + * BUG/MEDIUM: mux-quic: prevent BUG_ON() on aborted uni stream close + * BUG/MEDIUM: ssl: fix generate-certificates option when SNI greater than 64bytes + * BUG/MEDIUM: ssl: fix error path on generate-certificates + * BUG/MEDIUM: log: parsing log-forward options may result in segfault + * BUG/MEDIUM: promex: server iteration may rely on stale server + * BUG/MINOR: server: ensure server is detached from proxy list before being freed + * MINOR: cli: use srv_drop() when server was created using new_server() + * BUG/MINOR: cfgparse: fix "default" prefix parsing + * BUG/MINOR: proxy: free persist_rules + * BUG/MINOR: http_act: fix deinit performed on uninitialized lf_expr in release_http_map() + * BUG/MEDIUM: quic: fix ACK ECN frame parsing + * BUG/MINOR: hlua_fcn: ensure Patref:add_bulk() is given a table object before using it + * BUG/MINOR: hlua_fcn: fix broken yield for Patref:add_bulk() + * MINOR: cfgparse: remove duplicate "force-persist" in common kw list + * BUG/MINOR: ech/quic: enable ech configuration also for quic listeners + * REGTESTS: ssl: Fix reg-tests curve check + * BUG/MINOR: cli/stick-tables: argument to "show table" is optional + * BUILD: sockpair: fix build issue on macOS related to variable-length arrays + * BUG/MINOR: cfgparse: wrong section name upon error + * BUILD: tools: memchr definition changed in C23 + * BUILD: ssl: strchr definition changed in C23 + * BUG/MINOR: quic: fix deprecated warning for window size keyword + * BUG/MEDIUM: stconn: Move data from <kip> to <kop> during zero-copy forwarding + * BUG/MEDIUM: mworker: can't use signals after a failed reload + * BUG/MEDIUM: mux-h1: Take care to update <kop> value during zero-copy forwarding + * BUG/MEDIUM: peers: Properly handle shutdown when trying to get a line + * BUG/MINOR: mworker/cli: fix show proc pagination using reload counter + * DOC: config: fix the length attribute name for stick tables of type binary / string + * BUG/MINOR: backend: inspect request not response buffer to check for TFO + * BUG/MINOR: backend: fix the conn_retries check for TFO + * MINOR: mux-h2: perform a graceful close at 75% glitches threshold + * MINOR: mux-h2: add missing glitch count for non-decodable H2 headers + +------------------------------------------------------------------- +Wed Jan 28 15:08:53 UTC 2026 - Peter Varkoly <[email protected]> + +- Fix packages for Immutable Mode + +------------------------------------------------------------------- Old: ---- haproxy-3.3.1+git0.9c24c11a6.tar.gz New: ---- haproxy-3.3.2+git0.72df9192b.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ haproxy.spec ++++++ --- /var/tmp/diff_new_pack.DftkVo/_old 2026-01-30 18:22:41.302540302 +0100 +++ /var/tmp/diff_new_pack.DftkVo/_new 2026-01-30 18:22:41.302540302 +0100 @@ -49,7 +49,7 @@ %bcond_with ech Name: haproxy -Version: 3.3.1+git0.9c24c11a6 +Version: 3.3.2+git0.72df9192b Release: 0 # Summary: The Reliable, High Performance TCP/HTTP Load Balancer @@ -222,7 +222,7 @@ %if %{with rc_symlink} %{_sbindir}/rchaproxy %endif -%dir %attr(-,root,haproxy) %{pkg_home} +%dir %ghost %{pkg_home} %{_mandir}/man1/%{pkg_name}.1%{?ext_man} %dir %{_datadir}/vim %dir %{vim_data_dir} ++++++ _service ++++++ --- /var/tmp/diff_new_pack.DftkVo/_old 2026-01-30 18:22:41.378543491 +0100 +++ /var/tmp/diff_new_pack.DftkVo/_new 2026-01-30 18:22:41.386543827 +0100 @@ -6,7 +6,7 @@ <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="versionrewrite-replacement">\1</param> - <param name="revision">v3.3.1</param> + <param name="revision">v3.3.2</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.DftkVo/_old 2026-01-30 18:22:41.414545002 +0100 +++ /var/tmp/diff_new_pack.DftkVo/_new 2026-01-30 18:22:41.418545170 +0100 @@ -5,7 +5,7 @@ </service> <service name="tar_scm"> <param name="url">http://git.haproxy.org/git/haproxy-3.3.git/</param> - <param name="changesrevision">9c24c11a6e54ab1c280b43c2756edcb49cf873b1</param> + <param name="changesrevision">72df9192b9ff071abce66a040d74cb6f0fe8232c</param> </service> </servicedata> (No newline at EOF) ++++++ haproxy-3.3.1+git0.9c24c11a6.tar.gz -> haproxy-3.3.2+git0.72df9192b.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/CHANGELOG new/haproxy-3.3.2+git0.72df9192b/CHANGELOG --- old/haproxy-3.3.1+git0.9c24c11a6/CHANGELOG 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/CHANGELOG 2026-01-29 16:19:50.000000000 +0100 @@ -1,6 +1,60 @@ ChangeLog : =========== +2026/01/29 : 3.3.2 + - MINOR: mux-h2: add missing glitch count for non-decodable H2 headers + - MINOR: mux-h2: perform a graceful close at 75% glitches threshold + - BUG/MINOR: backend: fix the conn_retries check for TFO + - BUG/MINOR: backend: inspect request not response buffer to check for TFO + - DOC: config: fix the length attribute name for stick tables of type binary / string + - BUG/MINOR: mworker/cli: fix show proc pagination using reload counter + - BUG/MEDIUM: peers: Properly handle shutdown when trying to get a line + - BUG/MEDIUM: mux-h1: Take care to update <kop> value during zero-copy forwarding + - BUG/MEDIUM: mworker: can't use signals after a failed reload + - BUG/MEDIUM: stconn: Move data from <kip> to <kop> during zero-copy forwarding + - BUG/MINOR: quic: fix deprecated warning for window size keyword + - BUILD: ssl: strchr definition changed in C23 + - BUILD: tools: memchr definition changed in C23 + - BUG/MINOR: cfgparse: wrong section name upon error + - BUILD: sockpair: fix build issue on macOS related to variable-length arrays + - BUG/MINOR: cli/stick-tables: argument to "show table" is optional + - REGTESTS: ssl: Fix reg-tests curve check + - BUG/MINOR: ech/quic: enable ech configuration also for quic listeners + - MINOR: cfgparse: remove duplicate "force-persist" in common kw list + - BUG/MINOR: hlua_fcn: fix broken yield for Patref:add_bulk() + - BUG/MINOR: hlua_fcn: ensure Patref:add_bulk() is given a table object before using it + - BUG/MEDIUM: quic: fix ACK ECN frame parsing + - BUG/MINOR: http_act: fix deinit performed on uninitialized lf_expr in release_http_map() + - BUG/MINOR: proxy: free persist_rules + - BUG/MINOR: cfgparse: fix "default" prefix parsing + - MINOR: cli: use srv_drop() when server was created using new_server() + - BUG/MINOR: server: ensure server is detached from proxy list before being freed + - BUG/MEDIUM: promex: server iteration may rely on stale server + - BUG/MEDIUM: log: parsing log-forward options may result in segfault + - BUG/MEDIUM: ssl: fix error path on generate-certificates + - BUG/MEDIUM: ssl: fix generate-certificates option when SNI greater than 64bytes + - BUG/MEDIUM: mux-quic: prevent BUG_ON() on aborted uni stream close + - REGTESTS: ssl: fix generate-certificates w/ LibreSSL + - BUG/MINOR: proxy: fix deinit crash on defaults with duplicate name + - BUG/MEDIUM: hlua: fix invalid lua_pcall() usage in hlua_traceback() + - BUG/MINOR: hlua: consume error object if ignored after a failing lua_pcall() + - BUG/MINOR: promex: Detach promex from the server on error dump its metrics dump + - BUG/MEDIUM: mux-h1: Skip UNUSED htx block when formating the start line + - BUG/MINOR: proto_tcp: Properly report support for HAVE_TCP_MD5SIG feature + - MINOR: ssl: allow to disable certificate compression + - BUG/MINOR: ssl: fix error message of tune.ssl.certificate-compression + - MINOR: hlua: Add support for lua 5.5 + - DOC: reg-tests: update VTest upstream link in the starting guide + - BUG/MINOR: ssl: Properly manage alloc failures in SSL passphrase callback + - BUG/MINOR: ssl: Encrypted keys could not be loaded when given alongside certificate + - BUG/MAJOR: applet: Don't call I/O handler if the applet was shut + - DOC: config: mention some possible TLS versions restrictions for kTLS + - BUG/MINOR: stick-tables: abort startup on stk_ctr pool creation failure + - BUG/MINOR: config: check capture pool creations for failures + - BUG/MINOR: config/ssl: fix spelling of "expose-experimental-directives" + - BUG/MEDIUM: ssl: fix msg callbacks on QUIC connections + - BUG/MEDIUM: debug: only dump Lua state when panicking + 2025/12/19 : 3.3.1 - BUG/MEDIUM: mworker/listener: ambiguous use of RX_F_INHERITED with shards - BUG/MINOR: jwt: Missing "case" in switch statement diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/VERDATE new/haproxy-3.3.2+git0.72df9192b/VERDATE --- old/haproxy-3.3.1+git0.9c24c11a6/VERDATE 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/VERDATE 2026-01-29 16:19:50.000000000 +0100 @@ -1,2 +1,2 @@ $Format:%ci$ -2025/12/19 +2026/01/29 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/VERSION new/haproxy-3.3.2+git0.72df9192b/VERSION --- old/haproxy-3.3.1+git0.9c24c11a6/VERSION 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/VERSION 2026-01-29 16:19:50.000000000 +0100 @@ -1 +1 @@ -3.3.1 +3.3.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/addons/promex/service-prometheus.c new/haproxy-3.3.2+git0.72df9192b/addons/promex/service-prometheus.c --- old/haproxy-3.3.1+git0.9c24c11a6/addons/promex/service-prometheus.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/addons/promex/service-prometheus.c 2026-01-29 16:19:50.000000000 +0100 @@ -82,6 +82,7 @@ unsigned field_num; /* current field number (ST_I_PX_* etc) */ unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */ int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */ + struct watcher srv_watch; /* watcher to automatically update next pointer */ struct list modules; /* list of promex modules to export */ struct eb_root filters; /* list of filters to apply on metrics name */ }; @@ -1244,15 +1245,17 @@ if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) goto next_px; - if (!sv) + if (!sv) { + watcher_attach(&ctx->srv_watch, px->srv); sv = px->srv; + } while (sv) { labels[lb_idx].name = ist("server"); labels[lb_idx].value = ist2(sv->id, strlen(sv->id)); if (!stats_fill_sv_line(px, sv, 0, stats, ST_I_PX_MAX, &(ctx->field_num))) - return -1; + goto error; if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT)) goto next_sv; @@ -1397,10 +1400,11 @@ &val, labels, &out, max)) goto full; next_sv: - sv = sv->next; + sv = watcher_next(&ctx->srv_watch, sv->next); } next_px: + watcher_detach(&ctx->srv_watch); px = px->next; } ctx->flags |= PROMEX_FL_METRIC_HDR; @@ -1451,8 +1455,10 @@ if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) goto next_px2; - if (!sv) + if (!sv) { + watcher_attach(&ctx->srv_watch, px->srv); sv = px->srv; + } while (sv) { labels[lb_idx].name = ist("server"); @@ -1467,7 +1473,7 @@ counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod); if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num)) - return -1; + goto error; val = stats[ctx->field_num + ctx->mod_field_num]; metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER); @@ -1477,10 +1483,11 @@ goto full; next_sv2: - sv = sv->next; + sv = watcher_next(&ctx->srv_watch, sv->next); } next_px2: + watcher_detach(&ctx->srv_watch); px = px->next; } ctx->flags |= PROMEX_FL_METRIC_HDR; @@ -1500,11 +1507,6 @@ return -1; /* Unexpected and unrecoverable error */ } - /* Decrement server refcount if it was saved through ctx.p[1]. */ - srv_drop(ctx->p[1]); - if (sv) - srv_take(sv); - /* Save pointers (0=current proxy, 1=current server, 2=current stats module) of the current context */ ctx->p[0] = px; ctx->p[1] = sv; @@ -1513,6 +1515,10 @@ full: ret = 0; goto end; + + error: + watcher_detach(&ctx->srv_watch); + return -1; } /* Dump metrics of module <mod>. It returns 1 on success, 0 if <out> is full and @@ -2027,6 +2033,7 @@ LIST_INIT(&ctx->modules); ctx->filters = EB_ROOT; appctx->st0 = PROMEX_ST_INIT; + watcher_init(&ctx->srv_watch, &ctx->p[1], offsetof(struct server, watcher_list)); return 0; } @@ -2040,10 +2047,8 @@ struct promex_metric_filter *flt; struct eb32_node *node, *next; - if (appctx->st1 == PROMEX_DUMPER_SRV) { - struct server *srv = objt_server(ctx->p[1]); - srv_drop(srv); - } + if (appctx->st1 == PROMEX_DUMPER_SRV) + watcher_detach(&ctx->srv_watch); list_for_each_entry_safe(ref, back, &ctx->modules, list) { LIST_DELETE(&ref->list); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/doc/configuration.txt new/haproxy-3.3.2+git0.72df9192b/doc/configuration.txt --- old/haproxy-3.3.1+git0.9c24c11a6/doc/configuration.txt 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/doc/configuration.txt 2026-01-29 16:19:50.000000000 +0100 @@ -3,7 +3,7 @@ Configuration Manual ---------------------- version 3.3 - 2025/12/19 + 2026/01/29 This document covers the configuration language as implemented in the version @@ -1978,6 +1978,7 @@ - tune.ssl.cachesize - tune.ssl.capture-buffer-size - tune.ssl.capture-cipherlist-size (deprecated) + - tune.ssl.certificate-compression - tune.ssl.default-dh-param - tune.ssl.force-private-cache - tune.ssl.hard-maxrecord @@ -4189,7 +4190,10 @@ zero value here should probably be in the hundreds or thousands to be effective without affecting slightly bogus servers. It is also possible to only kill connections when the CPU usage crosses a certain level, by using - "tune.glitches.kill.cpu-usage". + "tune.glitches.kill.cpu-usage". Note that a graceful close is attempted at + 75% of the configured threshold by advertising a GOAWAY for a future stream. + This ensures that a slightly faulty connection will stop being used after + some time without risking to interrupt ongoing transfers. See also: tune.h2.fe.glitches-threshold, bc_glitches, and tune.glitches.kill.cpu-usage @@ -4246,7 +4250,11 @@ zero value here should probably be in the hundreds or thousands to be effective without affecting slightly bogus clients. It is also possible to only kill connections when the CPU usage crosses a certain level, by using - "tune.glitches.kill.cpu-usage". + "tune.glitches.kill.cpu-usage". Note that a graceful close is attempted at + 75% of the configured threshold by advertising a GOAWAY for a future stream. + This ensures that a slightly non-compliant client will have the opportunity + to create a new connection and continue to work unaffected without ever + triggering the hard close thus risking to interrupt ongoing transfers. See also: tune.h2.be.glitches-threshold, fc_glitches, and tune.glitches.kill.cpu-usage @@ -5207,6 +5215,22 @@ formats. If the value is 0 (default value) the capture is disabled, otherwise a buffer is allocated for each SSL/TLS connection. +tune.ssl.certificate-compression { auto | off } + This setting allows to configure the certificate compression support which is + an extension (RFC 8879) to TLS 1.3. + + When set to "auto" it uses the default value of the TLS library. + + With "off" it tries to explicitely disable the support of the feature. + HAProxy won't try to send compressed certificates anymore nor accept + compressed certificates. + + Configures both backend and frontend sides. + + This keyword is supported by OpenSSL >= 3.2.0. + + The default value is auto. + tune.ssl.default-dh-param <number> Sets the maximum size of the Diffie-Hellman parameters used for generating the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The @@ -17074,7 +17098,9 @@ ktls <on|off> [ EXPERIMENTAL ] Enables or disables ktls for those sockets. If enabled, kTLS will be used if the kernel supports it and the cipher is compatible. This is only - available on Linux kernel 4.17 and above. + available on Linux kernel 4.17 and above. Please note that some network + drivers and/or TLS stacks might restrict kTLS usage to TLS v1.2 only. See + also "force-tlsv12". label <label> Sets an optional label for these sockets. It could be used group sockets by @@ -18321,9 +18347,10 @@ ktls <on|off> [ EXPERIMENTAL ] May be used in the following contexts: tcp, http, log, peers, ring - Enables or disables ktls for those sockets. If enabled, kTLS will be used - if the kernel supports it and the cipher is compatible. - This is only available on Linux. + Enables or disables ktls for those sockets. If enabled, kTLS will be used if + the kernel supports it and the cipher is compatible. This is only available + on Linux 4.17 and above. Please note that some network drivers and/or TLS + stacks might restrict kTLS usage to TLS v1.2 only. See also "force-tlsv12". log-bufsize <bufsize> May be used in the following contexts: log @@ -29760,7 +29787,7 @@ which can represent a client identifier found in a request for instance. - * string [length <len>] + * string [len <len>] A table declared with "type string" will store substrings of up to <len> characters. If the string provided by the pattern extractor is larger than <len>, it will be truncated before @@ -29770,7 +29797,7 @@ limited to 32 characters. Increasing the length can have a non-negligible memory usage impact. - * binary [length <len>] + * binary [len <len>] A table declared with "type binary" will store binary blocks of <len> bytes. If the block provided by the pattern extractor is larger than <len>, it will be truncated before diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/doc/regression-testing.txt new/haproxy-3.3.2+git0.72df9192b/doc/regression-testing.txt --- old/haproxy-3.3.1+git0.9c24c11a6/doc/regression-testing.txt 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/doc/regression-testing.txt 2026-01-29 16:19:50.000000000 +0100 @@ -24,7 +24,7 @@ ------------------------ To use vtest you will have to download and compile the recent vtest -sources found at https://github.com/vtest/VTest. +sources found at https://github.com/vtest/VTest2. To compile vtest: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/include/haproxy/ssl_sock-t.h new/haproxy-3.3.2+git0.72df9192b/include/haproxy/ssl_sock-t.h --- old/haproxy-3.3.1+git0.9c24c11a6/include/haproxy/ssl_sock-t.h 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/include/haproxy/ssl_sock-t.h 2026-01-29 16:19:50.000000000 +0100 @@ -338,6 +338,8 @@ int renegotiate; /* Renegotiate mode (SSL_RENEGOTIATE_ flag) */ char **passphrase_cmd; int passphrase_cmd_args_cnt; + + unsigned int certificate_compression:1; /* allow to explicitely disable certificate compression */ }; /* The order here matters for picking a default context, @@ -361,6 +363,7 @@ const char *path; struct ckch_data *ckch_data; int passphrase_idx; + int callback_called; }; #endif /* USE_OPENSSL */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/reg-tests/ssl/ssl_generate_certificate.vtc new/haproxy-3.3.2+git0.72df9192b/reg-tests/ssl/ssl_generate_certificate.vtc --- old/haproxy-3.3.1+git0.9c24c11a6/reg-tests/ssl/ssl_generate_certificate.vtc 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/reg-tests/ssl/ssl_generate_certificate.vtc 2026-01-29 16:19:50.000000000 +0100 @@ -150,7 +150,7 @@ # Use another SNI - the server certificate should be generated and different # than the default one client c6 -connect ${h1_clearlst_sock} { - txreq -url "/P-384" -hdr "x-sni: unknown-sni.com" + txreq -url "/P-384" -hdr "x-sni: sni-longer-sni-longer-sni-longer.sni-longer-than-64-bytes-unknown-sni.com" rxresp expect resp.status == 200 expect resp.http.x-ssl-sig_alg == "ecdsa-with-SHA256" @@ -165,7 +165,7 @@ # The curve with the highest priority is X25519 for OpenSSL 1.1.1 and later, # and P-256 for OpenSSL 1.0.2. shell { - echo "Q" | openssl s_client -unix "${tmpdir}/ssl.sock" -servername server.ecdsa.com -tls1_2 2>/dev/null | grep -E "Server Temp Key: (ECDH, P-256, 256 bits|ECDH, prime256v1, 256 bits|X25519, 253 bits)" + echo "Q" | openssl s_client -unix "${tmpdir}/ssl.sock" -servername server.ecdsa.com -tls1_2 2>/dev/null | grep -E "(Server|Peer) Temp Key: (ECDH, P-256, 256 bits|ECDH, prime256v1, 256 bits|X25519, 253 bits)" } shell { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/applet.c new/haproxy-3.3.2+git0.72df9192b/src/applet.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/applet.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/applet.c 2026-01-29 16:19:50.000000000 +0100 @@ -848,7 +848,12 @@ input = applet_output_data(app); output = co_data(oc); - app->applet->fct(app); + + /* Don't call I/O handler if the applet was shut (release callback was + * already called) + */ + if (se_fl_test(app->sedesc, SE_FL_SHR | SE_FL_SHW)) + app->applet->fct(app); TRACE_POINT(APPLET_EV_PROCESS, app); @@ -945,7 +950,11 @@ applet_need_more_data(app); applet_have_no_more_data(app); - app->applet->fct(app); + /* Don't call I/O handler if the applet was shut (release callback was + * already called) + */ + if (!applet_fl_test(app, APPCTX_FL_SHUTDOWN)) + app->applet->fct(app); TRACE_POINT(APPLET_EV_PROCESS, app); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/backend.c new/haproxy-3.3.2+git0.72df9192b/src/backend.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/backend.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/backend.c 2026-01-29 16:19:50.000000000 +0100 @@ -1445,9 +1445,9 @@ if (unlikely(!conn || !conn->ctrl || !conn->ctrl->connect)) return SF_ERR_INTERNAL; - if (co_data(&s->res)) + if (co_data(&s->req)) conn_flags |= CONNECT_HAS_DATA; - if (s->conn_retries == s->max_retries) + if (s->conn_retries == 0) conn_flags |= CONNECT_CAN_USE_TFO; if (!conn_ctrl_ready(conn) || !conn_xprt_ready(conn)) { ret = conn->ctrl->connect(conn, conn_flags); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-listen.c new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-listen.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-listen.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-listen.c 2026-01-29 16:19:50.000000000 +0100 @@ -48,7 +48,7 @@ "server-state-file-name", "max-session-srv-conns", "capture", "retries", "http-request", "http-response", "http-after-response", "http-send-name-header", "block", "redirect", "use_backend", - "use-server", "force-persist", "ignore-persist", "force-persist", + "use-server", "force-persist", "ignore-persist", "stick-table", "stick", "stats", "option", "default_backend", "http-reuse", "monitor", "transparent", "maxconn", "backlog", "fullconn", "dispatch", "balance", "hash-type", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-quic.c new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-quic.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-quic.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-quic.c 2026-01-29 16:19:50.000000000 +0100 @@ -498,7 +498,7 @@ char *end_opt; memprintf(err, "'%s' is deprecated in 3.3 and will be removed in 3.5. " - "Please use the newer keyword syntax 'tune.quic.fe.stream.max-concurrent'.", args[0]); + "Please use the newer keyword syntax 'tune.quic.fe.cc.max-win-size'.", args[0]); cwnd = parse_window_size(args[0], args[1], &end_opt, err); if (!cwnd) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-ssl.c new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-ssl.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse-ssl.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/cfgparse-ssl.c 2026-01-29 16:19:50.000000000 +0100 @@ -496,6 +496,36 @@ } #endif +/* Allow to explicitely disable certificate compression when set to "off" */ +#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION +static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + if (too_many_args(1, args, err, NULL)) + return -1; + + if (strcmp(args[1], "auto") == 0) + global_ssl.certificate_compression = 1; + else if (strcmp(args[1], "off") == 0) + global_ssl.certificate_compression = 0; + else { + memprintf(err, "'%s' expects either 'auto' or 'off' but got '%s'.", args[0], args[1]); return -1; + } + + return 0; +} +#else +static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + memprintf(err, "'%s' is not supported by your TLS library. " + "It is known to work only with OpenSSL >= 3.2.0.", args[0]); + return -1; +} +#endif + /* parse "ssl.force-private-cache". * Returns <0 on alert, >0 on warning, 0 on success. */ @@ -943,7 +973,7 @@ return ERR_ALERT | ERR_FATAL; } if (!experimental_directives_allowed) { - memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directive'", args[cur_arg]); + memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[cur_arg]); return ERR_ALERT | ERR_FATAL; } if (!strcasecmp(args[cur_arg + 1], "on")) { @@ -2020,7 +2050,7 @@ } if (!experimental_directives_allowed) { - memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directive'", args[*cur_arg]); + memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[*cur_arg]); return ERR_ALERT | ERR_FATAL; } @@ -2759,6 +2789,7 @@ { CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level }, { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca }, { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int }, + { CFG_GLOBAL, "tune.ssl.certificate-compression", ssl_parse_certificate_compression }, { CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh }, { CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache }, { CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse.c new/haproxy-3.3.2+git0.72df9192b/src/cfgparse.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/cfgparse.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/cfgparse.c 2026-01-29 16:19:50.000000000 +0100 @@ -1534,7 +1534,7 @@ } } } else { - ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "users"); + ha_alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "userlist"); err_code |= ERR_ALERT | ERR_FATAL; } @@ -2637,9 +2637,14 @@ args[arg] = tmp; } else if (strcmp(args[0], "default") == 0) { + char *tmp; + kwm = KWM_DEF; + tmp = args[0]; for (arg=0; *args[arg+1]; arg++) args[arg] = args[arg+1]; // shift args after inversion + *tmp = '\0'; + args[arg] = tmp; } if (kwm != KWM_STD && strcmp(args[0], "option") != 0 && @@ -2834,6 +2839,12 @@ pool_head_capture = create_pool("capture", global.tune.cookie_len, MEM_F_SHARED); + /* both will have already emitted an error message if needed */ + if (!pool_head_requri || !pool_head_capture) { + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + /* Post initialisation of the users and groups lists. */ err_code = userlist_postinit(); if (err_code != ERR_NONE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/cli.c new/haproxy-3.3.2+git0.72df9192b/src/cli.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/cli.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/cli.c 2026-01-29 16:19:50.000000000 +0100 @@ -3732,9 +3732,8 @@ error: list_for_each_entry(child, &proc_list, list) { - free((char *)child->srv->conf.file); /* cast because of const char * */ - free(child->srv->id); - srv_free(&child->srv); + srv_detach(child->srv); + srv_drop(child->srv); } free(msg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/debug.c new/haproxy-3.3.2+git0.72df9192b/src/debug.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/debug.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/debug.c 2026-01-29 16:19:50.000000000 +0100 @@ -605,7 +605,11 @@ chunk_appendf(buf, "%sCurrent executing a Lua HTTP service -- ", pfx); } - if (hlua && hlua->T) { + /* only dump the Lua stack on panic because the approach is often + * destructive and the running program might not recover from this + * if called during warnings or "show threads". + */ + if (hlua && hlua->T && (get_tainted() & TAINTED_PANIC)) { chunk_appendf(buf, "stack traceback:\n "); append_prefixed_str(buf, hlua_traceback(hlua->T, "\n "), pfx, '\n', 0); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/haproxy.c new/haproxy-3.3.2+git0.72df9192b/src/haproxy.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/haproxy.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/haproxy.c 2026-01-29 16:19:50.000000000 +0100 @@ -1,6 +1,6 @@ /* * HAProxy : High Availability-enabled HTTP/TCP proxy - * Copyright 2000-2025 Willy Tarreau <[email protected]>. + * Copyright 2000-2026 Willy Tarreau <[email protected]>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/hlua.c new/haproxy-3.3.2+git0.72df9192b/src/hlua.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/hlua.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/hlua.c 2026-01-29 16:19:50.000000000 +0100 @@ -273,6 +273,7 @@ break; default: /* error was caught */ + lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it return NULL; } return str; @@ -323,6 +324,7 @@ break; default: /* error was caught */ + lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it dst = NULL; } va_end(cpy_argp); @@ -870,6 +872,7 @@ __LJMP static int _hlua_traceback(lua_State *L) { lua_Debug *ar = lua_touserdata(L, 1); + int ret; /* Fill fields: * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what; @@ -877,7 +880,10 @@ * 'n': fills in the field name and namewhat; * 't': fills in the field istailcall; */ - return lua_getinfo(L, "Slnt", ar); + ret = lua_getinfo(L, "Slnt", ar); + if (!ret) + WILL_LJMP(luaL_error(L, "unexpected")); + return 0; } @@ -896,10 +902,11 @@ lua_pushlightuserdata(L, &ar); /* safe getinfo */ - switch (lua_pcall(L, 1, 1, 0)) { + switch (lua_pcall(L, 1, 0, 0)) { case LUA_OK: break; default: + lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it goto end; // abort } @@ -998,6 +1005,7 @@ case LUA_OK: break; default: + lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it ret = 0; } @@ -10188,6 +10196,7 @@ return 1; default: /* error was caught */ + lua_pop(L, 1); // consume the lua object pushed on the stack since we ignore it return 0; } } @@ -14027,7 +14036,11 @@ struct prepend_path *pp; /* Init main lua stack. */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 505 + L = lua_newstate(hlua_alloc, &hlua_global_allocator, luaL_makeseed(0)); +#else L = lua_newstate(hlua_alloc, &hlua_global_allocator); +#endif if (!L) { fprintf(stderr, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/hlua_fcn.c new/haproxy-3.3.2+git0.72df9192b/src/hlua_fcn.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/hlua_fcn.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/hlua_fcn.c 2026-01-29 16:19:50.000000000 +0100 @@ -2796,6 +2796,11 @@ int count = 0; int ret; + if (!lua_istable(L, 2)) { + luaL_argerror(L, 2, "argument is expected to be a table"); + return 0; // not reached + } + if ((ref->flags & HLUA_PATREF_FL_GEN) && pat_ref_may_commit(ref->ptr, ref->curr_gen)) curr_gen = ref->curr_gen; @@ -2808,17 +2813,6 @@ const char *key; const char *value = NULL; - /* check if we may do something to try to prevent thread contention, - * unless we run from body/init state where hlua_yieldk is no-op - */ - if (count > 100 && hlua_gethlua(L)) { - /* let's yield and wait for being called again to continue where we left off */ - HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); - hlua_yieldk(L, 0, 0, _hlua_patref_add_bulk, TICK_ETERNITY, HLUA_CTRLYIELD); // continue - return 0; // not reached - - } - if (ref->ptr->flags & PAT_REF_SMP) { /* key:val table */ luaL_checktype(L, -2, LUA_TSTRING); @@ -2843,6 +2837,17 @@ /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); count += 1; + + /* check if we may do something to try to prevent thread contention, + * unless we run from body/init state where hlua_yieldk is no-op + */ + if (count > 100 && hlua_gethlua(L)) { + /* let's yield and wait for being called again to continue where we left off */ + HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); + hlua_yieldk(L, 0, 0, _hlua_patref_add_bulk, TICK_ETERNITY, HLUA_CTRLYIELD); // continue + return 0; // not reached + + } } HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock); lua_pushboolean(L, 1); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/http_act.c new/haproxy-3.3.2+git0.72df9192b/src/http_act.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/http_act.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/http_act.c 2026-01-29 16:19:50.000000000 +0100 @@ -960,6 +960,12 @@ hdr->namelen = 0; hdr->len = len; hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); + if (!hdr->pool) { + memprintf(err, "out of memory"); + free(hdr); + release_sample_expr(expr); + return ACT_RET_PRS_ERR; + } hdr->index = px->nb_req_cap++; px->req_cap = hdr; @@ -2005,6 +2011,8 @@ } rule->action_ptr = http_action_set_map; rule->release_ptr = release_http_map; + lf_expr_init(&rule->arg.map.key); + lf_expr_init(&rule->arg.map.value); cur_arg = *orig_arg; if (rule->action == 1 && (!*args[cur_arg] || !*args[cur_arg+1])) { @@ -2040,7 +2048,6 @@ } /* key pattern */ - lf_expr_init(&rule->arg.map.key); if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.key, LOG_OPT_NONE, cap, err)) { free(rule->arg.map.ref); return ACT_RET_PRS_ERR; @@ -2049,7 +2056,6 @@ if (rule->action == 1) { /* value pattern for set-map only */ cur_arg++; - lf_expr_init(&rule->arg.map.value); if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.value, LOG_OPT_NONE, cap, err)) { free(rule->arg.map.ref); return ACT_RET_PRS_ERR; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/log.c new/haproxy-3.3.2+git0.72df9192b/src/log.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/log.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/log.c 2026-01-29 16:19:50.000000000 +0100 @@ -6276,7 +6276,10 @@ /* only consider options that are frontend oriented and log oriented, such options may be set * in px->options2 because px->options is already full of tcp/http oriented options + * also, cfg_parse_listen_match_option() assumes global curproxy variable points to + * currently evaluated proxy */ + curproxy = cfg_log_forward; if (cfg_parse_listen_match_option(file, linenum, kwm, cfg_opts3, &err_code, args, PR_MODE_SYSLOG, PR_CAP_FE, &cfg_log_forward->options3, &cfg_log_forward->no_options3)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/mux_h1.c new/haproxy-3.3.2+git0.72df9192b/src/mux_h1.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/mux_h1.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/mux_h1.c 2026-01-29 16:19:50.000000000 +0100 @@ -832,6 +832,14 @@ return ((h1m->state == H1_MSG_DONE) ? 0 : b_data(&h1s->h1c->ibuf)); } +static inline void h1s_consume_kop(struct h1s *h1s, size_t count) +{ + if (h1s->sd->kop > count) + h1s->sd->kop -= count; + else + h1s->sd->kop = 0; +} + /* Creates a new stream connector and the associate stream. <input> is used as input * buffer for the stream. On success, it is transferred to the stream and the * mux is no longer responsible of it. On error, <input> is unchanged, thus the @@ -2432,8 +2440,10 @@ goto end; type = htx_get_blk_type(blk); sz = htx_get_blksz(blk); - if (type == HTX_BLK_UNUSED) + if (type == HTX_BLK_UNUSED) { + htx_remove_blk(htx, blk); continue; + } if (type != HTX_BLK_REQ_SL || sz > count) goto error; break; @@ -2521,8 +2531,10 @@ type = htx_get_blk_type(blk); sz = htx_get_blksz(blk); - if (type == HTX_BLK_UNUSED) + if (type == HTX_BLK_UNUSED) { + htx_remove_blk(htx, blk); continue; + } if (type != HTX_BLK_RES_SL || sz > count) goto error; break; @@ -3045,7 +3057,7 @@ goto error; } h1m->curr_len = (h1s->sd->kop ? h1s->sd->kop : count); - h1s->sd->kop = 0; + h1s_consume_kop(h1s, h1m->curr_len); /* Because chunk meta-data are prepended, the chunk size of the current chunk * must be handled before the end of the previous chunk. @@ -3137,7 +3149,7 @@ h1m->curr_len = 0; goto full; } - h1s->sd->kop = 0; + h1s_consume_kop(h1s, h1m->curr_len); h1m->state = H1_MSG_DATA; } @@ -4908,6 +4920,7 @@ goto out; } h1m->curr_len = count; + h1s_consume_kop(h1s, h1m->curr_len); } else { /* The producer does not know the chunk size, thus this will be emitted at the @@ -5043,11 +5056,13 @@ struct buffer buf = b_make(b_orig(&h1c->obuf), b_size(&h1c->obuf), b_peek_ofs(&h1c->obuf, b_data(&h1c->obuf) - sd->iobuf.data + sd->iobuf.offset), sd->iobuf.data); + h1_prepend_chunk_size(&buf, sd->iobuf.data, sd->iobuf.offset - ((h1m->state == H1_MSG_CHUNK_CRLF) ? 2 : 0)); if (h1m->state == H1_MSG_CHUNK_CRLF) h1_prepend_chunk_crlf(&buf); b_add(&h1c->obuf, sd->iobuf.offset); h1m->state = H1_MSG_CHUNK_CRLF; + h1s_consume_kop(h1s, sd->iobuf.data); } total = sd->iobuf.data; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/mux_h2.c new/haproxy-3.3.2+git0.72df9192b/src/mux_h2.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/mux_h2.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/mux_h2.c 2026-01-29 16:19:50.000000000 +0100 @@ -533,6 +533,7 @@ static int h2_send(struct h2c *h2c); static int h2_recv(struct h2c *h2c); static int h2_process(struct h2c *h2c); +static int h2c_send_goaway_error(struct h2c *h2c, struct h2s *h2s); /* h2_io_cb is exported to see it resolved in "show fd" */ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state); static inline struct h2s *h2c_st_by_id(struct h2c *h2c, int id); @@ -1709,10 +1710,25 @@ h2_be_glitches_threshold : h2_fe_glitches_threshold; h2c->glitches += increment; - if (thres && h2c->glitches >= thres && - (th_ctx->idle_pct <= global.tune.glitch_kill_maxidle)) { - h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM); - return 1; + if (unlikely(thres && h2c->glitches >= (thres * 3 + 1) / 4)) { + /* at 75% of the threshold, we switch to close mode + * to force clients to periodically reconnect. + */ + if (h2c->last_sid <= 0 || + h2c->last_sid > h2c->max_id + 2 * h2c_max_concurrent_streams(h2c)) { + /* not set yet or was too high */ + h2c->last_sid = h2c->max_id + 2 * h2c_max_concurrent_streams(h2c); + h2c_send_goaway_error(h2c, NULL); + } + + /* at 100% of the threshold and excess of CPU usage we also + * actively kill the connection. + */ + if (h2c->glitches >= thres && + (th_ctx->idle_pct <= global.tune.glitch_kill_maxidle)) { + h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM); + return 1; + } } return 0; } @@ -3721,6 +3737,7 @@ } /* stream error : send RST_STREAM */ + h2c_report_glitch(h2c, 1, "couldn't decode response HEADERS"); TRACE_ERROR("couldn't decode response HEADERS", H2_EV_RX_FRAME|H2_EV_RX_HDR, h2c->conn, h2s); h2s_error(h2s, H2_ERR_PROTOCOL_ERROR); h2c->st0 = H2_CS_FRAME_E; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/mux_quic.c new/haproxy-3.3.2+git0.72df9192b/src/mux_quic.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/mux_quic.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/mux_quic.c 2026-01-29 16:19:50.000000000 +0100 @@ -462,6 +462,13 @@ qcs->st = QC_SS_CLO; } + /* Cancel STOP_SENDING emission as it is now unneeded. */ + if (qcs->st == QC_SS_CLO && (qcs->flags & QC_SF_TO_STOP_SENDING)) { + qcs->flags &= ~QC_SF_TO_STOP_SENDING; + /* Remove from send_list. Necessary to ensure BUG_ON() below is not triggered. */ + LIST_DEL_INIT(&qcs->el_send); + } + if (qcs_is_completed(qcs)) { BUG_ON(LIST_INLIST(&qcs->el_send)); TRACE_STATE("add stream in purg_list", QMUX_EV_QCS_RECV, qcs->qcc->conn, qcs); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/mworker.c new/haproxy-3.3.2+git0.72df9192b/src/mworker.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/mworker.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/mworker.c 2026-01-29 16:19:50.000000000 +0100 @@ -509,6 +509,14 @@ mworker_kill(sig); } +/* handle operations that can't be done in the signal handler */ +static struct task *mworker_task_child_failure(struct task *task, void *context, unsigned int state) +{ + mworker_unblock_signals(); + task_destroy(task); + return NULL; +} + /* * Performs some routines for the worker process, which has failed the reload, * updates the global load_status. @@ -516,6 +524,7 @@ static void mworker_on_new_child_failure(int exitpid, int status) { struct mworker_proc *child; + struct task *t; /* increment the number of failed reloads */ list_for_each_entry(child, &proc_list, list) { @@ -532,6 +541,15 @@ * the READY=1 signal still need to be sent */ if (global.tune.options & GTUNE_USE_SYSTEMD) sd_notify(0, "READY=1\nSTATUS=Reload failed!\n"); + + /* call a task to unblock the signals from outside the sig handler */ + if ((t = task_new_here()) == NULL) { + ha_warning("Can't restore HAProxy signals!\n"); + return; + } + + t->process = mworker_task_child_failure; + task_wakeup(t, TASK_WOKEN_MSG); } /* @@ -808,7 +826,7 @@ struct cli_showproc_ctx { int debug; - int next_uptime; /* uptime must be greater than this value */ + int next_reload; /* reload number to resume from, 0 = from the beginning */ }; /* Displays workers and processes */ @@ -826,7 +844,7 @@ chunk_reset(&trash); - if (ctx->next_uptime == 0) { + if (ctx->next_reload == 0) { memprintf(&reloadtxt, "%d [failed: %d]", proc_self->reloads, proc_self->failedreloads); chunk_printf(&trash, "#%-14s %-15s %-15s %-15s %-15s", "<PID>", "<type>", "<reloads>", "<uptime>", "<version>"); if (ctx->debug) @@ -844,12 +862,12 @@ ha_free(&uptime); /* displays current processes */ - if (ctx->next_uptime == 0) + if (ctx->next_reload == 0) chunk_appendf(&trash, "# workers\n"); list_for_each_entry(child, &proc_list, list) { /* don't display current worker if we only need the next ones */ - if (ctx->next_uptime != 0) + if (ctx->next_reload != 0) continue; up = date.tv_sec - child->timestamp; @@ -875,15 +893,16 @@ return 0; /* displays old processes */ - if (old || ctx->next_uptime) { /* there's more */ - if (ctx->next_uptime == 0) + if (old || ctx->next_reload) { /* there's more */ + if (ctx->next_reload == 0) chunk_appendf(&trash, "# old workers\n"); list_for_each_entry(child, &proc_list, list) { up = date.tv_sec - child->timestamp; if (up <= 0) /* must never be negative because of clock drift */ up = 0; - if (child->timestamp < ctx->next_uptime) + /* If we're resuming, skip entries that were already printed (reload >= ctx->next_reload) */ + if (ctx->next_reload && child->reloads >= ctx->next_reload) continue; if (!(child->options & PROC_O_TYPE_WORKER)) @@ -896,17 +915,21 @@ chunk_appendf(&trash, "\t\t %-15d %-15d", child->ipc_fd[0], child->ipc_fd[1]); chunk_appendf(&trash, "\n"); ha_free(&uptime); - } - /* start from there if there's not enough place */ - ctx->next_uptime = child->timestamp; + /* Try to flush so we can resume after this reload on next page if the buffer is full. */ + if (applet_putchk(appctx, &trash) == -1) { + /* resume at this reload (exclude it on next pass) */ + ctx->next_reload = child->reloads; /* resume after entries >= this reload */ + return 0; + } + chunk_reset(&trash); + } - if (applet_putchk(appctx, &trash) == -1) - return 0; } } - /* dump complete */ + /* dump complete: reset resume cursor so next 'show proc' starts from the top */ + ctx->next_reload = 0; return 1; } /* reload the master process */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/peers.c new/haproxy-3.3.2+git0.72df9192b/src/peers.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/peers.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/peers.c 2026-01-29 16:19:50.000000000 +0100 @@ -1212,7 +1212,7 @@ int n = 0; TRACE_ENTER(PEERS_EV_SESS_IO|PEERS_EV_RX_MSG, appctx); - if (applet_get_inbuf(appctx) == NULL || !applet_input_data(appctx)) { + if (applet_get_inbuf(appctx) == NULL) { applet_need_more_data(appctx); goto out; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/proto_sockpair.c new/haproxy-3.3.2+git0.72df9192b/src/proto_sockpair.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/proto_sockpair.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/proto_sockpair.c 2026-01-29 16:19:50.000000000 +0100 @@ -237,12 +237,15 @@ struct iovec iov; struct msghdr msghdr; - char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0}; - char buf[CMSG_SPACE(sizeof(int))] = {0}; + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + char buf[CMSG_SPACE(sizeof(int))]; struct cmsghdr *cmsg = (void *)buf; int *fdptr; + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + memset(buf, 0, sizeof(buf)); + iov.iov_base = iobuf; iov.iov_len = sizeof(iobuf); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/proto_tcp.c new/haproxy-3.3.2+git0.72df9192b/src/proto_tcp.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/proto_tcp.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/proto_tcp.c 2026-01-29 16:19:50.000000000 +0100 @@ -1013,7 +1013,7 @@ static void __proto_tcp_init(void) { -#if defined(__linux__) && !defined(TCP_MD5SIG) +#if defined(__linux__) && defined(TCP_MD5SIG) hap_register_feature("HAVE_TCP_MD5SIG"); #endif } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/proxy.c new/haproxy-3.3.2+git0.72df9192b/src/proxy.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/proxy.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/proxy.c 2026-01-29 16:19:50.000000000 +0100 @@ -320,6 +320,12 @@ EXTRA_COUNTERS_FREE(p->extra_counters_fe); EXTRA_COUNTERS_FREE(p->extra_counters_be); + list_for_each_entry_safe(rule, ruleb, &p->persist_rules, list) { + LIST_DELETE(&rule->list); + free_acl_cond(rule->cond); + free(rule); + } + free_server_rules(&p->server_rules); list_for_each_entry_safe(rule, ruleb, &p->switching_rules, list) { @@ -872,6 +878,11 @@ hdr->namelen = 0; hdr->len = len; hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); + if (!hdr->pool) { + memprintf(err, "out of memory"); + free(hdr); + return -1; + } if (strcmp(args[2], "request") == 0) { hdr->next = curpx->req_cap; @@ -1583,13 +1594,34 @@ */ void proxy_destroy_defaults(struct proxy *px) { + struct proxy *prev; + if (!px) return; if (!(px->cap & PR_CAP_DEF)) return; BUG_ON(px->conf.refcount != 0); + cebis_item_delete((px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name, conf.name_node, id, px); + + /* If orphaned defaults list is not empty, it may contain <px> instance. + * In this case it is necessary to manually remove it from the list. + */ + if (orphaned_default_proxies) { + if (orphaned_default_proxies == px) { + orphaned_default_proxies = px->next; + } + else { + for (prev = orphaned_default_proxies; + prev && prev->next != px; prev = prev->next) + ; + if (prev) + prev->next = px->next; + } + px->next = NULL; + } + proxy_free_defaults(px); free(px); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/quic_frame.c new/haproxy-3.3.2+git0.72df9192b/src/quic_frame.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/quic_frame.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/quic_frame.c 2026-01-29 16:19:50.000000000 +0100 @@ -363,11 +363,16 @@ const unsigned char **pos, const unsigned char *end) { struct qf_ack *ack_frm = &frm->ack; + /* TODO implement ECN advertising */ + uint64_t ect0, ect1, ecn_ce; return quic_dec_int(&ack_frm->largest_ack, pos, end) && - quic_dec_int(&ack_frm->ack_delay, pos, end) && - quic_dec_int(&ack_frm->first_ack_range, pos, end) && - quic_dec_int(&ack_frm->ack_range_num, pos, end); + quic_dec_int(&ack_frm->ack_delay, pos, end) && + quic_dec_int(&ack_frm->ack_range_num, pos, end) && + quic_dec_int(&ack_frm->first_ack_range, pos, end) && + quic_dec_int(&ect0, pos, end) && + quic_dec_int(&ect1, pos, end) && + quic_dec_int(&ecn_ce, pos, end); } /* Encode a RESET_STREAM frame at <pos> buffer position. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/quic_ssl.c new/haproxy-3.3.2+git0.72df9192b/src/quic_ssl.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/quic_ssl.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/quic_ssl.c 2026-01-29 16:19:50.000000000 +0100 @@ -10,6 +10,9 @@ #include <haproxy/ssl_sock.h> #include <haproxy/stats.h> #include <haproxy/trace.h> +#ifdef USE_ECH +#include <haproxy/ech.h> +#endif DECLARE_TYPED_POOL(pool_head_quic_ssl_sock_ctx, "quic_ssl_sock_ctx", struct ssl_sock_ctx); const char *default_quic_ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384" @@ -810,6 +813,20 @@ cfgerr++; #endif +#ifdef USE_ECH + if (bind_conf->ssl_conf.ech_filedir) { + int loaded = 0; + + if (load_echkeys(ctx, bind_conf->ssl_conf.ech_filedir, &loaded) != 1) { + cfgerr += 1; + ha_alert("Proxy '%s': failed to load ECH key s from %s for '%s' at [%s:%d].\n", + bind_conf->frontend->id, bind_conf->ssl_conf.ech_filedir, + bind_conf->arg, bind_conf->file, bind_conf->line); + } + } +#endif + + return cfgerr; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/server.c new/haproxy-3.3.2+git0.72df9192b/src/server.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/server.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/server.c 2026-01-29 16:19:50.000000000 +0100 @@ -3433,8 +3433,9 @@ free_check(&newsrv->agent); free_check(&newsrv->check); MT_LIST_DELETE(&newsrv->global_list); + srv_detach(newsrv); } - srv_free(&newsrv); + srv_drop(newsrv); return i - srv->tmpl_info.nb_low; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_ckch.c new/haproxy-3.3.2+git0.72df9192b/src/ssl_ckch.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_ckch.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/ssl_ckch.c 2026-01-29 16:19:50.000000000 +0100 @@ -593,7 +593,7 @@ BIO *in = NULL; int ret = 1; EVP_PKEY *key = NULL; - struct passphrase_cb_data cb_data = { path, data, 0 }; + struct passphrase_cb_data cb_data = { path, data, 0, 0 }; if (buf) { /* reading from a buffer */ @@ -625,7 +625,7 @@ */ do { key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data); - } while (!key && cb_data.passphrase_idx != -1); + } while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called); if (key == NULL) { memprintf(err, "%sunable to load private key from file '%s'.\n", @@ -667,6 +667,7 @@ HASSL_DH *dh = NULL; STACK_OF(X509) *chain = NULL; struct issuer_chain *issuer_chain = NULL; + struct passphrase_cb_data cb_data = { path, data, 0, 0 }; if (buf) { /* reading from a buffer */ @@ -691,8 +692,18 @@ } } - /* Read Private Key */ - key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + /* Read Private Key + * Since multiple private keys might have different passphrases that are + * stored in a local cache, we want to try all the already known + * passphrases first before raising an error. The passphrase_idx field + * of the cb_data parameter will be modified in the callback and set to + * -1 after the external passphrase tool is called. + */ + /* We don't know yet if the private key requires a password. */ + data->encrypted_privkey = 0; + do { + key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data); + } while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called); /* no need to check for errors here, because the private key could be loaded later */ #ifndef OPENSSL_NO_DH diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_gencert.c new/haproxy-3.3.2+git0.72df9192b/src/ssl_gencert.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_gencert.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/ssl_gencert.c 2026-01-29 16:19:50.000000000 +0100 @@ -141,11 +141,14 @@ /* Set the subject name using the same, but the CN */ name = X509_NAME_dup(name); - if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - (const unsigned char *)servername, - -1, -1, 0) != 1) { - X509_NAME_free(name); - goto mkcert_error; + + if (strlen(servername) <= 64) { + if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (const unsigned char *)servername, + -1, -1, 0) != 1) { + X509_NAME_free(name); + goto mkcert_error; + } } if (X509_set_subject_name(newcrt, name) != 1) { X509_NAME_free(name); @@ -352,6 +355,8 @@ ssl_ctx = (SSL_CTX *)lru->data; if (!ssl_ctx && lru) { ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl); + if (!ssl_ctx) + goto error; lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free); } SSL_set_SSL_CTX(ssl, ssl_ctx); @@ -360,11 +365,14 @@ } else { ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl); + if (!ssl_ctx) + goto error; SSL_set_SSL_CTX(ssl, ssl_ctx); /* No LRU cache, this CTX will be released as soon as the session dies */ SSL_CTX_free(ssl_ctx); return 1; } +error: return 0; } int ssl_sock_generate_certificate_from_conn(struct bind_conf *bind_conf, SSL *ssl) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_sock.c new/haproxy-3.3.2+git0.72df9192b/src/ssl_sock.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/ssl_sock.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/ssl_sock.c 2026-01-29 16:19:50.000000000 +0100 @@ -153,6 +153,9 @@ #ifdef HAVE_ACME .acme_scheduler = 1, #endif +#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION + .certificate_compression = 1, +#endif .renegotiate = SSL_RENEGOTIATE_DFLT, .passphrase_cmd = NULL, .passphrase_cmd_args_cnt = 0, @@ -1803,11 +1806,15 @@ /* test heartbeat received (write_p is set to 0 for a received record) */ if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0)) { - struct ssl_sock_ctx *ctx = __conn_get_ssl_sock_ctx(conn); + struct ssl_sock_ctx *ctx = NULL; const unsigned char *p = buf; unsigned int payload; - ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT; + /* <conn> may be NULL in QUIC context */ + if (conn) { + ctx = __conn_get_ssl_sock_ctx(conn); + ctx->xprt_st |= SSL_SOCK_RECV_HEARTBEAT; + } /* Check if this is a CVE-2014-0160 exploitation attempt. */ if (*p != TLS1_HB_REQUEST) @@ -2158,12 +2165,6 @@ struct connection *conn = ssl_sock_get_conn(ssl, NULL); struct ssl_sock_msg_callback *cbk; - /* The connection be NULL only for QUIC which does not free its SSL object - * as this done for TCP. - */ - if (!conn) - return; - /* Try to call all callback functions that were registered by using * ssl_sock_register_msg_callback(). */ @@ -3813,6 +3814,8 @@ if (!data || data->passphrase_idx == -1) return -1; + data->callback_called = 1; + ckch_data = data->ckch_data; if (ckch_data) @@ -3832,13 +3835,16 @@ global_ssl.passphrase_cmd[1] = strdup(data->path); if (!global_ssl.passphrase_cmd[1]) { + data->passphrase_idx = -1; ha_alert("ssl_sock_passwd_cb: allocation failure\n"); return -1; } if (!passphrase_cache) - if (ssl_sock_create_passphrase_cache()) + if (ssl_sock_create_passphrase_cache()) { + data->passphrase_idx = -1; return -1; + } /* Try all the already known passphrases first. */ if (data->passphrase_idx < passphrase_idx) { @@ -4074,6 +4080,11 @@ options |= SSL_OP_NO_RENEGOTIATION; #endif +#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION + if (global_ssl.certificate_compression == 0) + options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION; +#endif + SSL_CTX_set_options(ctx, options); #ifdef SSL_MODE_ASYNC @@ -4462,7 +4473,7 @@ static void SSL_CTX_keylog(const SSL *ssl, const char *line) { struct ssl_keylog *keylog; - char *lastarg = NULL; + const char *lastarg = NULL; char *dst = NULL; #ifdef USE_QUIC_OPENSSL_COMPAT @@ -5127,6 +5138,11 @@ options &= ~SSL_OP_NO_RENEGOTIATION; #endif +#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION + if (global_ssl.certificate_compression == 0) + options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION; +#endif + SSL_CTX_set_options(ctx, options); #ifdef SSL_MODE_ASYNC diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/stconn.c new/haproxy-3.3.2+git0.72df9192b/src/stconn.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/stconn.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/stconn.c 2026-01-29 16:19:50.000000000 +0100 @@ -1351,6 +1351,7 @@ flags |= CO_RFL_BUF_FLUSH; goto abort_fastfwd; } + sc_ep_fwd_kip(sc, sc_opposite(sc)); ret = conn->mux->fastfwd(sc, ic->to_forward, flags); if (ret < 0) goto abort_fastfwd; @@ -2033,6 +2034,7 @@ flags |= CO_RFL_BUF_FLUSH; goto abort_fastfwd; } + sc_ep_fwd_kip(sc, sc_opposite(sc)); ret = appctx_fastfwd(sc, ic->to_forward, flags); if (ret < 0) goto abort_fastfwd; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/stick_table.c new/haproxy-3.3.2+git0.72df9192b/src/stick_table.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/stick_table.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/stick_table.c 2026-01-29 16:19:50.000000000 +0100 @@ -5968,7 +5968,9 @@ f = find_sample_fetch("src", strlen("src")); if (f) smp_fetch_src = f->process; - stkt_create_stk_ctr_pool(); + + if (stkt_create_stk_ctr_pool() & (ERR_ABORT | ERR_FATAL)) + exit(1); // error already reported by the function for (i = 0; i < CONFIG_HAP_TBL_BUCKETS; i++) { MT_LIST_INIT(&per_bucket[i].toadd_tables); @@ -5990,7 +5992,7 @@ static struct cli_kw_list cli_kws = {{ },{ { { "clear", "table", NULL }, "clear table <table> [<filter>]* : remove an entry from a table (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_CLR }, { { "set", "table", NULL }, "set table <table> key <k> [data.* <v>]* : update or create a table entry's data", cli_parse_table_req, cli_io_handler_table, NULL, (void *)STK_CLI_ACT_SET }, - { { "show", "table", NULL }, "show table <table> [<filter>]* : report table usage stats or dump this table's contents (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW }, + { { "show", "table", NULL }, "show table [<table> [<filter>]*] : report table usage stats or dump this table's contents (filter: data/key)", cli_parse_table_req, cli_io_handler_table, cli_release_show_table, (void *)STK_CLI_ACT_SHOW }, {{},} }}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/tcp_rules.c new/haproxy-3.3.2+git0.72df9192b/src/tcp_rules.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/tcp_rules.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/tcp_rules.c 2026-01-29 16:19:50.000000000 +0100 @@ -970,6 +970,12 @@ hdr->namelen = 0; hdr->len = len; hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); + if (!hdr->pool) { + memprintf(err, "parsing [%s:%d] : out of memory", file, line); + free(hdr); + release_sample_expr(expr); + return -1; + } hdr->index = curpx->nb_req_cap++; curpx->req_cap = hdr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.1+git0.9c24c11a6/src/tools.c new/haproxy-3.3.2+git0.72df9192b/src/tools.c --- old/haproxy-3.3.1+git0.9c24c11a6/src/tools.c 2025-12-19 16:43:34.000000000 +0100 +++ new/haproxy-3.3.2+git0.72df9192b/src/tools.c 2026-01-29 16:19:50.000000000 +0100 @@ -7182,7 +7182,7 @@ */ char *fgets_from_mem(char* buf, int size, const char **position, const char *end) { - char *new_pos; + const char *new_pos; int len = 0; /* keep fgets behaviour */
