Commit graph

9118 commits

Author SHA1 Message Date
Willy Tarreau
0af603f46f MEDIUM: threads: change the default max-threads-per-group value to 16
A lot of our subsystems start to be shared by thread groups now
(listeners, queues, stick-tables, stats, idle connections, LB algos).
This has allowed to recover the performance that used to be out of
reach on losely shared platforms (typically AMD EPYC systems), but in
parallel other large unified systems (Xeon and large Arm in general)
still suffer from the remaining contention when placing too many
threads in a group.

A first test running on a 64-core Neoverse-N1 processor with a single
backend with one server and no LB algo specifiied shows 1.58 Mrps with
64 threads per group, and 1.71 Mrps with 16 threads per group. The
difference is essentially spent updating stats counters everywhere.

Another test is the connection:close mode, delivering 85 kcps with
64 threads per group, and 172 kcps (202%) with 16 threads per group.
In this case it's mostly the more numerous listeners which improve
the situation as the change is mostly in the kernel:

max-threads-per-group 64:
  # perf top
  Samples: 244K of event 'cycles', 4000 Hz, Event count (approx.): 61065854708 los
  Overhead  Shared Object     Symbol
    10.41%  [kernel]          [k] queued_spin_lock_slowpath
    10.36%  [kernel]          [k] _raw_spin_unlock_irqrestore
     2.54%  [kernel]          [k] _raw_spin_lock
     2.24%  [kernel]          [k] handle_softirqs
     1.49%  haproxy           [.] process_stream
     1.22%  [kernel]          [k] _raw_spin_lock_bh

  # h1load
  time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
     1  1024    84560    83536        4761666      0 84k5 83k5 38M0 11.91m
     2  1024   168736   167713        9559698      0 84k0 84k0 38M3 11.98m
     3  1024   253865   252841       14412165      0 85k0 85k0 38M7 11.84m
     4  1024   339143   338119       19272783      0 85k1 85k1 38M8 11.80m
     5  1024   424204   423180       24121374      0 84k9 84k9 38M7 11.86m

max-threads-per-group 16:
  # perf top
  Samples: 1M of event 'cycles', 4000 Hz, Event count (approx.): 375998622679 lost
  Overhead  Shared Object     Symbol
    15.20%  [kernel]          [k] queued_spin_lock_slowpath
     4.31%  [kernel]          [k] _raw_spin_unlock_irqrestore
     3.33%  [kernel]          [k] handle_softirqs
     2.54%  [kernel]          [k] _raw_spin_lock
     1.46%  haproxy           [.] process_stream
     1.12%  [kernel]          [k] _raw_spin_lock_bh

  # h1load
      time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
         1  1020   172230   171211        9759255      0 172k 171k 78M0 5.817m
         2  1024   343482   342460       19520277      0 171k 171k 78M0 5.875m
         3  1021   515947   514926       29350953      0 172k 172k 78M5 5.841m
         4  1024   689972   688949       39270207      0 173k 173k 79M2 5.783m
         5  1024   863904   862881       49184274      0 173k 173k 79M2 5.795m

So let's change the default value to 16. It also happens to match what's
used by default on EPYC systems these days.

This change was marked MEDIUM as it will increase the number of listening
sockets on some systems, to match their counter parts from other vendors,
which is easier for capacity planning.
2026-04-16 10:48:43 +02:00
William Lallemand
69211b869f BUG/MINOR: acme: fix fallback state after failed initial DNS check
When the opportunistic initial DNS check (ACME_INITIAL_RSLV_READY) fails,
the state machine was incorrectly transitioning to ACME_RSLV_RETRY_DELAY
instead of ACME_CLI_WAIT. This caused the challenge to enter the DNS retry
loop rather than falling back to the normal cond_ready flow that waits for
the CLI signal.

Also reorder ACME_CLI_WAIT in the state enum and trace switch to reflect
the actual execution order introduced in the previous commit: it comes after
ACME_INITIAL_RSLV_READY, not before ACME_INITIAL_RSLV_TRIGGER.

No backport needed.
2026-04-15 16:06:59 +02:00
William Lallemand
c295a5c861 MINOR: acme: opportunistic DNS check for dns-persist-01 to skip challenge-ready steps
For dns-persist-01, the "_validation-persist.<domain>" TXT record is set once
and never changes between renewals. Add an initial opportunistic DNS check
(ACME_INITIAL_RSLV_TRIGGER / ACME_INITIAL_RSLV_READY states) that runs before
the challenge-ready conditions are evaluated. If all domains already have the
TXT record, the challenge is submitted immediately without going through the
cli/delay/dns challenge-ready steps, making renewals faster once the record is
in place.

The new ACME_RDY_INITIAL_DNS flag is automatically set for
dns-persist-01 in cond_ready.
2026-04-15 15:57:57 +02:00
Willy Tarreau
5fe0579d49 MEDIUM: threads: start threads by groups
Till now, threads were all started one at a time from thread 1. This
will soon cause us limitations once we want to reduce shared stuff
between thread groups.

Let's slightly change the startup sequence so that the first thread
starts one initial thread for each group, and that each of these
threads then starts all other threads from their group before switching
to the final task. Since it requires an intermediary step, we need to
store that threads' start function to access it from the group, so it
was put into the tgroup_info which still has plenty of room available.

It could also theoretically speed up the boot sequence, though in
practice it doesn't change anything because each thead's initialization
is made one at a time to avoid races during the early boot. However
ther is now a function in charge of starting all extra threads of a
group, and whih is called from this group.
2026-04-15 15:53:56 +02:00
Amaury Denoyelle
497cabd9e5 MEDIUM: quic: implement fe.stream.max-total
Implement a new setting to limit the total number of bidirectional
streams that the client may use on a single connection. By default, it
is set to 0 which means it is not limited at all.

If a positive value is configured, the client can only open a fixed
number of request streams per QUIC connection. Internally, this is
implemented in two steps :

* First, MAX_STREAMS_BIDI flow control advertizing will be reduced when
  approaching the limit before being completely turned off when reaching
  it. This guarantees that the client cannot exceed the limit without
  violating the flow control.

* Second, when attaching the latest stream with ID matching max-total
  setting, connection graceful shutdown is initiated. In HTTP/3, this
  results in a GOAWAY emission. This allows the remaining streams to be
  completed before the connection becomes completely idle.
2026-04-15 15:18:37 +02:00
Willy Tarreau
9c6e07c43f MINOR: stats: report the number of thread groups in "show info"
Since thread groups were enabled by default in 3.3, it has become an
important element of diagnostic that we're missing in "show info". Let's
add it under "NbThreadGroups".
2026-04-14 16:48:16 +02:00
Christopher Faulet
ebaa88a23a MINOR: htx: Add helper function to get type and size from the block info field
__htx_blkinfo_type() and __htx_blkinfo_size() function was added to return,
respectively, the type and the size from the block info field. The main
usage for these functions is internal to the htx code.
2026-04-14 14:07:21 +02:00
William Lallemand
3415abe56d MINOR: mjson: reintroduce mjson_next()
The lack of mjson_next() prevents to iterate easily and need to hack by
iterating on a loop of snprintf + $.field[XXX] combined with
mjson_find().

This reintroduce mjson_next() so we could iterate without having to
build the string.

The patch does not reintroduce MJSON_ENABLE_NEXT so it could be used
without having to define it.
2026-04-14 10:57:21 +02:00
Tim Duesterhus
2c748125f5 MINOR: check: Support generating a unique_id for checks
This implementation is directly modeled after `stream_generate_unique_id()` and
the corresponding `unique_id` field on `struct stream`.

It will be used in a future commit to enable the use of the `%[unique-id]`
fetch in check rules.
2026-04-13 20:01:42 +02:00
Tim Duesterhus
38796d4c06 MINOR: Allow inlining of stream_generate_unique_id()
With the introduction of the `generate_unique_id()` helper, the actual
complicated logic is sitting in a different file. Allow inlining of
`stream_generate_unique_id()`, so that callers can benefit from an abstraction
without hiding away the access of `strm->unique_id` behind a function call.
2026-04-13 20:01:42 +02:00
Tim Duesterhus
73040e3a8e MINOR: Add generate_unique_id() helper
This new function will handle the actual generation of the unique ID according
to a format. The caller is responsible to check that no unique ID is stored
yet.
2026-04-13 20:01:02 +02:00
Tim Duesterhus
4cf06a7d23 CLEANUP: Make lf_expr parameter of sess_build_logline_orig() const
Since this is safely possible without making any changes, we can provide this
hint to the compiler.
2026-04-13 19:59:12 +02:00
William Lallemand
39476040ec MINOR: acme: extend resolver-based DNS pre-check to dns-persist-01
Add challenge_type parameter to acme_rslv_start() to select the correct
DNS lookup prefix: _validation-persist.<domain> for dns-persist-01 and
_acme-challenge.<domain> for dns-01.

Default cond_ready to ACME_RDY_DNS|ACME_RDY_DELAY for dns-persist-01.
Extend ACME_CLI_WAIT to cover dns-persist-01 alongside dns-01.

In ACME_RSLV_READY, check only TXT record existence for dns-persist-01
since the resolver cannot parse multiple strings within a single TXT entry.
2026-04-13 18:45:08 +02:00
Tim Duesterhus
756ad19f04 CLEANUP: log: Return size_t from sess_build_logline_orig()
`sess_build_logline_orig()` takes a `size_t maxsize` as input and accordingly
should also return `size_t` instead of `int` as the resulting length. In
practice most of the callers already stored the result in a `size_t` anyways.
The few places that used an `int` were adjusted.

This Coccinelle patch was used to check for completeness:

    @@
    type T != size_t;
    T var;
    @@

    (
    * var = build_logline(...)
    |
    * var = build_logline_orig(...)
    |
    * var = sess_build_logline(...)
    |
    * var = sess_build_logline_orig(...)
    )

