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-02-20 17:42:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/haproxy (Old) and /work/SRC/openSUSE:Factory/.haproxy.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "haproxy" Fri Feb 20 17:42:06 2026 rev:177 rq:1333967 version:3.3.4+git0.c2bffae0a Changes: -------- --- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes 2026-02-12 17:30:57.244416434 +0100 +++ /work/SRC/openSUSE:Factory/.haproxy.new.1977/haproxy.changes 2026-02-20 17:44:19.191652878 +0100 @@ -1,0 +2,38 @@ +Thu Feb 19 13:52:23 UTC 2026 - Marcus Rueckert <[email protected]> + +- Update to version 3.3.4+git0.c2bffae0a: + * [RELEASE] Released version 3.3.4 + * BUG/MINOR: backend: check delay MUX before conn_prepare() + * BUG/MINOR: acme: fix X509_NAME leak when X509_set_issuer_name() fails + * CLEANUP: mux-h1: Remove unneeded null check + * BUG/MEDIUM: ssl: SSL backend sessions used after free + * CI: github: disable windows.yml by default on unofficials repo + * CI: vtest: move the vtest2 URL to vinyl-cache.org + * MINOR: stconn: Add missing SC_FL_NO_FASTFWD flag in sc_show_flags + * BUG/MINOR: http-ana: Stop to wait for body on client error/abort + * CLEANUP: compression: Remove unused static buffers + * BUG/MINOR: flt-trace: Properly compute length of the first DATA block + * DEV: term-events: Fix hanshake events decoding + * BUG/MEDIUM: applet: Fix test on shut flags for legacy applets (v2) + * BUG/MEDIUM: mux-h1: Stop sending vi fast-forward for unexpected states + * BUG/MEDIUM: mux-h2/quic: Stop sending via fast-forward if stream is closed + * BUG/MEDIUM: h3: reject frontend CONNECT as currently not implemented + * BUG/MAJOR: Revert "MEDIUM: mux-quic: add BUG_ON if sending on locally closed QCS" + * BUG/MINOR: ssl: error with ssl-f-use when no "crt" + * BUG/MINOR: ssl: clarify ssl-f-use errors in post-section parsing + * BUG/MINOR: ssl: fix leak in ssl-f-use parser upon error + * BUG/MINOR: ssl: double-free on error path w/ ssl-f-use parser + * BUG/MINOR: ssl: lack crtlist_dup_ssl_conf() declaration + * BUG/MINOR: deviceatlas: set cache_size on hot-reloaded atlas instance + * BUG/MINOR: deviceatlas: fix deinit to only finalize when initialized + * BUG/MINOR: deviceatlas: fix resource leak on hot-reload compile failure + * BUG/MINOR: deviceatlas: fix double-checked locking race in checkinst + * BUG/MINOR: deviceatlas: fix cookie vlen using wrong length after extraction + * BUG/MINOR: deviceatlas: fix off-by-one in da_haproxy_conv() + * BUG/MEDIUM: deviceatlas: fix resource leaks on init error paths + * BUG/MINOR: deviceatlas: add NULL checks on strdup() results in config parsers + * BUG/MINOR: deviceatlas: add missing return on error in config parsers + * DOC: proxy-proto: underline the packed attribute for struct pp2_tlv_ssl + * DOC: internals: addd mworker V3 internals + +------------------------------------------------------------------- Old: ---- haproxy-3.3.3+git0.465d8e2fc.tar.gz New: ---- haproxy-3.3.4+git0.c2bffae0a.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ haproxy.spec ++++++ --- /var/tmp/diff_new_pack.1zu7RP/_old 2026-02-20 17:44:21.947768719 +0100 +++ /var/tmp/diff_new_pack.1zu7RP/_new 2026-02-20 17:44:21.951768886 +0100 @@ -49,7 +49,7 @@ %bcond_with ech Name: haproxy -Version: 3.3.3+git0.465d8e2fc +Version: 3.3.4+git0.c2bffae0a Release: 0 # Summary: The Reliable, High Performance TCP/HTTP Load Balancer ++++++ _service ++++++ --- /var/tmp/diff_new_pack.1zu7RP/_old 2026-02-20 17:44:22.139776789 +0100 +++ /var/tmp/diff_new_pack.1zu7RP/_new 2026-02-20 17:44:22.143776957 +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.3</param> + <param name="revision">v3.3.4</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.1zu7RP/_old 2026-02-20 17:44:22.215779983 +0100 +++ /var/tmp/diff_new_pack.1zu7RP/_new 2026-02-20 17:44:22.219780151 +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">465d8e2fcfcbf4bbcf36c3f53a801369f4e7e922</param> + <param name="changesrevision">c2bffae0a2a44f7562c6ebd455cd8d2e79001fff</param> </service> </servicedata> (No newline at EOF) ++++++ haproxy-3.3.3+git0.465d8e2fc.tar.gz -> haproxy-3.3.4+git0.c2bffae0a.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/.github/workflows/windows.yml new/haproxy-3.3.4+git0.c2bffae0a/.github/workflows/windows.yml --- old/haproxy-3.3.3+git0.465d8e2fc/.github/workflows/windows.yml 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/.github/workflows/windows.yml 2026-02-19 14:03:31.000000000 +0100 @@ -18,6 +18,7 @@ msys2: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} + if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }} defaults: run: shell: msys2 {0} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG new/haproxy-3.3.4+git0.c2bffae0a/CHANGELOG --- old/haproxy-3.3.3+git0.465d8e2fc/CHANGELOG 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/CHANGELOG 2026-02-19 14:03:31.000000000 +0100 @@ -1,6 +1,40 @@ ChangeLog : =========== +2026/02/19 : 3.3.4 + - DOC: internals: addd mworker V3 internals + - DOC: proxy-proto: underline the packed attribute for struct pp2_tlv_ssl + - BUG/MINOR: deviceatlas: add missing return on error in config parsers + - BUG/MINOR: deviceatlas: add NULL checks on strdup() results in config parsers + - BUG/MEDIUM: deviceatlas: fix resource leaks on init error paths + - BUG/MINOR: deviceatlas: fix off-by-one in da_haproxy_conv() + - BUG/MINOR: deviceatlas: fix cookie vlen using wrong length after extraction + - BUG/MINOR: deviceatlas: fix double-checked locking race in checkinst + - BUG/MINOR: deviceatlas: fix resource leak on hot-reload compile failure + - BUG/MINOR: deviceatlas: fix deinit to only finalize when initialized + - BUG/MINOR: deviceatlas: set cache_size on hot-reloaded atlas instance + - BUG/MINOR: ssl: lack crtlist_dup_ssl_conf() declaration + - BUG/MINOR: ssl: double-free on error path w/ ssl-f-use parser + - BUG/MINOR: ssl: fix leak in ssl-f-use parser upon error + - BUG/MINOR: ssl: clarify ssl-f-use errors in post-section parsing + - BUG/MINOR: ssl: error with ssl-f-use when no "crt" + - BUG/MAJOR: Revert "MEDIUM: mux-quic: add BUG_ON if sending on locally closed QCS" + - BUG/MEDIUM: h3: reject frontend CONNECT as currently not implemented + - BUG/MEDIUM: mux-h2/quic: Stop sending via fast-forward if stream is closed + - BUG/MEDIUM: mux-h1: Stop sending vi fast-forward for unexpected states + - BUG/MEDIUM: applet: Fix test on shut flags for legacy applets (v2) + - DEV: term-events: Fix hanshake events decoding + - BUG/MINOR: flt-trace: Properly compute length of the first DATA block + - CLEANUP: compression: Remove unused static buffers + - BUG/MINOR: http-ana: Stop to wait for body on client error/abort + - MINOR: stconn: Add missing SC_FL_NO_FASTFWD flag in sc_show_flags + - CI: vtest: move the vtest2 URL to vinyl-cache.org + - CI: github: disable windows.yml by default on unofficials repo + - BUG/MEDIUM: ssl: SSL backend sessions used after free + - CLEANUP: mux-h1: Remove unneeded null check + - BUG/MINOR: acme: fix X509_NAME leak when X509_set_issuer_name() fails + - BUG/MINOR: backend: check delay MUX before conn_prepare() + 2026/02/12 : 3.3.3 - MEDIUM: h1: strictly verify quoting in chunk extensions - DOC: internals: cleanup few typos in master-worker documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/VERDATE new/haproxy-3.3.4+git0.c2bffae0a/VERDATE --- old/haproxy-3.3.3+git0.465d8e2fc/VERDATE 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/VERDATE 2026-02-19 14:03:31.000000000 +0100 @@ -1,2 +1,2 @@ $Format:%ci$ -2026/02/12 +2026/02/19 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/VERSION new/haproxy-3.3.4+git0.c2bffae0a/VERSION --- old/haproxy-3.3.3+git0.465d8e2fc/VERSION 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/VERSION 2026-02-19 14:03:31.000000000 +0100 @@ -1 +1 @@ -3.3.3 +3.3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/addons/deviceatlas/da.c new/haproxy-3.3.4+git0.c2bffae0a/addons/deviceatlas/da.c --- old/haproxy-3.3.3+git0.465d8e2fc/addons/deviceatlas/da.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/addons/deviceatlas/da.c 2026-02-19 14:03:31.000000000 +0100 @@ -57,6 +57,10 @@ return -1; } global_deviceatlas.jsonpath = strdup(args[1]); + if (unlikely(global_deviceatlas.jsonpath == NULL)) { + memprintf(err, "deviceatlas json file : out of memory.\n"); + return -1; + } return 0; } @@ -73,6 +77,7 @@ loglevel = atol(args[1]); if (loglevel < 0 || loglevel > 3) { memprintf(err, "deviceatlas log level : expects a log level between 0 and 3, %s given.\n", args[1]); + return -1; } else { global_deviceatlas.loglevel = (da_severity_t)loglevel; } @@ -101,6 +106,10 @@ return -1; } else { global_deviceatlas.cookiename = strdup(args[1]); + if (unlikely(global_deviceatlas.cookiename == NULL)) { + memprintf(err, "deviceatlas cookie name : out of memory.\n"); + return -1; + } } global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename); return 0; @@ -119,6 +128,7 @@ cachesize = atol(args[1]); if (cachesize < 0 || cachesize > DA_CACHE_MAX) { memprintf(err, "deviceatlas cache size : expects a cache size between 0 and %d, %s given.\n", DA_CACHE_MAX, args[1]); + return -1; } else { #ifdef APINOCACHE fprintf(stdout, "deviceatlas cache size : no-op, its support is disabled.\n"); @@ -180,6 +190,8 @@ if (status != DA_OK) { ha_alert("deviceatlas : '%s' json file is invalid.\n", global_deviceatlas.jsonpath); + free(global_deviceatlas.atlasimgptr); + da_fini(); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -189,6 +201,8 @@ if (status != DA_OK) { ha_alert("deviceatlas : data could not be compiled.\n"); + free(global_deviceatlas.atlasimgptr); + da_fini(); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -197,6 +211,14 @@ if (global_deviceatlas.cookiename == 0) { global_deviceatlas.cookiename = strdup(DA_COOKIENAME_DEFAULT); + if (unlikely(global_deviceatlas.cookiename == NULL)) { + ha_alert("deviceatlas : out of memory.\n"); + da_atlas_close(&global_deviceatlas.atlas); + free(global_deviceatlas.atlasimgptr); + da_fini(); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename); } @@ -231,15 +253,13 @@ free(global_deviceatlas.cookiename); da_atlas_close(&global_deviceatlas.atlas); free(global_deviceatlas.atlasimgptr); + da_fini(); } if (global_deviceatlas.atlasfd != -1) { munmap(global_deviceatlas.atlasmap, ATLASTOKSZ); close(global_deviceatlas.atlasfd); - shm_unlink(ATLASMAPNM); } - - da_fini(); } static void da_haproxy_checkinst(void) @@ -258,6 +278,10 @@ da_property_decl_t extraprops[1] = {{NULL, 0}}; #ifdef USE_THREAD HA_SPIN_LOCK(OTHER_LOCK, &dadwsch_lock); + if (base[0] == 0) { + HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock); + return; + } #endif strlcpy2(atlasp, base + sizeof(char), sizeof(atlasp)); jsonp = fopen(atlasp, "r"); @@ -275,6 +299,7 @@ fclose(jsonp); if (status == DA_OK) { if (da_atlas_open(&inst, extraprops, cnew, atlassz) == DA_OK) { + inst.config.cache_size = global_deviceatlas.cachesize; da_atlas_close(&global_deviceatlas.atlas); free(global_deviceatlas.atlasimgptr); global_deviceatlas.atlasimgptr = cnew; @@ -286,6 +311,8 @@ ha_alert("deviceatlas : instance update failed.\n"); free(cnew); } + } else { + free(cnew); } #ifdef USE_THREAD HA_SPIN_UNLOCK(OTHER_LOCK, &dadwsch_lock); @@ -371,8 +398,7 @@ { da_deviceinfo_t devinfo; da_status_t status; - const char *useragent; - char useragentbuf[1024] = { 0 }; + char useragentbuf[1024]; int i; if (global_deviceatlas.daset == 0 || smp->data.u.str.data == 0) { @@ -381,14 +407,12 @@ da_haproxy_checkinst(); - i = smp->data.u.str.data > sizeof(useragentbuf) ? sizeof(useragentbuf) : smp->data.u.str.data; - memcpy(useragentbuf, smp->data.u.str.area, i - 1); - useragentbuf[i - 1] = 0; - - useragent = (const char *)useragentbuf; + i = smp->data.u.str.data > sizeof(useragentbuf) - 1 ? sizeof(useragentbuf) - 1 : smp->data.u.str.data; + memcpy(useragentbuf, smp->data.u.str.area, i); + useragentbuf[i] = 0; status = da_search(&global_deviceatlas.atlas, &devinfo, - global_deviceatlas.useragentid, useragent, 0); + global_deviceatlas.useragentid, useragentbuf, 0); return status != DA_OK ? 0 : da_haproxy(args, smp, &devinfo); } @@ -445,13 +469,12 @@ memcpy(hbuf, n.ptr, n.len); hbuf[n.len] = 0; - pval = v.ptr; - vlen = v.len; evid = -1; i = v.len > sizeof(tval) - 1 ? sizeof(tval) - 1 : v.len; memcpy(tval, v.ptr, i); tval[i] = 0; pval = tval; + vlen = i; if (strcasecmp(hbuf, "Accept-Language") == 0) { evid = da_atlas_accept_language_evidence_id(&global_deviceatlas.atlas); @@ -469,7 +492,7 @@ continue; } - vlen -= global_deviceatlas.cookienamelen - 1; + vlen = pl; pval = p; evid = da_atlas_clientprop_evidence_id(&global_deviceatlas.atlas); } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/dev/term_events/term_events.c new/haproxy-3.3.4+git0.c2bffae0a/dev/term_events/term_events.c --- old/haproxy-3.3.3+git0.465d8e2fc/dev/term_events/term_events.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/dev/term_events/term_events.c 2026-02-19 14:03:31.000000000 +0100 @@ -30,10 +30,10 @@ }; static const char *tevt_hs_types[16] = { - [ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "rcv_err", - [ 4] = "snd_err", [ 5] = "-", [ 6] = "-", [ 7] = "-", - [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-", - [12] = "-", [13] = "-", [14] = "-", [15] = "-", + [ 0] = "-", [ 1] = "-", [ 2] = "-", [ 3] = "-", + [ 4] = "snd_err", [ 5] = "truncated_shutr", [ 6] = "truncated_rcv_err", [ 7] = "-", + [ 8] = "-", [ 9] = "-", [10] = "-", [11] = "-", + [12] = "-", [13] = "-", [14] = "-", [15] = "-", }; static const char *tevt_xprt_types[16] = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt new/haproxy-3.3.4+git0.c2bffae0a/doc/configuration.txt --- old/haproxy-3.3.3+git0.465d8e2fc/doc/configuration.txt 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/doc/configuration.txt 2026-02-19 14:03:31.000000000 +0100 @@ -3,7 +3,7 @@ Configuration Manual ---------------------- version 3.3 - 2026/02/12 + 2026/02/19 This document covers the configuration language as implemented in the version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/doc/internals/mworker.md new/haproxy-3.3.4+git0.c2bffae0a/doc/internals/mworker.md --- old/haproxy-3.3.3+git0.465d8e2fc/doc/internals/mworker.md 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/doc/internals/mworker.md 2026-02-19 14:03:31.000000000 +0100 @@ -208,3 +208,38 @@ Version 3.0 got rid of the libsystemd dependencies for sd_notify() after the events of xz/openssh, the function is now implemented directly in haproxy in src/systemd.c. + +### mworker V3 + +This version was implemented with HAProxy 3.1, the goal was to stop parsing and +applying the configuration in the master process. + +One of the caveats of the previous implementation was that the parser could take +a lot of time, and the master process would be stuck in the parser instead of +handling its polling loop, signals etc. Some parts of the configuration parsing +could also be less reliable with third-party code (EXTRA_OBJS), it could, for +example, allow opening FDs and not closing them before the reload which +would crash the master after a few reloads. + +The startup of the master-worker was reorganized this way: + +- the "discovery" mode, which is a lighter configuration parsing step, only + applies the configuration which need to be effective for the master process. + For example, "master-worker", "mworker-max-reloads" and less than 20 other + keywords that are identified by KWF_DISCOVERY in the code. It is really fast + as it don't need all the configuration to be applied in the master process. + +- the master will then fork a worker, with a PROC_O_INIT flag. This worker has + a temporary sockpair connected to the master CLI. Once the worker is forked, + the master initializes its configuration and starts its polling loop. + +- The newly forked worker will try to parse the configuration, which could + result in a failure (exit 1), or any bad error code. In case of success, the + worker will send a "READY" message to the master CLI then close this FD. At + this step everything was initialized and the worker can enter its polling + loop. + +- The master then waits for the worker, it could: + * receive the READY message over the mCLI, resulting in a successful loading + of haproxy + * receive a SIGCHLD, meaning the worker exited and couldn't load diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/doc/proxy-protocol.txt new/haproxy-3.3.4+git0.c2bffae0a/doc/proxy-protocol.txt --- old/haproxy-3.3.3+git0.465d8e2fc/doc/proxy-protocol.txt 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/doc/proxy-protocol.txt 2026-02-19 14:03:31.000000000 +0100 @@ -625,7 +625,10 @@ uint8_t client; uint32_t verify; struct pp2_tlv sub_tlv[0]; - }; + } __attribute__((packed)); + +Note the "packed" attribute which indicates that each field starts immediately +after the previous one (i.e. without type-specific alignment nor padding). The <verify> field will be zero if the client presented a certificate and it was successfully verified, and non-zero otherwise. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/qmux_http.h new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/qmux_http.h --- old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/qmux_http.h 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/qmux_http.h 2026-02-19 14:03:31.000000000 +0100 @@ -13,6 +13,7 @@ size_t qcs_http_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, char *fin); +size_t qcs_http_reset_buf(struct qcs *qcs, struct buffer *buf, size_t count); #endif /* USE_QUIC */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_crtlist.h new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/ssl_crtlist.h --- old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/ssl_crtlist.h 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/ssl_crtlist.h 2026-02-19 14:03:31.000000000 +0100 @@ -28,6 +28,7 @@ /* crt-list entry functions */ void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf); +struct ssl_bind_conf *crtlist_dup_ssl_conf(struct ssl_bind_conf *src); char **crtlist_dup_filters(char **args, int fcount); void crtlist_free_filters(char **args); void crtlist_entry_free(struct crtlist_entry *entry); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/stconn-t.h new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/stconn-t.h --- old/haproxy-3.3.3+git0.465d8e2fc/include/haproxy/stconn-t.h 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/include/haproxy/stconn-t.h 2026-02-19 14:03:31.000000000 +0100 @@ -224,7 +224,7 @@ _(SC_FL_NEED_BUFF, _(SC_FL_NEED_ROOM, _(SC_FL_RCV_ONCE, _(SC_FL_SND_ASAP, _(SC_FL_SND_NEVERWAIT, _(SC_FL_SND_EXP_MORE, _(SC_FL_ABRT_WANTED, _(SC_FL_SHUT_WANTED, _(SC_FL_ABRT_DONE, _(SC_FL_SHUT_DONE, - _(SC_FL_EOS, _(SC_FL_HAVE_BUFF)))))))))))))))))))); + _(SC_FL_EOS, _(SC_FL_HAVE_BUFF, _(SC_FL_NO_FASTFWD))))))))))))))))))))); /* epilogue */ _(~0U); return buf; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/scripts/build-vtest.sh new/haproxy-3.3.4+git0.c2bffae0a/scripts/build-vtest.sh --- old/haproxy-3.3.3+git0.465d8e2fc/scripts/build-vtest.sh 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/scripts/build-vtest.sh 2026-02-19 14:03:31.000000000 +0100 @@ -2,7 +2,7 @@ set -eux -curl -fsSL https://github.com/vtest/VTest2/archive/main.tar.gz -o VTest.tar.gz +curl -fsSL "https://code.vinyl-cache.org/vtest/VTest2/archive/main.tar.gz" -o VTest.tar.gz mkdir ../vtest tar xvf VTest.tar.gz -C ../vtest --strip-components=1 # Special flags due to: https://github.com/vtest/VTest/issues/12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/acme.c new/haproxy-3.3.4+git0.c2bffae0a/src/acme.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/acme.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/acme.c 2026-02-19 14:03:31.000000000 +0100 @@ -2681,8 +2681,10 @@ goto mkcert_error; } /* Set issuer name as itself */ - if (X509_set_issuer_name(newcrt, name) != 1) + if (X509_set_issuer_name(newcrt, name) != 1) { + X509_NAME_free(name); goto mkcert_error; + } X509_NAME_free(name); /* Autosign the certificate with the private key */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/applet.c new/haproxy-3.3.4+git0.c2bffae0a/src/applet.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/applet.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/applet.c 2026-02-19 14:03:31.000000000 +0100 @@ -852,7 +852,7 @@ /* 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)) + if (!se_fl_test(app->sedesc, SE_FL_SHR) || !se_fl_test(app->sedesc, SE_FL_SHW)) app->applet->fct(app); TRACE_POINT(APPLET_EV_PROCESS, app); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/backend.c new/haproxy-3.3.4+git0.c2bffae0a/src/backend.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/backend.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/backend.c 2026-02-19 14:03:31.000000000 +0100 @@ -2058,6 +2058,25 @@ srv_conn->sni_hash = ssl_sock_sni_hash(sni); } } + +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) + /* Delay mux initialization if SSL and ALPN/NPN is set + * and server cache is not yet populated. Note that in + * TCP mode this check is ignored as only mux-pt is + * available. + * + * This check must be performed before conn_prepare() + * to ensure consistency accross the whole stack, in + * particular for QUIC between quic-conn and mux layer. + */ + HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock); + if (IS_HTX_STRM(s) && srv->use_ssl && + (srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str) && + srv->path_params.nego_alpn[0] == 0) + may_start_mux_now = 0; + HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); +#endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */ + #endif /* USE_OPENSSL */ if (conn_prepare(srv_conn, proto, srv->xprt)) { @@ -2090,21 +2109,6 @@ } srv_conn->ctx = s->scb; -#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation) - /* Delay mux initialization if SSL and ALPN/NPN is set. Note - * that this is skipped in TCP mode as we only want mux-pt - * anyway. - */ - if (srv) { - HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock); - if (IS_HTX_STRM(s) && srv->use_ssl && - (srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str) && - srv->path_params.nego_alpn[0] == 0) - may_start_mux_now = 0; - HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); - } -#endif - /* process the case where the server requires the PROXY protocol to be sent */ srv_conn->send_proxy_ofs = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/cfgparse-ssl.c new/haproxy-3.3.4+git0.c2bffae0a/src/cfgparse-ssl.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/cfgparse-ssl.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/cfgparse-ssl.c 2026-02-19 14:03:31.000000000 +0100 @@ -2558,11 +2558,14 @@ } /* must set the ssl_conf in case of duplication of the crtlist_entry */ - entry->ssl_conf = n->ssl_conf; + entry->ssl_conf = crtlist_dup_ssl_conf(n->ssl_conf); err_code |= crtlist_load_crt(n->ckch_conf->crt, n->ckch_conf, newlist, entry, n->filename, n->linenum, &err); - if (err_code & ERR_CODE) + if (err_code & ERR_CODE) { + ha_alert("parsing [%s:%d] : %s", n->filename, n->linenum, err); + ha_free(&err); goto error; + } LIST_DELETE(&n->list); /* n->ssl_conf is reused so we don't free them here */ @@ -2574,7 +2577,8 @@ if (newlist) { if (ebst_insert(&crtlists_tree, &newlist->node) != &newlist->node) { - memprintf(&err, "Couldn't create the crt-list '%s', this name is already used by another crt-list!", crtlist_name); + memprintf(&err, "parsing [%s:%d] : Couldn't create the crt-list '%s', this name is already used by another crt-list!", + curproxy->conf.file, curproxy->conf.line, crtlist_name); err_code |= ERR_ALERT | ERR_FATAL; goto error; } @@ -2594,10 +2598,11 @@ error: if (err) - ha_alert("%s.\n", err); + ha_alert("%s", err); free(err); list_for_each_entry_safe(n, r, &cur_crtlist, list) { + ha_free(&n->filename); ckch_conf_clean(n->ckch_conf); ha_free(&n->ckch_conf); ssl_sock_free_ssl_conf(n->ssl_conf); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/flt_http_comp.c new/haproxy-3.3.4+git0.c2bffae0a/src/flt_http_comp.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/flt_http_comp.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/flt_http_comp.c 2026-02-19 14:03:31.000000000 +0100 @@ -44,9 +44,6 @@ /* Pools used to allocate comp_state structs */ DECLARE_STATIC_TYPED_POOL(pool_head_comp_state, "comp_state", struct comp_state); -static THREAD_LOCAL struct buffer tmpbuf; -static THREAD_LOCAL struct buffer zbuf; - static int select_compression_request_header(struct comp_state *st, struct stream *s, struct http_msg *msg); @@ -71,25 +68,6 @@ } static int -comp_flt_init_per_thread(struct proxy *px, struct flt_conf *fconf) -{ - if (b_alloc(&tmpbuf, DB_PERMANENT) == NULL) - return -1; - if (b_alloc(&zbuf, DB_PERMANENT) == NULL) - return -1; - return 0; -} - -static void -comp_flt_deinit_per_thread(struct proxy *px, struct flt_conf *fconf) -{ - if (tmpbuf.size) - b_free(&tmpbuf); - if (zbuf.size) - b_free(&zbuf); -} - -static int comp_strm_init(struct stream *s, struct filter *filter) { struct comp_state *st; @@ -789,8 +767,6 @@ /***********************************************************************/ struct flt_ops comp_ops = { .init = comp_flt_init, - .init_per_thread = comp_flt_init_per_thread, - .deinit_per_thread = comp_flt_deinit_per_thread, .attach = comp_strm_init, .detach = comp_strm_deinit, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/flt_trace.c new/haproxy-3.3.4+git0.c2bffae0a/src/flt_trace.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/flt_trace.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/flt_trace.c 2026-02-19 14:03:31.000000000 +0100 @@ -162,7 +162,7 @@ blk = htxret.blk; if (blk && htxret.ret && htx_get_blk_type(blk) == HTX_BLK_DATA) { - data += htxret.ret; + data += htx_get_blksz(blk) - htxret.ret; blk = htx_get_next_blk(htx, blk); } while (blk) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/h3.c new/haproxy-3.3.4+git0.c2bffae0a/src/h3.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/h3.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/h3.c 2026-02-19 14:03:31.000000000 +0100 @@ -812,6 +812,11 @@ goto out; } } + else { + h3s->err = H3_ERR_REQUEST_REJECTED; + len = -1; + goto out; + } flags |= HTX_SL_F_VER_11; flags |= HTX_SL_F_XFER_LEN; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/http_ana.c new/haproxy-3.3.4+git0.c2bffae0a/src/http_ana.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/http_ana.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/http_ana.c 2026-02-19 14:03:31.000000000 +0100 @@ -4312,7 +4312,12 @@ } /* we get here if we need to wait for more data */ - if (!(chn_prod(chn)->flags & (SC_FL_EOS|SC_FL_ABRT_DONE))) { + + if ((s->scf->flags & SC_FL_ERROR) || + ((s->scf->flags & (SC_FL_EOS|SC_FL_ABRT_DONE)) && + proxy_abrt_close_def(s->be, 1))) + ret = HTTP_RULE_RES_CONT; + else if (!(chn_prod(chn)->flags & (SC_FL_ERROR|SC_FL_EOS|SC_FL_ABRT_DONE))) { if (!tick_isset(chn->analyse_exp)) chn->analyse_exp = tick_add_ifset(now_ms, time); ret = HTTP_RULE_RES_YIELD; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/mux_h1.c new/haproxy-3.3.4+git0.c2bffae0a/src/mux_h1.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/mux_h1.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/mux_h1.c 2026-02-19 14:03:31.000000000 +0100 @@ -1331,11 +1331,9 @@ H1_EV_H1C_NEW|H1_EV_STRM_NEW, h1c->conn, h1c->h1s); } - if (t) { - h1_set_idle_expiration(h1c); - t->expire = tick_first(t->expire, h1c->idle_exp); - task_queue(t); - } + h1_set_idle_expiration(h1c); + t->expire = tick_first(t->expire, h1c->idle_exp); + task_queue(t); /* prepare to read something */ if (b_data(&h1c->ibuf)) @@ -4885,6 +4883,12 @@ h1s->sd->iobuf.flags |= IOBUF_FL_NO_FF; goto out; } + + if (h1m->state < H1_MSG_CHUNK_SIZE || h1m->state == H1_MSG_TRAILERS || h1m->state == H1_MSG_DONE) { + TRACE_STATE("Unexpected message state, disable fastfwd", H1_EV_STRM_SEND|H1_EV_STRM_ERR, h1c->conn, h1s); + h1s->sd->iobuf.flags |= IOBUF_FL_NO_FF; + goto out; + } if ((!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) || ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/mux_h2.c new/haproxy-3.3.4+git0.c2bffae0a/src/mux_h2.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/mux_h2.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/mux_h2.c 2026-02-19 14:03:31.000000000 +0100 @@ -8097,6 +8097,15 @@ TRACE_ENTER(H2_EV_H2S_SEND|H2_EV_STRM_SEND, h2s->h2c->conn, h2s); + if (h2s->st >= H2_SS_HLOC) { + /* Cannot emit any new data if stream already closed. Data + * draining will be performed via snd_buf. + */ + TRACE_DEVEL("stream already closed, disable FF", H2_EV_H2S_SEND, h2s->h2c->conn, h2s); + h2s->sd->iobuf.flags |= IOBUF_FL_NO_FF; + goto end; + } + /* If we were not just woken because we wanted to send but couldn't, * and there's somebody else that is waiting to send, do nothing, * we will subscribe later and be put at the end of the list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/mux_quic.c new/haproxy-3.3.4+git0.c2bffae0a/src/mux_quic.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/mux_quic.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/mux_quic.c 2026-02-19 14:03:31.000000000 +0100 @@ -4077,9 +4077,6 @@ TRACE_ENTER(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); - /* Sending forbidden if QCS is locally closed (FIN or RESET_STREAM sent). */ - BUG_ON(qcs_is_close_local(qcs) || (qcs->flags & QC_SF_TO_RESET)); - /* stream layer has been detached so no transfer must occur after. */ BUG_ON_HOT(qcs->flags & QC_SF_DETACH); @@ -4090,6 +4087,12 @@ goto end; } + /* Cannot emit data after FIN/RESET_STREAM, drain extra payload. */ + if (qcs_is_close_local(qcs) || (qcs->flags & QC_SF_TO_RESET)) { + ret = qcs_http_reset_buf(qcs, buf, count); + goto end; + } + if (LIST_INLIST(&qcs->el_buf)) { TRACE_DEVEL("leaving on no buf avail", QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); goto end; @@ -4145,9 +4148,6 @@ TRACE_ENTER(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); - /* Sending forbidden if QCS is locally closed (FIN or RESET_STREAM sent). */ - BUG_ON(qcs_is_close_local(qcs) || (qcs->flags & QC_SF_TO_RESET)); - /* stream layer has been detached so no transfer must occur after. */ BUG_ON_HOT(qcs->flags & QC_SF_DETACH); @@ -4165,6 +4165,15 @@ qcs->sd->iobuf.flags |= IOBUF_FL_NO_FF; goto end; } + + if (qcs_is_close_local(qcs) || (qcs->flags & QC_SF_TO_RESET)) { + /* Cannot emit any new data if stream already closed. Data + * draining will be performed via snd_buf. + */ + TRACE_DEVEL("stream already closed", QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); + qcs->sd->iobuf.flags |= IOBUF_FL_NO_FF; + goto end; + } if (LIST_INLIST(&qcs->el_buf)) { TRACE_DEVEL("leaving on no buf avail", QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/qmux_http.c new/haproxy-3.3.4+git0.c2bffae0a/src/qmux_http.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/qmux_http.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/qmux_http.c 2026-02-19 14:03:31.000000000 +0100 @@ -102,3 +102,23 @@ return ret; } + +/* QUIC MUX snd_buf reset. HTX data stored in <buf> of length <count> will be + * cleared. This can be used when data should not be transmitted any longer. + * + * Return the size in bytes of cleared data. + */ +size_t qcs_http_reset_buf(struct qcs *qcs, struct buffer *buf, size_t count) +{ + struct htx *htx; + + TRACE_ENTER(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); + + htx = htx_from_buf(buf); + htx_reset(htx); + htx_to_buf(htx, buf); + + TRACE_LEAVE(QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs); + + return count; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/ssl_crtlist.c new/haproxy-3.3.4+git0.c2bffae0a/src/ssl_crtlist.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/ssl_crtlist.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/ssl_crtlist.c 2026-02-19 14:03:31.000000000 +0100 @@ -515,6 +515,13 @@ struct stat st; int cfgerr = 0; + if (!crt_path) { + memprintf(err, "%sTrying to load a certificate but no 'crt' keyword specified.\n", + err && *err ? *err : ""); + cfgerr |= ERR_ALERT | ERR_FATAL; + goto error; + } + /* Look for a ckch_store or create one */ ckchs = ckchs_lookup(crt_path); if (ckchs == NULL) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/haproxy-3.3.3+git0.465d8e2fc/src/ssl_sock.c new/haproxy-3.3.4+git0.c2bffae0a/src/ssl_sock.c --- old/haproxy-3.3.3+git0.465d8e2fc/src/ssl_sock.c 2026-02-12 14:25:57.000000000 +0100 +++ new/haproxy-3.3.4+git0.c2bffae0a/src/ssl_sock.c 2026-02-19 14:03:31.000000000 +0100 @@ -6006,8 +6006,9 @@ * another thread */ HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock); - if (s->ssl_ctx.reused_sess[tid].ptr) - ha_free(&s->ssl_ctx.reused_sess[tid].ptr); + HA_RWLOCK_WRLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[tid].sess_lock); + ha_free(&s->ssl_ctx.reused_sess[tid].ptr); + HA_RWLOCK_WRUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.reused_sess[tid].sess_lock); HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock); }