Reviewed-by: Volker Dusch <github@wallbash.com>
2026-04-13 14:02:29 +02:00
Miroslav Zagorac
cd14abf9f3 MEDIUM: otel: added OpenTelemetry filter skeleton
The OpenTelemetry (OTel) filter enables distributed tracing of requests
across service boundaries, export of metrics such as request rates,
latencies and error counts, and structured logging tied to trace context,
giving operators a unified view of HAProxy traffic through any
OpenTelemetry-compatible backend.

The OTel filter is implemented using the standard HAProxy stream filter
API.  Stream filters attach to proxies and intercept traffic at each stage
of processing: they receive callbacks on stream creation and destruction,
channel analyzer events, HTTP header and payload processing, and TCP data
forwarding.  This allows the filter to collect telemetry data at every
stage of the request/response lifecycle without modifying the core proxy
logic.

This commit added the minimum set of files required for the filter to
compile: the addon Makefile with pkg-config-based detection of the
opentelemetry-c-wrapper library, header files with configuration
constants, utility macros and type definitions, and the source files
containing stub filter operation callbacks registered through
flt_otel_ops and the "opentelemetry" keyword parser entry point.

The filter uses the opentelemetry-c-wrapper library from HAProxy
Technologies, which provides a C interface to the OpenTelemetry C++ SDK.
This wrapper allows HAProxy, a C codebase, to leverage the full
OpenTelemetry observability pipeline without direct C++ dependencies
in the HAProxy source tree.

  https://github.com/haproxytech/opentelemetry-c-wrapper
  https://github.com/open-telemetry/opentelemetry-cpp

Build options:

  USE_OTEL     - enable the OpenTelemetry filter
  OTEL_DEBUG   - compile the filter in debug mode
  OTEL_INC     - force the include path to the C wrapper
  OTEL_LIB     - force the library path to the C wrapper
  OTEL_RUNPATH - add the C wrapper RUNPATH to the executable

Example build with OTel and debug enabled:

  make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
2026-04-13 09:23:26 +02:00
Christopher Faulet
313121639e Revert "BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c"
This reverts commit 8056117e98.

Moving haterm init from haproxy is not the right way to fix the issue
because it should be possible to use a haterm configuration in haproxy.

So let's revert the commit above.
2026-04-10 16:32:29 +02:00
Amaury Denoyelle
792e055c7c MEDIUM: xprt_qstrm: implement QMux record parsing
This patch implements the new QMux record layer parsing for xprt_qstrm.
This is mostly similar to the MUX code from the previous patch.

Along with this change, a new xprt_qstrm layer accessor exposes the
possible remaining record length after Transport parameters parsing.
This can only occur when xprt_qstrm Rx buffer is not completely emptied
due to other following frames. If stored in the same record, MUX layer
has to know the remaining record length.

Thus, xprt_qstrm_rxrlen() is now used in qmux_init() to preinitialize
<rx.rlen> QCC field.
2026-04-10 10:20:52 +02:00
Amaury Denoyelle
5271cdaca3 MEDIUM: mux-quic: implement QMux record parsing
This is the first patch of a serie which aims to support the new Record
layer defined by the draft 01 of QMux protocol.

  https://www.ietf.org/archive/id/draft-ietf-quic-qmux-01.html#name-qmux-records

This patch deals with QMux reception at the MUX layer. The function
qcc_qstrm_recv() is adapted to read record headers before frame parsing.
This requires to keep the last record length read in a new QCC field
named <rx.rlen>.

Frames are only parsed once a full record is received. One of the
advantage of the record layer is that it can only contains whole frame
without truncation.
2026-04-10 10:20:52 +02:00
Amaury Denoyelle
10f2867dc2 MINOR: xprt_qstrm: handle connection errors
This patch implements proper connection error handling for xprt_qstrm
layer. Basically, processing is interrupted if CO_FL_ERROR is
encountered after either rcv_buf or snd_buf operations. Connectionn
error is set to the newly defined value CO_ER_QSTRM.
2026-04-10 10:20:52 +02:00
Amaury Denoyelle
fb3b268747 MINOR: xprt_qstrm/mux-quic: handle extra QMux frames after params
Layer xprt_qstrm is responsible to read the initial QMux transport
parameters frame. However, it could receive more data if some other
frames follow it. This extra content can only be handled by the MUX
layer once initialized.

Theorically, it could have been implemented via MSG_PEEK. However, this
flag is currently ignored by SSL layer. Besides, it is tedious to
implement safely. A new approach has been prefered where the MUX layer
is responsible to retrieve remaining data via xprt_qstrm_rxbuf()
accessor function during its initialization.

Thus, qmux_init() now may retrieve the buffer from xprt_qstrm layer.
This is performed via b_xfer() which will result in a zero copy
transfer. If this happens, tasklet is immediately scheduled to start
demuxing.
2026-04-10 10:20:52 +02:00
Christopher Faulet
b0a9216ca5 BUG/MEDIUM: samples: Fix handling of SMP_T_METH samples
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Samples of type SMP_T_METH were not properly handled in smp_dup(),
smp_is_safe() and smp_is_rw(). For "other" methods, for instance PATCH, a
fallback was performed on the SMP_T_STR type. Only the buffer considered
changed. "smp->data.u.meth.str" should be used for the SMP_T_METH samples
while smp->data.u.str should be used for SMP_T_STR samples. However, in
smp_dup(), the result was stored in wrong buffer, the string one instead of
the method one. In smp_is_safe() and smp_is_rw(), the method buffer was not
used at all.

We now take care to use the right buffer.

This patch must be backported to all stable versions.
2026-04-09 22:05:12 +02:00
Greg Kroah-Hartman
bd03f05007 BUG/MINOR: spoe: fix pointer arithmetic overflow in spoe_decode_buffer()
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
decode_varint() has no iteration cap and accepts varints decoding to
any uint64_t value. When sz is large enough that p + sz wraps modulo
2^64, the check "p + sz > end" passes, *buf is set to the wrapped
pointer, and the caller's parsing loop continues from an arbitrary
relative offset before the demux buffer.

A malicious SPOE agent sending an AGENT_HELLO frame with a key-name
length varint of 0xfffffffffffff000 causes spop_conn_handle_hello()
to dereference memory ~64KB before the dbuf allocation, resulting in
SIGSEGV (DoS) or, if the read lands on live heap data, parser
confusion. The relative offset is fully attacker-controlled and
ASLR-independent.

Compare against the remaining length instead of computing p + sz.
Since p <= end is guaranteed after a successful decode_varint(),
end - p is non-negative.

This patch must be backport to all stable versions.
2026-04-09 16:47:19 +02:00
Olivier Houchard
d759e60a32 MEDIUM: check: Revamp the way the protocol and xprt are determined
Storing the protocol directly into the check was not a good idea,
because the protocol may not be determined until after a DNS resolution
on the server, and may even change at runtime, if the DNS changes.
What we can, however, figure out at start up, is the net_addr_type,
which will contain all that we need to find out which protocol to use
later.
Also revert the changes made by commit 07edaed191
that would not reuse the server xprt if a different alpn is set for
checks. The alpn is just a string, and should not influence the choice
of the xprt.
We'll now make sure to use the server xprt, unless an address is
provided, in which case we'll use whatever xprt matches that address, or
a port, in which case we'll assume we want TCP, and use check_ssl to
know whetver we want the SSL xprt or not.
Now that the check contains all that is needed to know which protocol to
look up, always just use that when creating a new check connection if it
is the default check connection, and for now, always use TCP when a
tcp-check or http-check connect rule is used (which means those can't be
used for QUIC so far).

This should hopefully fix github issue #3324.
2026-04-08 18:41:48 +02:00
Olivier Houchard
2140249c18 MINOR: tools: Implement net_addr_type_is_quic()
Implement net_addr_type_is_quic(), that returns 1 if the provided
net_addr_type looks like it is using QUIC, and 0 otherwise.
2026-04-08 18:41:48 +02:00
Olivier Houchard
2eefd489c2 MEDIUM: connections: Really enforce mux protocol requirements
Commit 1b0dfff552 attempted to make it so
the mux would expect a QUIC-like protocol or not, however it only made
that we would not instantiate a non-QUIC mux on a QUIC protocol, but not
that we tried to instance a QUIC mux on a non-QUIC protocol, so fix
that.
2026-04-08 18:41:48 +02:00
Christopher Faulet
8056117e98 BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c
Functions used to initialize haterm (the splicing and the response buffers)
were defined and registered in haterm.c. The problem is that this file in
compiled with haproxy. So it may be an issue. And for the splicing part,
warnings may be emitted when haproxy is started.

To avoid any issue during haproxy startup and to avoid to initialize some
part of haterm, all init functions were moved into haterm_init.c file.

No backport needed.
2026-04-03 15:09:44 +02:00
William Lallemand
910a182f05 Revert "CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()"
This reverts commit 51e1562a0d.
2026-04-03 14:15:11 +02:00
Aurelien DARRAGON
8d28c0e37b MEDIUM: filters: add "filter-sequence" directive
This is another pre-requisite work for upcoming decompression filter.

In this patch we implement the "filter-sequence" directive which can be
used in proxy section (frontend,backend,listen) and takes 2 parameters

The first one is the direction (request or response), the second one
is a comma separated list of filter names previously declared on the
proxy using the "filter" keyword.

The main goal of this directive is to be able to instruct haproxy in which
order the filters should be executed on request and response paths,
especially if the ordering between request and response handling must
differ, and without relying on the filter declaration ordering (within
the proxy) which is used by default by haproxy.

Another benefit of this feature is that it becomes possible to "ignore"
a previously declared filter on the proxy. Indeed, when filter-sequence
is defined for a given direction (request/response), then it will be used
over the implicit filter ordering, but if a filter which was previously
declared is not specified in the related filter-sequence, it will not be
executed on purpose. This can be used as a way to temporarily disable a
filter without completely removing its configuration.

Documentation was updated (check examples for more info)
2026-04-03 12:10:27 +02:00
Aurelien DARRAGON
629a5ae531 MINOR: filters: add filter name to flt_conf struct
flt_conf struct stores the filter id, which is used internally to check
match the filter against static pointer identifier, and also used as
descriptive text to describe the filter. But the id is not consistent
with the public name as used in the configuration (for instance when
selecting filter through the 'filter' directive).

What we do in this patch is that we add flt_conf->name member, which
stores the real filter name as seen in the configuration. This will
allow to select filters by their name from other directives in the
configuration.
2026-04-03 12:10:20 +02:00
Christopher Faulet
3ab5044c1c MINOR: haterm: Handle boolean request options as flags
Following request options are now handled as flags:

  - ?k=1 => flag HS_ST_OPT_CHUNK_RES is set
  - ?c=0 => flag HS_ST_OPT_NO_CACHE is set
  - ?R=1 => flag HS_ST_OPT_RANDOM_RES is set
  - ?A=A => flag HS_ST_OPT_REQ_AFTER_RES is set.

By default, none is set.
2026-04-03 10:46:15 +02:00
William Lallemand
d89ae36adc MINOR: ssl: add the ssl_fc_crtname sample fetch
This new sample fetch returns the name of the certificate selected for
an incoming SSL/TLS connection, as it would appear in "show ssl cert".
It may be a filename with its relative or absolute path, or an alias,
depending on how the certificate was declared in the configuration.

The certificate name is stored as ex_data on the SSL_CTX at load time
in ckch_inst_new_load_store(), and freed via a dedicated free callback.
2026-04-03 10:41:00 +02:00
William Lallemand
6df3662077 MEDIUM: acme: split the initial delay from the retry DNS delay
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The previous ACME_RSLV_WAIT state served a dual role: it applied the
initial dns-delay before the first DNS probe and also handled the
delay between retries. There was no way to simply wait a fixed delay
before submitting the challenge without also triggering DNS pre-checks.

Replace ACME_RSLV_WAIT with two distinct states:
  - ACME_INITIAL_DELAY: an optional initial wait before proceeding,
    only applied when "challenge-ready" includes the new "delay" keyword
  - ACME_RSLV_RETRY_DELAY: the delay between resolution retries, always
    applied when DNS pre-checks are in progress

The new "delay" keyword in "challenge-ready" can be used standalone
(wait then submit the challenge directly) or combined with "dns" (wait
then start the DNS pre-checks). When "delay" is not set, the first DNS
probe fires immediately.

Update the documentation accordingly.
2026-04-02 18:29:26 +02:00
Amaury Denoyelle
3636ebd062 DEBUG: connection/flags: add QSTRM flags for the decoder
Add new flags CO_FL_QSTRM_SEND and CO_FL_QSTRM_RECV in conn_show_flags()
so that they can be decoded by dev/flags/flags utility.

No backport needed.
2026-04-02 16:58:00 +02:00
William Lallemand
6228ec6a81 MINOR: acme: split the CLI wait from the resolve wait
Add a new state ACME_CLI_WAIT which allows to split the CLI wait logic
from the resolve wait logic.
2026-04-02 15:54:02 +02:00
Amaury Denoyelle
490b465fd1 MAJOR: mux-quic: activate QMux for frontend side
To be able to support QMux protocol, xprt_qstrm is activated by the
session for transport parameters exchange, prior to the mux layer
initialization.
2026-04-02 14:02:05 +02:00
Amaury Denoyelle
b26178396a MINOR: mux-quic: use QMux transport parameters from qstrm xprt
Defines an API for xprt_qstrm so that the QMux transport parameters can
be retrieved by the MUX layer on its initialization. This concerns both
local and remote parameters.

Functions xprt_qstrm_lparams/rparams() are defined and exported for
this. They are both used in qmux_init() if QMux protocol is active.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
f1ed1de317 MINOR: xprt_qstrm: implement sending of transport parameters
This patch implements QMux emission of transport parameters via
xprt_qstrm. Similarly to receive, this is performed in conn_send_qstrm()
which uses lower xprt snd_buf operation. The connection must first be
flagged with CO_FL_QSTRM_SEND to trigger this step.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
531a2b9f1a MINOR: xprt_qstrm: implement reception of transport parameters
Extend xprt_qstrm to implement the reception of QMux transport
parameters. This is performed via conn_recv_qstrm() which relies on the
lower xprt rcv_buf operation. Once received, parameters are kept in
xprt_qstrm context, so that the MUX can retrieve them on init.

For the reception of parameters to be active, the connection must first
be flagged with CO_FL_QSTRM_RECV.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
4dd224b5ef MINOR: xprt_qstrm: define new xprt module for QMux protocol
Define a new XPRT layer for the new QMux protocol. Its role will be to
perform the initial exchange of transport parameters.

On completion, contrary to XPRT handshake, xprt_qstrm will first init
the MUX and then removes itself. This will be necessary so that the
parameters can be retrieved by the MUX during its initialization.

This patch only declares the new xprt_qstrm along with basic operations.
Future commits will implement the proper reception/emission steps.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
782894f5b8 MINOR: mux-quic: define Tx connection buffer for QMux
Similarly to reception, a new buffer is defined in QCC connection to
handle emission for QMux protocol. This replaces the trash buffer usage
in qcc_qstrm_send_frames().

This buffer is necessary to handle partial emission. On retry, the
buffer must be completely emitted before starting to send new frames.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
621f21f6fd MINOR: mux-quic: implement qstream send callback
Each time a QUIC frame is emitted, mux-quic layer is notified via a
callback to update the underlying QCS. For QUIC, this is performed via
qc_stream_desc element.

In QMux protocol, this can be simplified as there is no
qc_stream_desc/quic_conn layer interaction. Instead, each time snd_buf
is called, QCS can be updated immediately using its return value. This
is performed via a new function qstrm_ctrl_send().

Its work is similar to the QUIC equivalent but in a simpler mode. In
particular, sent data can be immediately removed from the Tx buffer as
there is no need for retransmission when running above TCP.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
e8d9eb4f7a MEDIUM: mux-quic: implement QMux send
This patchs implement mux-quic reception for the new QMux protocol. This
is performed via the new function qcc_qstrm_send_frames(). Its interface
is similar to the QUIC equivalent : it takes a list of frames and
encodes them in a buffer before sending it via snd_buf.

Contrary to QUIC, a check on CO_FL_ERROR flag is performed prior to
every qcc_qstrm_send_frames() invokation to interrupt emission. This is
necessary as the transport layer may set it during snd_buf. This is not
the case currently for quic_conn layer, but maybe a similar mechanism
should be implemented as well for QUIC in the future.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
81f22cd68a MINOR: mux-quic: define Rx connection buffer for QMux
When QMux is used, mux-quic must actively performed reception of new
content. This has been implemented by the previous patch.

The current patch extends this by defining a buffer on QCC dedicated to
this operation. This replaces the usage of the trash buffer. This is
necessary to deal with incomplete reads.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
6ae22a50e5 MEDIUM: mux-quic: implement QMux receive
This patch implements a new function qcc_qstrm_recv() dedicated to the
new QMux protocol. It is responsible to perform data reception via
rcv_buf() callback. This is defined in a new mux_quic_strm module.

Read data are parsed in frames. Each frame is handled via standard
mux-quic functions. Currently, only STREAM and RESET_STREAM types are
implemented.

One major difference between QUIC and QMux is that mux-quic is passive
on the reception side on the former protocol. For the new one, mux-quic
becomes active. Thus, a new call to qcc_qstrm_recv() is performed via
qcc_io_recv().
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
f16c851625 MINOR: quic: abstract stream type in qf_stream frame
STREAM frame will also be used by the new QMux protocol. This requires
some adaptation in the qf_stream structure. Reference to qc_stream_desc
object is replaced by a generic void* pointer.

This change is necessary as QMux protocol will not use any
qc_stream_desc elements for emission.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
3078a63335 MINOR: mux-quic: prepare Tx support for QMux
Adapts mux-quic functions related to emission for future QMux protocol
support.

In short, QCS will not used a qc_stream_desc object but instead a plain
buffer. This is inserted as a union in QCS structure. Every access to
QUIC qc_stream_desc is protected by a prior conn_is_quic() check. Also,
pacing is useless for QMux and thus is disabled for such protocol.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
10094fdd00 MINOR: mux-quic: move qcs stream member into tx inner struct
Move <stream> field from qcs type into the inner structure 'tx'. This
change is only a minor refactoring without any impact. It is cleaner as
Rx buffer elements are already present in 'rx' inner structure.

This reorganization is performed before introducing of a new Tx buffer
field used for QMux protocol.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
62fcc48bcf MINOR: quic: implement QMux transport params frame parser/builder
Implement parse/build methods for QX_TRANSPORT_PARAMETER frame. Both
functions may fail due to buffer space too small (encoding) or truncated
frame (parsing).
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
ea5cb23307 MINOR: quic: define QMux transport parameters frame type
Define a new frame type for QMux transport parameter exchange. Frame
type is 0x3f5153300d0a0d0a and is declared as an extra frame, outside of
quic_frame_parsers / quic_frame_builders.

The next patch will implement parsing/encoding of this frame payload.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
9a2db73e32 MINOR: quic: remove useless quic_tp_dec_err type
The previous patch refactored QUIC transport parameters decoding and
validity checks. These two operation are now performed in two distinct
functions. This renders quic_tp_dec_err type useless. Thus, this patch
removes it. Function returns are converted to a simple integer value.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
011b085803 MINOR: quic: refactor frame encoding
This patch is a direct follow-up of the previous one. This time,
refactoring is performed on qc_build_frm() which is used for frame
encoding.

Function prototype has changed as now packet argument is removed. To be
able to check frame validity with a packet, one can use the new parent
function qc_build_frm_pkt() which relies on qc_build_frm().

As with the previous patch, there is no function change expected. The
objective is to facilitate a future QMux implementation.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
48e41e4ce0 MINOR: quic: refactor frame parsing
This patch refactors parsing in QUIC frame module. Function
qc_parse_frm() has been splitted in three :
* qc_parse_frm_type()
* qc_parse_frm_pkt()
* qc_parse_frm_payload()

No functional change. The main objective of this patch is to facilitate
a QMux implementation. One of the gain is the ability to manipulate QUIC
frames without any reference to a QUIC packet as it is irrelevant for
QMux. Also, quic_set_connection_close() calls are extracted as this
relies on qc type. The caller is now responsible to set the required
error code.
2026-04-02 14:02:04 +02:00
Amaury Denoyelle
1e08247961 MINOR: connection: add function to identify a QUIC connection
Add a simple helper conn_is_quic() function which tells if a connection
runs over QUIC protocol. It will be useful when implementing QMux
alternative.
2026-04-02 14:02:04 +02:00
William Lallemand
7f6999b764 MINOR: acme: add 'dns-timeout' keyword for dns-01 challenge
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
When using the dns-01 challenge method with "challenge-ready dns", HAProxy
retries DNS resolution indefinitely at the interval set by "dns-delay". This
adds a "dns-timeout" keyword to set a maximum duration for the DNS check phase
(default: 600s). If the next resolution attempt would be scheduled beyond that
deadline, the renewal is aborted with an explicit error message.

A new "dnsstarttime" field is stored in the acme_ctx to record when DNS
resolution began, used to evaluate the timeout on each retry.
2026-04-01 18:56:13 +02:00
Christopher Faulet
6fbccae1ab MEDIUM: tcpcheck/server: Add healthcheck server keyword
Thanks to this patch, it is now possible to specify an healthcheck section
on the server line. In that case, the server will use the tcpcheck as
defined in the correspoding healthcheck section instead of the proxy's one.
2026-04-01 16:34:38 +02:00
Christopher Faulet
44c02854ca MINOR: tcpcheck: Extract tcpheck ruleset post-config in a dedicated function
This will be mandatory to attache a healthcheck section to a server.
check_tcpcheck_ruleset() function is introduced for this purpose.
2026-04-01 16:34:38 +02:00
Christopher Faulet
275bd9ec03 MEDIUM: tcpcheck: Add parsing support for healthcheck sections
tcpcheck_ruleset struct was extended to host a config part that will be used
for healthcheck sections. This config part is mainly used to store element
for the server's tcpcheck part.

When a healthcheck section is parsed, a ruleset is created with its name
(which must be unique). "*healthcheck-{NAME}" is used for these ruleset. So
it is not possible to mix them with regular rulesets.

For now, in a healthcheck section, the type must be defined, based on the
options name (tcp-check, httpchk, redis-check...). In addition, several
"tcp-check" or "http-check" rules can be specified, depending on the
healthcheck type.
2026-04-01 16:34:38 +02:00
Christopher Faulet
954e87ee01 MINOR: tcpcheck: Add a function to stringify the healthcheck type
tcpcheck_ruleset_type_to_str() function is created to return a string
corresponding to a tcpcheck type.
2026-04-01 16:34:38 +02:00
Christopher Faulet
51e1562a0d CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()
proxy_parse_tcpcheck() function is not used outside of tcpcheck.c file. So
stop to export it.
2026-04-01 16:34:38 +02:00
Christopher Faulet
64e3029e8b MINOR: tcpcheck: Use tcpcheck flags to know a healthcheck uses SSL connections
The proxy flag PR_O_TCPCHK_SSL is replaced by a flag on the tcpcheck
itself. When TCPCHK_FL_USE_SSL flag is set, it means the healthcheck will
use an SSL connection and the SSL xprt must be prepared for the server.
2026-04-01 16:34:38 +02:00
Christopher Faulet
978119caa6 MINOR: tcpcheck: Deal with disable-on-404 and send-state in the tcp-check itself
disable-on-404 and send-state options, configured on an HTTP healtcheck,
were handled as proxy options. Now, these options are handled in the
tcp-check itself. So the corresponding PR_O and PR_02 flags are removed.
2026-04-01 16:34:37 +02:00
Christopher Faulet
dc7c8bd2f8 MEDIUM: tcpcheck: Refactor how tcp-check rulesets are stored
The tcpcheck_rules structure is replaced by the tcpcheck structure. The main
difference is that the ruleset is now referenced in the tcpcheck structure,
instead of the rules list. The flags about the ruleset type are moved into
the ruleset structure and flags to track unused rules remains on the
tcpcheck structure. So it should be easier to track unused rulesets. But it
should be possible to configure a set of tcpcheck rules outside of the proxy
scope.

The main idea of these changes is to prepare the parsing of a new
healthcheck section. So this patch is quite huge, but it is mainly about
renaming some fields.
2026-04-01 16:34:37 +02:00
Christopher Faulet
2adcdbacc2 MINOR: action: Add a sample expression field in arguments used by HTTP actions
This could be useful for some HTTP actions. It was possible to rely on a
log-format string. It is now possible to also use a sample expression.
2026-04-01 16:34:37 +02:00
William Lallemand
c8bfd06b57 MINOR: ssl/log: add keylog format variables and env vars
Add keylog_format_fc and keylog_format_bc global variables containing
the SSLKEYLOGFILE log-format strings for the frontend (client-facing)
and backend (server-facing) TLS connections respectively. These produce
output compatible with the SSLKEYLOGFILE format described at:
https://tlswg.org/sslkeylogfile/draft-ietf-tls-keylogfile.html

Both formats are also exported as environment variables at startup:
  HAPROXY_KEYLOG_FC_LOG_FMT
  HAPROXY_KEYLOG_BC_LOG_FMT

These variables contains \n so they might not be compatible with syslog
servers, using them with stderr or a sink might be required.

These can be referenced directly in "log-format" directives to produce
SSLKEYLOGFILE-compatible output, usable by network analyzers such as
Wireshark to decrypt captured TLS traffic.
2026-04-01 16:28:49 +02:00
Olivier Houchard
e264523112 MINOR: servers: Don't update last_sess if it did not change
Check that last_sess actually changed before attempting to set it, as it
should only change once every second, that will avoid a lot of atomic
writes on a busy cache line.
2026-04-01 15:06:55 +02:00
Olivier Houchard
eaf42ee886 MINOR: backends: Don't update last_sess if it did not change
Check that last_sess actually changed before attempting to set it, as it
should only change once every second, that will avoid a lot of atomic
writes on a busy cache line.
2026-04-01 14:58:59 +02:00
Olivier Houchard
397530b1e9 MEDIUM: stats: Hide the version by default and add stats-showversion
Reverse the default, to hide the version from stats by default, and add
a new keyword, "stats show-version", to enable them, as we don't want to
disclose the version by default, especially on public websites.
2026-04-01 14:39:28 +02:00
Nenad Merdanovic
daf378d2b4 MEDIUM: Add set-headers-bin, add-headers-bin and del-headers-bin actions
These actions allow setting, adding and deleting multiple headers from
the same action, without having to know the header names during parsing.
This is useful when doing things with SPOE.
2026-03-31 19:56:28 +02:00
William Lallemand
2b0c510aff MEDIUM: acme: new 'challenge-ready' option
The previous patch implemented the 'dns-check' option. This one replaces
it by a more generic  'challenge-ready' option, which allows the user to
chose the condition to validate the readiness of a challenge. It could
be 'cli', 'dns' or both.

When in dns-01 mode it's by default to 'cli' so the external tool used to
configure the TXT record can validate itself. If the tool does not
validate the TXT record, you can use 'cli,dns' so a DNS check would be
done after the CLI validated with 'challenge_ready'.

For an automated validation of the challenge, it should be set to 'dns',
this would check that the TXT record is right by itself.
2026-03-30 18:24:28 +02:00
William Lallemand
631fd5f99b MEDIUM: acme: add dns-01 DNS propagation pre-check
When using the dns-01 challenge type, TXT record propagation across
DNS servers can take time. If the ACME server verifies the challenge
before the record is visible, the challenge fails and it's not possible
to trigger it again.

This patch introduces an optional DNS pre-check mechanism controlled
by two new configuration directives in the "acme" section:

  - "dns-check on|off": enable DNS propagation verification before
    notifying the ACME server (default: off)
  - "dns-delay <time>": delay before querying DNS (default: 300s)

When enabled, three new states are inserted in the state machine
between AUTH and CHALLENGE:

  - ACME_RSLV_WAIT: waits dns-delay seconds before starting
  - ACME_RSLV_TRIGGER: starts an async TXT resolution for each
    pending authorization using HAProxy's resolver infrastructure
  - ACME_RSLV_READY: compares the resolved TXT record against the
    expected token; retries from ACME_RSLV_WAIT if any record is
    missing or does not match

The "acme_rslv" structure is implemented in acme_resolvers.c, it holds
the resolution for each domain. The "auth" structure which contains each
challenge to resolve contains an "acme_rslv" structure. Once
ACME_RSLV_TRIGGER leaves, the DNS tasks run on the same thread, and the
last DNS task which finishes will wake up acme_process().

Note that the resolution goes through the configured resolvers, not
through the authoritative name servers of the domain. The result may
therefore still be affected by DNS caching at the resolver level.
2026-03-30 18:24:28 +02:00
William Lallemand
e418e828aa MINOR: resolvers: basic TXT record implementation
This patch adds support for TXT records. It allows to get the first
string of a TXT-record which is limited to 255 characters.
The rest of the record is ignored.
2026-03-30 18:24:28 +02:00
Willy Tarreau
cf3173d92b MINOR: stconn: flag the stream endpoint descriptor when the app has started
In order to improve our ability to distinguish operations that had
already started from others under high loads, it would be nice to know
if an application layer (stream) has started to work with an endpoint
or not. The use case typically is a frontend mux instantiating a stream
to instantly cancel it. Currently this info will take some time to be
detected and processed if the applcation's task takes time to wake up.
By flagging the sedesc with SE_FL_APP_STARTED the first time a the app
layer starts, the lower layers can know whether they're cancelling a
stream that has started to work or not, and act accordingly. For now
this is done unconditionally on the backend, and performed early in the
only two app layers that can be reached by a frontend: process_stream()
and process_hstream() (for haterm).
2026-03-30 16:27:53 +02:00
Christopher Faulet
5280130343 BUG/MINOR: stconn: Always declare the SC created from healthchecks as a back SC
The SC created from a healthcheck is always a back SC. But SC_FL_ISBACK
flags was missing. Instead of passing it when sc_new_from_check() is called,
the function was simplified to set SC_FL_ISBACK flag systematically when a
SC is created from a healthcheck.

This patch should be backported as far as 2.6.
2026-03-30 15:47:36 +02:00
Christopher Faulet
d4eee1f206 CLEANUP: stconn: Remove usless sc_new_from_haterm() declaration
This function does not exist. Let's remove its declaration.
2026-03-30 15:47:05 +02:00
Ilia Shipitsin
b7d1c2f91d CLEANUP: fix typos and spelling in comments and documentation
Corrected multiple spelling mistakes across CLI scripts, documentation,
and source comments (e.g. "Specifiy" → "Specify", "explicitely" → "explicitly",
"transfert" → "transfer", "resetted" → "reset", etc.). These changes
improve readability and consistency without altering functionality.
2026-03-30 09:24:19 +02:00
Mia Kanashi
418f0c0bbe BUG/MEDIUM: acme: skip doing challenge if it is already valid
If server returns an auth with status valid it seems that client
needs to always skip it, CA can recycle authorizations, without
this change haproxy fails to obtain certificates in that case.
It is also something that is explicitly allowed and stated
in the dns-persist-01 draft RFC.

Note that it would be better to change how haproxy does status polling,
and implements the state machine, but that will take some thought
and time, this patch is a quick fix of the problem.

See:
https://github.com/letsencrypt/boulder/issues/2125
https://github.com/letsencrypt/pebble/issues/133

This must be backported to 3.2 and later.
2026-03-27 14:41:11 +01:00
Olivier Houchard
1b0dfff552 MEDIUM: connections: Enforce mux protocol requirements
When picking a mux, pay attention to its MX_FL_FRAMED. If it is set,
then it means we explicitely want QUIC, so don't use that mux for any
protocol that is not QUIC.
2026-03-26 15:09:13 +01:00
Olivier Houchard
d3ad730d5f MINOR: protocols: Add a new proto_is_quic() function
Add a new function, proto_is_quic(), that returns true if the protocol
is QUIC (using a datagram socket but provides a stream transport).
2026-03-26 15:09:13 +01:00
Olivier Houchard
cca9245416 MINOR: checks: Store the protocol to be used in struct check
When parsing the check address, store the associated proto too.
That way we can use the notation like quic4@address, and the right
protocol will be used. It is possible for checks to use a different
protocol than the server, ie we can have a QUIC server but want to run
TCP checks, so we can't just reuse whatever the server uses.
WIP: store the protocol in checks
2026-03-26 15:09:13 +01:00
Christopher Faulet
ada33006ef MINOR: proxy: Add use-small-buffers option to set where to use small buffers
Thanks to previous commits, it is possible to use small buffers at different
places: to store the request when a connection is queued or when L7 retries
are enabled, or for health-checks requests. However, there was no
configuration parameter to fine tune small buffer use.

It is now possible, thanks to the proxy option "use-small-buffers".
Documentation was updated accordingly.
2026-03-23 14:02:43 +01:00
Christopher Faulet
125cbecfa9 MINOR: proxy: Review options flags used to configure healthchecks
When healthchecks were configured for a proxy, an enum-like was used to
sepcify the check's type. The idea was to reserve some values for futur
types of healthcheck. But it is overkill. I doubt we will ever have
something else than tcp and external checks. So corresponding PR_O2 flags
were slightly reviewed and a hole was filled.

Thanks to this change, some bits were released in options2 bitfield.
2026-03-23 14:02:43 +01:00
Christopher Faulet
a61ea0f414 MEDIUM: tcpcheck: Use small buffer if possible for healthchecks
If support for small buffers is enabled, we now try to use them for
healthcheck requests. First, we take care the tcpcheck ruleset may use small
buffers. Send rules using LF strings or too large data are excluded. The
ability to use small buffers or not are set on the ruleset. All send rules
of the ruleset must be compatible. This info is then transfer to server's
healthchecks relying on this ruleset.

Then, when a healthcheck is running, when a send rule is evaluated, if
possible, we try to use small buffers. On error, the ability to use small
buffers is removed and we retry with a regular buffer. It means on the first
error, the support is disabled for the healthcheck and all other runs will
use regular buffers.
2026-03-23 14:02:43 +01:00
Christopher Faulet
92a24a4e87 MEDIUM: chunk: Add support for small chunks
In the same way support for large chunks was added to properly work with
large buffers, we are now adding supports for small chunks because it is
possible to process small buffers.

So a dedicated memory pool is added to allocate small
chunks. alloc_small_trash_chunk() must be used to allocate a small
chunk. alloc_trash_chunk_sz() and free_trash_chunk() were uppdated to
support small chunks.

In addition, small trash buffers are also created, using the same mechanism
than for regular trash buffers. So three thread-local trash buffers are
created. get_small_trash_chunk() must be used to get a small trash buffer.
And get_trash_chunk_sz() was updated to also deal with small buffers.
2026-03-23 14:02:42 +01:00
Christopher Faulet
0213dd70c9 MINOR: htx: Add helper functions to xfer a message to smaller or larger one
htx_move_to_small_buffer()/htx_move_to_large_buffer() and
htx_copy_to_small_buffer()/htx_copy_to_large_buffer() functions can now be
used to move or copy blocks from a default buffer to a small or large
buffer. The destination buffer is allocated and then each blocks are
transferred into it.

These funtions relies in htx_xfer() function.
2026-03-23 14:02:42 +01:00
Christopher Faulet
5ead611cc2 MEDIUM: htx: Add htx_xfer function to replace htx_xfer_blks
htx_xfer() function should replace htx_xfer_blks(). It will be a bit easier to
maintain and to use. The behavior of htx_xfer() can be changed by calling it
with specific flags:

  * HTX_XFER_KEEP_SRC_BLKS: Blocks from the source message are just copied
  * HTX_XFER_PARTIAL_HDRS_COPY: It is allowed to partially xfer headers or trailers
  * HTX_XFER_HDRS_ONLY: only headers are xferred

By default (HTX_XFER_DEFAULT or 0), all blocks from the source message are moved
into to the destination mesage. So copied in the destination messageand removed
from the source message.

The caller must still define the maximum amount of data (including meta-data)
that can be xferred.

It is no longer necessary to specify a block type to stop the copy. Most of
time, with htx_xfer_blks(), this parameter was set to HTX_BLK_UNUSED. And
otherwise it was only specified to transfer headers.

It is important to not that the caller is responsible to verify the original
HTX message is well-formated. Especially, it must be sure headers part and
trailers part are complete (finished by EOH/EOT block).

For now, htx_xfer_blks() is not removed for compatiblity reason. But it is
deprecated.
2026-03-23 14:02:42 +01:00
Christopher Faulet
f8c96bf9cb MINOR: dynbuf: Add helper functions to alloc large and small buffers
b_alloc_small() and b_alloc_large() can now be used to alloc small or larger
buffers. For now, unlike default buffers, buffer_wait lists are not used.
2026-03-23 14:02:42 +01:00
Christopher Faulet
4d6cba03f2 MINOR: buffers: Move small buffers management from quic to dynbuf part
Because small buffers were only used by QUIC streams, the pool used to alloc
these buffers was located in the quic code. However, their usage will be
extended to other parts. So, the small buffers pool was moved into the
dynbuf part.
2026-03-23 14:02:42 +01:00
Amaury Denoyelle
d250b381dc MINOR: http_htx: split check/init of http_errors
Function proxy_check_errors() is used when configuration parsing is
over. This patch splits it in two newly named ones.

The first function is named proxy_check_http_errors(). It is responsible
to check for the validity of any "errorfiles" directive which could
reference non-existent http-errors section or code not defined in such
section. This function is now called via proxy_finalize().

The second function is named proxy_finalize_http_errors(). It converts
each conf_errors type used during parsing in a proper http_reply type
for runtime usage. This function is still called via post-proxy-check,
after proxy_finalize().

This patch does not bring any functional change. However, it will become
necessary to ensure http-errors can be used as expected with dynamic
backends.
2026-03-23 10:51:33 +01:00
Amaury Denoyelle
fedaf054c4 MINOR: http_htx: use enum for arbitrary values in conf_errors
In conf_errors struct, arbitrary integer values were used for both
<type> field and <status> array. This renders the code difficult to
follow.

Replaces these values with proper enums type. Two new types are defined
for each of these fields. The first one represents the directive type,
derived from the keyword used (errorfile vs errorfiles). This directly
represents which part of <info> union should be manipulated.

The second enum is used for errorfiles directive with a reference on a
http-errors section. It indicates whether or not if a status code should
be imported from this section, and if this import is explicit or
implicit.
2026-03-23 10:51:33 +01:00
Willy Tarreau
7d40b3134a MEDIUM: sched: do not run a same task multiple times in series
There's always a risk that some tasks run multiple times if they wake
each other up. Now we include the loop counter in the task struct and
stop processing the queue it's in when meeting a task that has already
run. We only pick 16 bits since that's only what remains free in the
task common part, so from time to time (once every 65536) it will be
possible to wrongly match a task as having already run and stop evaluating
its queue, but it's rare enough that we don't care, because this will
be OK on the next iteration.
2026-03-23 06:52:24 +01:00
Aurelien DARRAGON
5617e47f91 MINOR: log: support optional 'profile <log_profile_name>' argument to do-log action
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
We anticipated that the do-log action should be expanded with optional
arguments at some point. Now that we heard of multiple use-cases
that could be achieved with do-log action, but that are limitated by the
fact that all do-log statements inherit from the implicit log-profile
defined on the logger, we need to provide a way for the user to specify
that custom log-profile that could be used per do-log actions individually

This is what we try to achieve in this commit, by leveraging the
prerequisite work performed by the last 2 commits.
2026-03-20 11:42:48 +01:00
Willy Tarreau
b3a84800b4 MINOR: task: maintain a per-thread indicator of the peak run-queue size
The new field th_ctx->rq_tot_peak contains the computed peak run queue
length averaged over the last 512 calls. This is computed when entering
process_runnable_tasks. It will not take into account new tasks that are
created or woken up during this round nor those which are evicted, which
is the reason why we're using a peak measurement to increase chances to
observe transient high values. Tests have shown that 512 samples are good
to provide a relatively smooth average measurement while still fading
away in a matter of milliseconds at high loads. Since this value is
only updated once per round, it cannot be used as a statistic and
shouldn't be exposed, it's only for internal use (self-regulation).
2026-03-19 16:24:31 +01:00
Willy Tarreau
eec60f14dd MINOR: freq_ctr: add a function to add values with a peak
Sometimes it's desirable to observe fading away peak values, where a new
value that is higher than the historical one instantly replaces it,
otherwise contributes to it. It is convenient when trying to observe
certain phenomenons like peak queue sizes. The new function
swrate_add_peak_local() does that to a private variable (no atomic ops
involved as it's not worth the cost since such use cases are typically
local).
2026-03-19 16:24:31 +01:00
Willy Tarreau
e1738b665d MINOR: debug: read all libs in memory when set-dumpable=libs
When "set-dumpable" is set to "libs", in addition to marking the process
dumpable, haproxy also reads the binary and shared objects into memory as
a tar archive in a page-aligned location so that these files are easily
extractable from a future core dump. The goal here is to always have
access to the exact same binary and libs as those which caused the core
to happen. It's indeed very frequent to miss some of these, or to get
mismatching files due to a local update that didn't experience a reload,
or to get those of a host system instead of the container.

The in-memory tar file presents everything under a directory called
"core-%d" where %d corresponds to the PID of the worker process. In
order to ease the finding of these data in the core dump, the memory
area is contiguous and surrounded by PROT_NONE pages so that it appears
in its own segment in the core file. The total size used by this is a
few tens of MB, which is not a problem on large systems.
2026-03-18 15:30:39 +01:00
Willy Tarreau
94a4578ccf MINOR: tools: add a function to load a file into a tar archive
New function load_file_into_tar() concatenates a file into an in-memory
tar archive and grows its size. Only the base name and a provided prefix
are used to name the faile. If the file cannot be loaded, it's added as
size zero and permissions 0 to show that it failed to load. This will
be used to load post-mortem information so it needs to remain simple.
2026-03-18 15:30:39 +01:00
Willy Tarreau
c1dfea3ab3 MINOR: tools: add a function to create a tar file header
The purpose here is to create a tar file header in memory from a known
file name, prefix, size and mode. It will be used to prepare archives
of libs in use for improved debugging, but may probably be useful for
other purposes due to its simplicity.
2026-03-18 15:30:34 +01:00
Aurelien DARRAGON
4319c20363 MEDIUM: stats-file/clock: automatically update now_offset based on shared clock
We no longer rely on now_offset stored in the shm-stats-file. Instead
haproxy automatically computes the now_offset relative to the monotonic
clock and the shared global clock.

Indeed, the previous model based on static now_offset when monotonic
clock is available proved to be insufficient when used in
combination with shm-stats-file (that is when monotonic clock is shared
between multiple co-processes). In ideal situation co-processes would
correctly apply the offset to their local monotonic clock and end up
with consistent now_ns. But when restarting from an existing
shm-stats-file from a previous session (ie: prior to reboot), then the
local monotonic clock would no longer be consistent with the one used
to update the file previously, so applying a static offset would fail
to restore clock consistency.

For this specific issue, a workaround was brought by 09bf116
("BUG/MEDIUM: stats-file: detect and fix inconsistent shared clock when resuming from shm-stats-file")
but the solution implemented there was deemed too fragile, because there
is a 60sec window where the fix would fail to detect inconsistent clock
and would leave haproxy with a broken clock ranging from 0 to 60 seconds,
which can be huge..

By simply recomputing the now_offset each time we learn from another
process (through the shared map by reading global_now_ns), we simply
recompute our local offset (difference between OUR monotonic clock
and the SHARED one). Also, in clock_update_global_date(), we make
sure we always recompute the now_offset as now_ms may have been
updated from shared clock if shared clock was ahead of us.

Thanks to that new logic, interrupted processes, resumed processes,
processed started with shm-stats-file from previous session now
correctly recover from those various situations and multiple
co-processes with diverting clocks on startup end up converging to
the same values.

Since it is no longer relevant to save now_offset in the map, it was
removed but to prevent shm-stats-file incompatibility with previous
versions, 8-byte hole was forced, and we didn't bump the shm-stats-file
version on purpose.

This patch may be backported in 3.3 after a solid period of observation
to ensure we didn't break things.
2026-03-18 11:18:33 +01:00
Christopher Faulet
fbdb0a991a MINOR: htx: Add function to truncate all blocks after a specific block
htx_truncated_blk() function does the same than htx_trunctate(), except data
are truncated relatively to a block in the message instead of an offset.
2026-03-17 07:48:02 +01:00
Maxime Henrion
a390daaee4 MINOR: traces: defer processing of "-dt" options
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
We defer processing of the "-dt" options until after the configuration
file has been read. This will be useful if we ever allow trace sources
to be registered later, for instance with LUA.

No backport needed.
2026-03-13 09:13:24 +01:00
Willy Tarreau
f7820bcbaa MINOR: activity: raise the default number of memprofile buckets to 4k
It was set to 1k by default but with the refinement of exec_ctx it's
becoming short, so let's raise it now.
2026-03-12 18:06:38 +01:00
Willy Tarreau
17cbec485a MINOR: cli: implement execution context for manually registered keywords
Keywords registered out of an initcall will have a TH_EX_CTX_CLI_KWL
execution context pointing to the keyword list. The report will indicate
the 5 first words of the first command of the list, e.g.:

     exec_ctx: cli kwl starting with 'debug counters   '

This should also work for CLI keywords registered in Lua.
2026-03-12 18:06:38 +01:00
Willy Tarreau
5cd71f69ba MINOR: cli: keep track of the initcall context since kw registration
Now CLI keywords registered via an initcall will be tracked during
execution, by keeping a link to their initcall location. "show threads"
now shows "exec_ctx: kw registered at @debug.c:3093" which indeed
corresponds to the initcall for the debugging commands.
2026-03-12 18:06:38 +01:00
Willy Tarreau
8139795c64 MINOR: cli: keep the info of the current keyword being processed in the appctx
Till now the CLI didn't know what keyword was being processed after it
was parsed. In order to report the execution context, we'll need to
store it. And this may even help for post-mortem analysis to know the
exact keyword being processed, so let's store the pointer in the cli_ctx
part of the appctx.
2026-03-12 18:06:38 +01:00
Willy Tarreau
9cb11d0859 MINOR: applet: set execution context on applet calls
It allows to know when a thread is currnetly running inside an applet.
For example now "show threads" will show "applet '<CLI>'" for the thread
issuing this command.
2026-03-12 18:06:38 +01:00
Willy Tarreau
c0bf395cde MINOR: task: set execution context on task/tasklet calls
It now appears almost everywhere due to callbacks (e.g. ssl_sock_io_cb).
Muxes also become visible now on memory profiling. A small test on h1+ssl
yields 838 lines of statistics. The number of buckets should definitely
be increased, and more grouping criteria should be added.

A performance test was conducted to observe the possible effect of
setting the execution context on each task switch, and it didn't change
at all, remaining at about 1.01 billion ctxsw/s on a 128-thread EPYC.
2026-03-12 18:06:38 +01:00
Willy Tarreau
ec7b07b650 MINOR: connection: track mux calls to report their allocation context
Most calls to mux ops were instrumented with a CALL_MUX_WITH_RET() or
CALL_MUX_NO_RET() macro in order to make the current thread's context
point to the called mux and be able to track its allocations. Only
a bunch of harmless mux_ctl() and ->subscribe/unsubscribe calls were
left untouched since useless. But destroy/detach/shut/init/snd_buf
and rcv_buf are now tracked.

It will not show allocations performed in IO callback via tasklet
wakeups however.

In order to ease reading of the output, cmp_memprof_ctx() knows about
muxes and sorts based on the .subscribe function address instead of
the mux_ops address so as to keep various callers grouped.
2026-03-12 18:06:38 +01:00
Willy Tarreau
3fb8659d04 MINOR: filters: set the exec context to the current filter config
Doing this allows to report the allocations/releases performed by filters
when running with memory profiling enabled. The flt_conf pointer is kept
and the report shows the filter name.
2026-03-12 18:06:38 +01:00
Willy Tarreau
43b56c22c7 MINOR: actions: also report execution contexts registered directly
This now reports directly registered actions using new type
TH_EX_CTX_ACTION which will report the first keyword of the
list.
2026-03-12 18:06:38 +01:00
Willy Tarreau
861d1111c3 MINOR: actions: store the location of keywords registered via initcalls
A bit similar to what was done for sample fetch functions and converters,
we now store with each action keyword the location of the initcall when
they're registered this way. Since there are many functions only calling
a LIST_APPEND() (one per ruleset), we now implement a dedicated function
to store the context in all keywords before doing the append.

However that's not sufficient, because keywords are not mandatory for
actions, so we cannot safely rely on rule->kw. Thus we then set the
exec_ctx per rule when they are all scanned in check_action_rules(),
based on the keyword if it exists, otherwise we make a context from
the action_ptr function if it is set (it should).

Finally at all call points we now check rule->exec_ctx.
2026-03-12 18:06:38 +01:00
Willy Tarreau
261cae3b6d MINOR: tools: support an execution context that is just a function
The purpose here is to be able to spot certain callbacks, such as the
SSL message callbacks, which are difficult to associate to anything.
Thus we introduce a new context type, TH_EX_CTX_FUNC, for which the
context is just the function pointed to by the void *pointer. One
difficulty with callbacks is that the allocation and release contexts
will likely be different, so the code should be properly structured
to allow proper tracking, either by instrumenting all calls, or by
making sure that the free calls are easy to spot in a report.
2026-03-12 18:06:38 +01:00
Willy Tarreau
aa4d5dd217 MINOR: sample: also report contexts registered directly
With the two new context types TH_EX_CTX_SMPF/CONV, we can now also
report contexts corresponding to direct calls to sample_register_fetches()
and sample_register_convs(). In this case, the first word of the keyword
list is reported.
2026-03-12 18:06:38 +01:00
Willy Tarreau
6e819dc4fa MINOR: sample: store location for fetch/conv via initcalls
Now keywords are registered with an exec_ctx and this one is passed
when calling ->process. The ctx is of type INITCALL when passed via
an initcall where we know the file name and line number.

This was tested with and extra "malloc(15)" added in smp_fetch_path()
which shows that it works:

  $ socat /tmp/sock1 - <<< "show profiling memory"|grep via
           Calls         |         Tot Bytes           |       Caller and method  [via]
      1893399           0       60592592              0|         0x78b2ec task_run_applet+0x3339c malloc(32) [via initcall @http_fetch.c:2416]
2026-03-12 18:06:38 +01:00
Willy Tarreau
2cd0cd84c6 MINOR: tools: support decoding ha_caller type exec context
The TH_EX_CTX_CALLER type takes an ha_caller pointer which allows a
caller to mark its caller's location using MK_CALLER().
2026-03-12 18:06:38 +01:00
Willy Tarreau
6e75da7a91 MINOR: tools: decode execution context TH_EX_CTX_INITCALL
When the execution context is set to TH_EX_CTX_INITCALL, the pointer
points to a valid initcall, and the decoder will show "kw registered
at %s:%d" with file and line number of the initcall declaration. It's
up to the caller to make the initcall pointer point to the one that was
set during the initcall. The purpose here is to be able to preserve and
pass that knowledge of an initcall down the chain so that future calls
to functions registered via the initcall are still assigned to it.
2026-03-12 18:06:38 +01:00
Willy Tarreau
33c928c745 MINOR: initcall: record the file and line declaration of an INITCALL
The INITCALL macros will now store the file and line number where they
are declared into the initcall struct, and RUN_INITCALLS() will assign
them to the global caller_file and caller_line variables, and will even
set caller_initcall to the current initall so that at any instant such
functions know where their caller declared them. This will help with
error messages and traces where a bit of context will be welcome.
2026-03-12 18:06:38 +01:00
Willy Tarreau
5d3246205b MINOR: tools: add a function to write a thread execution context.
The new function chunk_append_thread_ctx() appends to a buffer the given
execution context based on its type and pointer. The goal is to easily
use it in profiling output and thread dumps. For now it only handles
TH_EX_CTX_NONE (which prints nothing) and TH_EX_CTX_OTHER (which indicates
"other ctx" followed by the pointer). It will be extended by new types as
they arrive.
2026-03-12 18:06:37 +01:00
Willy Tarreau
2dfc8417cf MINOR: memprof: prepare to consider exec_ctx in reporting
This now allows to report the same function in multiple bins based on the
th_ctx's exec_ctx discriminant. It's also worth noting that the context is
not atomically committed, but this shouldn't be a problem since a single
entry can get it. In the worst case, a second thread trying to create the
same context in parallel would create a different bin just for this call,
which is harmless. The same situation already exists with the caller
pointer.
2026-03-12 18:06:37 +01:00
Willy Tarreau
b7c8fab507 MINOR: tinfo: start to add basic thread_exec_ctx
We have the struct made of a type and a pointer in the th_ctx and a
function to switch it for the current thread. Two macros are provided
to enclose a callee within a temporary context. For now only type OTHER
is supported (only a generic pointer).
2026-03-12 18:06:37 +01:00
Willy Tarreau
3b4275b072 MINOR: tools: add a new pointer hash function that also takes an argument
The purpose here is to combine two pointers and a long argument instead
of having the caller perform the mixing. Also it's cleaner and more
efficient this was as the arg is mixed after the multiplications, and
modern processors are efficient at multiplying then adding.
2026-03-12 18:06:37 +01:00
Willy Tarreau
825e5611ba MINOR: tools: extend the pointer hashing code to ease manipulations
We'll need to further extend the pointer hashing code to pass extra
parameters and to retrieve the dropped bits, so let's first split the
part that hashes the pointer from the part that reduces the hash to
the desired size.
2026-03-12 18:06:37 +01:00
William Lallemand
73732abfb2 BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready
Starting with OpenSSL 4.0, X509_get_subject_name(), X509_get_issuer_name(),
and X509_CRL_get_issuer() return a const-qualified X509_NAME pointer.
Similarly, X509_NAME_get_entry() returns a const X509_NAME_ENTRY *, and
X509_NAME_ENTRY_get_data() returns a const ASN1_STRING *.

Introduce the __X509_NAME_CONST__ macro (defined to 'const' for OpenSSL
>= 4.0.0, empty for WolfSSL and older OpenSSL version which lacks const
on these APIs) and use it to qualify X509_NAME * variables and the
parameters of the three DN helper functions ssl_sock_get_dn_entry(),
ssl_sock_get_dn_formatted(), and ssl_sock_get_dn_oneline(). This avoids
both const-qualifier warnings on OpenSSL 4.0 and discarded-qualifier
warnings on WolfSSL, without needing explicit casts at call sites.

In ssl_sock.c (ssl_get_client_ca_file) and ssl_gencert.c
(ssl_sock_do_create_cert), a __X509_NAME_CONST__ X509_NAME * variable was
being reused to store the result of X509_NAME_dup() and then passed to
mutating functions (X509_NAME_add_entry_by_txt, X509_NAME_free). Introduce
separate X509_NAME * variables (xn_dup, subject) to hold the mutable
duplicate.

Original patch from Alexandr Nedvedicky <sashan@openssl.org>:
https://www.mail-archive.com/haproxy@formilux.org/msg46696.html
2026-03-11 17:00:59 +01:00
Christopher Faulet
fb1bc592f5 MINOR: stconn: Totally app_ops from the stconns
The stconn app_ops structure is now empty and can be safely removed. So let's do
so.
2026-03-10 15:10:34 +01:00
Christopher Faulet
990456462f MINOR: stconn: Remove .shutdown() callback functions
These callback functions are no longer used, so they can safely be
removed. In addition, the field was removed from the app_ops structure.
2026-03-10 15:10:34 +01:00
Christopher Faulet
c65526ad57 MEDIUM: stconn: Merge all .shutdown() callback functions in sc_shutdown()
sc_shutdown() is no longer relying on .shutdown() callback functions.
Everything was merged in sc_shutdown() with a test on the app type.
2026-03-10 15:10:34 +01:00
Christopher Faulet
9dfff87b69 MINOR: stconn: Remove .abort() callback functions
These callback functions are no longer used, so they can safely be
removed. In addition, the field was removed from the app_ops structure.
2026-03-10 15:10:34 +01:00
Christopher Faulet
0fc6884bc7 MEDIUM: stconn: Merge all .abort() callback functions in sc_abort()
sc_abort() is no longer relying on .abort() callback functions.  Everything
was merged in abort() with a test on the app type.
2026-03-10 15:10:34 +01:00
Christopher Faulet
0c9741b70a MINOR: stconn: Remove .chk_snd() callback functions
These callback functions are no longer used, so they can safely be
removed. In addition, the field was removed from the app_ops structure.
2026-03-10 15:10:34 +01:00
Christopher Faulet
e33dfc4f26 MEDIUM: stconn: Merge all .chk_snd() callback functions in sc_chk_snd()
sc_chk_snd() is no longer relying on .chk_snd() callback functions.
Everything was merged in sc_chk_snd() with a test on the app type.
2026-03-10 15:10:34 +01:00
Christopher Faulet
5aa67f0587 MINOR: stconn: Remove .chk_rcv() callback functions
These callback functions are no longer used, so they can safely be
removed. In addition, the field was removed from the app_ops structure.
2026-03-10 15:10:34 +01:00
Christopher Faulet
aef7afbe65 MEDIUM: stconn: Merge all .chk_rcv() callback functions in sc_chk_rcv()
sc_chk_rcv() is no longer relying on .chk_rcv() callback functions.
Everything was merged in sc_chk_rcv() with a test on the app type.
2026-03-10 15:10:34 +01:00
Christopher Faulet
aaa97c4441 MINOR: haterm: Remove hstream_wake() function
This function is no longer used, so it can be safely removed.
2026-03-10 15:10:34 +01:00
Christopher Faulet
d491329de9 MINOR: check: Remove wake_srv_chk() function
wake_srv_chk() function is now only used by srv_chk_io_cb(), the
health-checl I/O callback function. So let's remove it. The code of the
function was moved in srv_chk_io_cb().
2026-03-10 15:10:34 +01:00
Christopher Faulet
9c7c669d7a MEDIUM: stconn: Remove .wake() callback function from app_ops
.wake() callback function is no longer used by endpoints. So it can be
removed from the app_ops structure.
2026-03-10 15:10:34 +01:00
Christopher Faulet
a33b42035b MINOR: connection: Call sc_conn_process() instead of .wake() callback function
At we fail to create a mux, in conn_create_mux(), instead of calling the
app_ops .wake() callback function, we can directly call sc_conn_process().
At this stage, we know we are using an connection, so it is safe to do so.
2026-03-10 15:10:34 +01:00
Christopher Faulet
7be95eb892 MINOR: applet: Call sc_applet_process() instead of .wake() callback function
At the end of task_run_applet() and task_process_applet(), instead of
calling the app_ops .wake() callback function, we can directly call
sc_applet_process(). At this stage, we know we are using an applet, so it is
safe to do so.
2026-03-10 15:10:34 +01:00
Remi Tricot-Le Breton
e34b633be3 MINOR: jwt: Improve 'jwt_tokenize' function
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The 'jwt_tokenize' function that can be used to split a JWT token into
its subparts can either fully process the token (from beginning to end)
when we need to check its signature, or only partially when using the
jwt_header_query or jwt_member_query converters. In this case we relied
on the fact that the return value of the 'jwt_tokenize' function was not
checked because a '-1' was returned (which was not actually an error).

In order to make this logic more explicit, the 'jwt_tokenize' function
now has a way to warn the caller that the token was invalid (less
subparts than the specified 'item_num') or that the token was not
processed in full (enough subparts found without parsing the token all
the way).
The function will now only return 0 if we found strictly the same number
of subparts as 'item_num'.
2026-03-10 14:20:42 +01:00
Aurelien DARRAGON
cbebdb4ba8 MEDIUM: flt_http_comp: split "compression" filter in 2 distinct filters
Existing "compression" filter is a multi-purpose filter that will try
to compress both requests and responses according to "compression"
settings, such as "compression direction".

One of the pre-requisite work identified to implement decompression
filter is that we needed a way to manually define the sequence of
enabled filters to chain them in the proper order to make
compression and decompression chains work as expected in regard
to the intended use-case.

Due to the current nature of the "compression" filter this was not
possible, because the filter has a combined action as it will try
to compress both requests and responses, and as we are about to
implement "filter-sequence" directive, we will not be able to
change the order of execution of the compression filter between
requests and responses.

A possible solution we identified to solve this issue is to split the
existing "compression" filter into 2 distinct filters, one which is
request-oriented, "comp-req", and another one which is response-oriented
"comp-res". This is what we are doing in this commit. Compression logic
in itself is unchanged, "comp-req" will only aim to compress the request
while "comp-res" will try to compress the response. Both filters will
still be invoked on request and responses hooks, but they only do their
part of the job.

From now on, to compress both requests and responses, both filters have
to be enabled on the proxy. To preserve original behavior, the "compression"
filter is still supported, what it does is that it instantiates both
"comp-req" and "comp-res" filters implicitly, as the compression filter is
now effectively split into 2 separate filters under the hood.

When using "comp-res" and "comp-req" filters explicitly, the use of the
"compression direction" setting is not relevant anymore. Indeed, the
compression direction is assumed as soon as one or both filters are
enabled. Thus "compression direction" is kept as a legacy option in
order to configure the "compression" generic filter.

Documentation was updated.
2026-03-06 13:55:31 +01:00
Christopher Faulet
b48c9a1465 BUG/MINOR: stconn: Increase SC bytes_out value in se_done_ff()
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
When data are sent via the zero-copy data forwarding, we must not forget to
increase the stconn bytes_out value.

This patch must be backport to 3.3.
2026-03-05 16:17:33 +01:00
Olivier Houchard
5d02d33ee1 MINOR: stats: Add an option to disable the calculation of max counters
Add a new option, "stats calculate-max-counters [on|off]".
It makes it possible to disable the calculation of max counters, as they
can have a performance cost.
2026-03-05 15:39:42 +01:00
Olivier Houchard
0087651128 MINOR: counters: Introduce COUNTERS_UPDATE_MAX()
Introduce COUNTERS_UPDATE_MAX(), and use it instead of using
HA_ATOMIC_UPDATE_MAX() directly.
For now it just calls HA_ATOMIC_UPDATE_MAX(), but will later be modified
so that we can disable max calculation.
This can be backported up to 2.8 if the usage of COUNTERS_UPDATE_MAX()
generates too many conflicts.
2026-03-05 15:39:42 +01:00
Christopher Faulet
e0728ebcf4 BUG/MINOR: channel: Increase the stconn bytes_in value in channel_add_input()
This function is no longer used. So it is not really an bug. But it is still
available and could be used by legacy applets. In that case, we must take
care to increment the stconn bytes_in value accordingly when input data are
inserted.

This patch must be backported to 3.3.
2026-03-05 15:34:47 +01:00
Christopher Faulet
7bfb66d2b1 MINOR: http-ana: Save the message version in the http_msg structure
When the request or the response is received, the numerical value of the
message version is now saved. To do so, the field "vsn" was added in the
http_msg structure. It is an unsigned char. The 4 MSB bits are used for the
major digit and the 4 LSB bits for the minor one.

Of couse, the version must be valid. the HTX_SL_F_NOT_HTTP flag of the
start-line is used to be sure the version is valid. But because this flag is
quite new, we also take care the string representation of the version is 8
bytes length. 0 means the version is not valid.
2026-03-05 15:34:46 +01:00
Christopher Faulet
88765b69e0 MINOR: h1-htx: Reports non-HTTP version via dedicated flags
Now, when the HTTP version format is not strictly valid, flags are set on
the h1 parser and the HTX start-line. H1_MF_NOT_HTTP is set on the H1 parser
and HTX_SL_F_NOT_HTTP is set on the HTX start-line. These flags were
introduced to avoid parsing again and again the version to know if it is a
valid version or not, escpecially because it is most of time valid.
2026-03-05 15:34:46 +01:00
Christopher Faulet
9951f9cf85 MINOR: htx: Add a function to retrieve the HTTP version from a start-line
htx_sl_vsn() function can now be used to retrieve the ist string
representing the HTTP version from a start-line passed as parameter. This
function takes care to return the right part of the start-line, depending on
its type (request or response).
2026-03-05 15:34:46 +01:00
Amaury Denoyelle
940e1820f6 MEDIUM: quic/mux-quic: adjust app-ops install
This patch reworks the installation of app-ops layer by QUIC MUX.
Previously, app_ops field was stored directly into the quic_conn
structure. Then the MUX reused it directly during its qmux_init().

This patch removes app_ops field from quic_conn and replaces it with a
copy of the negotiated ALPN. By using quic_alpn_to_app_ops(), it ensures
it remains compatible with a known application layer.

On the MUX layer, qcc_install_app_ops() now uses the standard
conn_get_alpn() to retrieve the ALPN from the transport layer. This is
done via the newly defined <get_alpn> QUIC xprt callback.

This new architecture should be cleaner as it better highlights the
responsibility of each layers in the ALPN/app negotiation.
2026-03-03 16:22:57 +01:00
Amaury Denoyelle
9c7cf1c684 MINOR: mux-quic: add function for ALPN to app-ops conversion
Extract the conversion from ALPN to qcc_app_ops type from quic_conn
source file into QUIC MUX. The newly created function is named
quic_alpn_to_app_ops(). This will serve as a central point to identify
which ALPNs are currently supported in our QUIC stack.

This patch is purely a small refactoring. It will be useful for the next
one which rework MUX app-ops layer init. The current cleanup allows
notably to remove H3/hq-interop headers from quic_conn source file.
2026-03-03 16:20:16 +01:00
Amaury Denoyelle
4120faf289 MINOR: quic/h3: reorganize stream reject after MUX closure
The QUIC MUX layer is closed after its transport counterpart. This may
be necessary then to reject any new streams opened by the remote peer.
This operation is dependent however from the application protocol.

Previously, a function qc_h3_request_reject() was directly implemented
in quic_conn source file for use when HTTP/3 was previously negotiated.
However, this solution was not evolutive and broke layering.

This patch introduces a new proper separation with a <strm_reject>
callback defined in quic_conn structure. When set, it will be used to
preemptively close any new stream. QUIC MUX is responsible to set it
just before its closure.

No functional change. This patch is purely a refactoring with a better
architecture design. Especially, H3 specific code from transport layer
is now completely removed.
2026-03-03 16:19:13 +01:00
Amaury Denoyelle
58830990d0 MINOR: quic: use signed char type for ALPN manipulation
In most of haproxy code, ALPN is used as a signed char pointer. In QUIC
code instead, it is manipulated as unsigned.

Unifies this by using signed type in QUIC code. This allows to remove a
bunch of unnecessary casts.
2026-03-03 16:11:58 +01:00
Christopher Faulet
13c3445163 BUG/MEDIUM: stream: Handle TASK_WOKEN_RES as a stream event
The conversion of TASK_WOKEN_RES to a stream event was missing. Among other
things, this wakeup reason is used when a stream is dequeued. So it was
possible to skip the connection establishment if the stream was also woken
up for a timer reason. When this happened, the stream was blocked till the
queue timeout expiration.

Converting TASK_WOKEN_RES to STRM_EVT_RES fixes the issue.

This patch should fix the issue #3290. It must be backported as far as 3.2.
2026-03-03 15:16:10 +01:00
Amaury Denoyelle
f58b2698ce MEDIUM: proxy: add lock for global accesses during proxy free
Define a new lock with label PROXIES_DEL_LOCK. Its purpose is to protect
operations performed on global lists or trees while a proxy is freed.

Currently, this lock is unneeded as proxies are only freed on
single-thread init or deinit. However, with the incoming dynamic backend
deletion, this operation will be also performed at runtime, outside of
thread isolation.
2026-03-02 14:09:25 +01:00