Compare commits

..

No commits in common. "master" and "v3.4-dev11" have entirely different histories.

229 changed files with 1487 additions and 4861 deletions

18
.cirrus.yml Normal file
View file

@ -0,0 +1,18 @@
FreeBSD_task:
freebsd_instance:
matrix:
image_family: freebsd-14-3
only_if: $CIRRUS_BRANCH =~ 'master|next'
install_script:
- pkg update -f && pkg upgrade -y && pkg install -y openssl git gmake lua54 socat pcre2
script:
- sudo sysctl kern.corefile=/tmp/%N.%P.core
- sudo sysctl kern.sugid_coredump=1
- scripts/build-vtest.sh
- gmake CC=clang V=1 ERR=1 TARGET=freebsd USE_ZLIB=1 USE_PCRE2=1 USE_PCRE2_JIT=1 USE_OPENSSL=1 USE_LUA=1 LUA_INC=/usr/local/include/lua54 LUA_LIB=/usr/local/lib LUA_LIB_NAME=lua-5.4
- ./haproxy -vv
- ldd haproxy
test_script:
- env VTEST_PROGRAM=../vtest/vtest gmake reg-tests REGTESTS_TYPES=default,bug,devel
on_failure:
debug_script: (for folder in /tmp/*regtest*/vtc.*; do cat $folder/INFO $folder/LOG; done && ls /tmp/haproxy.*.core && gdb -ex 'thread apply all bt full' ./haproxy /tmp/haproxy.*.core)

View file

@ -1,38 +0,0 @@
name: FreeBSD
on:
push:
branches:
- master
- next
workflow_dispatch:
permissions:
contents: read
jobs:
clang:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- name: "Checkout repository"
uses: actions/checkout@v6
- name: "Build and test on FreeBSD"
uses: vmactions/freebsd-vm@v1
with:
release: "14.3"
prepare: |
pkg update -f && pkg upgrade -y && pkg install -y openssl git gmake lua54 socat pcre2 python3
run: |
sysctl kern.corefile=/tmp/%N.%P.core
sysctl kern.sugid_coredump=1
scripts/build-vtest.sh
gmake CC=clang V=1 ERR=1 TARGET=freebsd USE_ZLIB=1 USE_PCRE2=1 USE_PCRE2_JIT=1 USE_OPENSSL=1 USE_LUA=1 LUA_INC=/usr/local/include/lua54 LUA_LIB=/usr/local/lib LUA_LIB_NAME=lua-5.4
./haproxy -vv
ldd haproxy
if ! env VTEST_PROGRAM=../vtest/vtest gmake reg-tests REGTESTS_TYPES=default,bug,devel; then
for folder in /tmp/*regtest*/vtc.*; do cat $folder/INFO $folder/LOG; done
ls /tmp/haproxy.*.core 2>/dev/null && gdb -ex 'thread apply all bt full' ./haproxy /tmp/haproxy.*.core
exit 1
fi

View file

@ -2,7 +2,7 @@ name: Illumos
on:
schedule:
- cron: "0 3 * * 1"
- cron: "0 0 25 * *"
workflow_dispatch:
permissions:

View file

@ -137,7 +137,7 @@ release. These branches were emitted at a pace of one per year since 1.5 in
2014. As of 2019, 1.5 is still supported and widely used, even though it very
rarely receives updates. After a few years these LTS branches enter a
"critical fixes only" status, which means that they will rarely receive a fix
but if that a critical issue affects them, a release will be made, with or
but if that a critital issue affects them, a release will be made, with or
without any other fix. Once a version is not supported anymore, it will not
receive any fix at all and it will really be time for you to upgrade to a more
recent branch. Please note that even when an upgrade is needed, a great care is

324
CHANGELOG
View file

@ -1,330 +1,6 @@
ChangeLog :
===========
2026/06/03 : 3.5-dev0
- MINOR: version: mention that it's development again
2026/06/03 : 3.4.0
- BUG/MINOR: tcpcheck: Check LDAP response to not read more data than available
- BUG/MINOR: ssl-gencert: validate SNI characters to prevent SAN certificate injection
- BUG/MINOR: mux-h1: H2 preface rejection doesn't update stick-table glitches
- BUG/MEDIUM: cpu-topo: Enforce thread-hard-limit on policy
- BUG/MEDIUM: qmux: do not crash on too large record
- BUG/MEDIUM: qmux: do not crash on receiving an invalid first frame
- BUG/MINOR: qmux: reject too large initial record
- Revert "BUG/MEDIUM: dns: fix long loops in additional records parse on name failure"
- BUG/MINOR: qpack: Fix index calculation in debug functions
- BUG/MINOR: qpack: fix potential null-pointer dereference in qpack_dht_insert()
- CLEANUP: qpack: fix copy-paste typo in value Huffman debug string
- BUG/MINOR: qpack: fix sign bit mask in qpack_decode_fs_pfx()
- CLEANUP: qpack: fix copy-paste typo in value Huffman debug string for WLN
- BUG/MINOR: qpack: fix huff_dec() error handling in qpack_decode_fs()
- CLEANUP: qpack: move encoded macros to qpack-t.h to avoid duplication
- BUG/MEDIUM: quic: handle ECONNREFUSED on RX side
- BUG/MINOR: quic: Fix memory leak in quic_deallocate_dghdlrs()
- BUG/MEDIUM: lua: defer Lua VM initialisation to the first Lua config keyword
- REGTESTS: lua: fix tune.lua.openlibs in Lua reg-tests
- BUG/MINOR: mux-h2: Count padding for connection flow control on error path
- BUILD: addons: convert 51d addon to EXTRA_MAKE
- BUILD: addons: convert deviceatlas addon to EXTRA_MAKE
- BUILD: addons: convert WURFL addon to EXTRA_MAKE
- MINOR: mux_quic/flags: add missing flags
- BUG/MINOR: mux_quic: open an idle QCS on reset on BE side
- BUG/MINOR: mux_quic: fix BE conn removal on app shutdown
- BUG/MINOR: mux_quic: prevent BE reuse with an errored conn
- BUG/MINOR: quic: fix ack range node pool_free call passing wrong pointer type
- MEDIUM: quic: optimize HKDF operations by reusing per-thread contexts
- BUG/MEDIUM: quic: reset cwnd in slow_start on persistent congestion (cubic)
- BUG/MEDIUM: quic: reset consecutive_losses on exit from recovery period (cubic)
- BUG/MINOR: quic: update drs->lost before calling on_ack_recv
- Revert "MEDIUM: quic: optimize HKDF operations by reusing per-thread contexts"
- BUG/MEDIUM: lua: register hlua_init() as a pre-check to fix crash without Lua config
- REGTESTS: quic: disable quic/ocsp_auto_update for now
- BUG/MINOR: threads: set at least grp_max when mtpg is too small
- BUG/MEDIUM: threads: ignore max-threads-per-group when thread-groups is set
- CLEANUP: thread: indicate when max-threads-per-group is ignored
- MINOR: cpu-topo: notify when cpu-policy is ignored due to other settings
- MINOR: thread: report when thread-groups or nbthread results in less threads
- BUILD: makefile: include EXTRA_MAKE in the .build_opts construction
- BUG/MINOR: quic: Fix another buffer overflow with sockaddr_in46
- MINOR: quic: Copy sin6_flowinfo and sin6_scope_id too
- BUILD: Makefile: put EXTRA_MAKE help at the right place
- BUG/MINOR: cache: fix cache tree iteration
- BUG/MEDIUM: resolvers: Wait a bit before calling the xprt prepare_srv
- CLEANUP: addons/51degrees: initialize variables
- MINOR: addons/51degrees: handle memory allocation failures
- CLEANUP: ncbmbuf: improve handling of memory allocation errors in unit tests
- CLEANUP: admin/halog: improve handling of memory allocation errors
- DOC: internals: clarify ambiguous wording in core-principles
- DOC: internals: add a threat model definition
- DOC: add security.txt describing how to report security issues
- DOC: security: also add a note to exclude dev/ and admin/
- BUG/MEDIUM: qmux: Close connection on invalid frame
- CLEANUP: fix comment typo
- BUG/MEDIUM: h3: fix MAX_PUSH_ID handling
- BUG/MINOR: cache: Fix copy of value when parsing maxage
- BUG/MEDIUM: mux-h1: Dup connection/upgrade value to parse it when making headers
- BUG/MEDIUM: htx: Fix headers rollback on partial copy in htx_xfer()
- MINOR: deinit: release the in-memory copy of shared libs
- MINOR: debug: add -dA to dump an archive of all dependencies
- BUG/MEDIUM: ssl: Make sure the alpn length is small enough
- BUG/MINOR: applet: Commit changes into input buffer after sending HTX data
- BUG/MINOR: mux-spop: Fix possible off-by-one OOB read in spop_get_varint()
- BUG/MEDIUM: leastconn: Unlock the write lock on allocation failure
- BUG/MINOR: tasks: Increase the right niced_task counter
- BUILD: makefile: search for Lua 5.5 as well
- DEV: dev/gdb: improve ebtree pointer handling
- DEV: dev/gdb: add simple task dump
- DEV: dev/gdb: add simple thread dump
- DEV: dev/gdb: add fdtab dump
- DOC: config: add a few more explanation in http-reusee regarding sni-auto
- REGTESTS: add basic QMux tests
- BUG/MINOR: http-act: Properly handle final evaluation in pause action
- BUILD: makefile/lua: use the system's default library before all other variants
- BUG/MINOR: startup: unbreak chroot with CAP_SYS_CHROOT
- BUG/MINOR: haterm: do not try to bind QUIC when not supported
- BUG/MINOR: haterm: also apply the tcp-bind-opts to clear TCP "bind" lines
- CLEANUP: haterm: do not try to bind to SSL when not built in
- MINOR: haterm: enable ktls on the SSL bind line when supported
- CI: github: replace cirrus by a vmactions/freebsd-vm job
- BUILD: makefile: fix build error with GNU make 4.2.1 and /bin/dash
- BUG/MEDIUM: channel: Fix condition to know if a channel may send
- BUG/MEDIUM: vars: Properly eval set-var-fmt action for emtpy log-format string
- CI: github: run illumos job weekly on Mondays at 03:00 instead of monthly
- BUG/MEDIUM: stream: Don't use small buffer on queuing with a request data filter
- BUG/MINOR: jwe: don't write randoms past MAX_DECRYPTED_CEK_LEN in RSA_PKCS1_PADDING
- BUG/MEDIUM: chunk: do not rely on small trash by default for expressions
- CLEANUP: map: always test pat->ref in sample_conv_map_key()
- DEV: patchbot: prepare for new version 3.5-dev
- MINOR: version: mention that it's 3.4 LTS now.
2026/05/26 : 3.4-dev14
- MINOR: config: shm-stats-file is no longer experimental
- BUILD: proxy: unstatify the proxies_del_lock to avoid a warning without threads
- BUG/MEDIUM: net_helper: fix a remaining possibly infinite loop in converters
- MINOR: ssl_sock: remove unneeded check on QMux flags
- MINOR: connection: define xprt_add_l6hs()
- MINOR: xprt_qmux: define default value for get_alpn
- MINOR: connection: define mask CO_FL_WAIT_XPRT_L6
- MINOR: session: support QMux in clear on FE side
- MINOR: backend: support QMux in clear for BE side
- BUG/MINOR: ocsp: Manage date too far away in the future
- MINOR: mux_quic: handle STOP_SENDING in QMux
- MINOR: mux_quic: handle MAX_STREAMS for uni stream in QMux
- MINOR: mux_quic: do not crash on unhandled QMux frame reception
- BUG/MEDIUM: applet: Properly handle receives of size 0
- BUG/MEDIUM: resolvers: Fix test on dn label size in resolv_dn_label_to_str()
- BUG/MEDIUM: ssl-gencert: Unlock LRU cache if failing to generate certificate
- BUG/MINOR: quic: fix ODCID lookup from derived value
- BUG/MEDIUM: dict: hold lock while decrementing refcount in dict_entry_unref
- BUG/MINOR: tcpchecks: Limit parsing of agent-check reply to the buffer
- BUG/MEDIUM: hlua: Fix integer underflow when receiving line from lua cosocket
- BUG/MEDIUM: cli: Fix parsing of pattern finishing a command payload
- BUG/MEDIUM: acme: NUL terminate response buffer before PEM parsing
- BUILD: intops: mask the fail value in array_size_or_fail()
- BUG/MEDIUM: log-forward: make sure the month is unsigned
- BUG/MEDIUM: regex: allocate a large enough pcre2 match for all matches
- BUG/MEDIUM: tcpcheck/spoe: bound the SPOP error code to valid values
- BUG/MEDIUM: cache: fix a refcount leak for missed secondary entries
- BUG/MINOR: log: free logformat expr on compile failure in cfg_parse_log_profile
- BUG/MINOR: resolvers: fix room for trailing zero in resolv_dn_label_to_str()
- BUG/MINOR: resolvers: fix risk of appending garbage past the domain name
- BUG/MINOR: mux-h2: validate HEADERS frame length before reading stream dep
- BUG/MINOR: log: look for the end of priority before the end of the buffer
- BUG/MINOR: dict: fix refcount race on insert collision
- BUG/MINOR: init: use more than ha_random64() for the cluster secret
- BUG/MINOR: sample: limit the be2hex converter's chunk size
- CLEANUP: resolvers: use read_n32() instead of open-coded big-endian read
- CLEANUP: resolvers: remove pool_free(NULL) in SRV additional record matching
- CLEANUP: resolvers: fix comment typos and wrong filenames in file headers
- BUG/MINOR: haterm: fix the random suffix multiplication
- MINOR: haterm: enable h3 for TCP bindings
- MINOR: haterm: do not emit a warning when not using SSL
- BUG/MEDIUM: h1: drop headers whose names contain invalid chars
- BUG/MEDIUM: h1: limit status codes to 3 digits by default
- BUG/MEDIUM: cache: always verify the primary hash in get_secondary_entry()
- BUG/MINOR: cache: also recognize directives in the form "token="
- BUG/MINOR: resolvers: relax size checks in authority record parsing
- BUG/MINOR: sample: request an extra output byte for the url_dec converter
- BUG/MINOR: http-fetch: check against the whole token in get_http_auth()
- BUG/MEDIUM: acme: protect against risk of null-deref on connection failure
- BUG/MINOR: http-ext: always check remaining data when reading rfc7239 nodeport
- BUG/MINOR: base64: return empty string for empty input in base64dec()
- BUG/MINOR: payload: fix the handshake length bounds check smp_client_hello_parse()
- BUG/MINOR: ssl-hello: make use of the null-terminated servername
- BUG/MINOR: resolvers: switch to a better PRNG for query IDs
- BUG/MINOR: addons/51d: NUL-terminate headers before passing them to Trie API
- BUG/MEDIUM: tools: insert an XXH64 layer on the PRNG output
- MINOR: tools: provide a function to generate a hashed random pair
- MEDIUM: init: fall back to ha_random64_pair_hashed() for the cluster secret
- MEDIUM: tools: use the hashed random pair for UUID generation
- MEDIUM: h1: use ha_random64_pair_hashed() for the WebSocket key
- MEDIUM: quic: use ha_random64_pair_hashed() to generate the QUIC retry tokens
- MEDIUM: tools: switch the main PRNG to a thread-local xoshiro256**
- BUG/MEDIUM: h3: reject client push stream
- BUG/MINOR: h3: reject server push stream
- BUG/MINOR: h3: reject client CANCEL_PUSH frame
- BUG/MINOR: h3: adjust error on PUSH_PROMISE frame reception
- BUG/MINOR: h3: reject server MAX_PUSH_ID frame
- BUG/MEDIUM: auth: fix unconfigured password NULL deref
- BUG/MINOR: h3: add missing break on rcv_buf()
- BUG/MINOR: hlua: prevent Lua from passing CR/LF/NUL in HTTP headers
- BUG/MINOR: qmux: do not crash on frame parsing issue
- BUG/MINOR: quic: reject packet too short for HP decryption
- BUG/MINOR: jwe: enforce GCM tag length to 128 bits
- BUG/MEDIUM: jwe: substitute random CEK on RSA1_5 decryption failure per RFC 7516 #11.5
- BUG/MEDIUM: mux-fcgi: reject stream ID 0 for application records
- MINOR: http: Add function to remove all occurrences of a value in a header
- MINOR: h1: Add a H1M flag to specify a non-empty 'Upgrade:' header was parsed
- BUG/MEDIUM: h1-htx: Sanitize parsing to properly handle upgrade requests
- BUG/MINOR: mux-fcgi: Use relative offset to compute contig data in demux buf
- BUG/MINOR: mux-spop: Use relative offset to compute contig data in demux buf
- CLEANUP: mux-fcgi/mux-spop: Remove copy/pasted comment about slow realign
2026/05/20 : 3.4-dev13
- BUG/MINOR: backend: correct parameter value validation in get_server_ph_post()
- BUG/MINOR: config/dns: properly fail on duplicate nameserver name detection
- BUG/MEDIUM: dns: fix long loops in additional records parse on name failure
- BUG/MEDIUM: resolvers: fix name compression pointer validation in resolv_read_name()
- BUG/MEDIUM: dns: fix memory leak of sockaddr in dns_session_init() error path
- CLEANUP: proxy: fix tiny mistakes in parse error messages
- CLEANUP: dns: fix misleading error messages in dns_stream_init()
- BUG/MINOR: server: better handling of OOM in srv_set_fqdn()
- BUG/MINOR: servers: use proper source of pool_conn_name in srv_settings_cpy()
- BUG/MEDIUM: server/cli: unlock server lock on failure in cli_parse_set_server
- BUG/MINOR: resolvers: fix dangling list pointer in resolvers_new() error paths
- BUG/MINOR: dns: fix dangling dgram pointer on dns_dgram_init() failure path
- BUG/MINOR: proxy: use proxy_drop() in parse_new_proxy() error path
- CLEANUP: resolvers: properly initialize the sample in resolv_action_do_resolve()
- BUG/MINOR: resolvers: report the expression error in the do-resolve() action parser
- BUG/MINOR: resolvers: fix leaked dgram and dns_ring struct in parse_resolve_conf()
- BUG/MINOR: resolvers: fix leaked fields on cfg_parse_resolvers() error paths
- BUG/MINOR: resolvers: fix missing task_idle destruction in resolvers_destroy()
- CLEANUP: proxy: fix duplicate declaration of cli_find_frontend in proxy.h
- CLEANUP: address a few typos and copy-paste errors in httpclient and dns
- DOC: internal: add a few rules about internal core principles
- BUG/MINOR: session/trace: use distinct flags for SESS_EV_END and _ERR
- CLEANUP: stick-table: uniformize the different action_inc_gpc*()
- REGTESTS: do not run quic/tls13_ssl_crt-list_filters in quic openssl compat mode
- REGTESTS: quic/issuers_chain_path: do not forget to enable QUIC compat mode
- BUG/MINOR: sock: store the connection error status
- BUG/MINOR: check: properly report errno in chk_report_conn_err()
- CLEANUP: tcpcheck: mention that we're a bit far for a sync errno
- BUG/MINOR: jwt: fix possible memory leak in convert_ecdsa_sig() error path
- CLEANUP: jwe: fix theoretical overflow in AAD length calculation
- DOC: config: further clarify that resolvers "default" exists
- MINOR: proxy: remove the experimental status on dynamic backends
- BUG/MEDIUM: limits: properly account for global.maxpipes in compute_ideal_maxconn()
- BUG/MINOR: jws: fix OpenSSL 3.0 version check from > to >=
- BUG/MINOR: jws: Add missing return value check (EVP_PKEY_get_bn_param)
- BUG/MINOR: server: Properly handle init-state value during haproxy startup
- BUG/MINOR: httpclient-cli: Destroy http-client context if failing to start it
- BUG/MEDIUM: h1: Skip all h2c values from Upgrade headers during parsing
- BUG/MINOR: h1: Don't mask websocket protocol if multiple protocols used
- MINOR: haterm: Don't init haterm master pipe if not used
- CLEANUP: haterm: Remove "(too old kernel)" from warning message during init
- BUG/MINOR: httpclient-cli: fix uninit variable in error label
- MINOR: mux: Rename the "token" from mux_proto_list to mux_proto
- MEDIUM: connections: Use both mux_proto and alpn to pick a mux
- MINOR: connection: define conn_select_mux_fe()
- MINOR: connection: define conn_select_mux_be()
- MINOR: connection/mux_quic: add MUX <init_xprt> field for QMux handshake
- MINOR: proxy/server: reject TCP ALPN h3 without experimental
- MEDIUM: ssl: allow h3/QMux negotiation without explicit proto
- BUG/MINOR: server: accept server IDs above 2^31 and clarify error message
- BUG/MINOR: backend: fix balance hash calculation when using hash-type none
- MINOR: server: support hash-key id32 for a cleaner distribution
- MINOR: backend: support hash-key guid for a stabler distribution
- MINOR: startup: support unprivileged chroot if possible
- MEDIUM: startup: add automatic chroot feature
- MINOR: h2: explain committed_extra_streams dec on h2_init() error
- OPTIM: h2: do not update committed streams if elasticity disabled
- MINOR: mux_quic: implement basic committed_extra_streams accounting
- MINOR: quic: use stream elasticity value for initial advertisement
- MINOR: mux_quic: define ms_bidi_rel QCC member
- MAJOR: mux_quic: support stream elasticity during connection lifetime
- BUG/MEDIUM: servers: Store the connection hash with the parameter cache
- BUG/MINOR: prevent conn leak in case of xprt_qmux init failure
- BUILD: traces: set a few __maybe_unused on vars used only for traces
- BUILD: traces: add USE_TRACE allowing to disable traces
- MINOR: startup: do not execute chroot() when "/"
- MEDIUM: startup: warn when chroot is not set for root
- BUG/MEDIUM: servers: Don't forget to set srv_hash when needed
- DOC: fix typo on QUIC stream.max-concurrent reference
- BUG/MINOR: mux_quic: do not exceed stream.max-concurrent on backend side
- BUG/MINOR: htx: Fix value of HTX_XFER_HDRS_ONLY flag
- MEDIUM: htx: Improve htx_xfer API to not count HTX meta-data
- BUG/MEDIUM: applet: Fix transfer of HTX data to the applet
- BUG/MEDIUM: htx: Alloc a chunk of right size in htx_replace_blk_value()
- MEDIUM: stick-tables: Avoid freeing elements while holding a lock
- MINOR: intops: add a multiply overflow detection for ulong and size_t
- CLEANUP: tree-wide: use array_size_or_fail() in array size for allocations
- DOC: update supported gcc and openssl versions in INSTALL
2026/05/13 : 3.4-dev12
- SCRIPTS: announce-release: add a link to the OpenTelemetry filter
- BUG/MEDIUM: servers: Only requeue servers if they are up
- MINOR: tinfo: store the number of committed extra streams in the tgroup
- MINOR: connection: add a function to calculate elastic streams limit
- MINOR: mux-h2: consider the elastic streams limit on frontend
- MINOR: lb: make LB initialization even more declarative
- BUG/MINOR: cfgparse-listen: do not emit extraneous line in rule order warnings
- CLEANUP: tree-wide: fix typos in non user-visible comments in 15 files
- CLEANUP: h1/htx: fix a few typos in warning, debug and trace messages
- BUG/MINOR: mux-h1: only check h1s if not NULL
- BUG/MINOR: http-fetch: fix smp_fetch_hdr_ip()'s handling of brackets for IPv6
- BUG/MINOR: http-fetch: make http_first_req() check for HTTP first
- BUG/MINOR: http-act: set-status() must check the response message, not the request
- BUG/MINOR: tools: fix memory leak in env_expand() error path
- BUG/MINOR: auth: free user groups on error paths in userlist_postinit()
- BUG/MINOR: uri-auth: avoid leaks on initialization error
- BUG/MINOR: cache: fix memory leak in parse_cache_rule error path
- BUG/MINOR: cfgcond: make KQUEUE check for GTUNE_USE_KQUEUE not GTUNE_USE_EPOLL
- BUG/MINOR: mqtt: connack parser returns MQTT_NEED_MORE_DATA on unknown property
- BUG/MINOR: mqtt: connect parser uses wrong bit field for TOPIC_ALIAS_MAXIMUM
- BUG/MINOR: mqtt: connack parser uses wrong bit for SUBSCRIPTION_IDENTIFIERS_AVAILABLE
- BUG/MINOR: mqtt: fix PUBLISH flags validation that want all bits to be set
- CLEANUP: http_htx: rename inner 'type' to 'ptype' to avoid variable shadowing
- CLEANUP: mux-h2: fix minor output debugging format issues
- CLEANUP: http-rules: fix a few '&' vs '&&' checks for clarity
- CLEANUP: auth: remove undeclared auth_resolve_groups() from auth.h
- CLEANUP: cache: remove redundant res_htx assignment in http_cache_io_handler()
- CLEANUP: channel: remove bogus and unused definition of channel_empty()
- CLEANUP: flt_http_comp: remove duplicate rate limit and CPU usage checks
- CLEANUP: mqtt: remove duplicate MQTT_FN_BIT_USER_PROPERTY in CONNECT fields
- BUG/MINOR: uri-auth: fix possible null-deref in latest fix for leaks
- BUG/MEDIUM: tasks: Keep the TASK_RUNNING flag until queued
- CLEANUP: mqtt: fix spelling of shared_subscription_available
- CLEANUP: regex: pre-initialize error variable in regex_comp() to calm analysis
- BUILD: compiler: fix redefinition of __nonstring
- CLEANUP: defaults: adjust MAX_THREADS multiplier number in comment
- CLEANUP: src/cpuset.c: fix missing return in functions returning int
- REGTESTS: Use ${tmpdir} instead of hardcoded /tmp/
- REGTESTS: Don't try to use real nameservers for testcases
- CLEANUP: tree-wide: fix typos in non user-visible comments in 3 more files
- MINOR: cli: improve forward compatibility for show fd
- DOC: management: document the <tgid>/<fd> form of show fd
- CLEANUP: tree-wide: fix more typos and outdated explanations in comments
- BUG/MEDIUM: dict: hold read lock while incrementing refcount in dict_insert
- BUG/MEDIUM: http-client: Only consume input buffer when hc one is empty
- BUG/MINOR: xprt_qstrm: fix conflicting prototype
- REORG: mux_quic: use newer qcm prefix for legacy qmux files
- MINOR: mux_quic: use qcm prefix for mux callbacks
- MINOR: mux_quic: use qcm prefix for mux functions
- MINOR: mux_quic: use qcm prefix for traces functions/structs
- MINOR: mux_quic: rename qstrm files to qmux
- MINOR: mux_quic: remove qstrm naming in QUIC MUX
- MINOR: connection: rename QMux related flags
- MINOR: xprt_qmux: use qmux instead of qstrm naming
- MINOR: trace: implement source alias
- MEDIUM: mux_quic: rename qmux traces to qcm
- MINOR: sample: add a generic reverse converter
- MINOR: sample: add a reverse_dom converter
- DOC: proxy-protocol: clarify UDP usage
- BUILD: 51d.c: cleanup, fix preprocessor ifdefs
- CLEANUP: tree-wide: fix typos in user-invisible files
- CLEANUP: htx: Adjust numbering of HTX blocks' types in the description
2026/05/08 : 3.4-dev11
- BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
- BUG/MINOR: acme: skip auth/challenge steps when newOrder returns a certificate

14
INSTALL
View file

@ -11,7 +11,7 @@ this task seriously and are doing a good job at backporting important fixes.
If for any reason you would prefer a different version than the one packaged
for your system, you want to be certain to have all the fixes or to get some
commercial support, other choices are available at https://www.haproxy.com/.
commercial support, other choices are available at http://www.haproxy.com/.
Areas covered in this document
@ -111,12 +111,12 @@ HAProxy requires a working GCC or Clang toolchain and GNU make :
may want to retry with "gmake" which is the name commonly used for GNU make
on BSD systems.
- GCC >= 4.7 (up to 16 tested). Older versions are no longer supported due to
- GCC >= 4.7 (up to 15 tested). Older versions are no longer supported due to
the latest mt_list update which only uses c11-like atomics. Newer versions
may sometimes break due to compiler regressions or behaviour changes. The
version shipped with your operating system is very likely to work with no
trouble. Clang >= 3.0 is also known to work as an alternative solution, and
versions up to 21 were successfully tested. Recent versions may emit a bit
versions up to 19 were successfully tested. Recent versions may emit a bit
more warnings that are worth reporting as they may reveal real bugs. TCC
(https://repo.or.cz/tinycc.git) is also usable for developers but will not
support threading and was found at least once to produce bad code in some
@ -237,7 +237,7 @@ to forcefully enable it using "USE_LIBCRYPT=1".
-----------------
For SSL/TLS, it is necessary to use a cryptography library. HAProxy currently
supports the OpenSSL library, and is known to build and work with branches
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 4.0. It is recommended to use
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 3.6. It is recommended to use
at least OpenSSL 1.1.1 to have support for all SSL keywords and configuration
in HAProxy. OpenSSL follows a long-term support cycle similar to HAProxy's,
and each of the branches above receives its own fixes, without forcing you to
@ -426,9 +426,9 @@ Lua is an embedded programming language supported by HAProxy to provide more
advanced scripting capabilities. Only versions 5.3 and above are supported.
In order to enable Lua support, please specify "USE_LUA=1" on the command line.
Some systems provide this library under various names to avoid conflicts with
previous versions. By default, HAProxy looks for "lua5.5", "lua55", "lua5.4",
"lua54", "lua5.3", "lua53", "lua". If your system uses a different naming, you
may need to set the library name in the "LUA_LIB_NAME" variable.
previous versions. By default, HAProxy looks for "lua5.4", "lua54", "lua5.3",
"lua53", "lua". If your system uses a different naming, you may need to set the
library name in the "LUA_LIB_NAME" variable.
If Lua is not provided on your system, it can be very simply built locally. It
can be downloaded from https://www.lua.org/, extracted and built, for example :

View file

@ -44,7 +44,6 @@
# USE_CLOSEFROM : enable use of closefrom() on *bsd, solaris. Automatic.
# USE_PRCTL : enable use of prctl(). Automatic.
# USE_PROCCTL : enable use of procctl(). Automatic.
# USE_TRACE : enable trace subsystem. Always on.
# USE_ZLIB : enable zlib library support and disable SLZ
# USE_SLZ : enable slz library instead of zlib (default=enabled)
# USE_CPU_AFFINITY : enable pinning processes to CPU on Linux. Automatic.
@ -61,6 +60,7 @@
# USE_OBSOLETE_LINKER : use when the linker fails to emit __start_init/__stop_init
# USE_THREAD_DUMP : use the more advanced thread state dump system. Automatic.
# USE_OT : enable the OpenTracing filter
# EXTRA_MAKE : space-separated list of external addons using a Makefile.inc
# USE_MEMORY_PROFILING : enable the memory profiler. Linux-glibc only.
# USE_LIBATOMIC : force to link with/without libatomic. Automatic.
# USE_PTHREAD_EMULATION : replace pthread's rwlocks with ours
@ -94,7 +94,6 @@
# SILENT_DEFINE may be used to specify other defines which will not be
# reported by "haproxy -vv".
# EXTRA is used to force building or not building some extra tools.
# EXTRA_MAKE space-separated list of external addons using a Makefile.inc
# DESTDIR is not set by default and is used for installation only.
# It might be useful to set DESTDIR if you want to install haproxy
# in a sandbox.
@ -124,7 +123,7 @@
# LUA_LIB : force the lib path to lua
# LUA_INC : force the include path to lua
# LUA_LIB_NAME : force the lib name (or automatically evaluated, by order of
# priority: lua5.5, lua55, lua5.4, lua54, lua5.3, lua53, lua).
# priority : lua5.4, lua54, lua5.3, lua53, lua).
# OT_DEBUG : compile the OpenTracing filter in debug mode
# OT_INC : force the include path to libopentracing-c-wrapper
# OT_LIB : force the lib path to libopentracing-c-wrapper
@ -344,7 +343,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER USE_POLL \
USE_TPROXY USE_LINUX_TPROXY USE_LINUX_CAP \
USE_LINUX_SPLICE USE_LIBCRYPT USE_CRYPT_H USE_ENGINE \
USE_GETADDRINFO USE_OPENSSL USE_OPENSSL_WOLFSSL USE_OPENSSL_AWSLC \
USE_ECH USE_TRACE \
USE_ECH \
USE_SSL USE_LUA USE_ACCEPT4 USE_CLOSEFROM USE_ZLIB USE_SLZ \
USE_CPU_AFFINITY USE_TFO USE_NS USE_DL USE_RT USE_LIBATOMIC \
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
@ -367,9 +366,6 @@ $(warn_unknown_options)
# on the make command line.
USE_POLL = default
# traces are always enabled
USE_TRACE = default
# SLZ is always supported unless explicitly disabled by passing USE_SLZ=""
# or disabled by enabling ZLIB using USE_ZLIB=1
ifeq ($(USE_ZLIB:0=),)
@ -671,11 +667,11 @@ OPTIONS_OBJS += src/mux_quic.o src/h3.o src/quic_rx.o src/quic_tx.o \
src/quic_cc_bbr.o src/quic_retry.o \
src/cfgparse-quic.o src/xprt_quic.o src/quic_token.o \
src/quic_ack.o src/qpack-dec.o src/quic_cc_newreno.o \
src/qcm_http.o src/qcm_trace.o src/quic_rules.o \
src/qmux_http.o src/qmux_trace.o src/quic_rules.o \
src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.o \
src/h3_stats.o src/quic_stats.o src/qpack-enc.o \
src/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o \
src/quic_enc.o src/qcm_qmux.o src/xprt_qmux.o \
src/quic_enc.o src/mux_quic_qstrm.o src/xprt_qstrm.o \
src/mpring.o
endif
@ -684,15 +680,15 @@ OPTIONS_OBJS += src/quic_openssl_compat.o
endif
ifneq ($(USE_LUA:0=),)
check_lua_inc = $(shell if [ ! -e /usr/include/lua.h -a -e $(2)$(1)/lua.h ]; then echo $(2)$(1); fi;)
LUA_INC := $(firstword $(foreach lib,lua5.5 lua55 lua5.4 lua54 lua5.3 lua53 lua,$(call check_lua_inc,$(lib),"/usr/include/")))
check_lua_inc = $(shell if [ -d $(2)$(1) ]; then echo $(2)$(1); fi;)
LUA_INC := $(firstword $(foreach lib,lua5.4 lua54 lua5.3 lua53 lua,$(call check_lua_inc,$(lib),"/usr/include/")))
check_lua_lib = $(shell echo "int main(){}" | $(CC) $(if $(LUA_INC),-I$(LUA_INC)) -o /dev/null -x c - $(2) -l$(1) 2>/dev/null && echo $(1))
check_lua_lib = $(shell echo "int main(){}" | $(CC) -o /dev/null -x c - $(2) -l$(1) 2>/dev/null && echo $(1))
LUA_LD_FLAGS := -Wl,$(if $(EXPORT_SYMBOL),$(EXPORT_SYMBOL),--export-dynamic) $(if $(LUA_LIB),-L$(LUA_LIB))
# Try to automatically detect the Lua library if not set
ifeq ($(LUA_LIB_NAME),)
LUA_LIB_NAME := $(firstword $(foreach lib,lua lua5.5 lua55 lua5.4 lua54 lua5.3 lua53,$(call check_lua_lib,$(lib),$(LUA_LD_FLAGS))))
LUA_LIB_NAME := $(firstword $(foreach lib,lua5.4 lua54 lua5.3 lua53 lua,$(call check_lua_lib,$(lib),$(LUA_LD_FLAGS))))
endif
# Lua lib name must be set now (forced/detected above)
@ -722,15 +718,70 @@ ifneq ($(USE_PROMEX:0=),)
endif
ifneq ($(USE_DEVICEATLAS:0=),)
EXTRA_MAKE += addons/deviceatlas
# Use DEVICEATLAS_SRC and possibly DEVICEATLAS_INC and DEVICEATLAS_LIB to force path
# to DeviceAtlas headers and libraries if needed. In this context, DEVICEATLAS_NOCACHE
# can be used to disable the cache support if needed (this also removes the necessity of having
# a C++ toolchain installed).
DEVICEATLAS_INC = $(DEVICEATLAS_SRC)
DEVICEATLAS_LIB = $(DEVICEATLAS_SRC)
include addons/deviceatlas/Makefile.inc
OPTIONS_OBJS += addons/deviceatlas/da.o
endif
# Use 51DEGREES_SRC and possibly 51DEGREES_INC and 51DEGREES_LIB to force path
# to 51degrees v3/v4 headers and libraries if needed. Note that the SRC/INC/
# LIB/CFLAGS/LDFLAGS variables names all use 51DEGREES as the prefix,
# regardless of the version since they are mutually exclusive. The version
# (51DEGREES_VER) must be either 3 or 4, and defaults to 3 if not set.
51DEGREES_INC = $(51DEGREES_SRC)
51DEGREES_LIB = $(51DEGREES_SRC)
51DEGREES_VER = 3
ifneq ($(USE_51DEGREES:0=),)
EXTRA_MAKE += addons/51degrees
ifeq ($(51DEGREES_VER),4) # v4 here
_51DEGREES_SRC = $(shell find $(51DEGREES_LIB) -maxdepth 2 -name '*.c')
OPTIONS_OBJS += $(_51DEGREES_SRC:%.c=%.o)
51DEGREES_CFLAGS += -DUSE_51DEGREES_V4
ifeq ($(USE_THREAD:0=),)
51DEGREES_CFLAGS += -DFIFTYONEDEGREES_NO_THREADING -DFIFTYONE_DEGREES_NO_THREADING
endif
USE_LIBATOMIC = implicit
endif # 51DEGREES_VER==4
ifeq ($(51DEGREES_VER),3) # v3 here
OPTIONS_OBJS += $(51DEGREES_LIB)/../cityhash/city.o
OPTIONS_OBJS += $(51DEGREES_LIB)/51Degrees.o
ifeq ($(USE_THREAD:0=),)
51DEGREES_CFLAGS += -DFIFTYONEDEGREES_NO_THREADING
else
OPTIONS_OBJS += $(51DEGREES_LIB)/../threading.o
endif
else
ifneq ($(51DEGREES_VER),4)
$(error 51Degrees version (51DEGREES_VER) must be either 3 or 4)
endif
endif # 51DEGREES_VER==3
OPTIONS_OBJS += addons/51degrees/51d.o
51DEGREES_CFLAGS += $(if $(51DEGREES_INC),-I$(51DEGREES_INC))
51DEGREES_LDFLAGS += $(if $(51DEGREES_LIB),-L$(51DEGREES_LIB))
USE_MATH = implicit
endif # USE_51DEGREES
ifneq ($(USE_WURFL:0=),)
EXTRA_MAKE += addons/wurfl
# Use WURFL_SRC and possibly WURFL_INC and WURFL_LIB to force path
# to WURFL headers and libraries if needed.
WURFL_INC = $(WURFL_SRC)
WURFL_LIB = $(WURFL_SRC)
OPTIONS_OBJS += addons/wurfl/wurfl.o
WURFL_CFLAGS = $(if $(WURFL_INC),-I$(WURFL_INC))
ifneq ($(WURFL_DEBUG),)
WURFL_CFLAGS += -DWURFL_DEBUG
endif
ifneq ($(WURFL_HEADER_WITH_DETAILS),)
WURFL_CFLAGS += -DWURFL_HEADER_WITH_DETAILS
endif
WURFL_LDFLAGS = $(if $(WURFL_LIB),-L$(WURFL_LIB)) -lwurfl
endif
ifneq ($(USE_PCRE:0=)$(USE_STATIC_PCRE:0=)$(USE_PCRE_JIT:0=),)
@ -1003,7 +1054,7 @@ IGNORE_OPTS=help install install-man install-doc install-bin \
ifneq ($(TARGET),)
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(IGNORE_OPTS)),)
build_opts = $(shell rm -f .build_opts.new; echo \'$(TARGET) $(BUILD_OPTIONS) $(EXTRA_MAKE) $(VERBOSE_CFLAGS) $(WARN_CFLAGS) $(NOWARN_CFLAGS) $(DEBUG)\' > .build_opts.new; if cmp -s .build_opts .build_opts.new; then rm -f .build_opts.new; else mv -f .build_opts.new .build_opts; fi)
build_opts = $(shell rm -f .build_opts.new; echo \'$(TARGET) $(BUILD_OPTIONS) $(VERBOSE_CFLAGS) $(WARN_CFLAGS) $(NOWARN_CFLAGS) $(DEBUG)\' > .build_opts.new; if cmp -s .build_opts .build_opts.new; then rm -f .build_opts.new; else mv -f .build_opts.new .build_opts; fi)
.build_opts: $(build_opts)
else
.build_opts:

View file

@ -4,7 +4,7 @@
[![Illumos](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml)
[![NetBSD](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml)
[![CrossCompile](https://github.com/haproxy/haproxy/actions/workflows/cross-zoo.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/cross-zoo.yml)
[![FreeBSD](https://github.com/haproxy/haproxy/actions/workflows/freebsd.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/freebsd.yml)
[![FreeBSD](https://api.cirrus-ci.com/github/haproxy/haproxy.svg?task=FreeBSD)](https://cirrus-ci.com/github/haproxy/haproxy/)
[![VTest](https://github.com/haproxy/haproxy/actions/workflows/vtest.yml/badge.svg)](https://github.com/haproxy/haproxy/actions/workflows/vtest.yml)
![HAProxy logo](doc/HAProxyCommunityEdition_60px.png)

View file

@ -1,2 +1,2 @@
$Format:%ci$
2026/06/03
2026/05/08

View file

@ -1 +1 @@
3.5-dev0
3.4-dev11

View file

@ -127,16 +127,7 @@ static int _51d_property_name_list(char **args, int section_type, struct proxy *
while (*(args[cur_arg])) {
name = calloc(1, sizeof(*name));
if (!name) {
memprintf(err, "'%s' failed to allocate memory.", args[0]);
return -1;
}
name->name = strdup(args[cur_arg]);
if (!name->name) {
free(name);
memprintf(err, "'%s' failed to allocate memory.", args[0]);
return -1;
}
LIST_APPEND(&global_51degrees.property_names, &name->list);
++cur_arg;
}
@ -312,7 +303,6 @@ static void _51d_init_device_offsets(fiftyoneDegreesDeviceOffsets *offsets) {
static void _51d_set_device_offsets(struct sample *smp, fiftyoneDegreesDeviceOffsets *offsets)
{
struct buffer *temp = get_trash_chunk();
struct channel *chn;
struct htx *htx;
struct http_hdr_ctx ctx;
@ -334,15 +324,7 @@ static void _51d_set_device_offsets(struct sample *smp, fiftyoneDegreesDeviceOff
if (http_find_header(htx, name, &ctx, 1)) {
(offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global_51degrees.header_offsets + i);
/* Copy value into trash and NUL-terminate before passing to the
* 51Degrees Trie API, which expects a C string.
*/
if (ctx.value.len >= temp->size)
continue;
memcpy(temp->area, ctx.value.ptr, ctx.value.len);
temp->area[ctx.value.len] = '\0';
temp->data = ctx.value.len + 1;
(offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(&global_51degrees.data_set, temp->area);
(offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(&global_51degrees.data_set, ctx.value.ptr);
offsets->size++;
}
}
@ -568,8 +550,6 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
char valuesBuffer[1024];
#endif
#if defined(FIFTYONEDEGREES_H_PATTERN_INCLUDED) || defined(FIFTYONEDEGREES_H_TRIE_INCLUDED) || defined(FIFTYONE_DEGREES_HASH_INCLUDED)
char no_data[] = "NoData"; /* response when no data could be found */
struct buffer *temp = get_trash_chunk();
int i = 0, found;
@ -656,7 +636,6 @@ static void _51d_process_match(const struct arg *args, struct sample *smp)
smp->data.u.str.area = temp->area;
smp->data.u.str.data = temp->data;
}
#endif
/* Sets the sample data as a constant string. This ensures that the
* string will be processed correctly.
@ -937,10 +916,6 @@ static int init_51degrees(void)
list_for_each_entry(name, &global_51degrees.property_names, list)
++i;
_51d_property_list = calloc(i, sizeof(*_51d_property_list));
if (!_51d_property_list) {
ha_alert("51Degrees: Failed to allocate property list.\n");
return (ERR_FATAL | ERR_ALERT);
}
i = 0;
list_for_each_entry(name, &global_51degrees.property_names, list)
@ -1075,7 +1050,7 @@ static int init_51degrees(void)
static void deinit_51degrees(void)
{
struct _51d_property_names *_51d_prop_name = NULL, *_51d_prop_nameb = NULL;
struct _51d_property_names *_51d_prop_name, *_51d_prop_nameb;
#if defined(FIFTYONEDEGREES_H_PATTERN_INCLUDED) || defined(FIFTYONEDEGREES_H_TRIE_INCLUDED)
free(global_51degrees.header_names);

View file

@ -1,37 +0,0 @@
# Use 51DEGREES_SRC and possibly 51DEGREES_INC and 51DEGREES_LIB to force path
# to 51degrees v3/v4 headers and libraries if needed. Note that the SRC/INC/
# LIB/CFLAGS/LDFLAGS variables names all use 51DEGREES as the prefix,
# regardless of the version since they are mutually exclusive. The version
# (51DEGREES_VER) must be either 3 or 4, and defaults to 3 if not set.
51DEGREES_INC = $(51DEGREES_SRC)
51DEGREES_LIB = $(51DEGREES_SRC)
51DEGREES_VER = 3
ifeq ($(51DEGREES_VER),4) # v4 here
_51DEGREES_SRC = $(shell find $(51DEGREES_LIB) -maxdepth 2 -name '*.c')
OPTIONS_OBJS += $(_51DEGREES_SRC:%.c=%.o)
51DEGREES_CFLAGS += -DUSE_51DEGREES_V4
ifeq ($(USE_THREAD:0=),)
51DEGREES_CFLAGS += -DFIFTYONEDEGREES_NO_THREADING -DFIFTYONE_DEGREES_NO_THREADING
endif
USE_LIBATOMIC = implicit
endif # 51DEGREES_VER==4
ifeq ($(51DEGREES_VER),3) # v3 here
OPTIONS_OBJS += $(51DEGREES_LIB)/../cityhash/city.o
OPTIONS_OBJS += $(51DEGREES_LIB)/51Degrees.o
ifeq ($(USE_THREAD:0=),)
51DEGREES_CFLAGS += -DFIFTYONEDEGREES_NO_THREADING
else
OPTIONS_OBJS += $(51DEGREES_LIB)/../threading.o
endif
else
ifneq ($(51DEGREES_VER),4)
$(error 51Degrees version (51DEGREES_VER) must be either 3 or 4)
endif
endif # 51DEGREES_VER==3
OPTIONS_OBJS += addons/51degrees/51d.o
51DEGREES_CFLAGS += $(if $(51DEGREES_INC),-I$(51DEGREES_INC))
51DEGREES_LDFLAGS += $(if $(51DEGREES_LIB),-L$(51DEGREES_LIB))
USE_MATH = implicit

View file

@ -1,13 +1,6 @@
# DEVICEATLAS_SRC : DeviceAtlas API source root path
# Use DEVICEATLAS_SRC and possibly DEVICEATLAS_INC and DEVICEATLAS_LIB to force path
# to DeviceAtlas headers and libraries if needed. In this context, DEVICEATLAS_NOCACHE
# can be used to disable the cache support if needed (this also removes the necessity of having
# a C++ toolchain installed).
DEVICEATLAS_INC = $(DEVICEATLAS_SRC)
DEVICEATLAS_LIB = $(DEVICEATLAS_SRC)
CXX := c++
CXXLIB := -lstdc++
@ -35,7 +28,5 @@ OPTIONS_OBJS += $(DEVICEATLAS_SRC)/dadwcurl.o
OPTIONS_OBJS += $(DEVICEATLAS_SRC)/Os/daunix.o
endif
OPTIONS_OBJS += addons/deviceatlas/da.o
addons/deviceatlas/dummy/%.o: addons/deviceatlas/dummy/%.cpp
$(cmd_CXX) $(CXXFLAGS) -c -o $@ $<

View file

@ -1,13 +0,0 @@
# Use WURFL_SRC and possibly WURFL_INC and WURFL_LIB to force path
# to WURFL headers and libraries if needed.
WURFL_INC = $(WURFL_SRC)
WURFL_LIB = $(WURFL_SRC)
OPTIONS_OBJS += addons/wurfl/wurfl.o
WURFL_CFLAGS = $(if $(WURFL_INC),-I$(WURFL_INC))
ifneq ($(WURFL_DEBUG),)
WURFL_CFLAGS += -DWURFL_DEBUG
endif
ifneq ($(WURFL_HEADER_WITH_DETAILS),)
WURFL_CFLAGS += -DWURFL_HEADER_WITH_DETAILS
endif
WURFL_LDFLAGS = $(if $(WURFL_LIB),-L$(WURFL_LIB)) -lwurfl

View file

@ -1801,8 +1801,6 @@ void filter_count_ip(const char *source_field, const char *accept_field, const c
*/
if (unlikely(!ustat))
ustat = calloc(1, sizeof(*ustat));
if (!ustat)
return;
ustat->nb_err = err;
ustat->nb_req = 1;

View file

@ -26,7 +26,7 @@ end
# returns $node filled with the first node of ebroot $arg0
define ebtree_first
# browse ebtree left until encountering leaf
set $node = (struct eb_node *)((struct eb_root*)$arg0)->b[0]
set $node = (struct eb_node *)$arg0->b[0]
while 1
_ebtree_set_tag_node $node
if $tag == 0
@ -41,7 +41,7 @@ end
# finds next ebtree node after $arg0, and returns it in $node
define ebtree_next
# get parent
set $node = (struct eb_root *)((struct eb_node *)$arg0)->leaf_p
set $node = (struct eb_root *)$arg0->leaf_p
# Walking up from right branch, so we cannot be below root
# while (eb_gettag(t) != EB_LEFT) // #define EB_LEFT 0
while 1

View file

@ -1,39 +0,0 @@
# list info about open FD
define fd_dump
set $f = 0
while $f < $g.maxsock
if fdtab[$f].owner != 0
printf "fd %5d: rm=%#lx tm=%#lx um=%#lx cb=%p ownr=%p st=%#x refc=%#x tkov=%u gen=%u\n", $f, fdtab[$f].running_mask, fdtab[$f].thread_mask, fdtab[$f].update_mask, fdtab[$f].iocb, fdtab[$f].owner, fdtab[$f].state, fdtab[$f].refc_tgid, fdtab[$f].nb_takeover, fdtab[$f].generation
end
set $f = $f + 1
end
end
# only those attached to a listener
define fd_dump_listener
set $f = 0
while $f < $g.maxsock
if fdtab[$f].owner != 0 && fdtab[$f].iocb == &sock_accept_iocb
set $c = (struct listener *)fdtab[$f].owner
printf "fd %5d: rm=%#lx tm=%#lx um=%#lx st=%#x refc=%#x tkov=%u gen=%u listener=%p(%s): flg=%#x state=%d fe=%p(%s) acc=%p\n", $f, fdtab[$f].running_mask, fdtab[$f].thread_mask, fdtab[$f].update_mask, fdtab[$f].state, fdtab[$f].refc_tgid, fdtab[$f].nb_takeover, fdtab[$f].generation, fdtab[$f].owner, $c->name, $c->flags, $c->state, $c->bind_conf.frontend, $c->bind_conf.frontend.id, $c->bind_conf.accept
end
set $f = $f + 1
end
end
# only those attached to a connection
define fd_dump_conn
set $f = 0
while $f < $g.maxsock
if fdtab[$f].owner != 0 && fdtab[$f].iocb == &sock_conn_iocb
set $c = (struct connection *)fdtab[$f].owner
printf "fd %5d: rm=%#lx tm=%#lx um=%#lx st=%#x refc=%#x tkov=%u gen=%u conn=%p: flg=%#x err=%#x ctrl=%p xprt=%p mux=%p", $f, fdtab[$f].running_mask, fdtab[$f].thread_mask, fdtab[$f].update_mask, fdtab[$f].state, fdtab[$f].refc_tgid, fdtab[$f].nb_takeover, fdtab[$f].generation, fdtab[$f].owner, $c->flags, $c->err_code, $c->ctrl, $c->xprt, $c->mux
if *$c->target == OBJ_TYPE_LISTENER
set $s = (struct session *)$c->owner
printf " sess=%p: fe=%p id=%s age=%dms", $s, $s->fe, $s->fe->id, (*global_now_ns - $s->accept_ts) / 1000000
end
printf "\n"
end
set $f = $f + 1
end
end

View file

@ -1,31 +0,0 @@
# lists all tasks in the wait queue whose ebroot pointed to by $arg0
# e.g.
# task_dump_wq &ha_tgroup_ctx[0].timers
# task_dump_wq &ha_thread_ctx[0].timers
#
define task_dump_rq
set $tot=0
ebtree_first ($arg0)
while ($node != 0)
set $tot = $tot+1
set $p = (struct task *)((void*)$node-(long)&((struct task*)0).rq)
printf "task %p ",$p
p -pretty off -- /a *$p
ebtree_next $node
end
printf "Total: %d tasks.\n",$tot
end
define task_dump_wq
set $tot=0
ebtree_first ($arg0)
while ($node != 0)
set $tot = $tot+1
set $p = (struct task *)((void*)$node-(long)&((struct task*)0).wq)
printf "task %p ",$p
p -pretty off -- /a *$p
ebtree_next $node
end
printf "Total: %d tasks.\n",$tot
end

View file

@ -1,10 +0,0 @@
# list info about current threads (ptr, now_ms, queue, current)
define thread_dump
set $t = 0
while $t < $g.nbthread
set $i = $ti[$t].pth_id
set $h = $tc[$t].current
printf "Tid %4d: pth=%p mono=%llu now_ms=%u fl=0x%02x rq=%d cq=%d current=%p\n", $t, $i, $tc[$t].curr_mono_time, (unsigned)(($tc[$t].curr_mono_time + now_offset)/1000000), $tc[$t].flags, $tc[$t].current_queue, $tc[$t].rq_total, $h
set $t = $t + 1
end
end

View file

@ -1,70 +0,0 @@
BEGININPUT
BEGINCONTEXT
HAProxy's development cycle consists in one development branch, and multiple
maintenance branches.
All the development is made into the development branch exclusively. This
includes mostly new features, doc updates, cleanups and or course, fixes.
The maintenance branches, also called stable branches, never see any
development, and only receive ultra-safe fixes for bugs that affect them,
that are picked from the development branch.
Branches are numbered in 0.1 increments. Every 6 months, upon a new major
release, the development branch enters maintenance and a new development branch
is created with a new, higher version. The current development branch is
3.5-dev, and maintenance branches are 3.4 and below.
Fixes created in the development branch for issues that were introduced in an
earlier branch are applied in descending order to each and every version till
that branch that introduced the issue: 3.4 first, then 3.2, then 3.1, then 3.0
and so on. This operation is called "backporting". A fix for an issue is never
backported beyond the branch that introduced the issue. An important point is
that the project maintainers really aim at zero regression in maintenance
branches, so they're never willing to take any risk backporting patches that
are not deemed strictly necessary.
Fixes consist of patches managed using the Git version control tool and are
identified by a Git commit ID and a commit message. For this reason we
indistinctly talk about backporting fixes, commits, or patches; all mean the
same thing. When mentioning commit IDs, developers always use a short form
made of the first 8 characters only, and expect the AI assistant to do the
same.
It seldom happens that some fixes depend on changes that were brought by other
patches that were not in some branches and that will need to be backported as
well for the fix to work. In this case, such information is explicitly provided
in the commit message by the patch's author in natural language.
Developers are serious and always indicate if a patch needs to be backported.
Sometimes they omit the exact target branch, or they will say that the patch is
"needed" in some older branch, but it means the same. If a commit message
doesn't mention any backport instructions, it means that the commit does not
have to be backported. And patches that are not strictly bug fixes nor doc
improvements are normally not backported. For example, fixes for design
limitations, architectural improvements and performance optimizations are
considered too risky for a backport. Finally, all bug fixes are tagged as
"BUG" at the beginning of their subject line. Patches that are not tagged as
such are not bugs, and must never be backported unless their commit message
explicitly requests so.
ENDCONTEXT
A developer is reviewing the development branch, trying to spot which commits
need to be backported to maintenance branches. This person is already expert
on HAProxy and everything related to Git, patch management, and the risks
associated with backports, so he doesn't want to be told how to proceed nor to
review the contents of the patch.
The goal for this developer is to get some help from the AI assistant to save
some precious time on this tedious review work. In order to do a better job, he
needs an accurate summary of the information and instructions found in each
commit message. Specifically he needs to figure if the patch fixes a problem
affecting an older branch or not, if it needs to be backported, if so to which
branches, and if other patches need to be backported along with it.
The indented text block below after an "id" line and starting with a Subject line
is a commit message from the HAProxy development branch that describes a patch
applied to that branch, starting with its subject line, please read it carefully.

View file

@ -1,29 +0,0 @@
ENDINPUT
BEGININSTRUCTION
You are an AI assistant that follows instruction extremely well. Help as much
as you can, responding to a single question using a single response.
The developer wants to know if he needs to backport the patch above to fix
maintenance branches, for which branches, and what possible dependencies might
be mentioned in the commit message. Carefully study the commit message and its
backporting instructions if any (otherwise it should probably not be backported),
then provide a very concise and short summary that will help the developer decide
to backport it, or simply to skip it.
Start by explaining in one or two sentences what you recommend for this one and why.
Finally, based on your analysis, give your general conclusion as "Conclusion: X"
where X is a single word among:
- "yes", if you recommend to backport the patch right now either because
it explicitly states this or because it's a fix for a bug that affects
a maintenance branch (3.4 or lower);
- "wait", if this patch explicitly mentions that it must be backported, but
only after waiting some time.
- "no", if nothing clearly indicates a necessity to backport this patch (e.g.
lack of explicit backport instructions, or it's just an improvement);
- "uncertain" otherwise for cases not covered above
ENDINSTRUCTION
Explanation:

View file

@ -2,8 +2,8 @@
HAProxy
Configuration Manual
----------------------
version 3.5
2026/06/03
version 3.4
2026/05/08
This document covers the configuration language as implemented in the version
@ -2001,7 +2001,6 @@ The following keywords are supported in the "global" section :
- tune.sndbuf.client
- tune.sndbuf.frontend
- tune.sndbuf.server
- tune.streams-elasticity
- tune.stick-counters
- tune.ssl.cachesize
- tune.ssl.capture-buffer-size
@ -2126,28 +2125,13 @@ ca-base <dir>
directives. Absolute locations specified in "ca-file", "ca-verify-file" and
"crl-file" prevail and ignore "ca-base".
chroot { <jail dir> | auto }
chroot <jail dir>
Changes current directory to <jail dir> and performs a chroot() there before
dropping privileges. This increases the security level in case an unknown
vulnerability would be exploited, since it would make it very hard for the
attacker to exploit the system. It is important to ensure that <jail dir>
is both empty and non-writable to anyone. When the process is started with
superuser privileges, the chroot() is performed directly. On Linux, when
started unprivileged, haproxy attempts to perform it from inside a new
user namespace created with unshare(CLONE_NEWUSER); if that mechanism is
unavailable the chroot() will fail with the usual error.
As a special case, <jail dir> may be set to "auto", in which case haproxy
creates an anonymous temporary directory, unlinks it, and chroots into it.
The resulting jail has no name in the filesystem and is empty and read-only,
removing the need to prepare a dedicated jail directory.
When starting with superuser privileges, a warning will be displayed if no
chroot is used, in order to encourage users to always use the mechanism. If
for any reason there is a compelling reason not to use chroot (e.g. access to
a server via a UNIX socket with an unconvenient path), it remains possible to
silence the warning by adding an explicit "chroot /", which has the benefit
of being visible in a configuration.
attacker to exploit the system. This only works when the process is started
with superuser privileges. It is important to ensure that <jail_dir> is both
empty and non-writable to anyone.
close-spread-time <time>
Define a time window during which idle connections and active connections
@ -3329,7 +3313,7 @@ setenv <name> <value>
the configuration file sees the new value. See also "presetenv", "resetenv",
and "unsetenv".
shm-stats-file <name>
shm-stats-file <name> [ EXPERIMENTAL ]
When this directive is set, it enables the use of shared memory for storing
stats counters. <name> is used as argument to shm_open() to open the shared
memory at a unique location. It also means that the directive is only
@ -3345,7 +3329,7 @@ shm-stats-file <name>
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
shm-stats-file-max-objects <number>
shm-stats-file-max-objects <number> [ EXPERIMENTAL ]
This setting defines the maximum number of objects the shared memory used
for shared counters will be able to store per thread group. It is directly
related to the maximum memory size of the shm and is used to "premap" the
@ -4940,8 +4924,8 @@ tune.lua.openlibs [all | none | <lib>[,<lib>...]]
tune.lua.openlibs string,math,table,utf8 # safe subset, no I/O or OS
tune.lua.openlibs all # default, load everything
This setting must be set before any "lua-load", "lua-load-per-thread" or
"lua-prepend-path" directive, otherwise a parse error is returned.
This setting must be set before any "lua-load" or "lua-load-per-thread"
directive, otherwise a parse error is returned.
tune.lua.service-timeout <timeout>
This is the execution timeout for the Lua services. This is useful for
@ -5321,26 +5305,17 @@ tune.quic.frontend.stream-data-ratio <0..100, in percent> (deprecated)
tune.quic.be.stream.max-concurrent <number>
tune.quic.fe.stream.max-concurrent <number>
On frontend side, this is used as the value for the advertised
initial_max_streams_bidi transport parameter. This is enforced as the maximum
number of bidirectional streams that the remote peer will be authorized to
open concurrently during the connection lifetime. This effectively limits the
number of concurrent HTTP/3 client requests.
Sets the QUIC initial_max_streams_bidi transport parameter either on frontend
or backend side. This is the maximum number of bidirectional streams that the
remote peer will be authorized to open concurrently during the connection
lifetime. On frontend side, this limits the number of concurrent HTTP/3
client requests.
The default value is 100. Note that if you reduces it, it can restrict the
buffering capabilities of streams on receive, which would result in poor
upload throughput. It can be corrected by increasing the QUIC stream rxbuf
connection setting.
On backend side, this is enforced locally by haproxy to limit the number of
concurrent requests multiplexed over a single connection. This may be further
restricted by the peer flow control. It may be necessary to reduce the
default value of 100 to improve a site's responsiveness at the expense of a
higher number of opened backend connections. Similarly to the frontend side,
this setting also directly impacts the Rx buffering capability, this time
though limiting the HTTP download capacity. QUIC stream rxbuf setting can be
increased when dealing mostly with HTTP responses larger than "tune.bufsize".
See also: "tune.quic.be.stream.rxbuf", "tune.quic.fe.stream.rxbuf",
"tune.quic.be.stream.data-ratio", "tune.quic.fe.stream.data-ratio"
@ -5714,49 +5689,6 @@ tune.ssl.ssl-ctx-cache-size <number>
dynamically is expensive, they are cached. The default cache size is set to
1000 entries.
tune.streams-elasticity <number>
Defines a target percentage of streams per frontend connection relative to
the maximum number of concurrent connections (maxconn) when all connections
are established. This metric applies to multiplexed protocols like HTTP/2 or
QUIC, where each connection may receive multiple streams. At least one is
always guaranteed, so the percentage must be at least 100%. During connection
setup, HAProxy dynamically advertises additional streams up to the configured
limit, maintaining the target ratio. At connection establishment, every
frontend connection receives at least one stream; extra streams are assigned
based on the target percentage and configured stream limits. This ensures
efficient stream allocation under varying load conditions (more streams at
low loads, fewer at high loads).
Highly dynamic sites with many objects per page benefit from high ratios,
enabling many streams per connection. Sites using fewer streams on average
(WebSocket, application code) may prefer small ratios closer to 120 or 150
(20 to 50% more streams than connections) preventing excessive stream counts
under sustained loads.
The default value is 0, meaning no enforcement at this level, so only H2 and
QUIC configurations apply (with the default setting of 100 streams per
connection, this corresponds to 10000%). This remains the recommended setting
for small deployments (maxconn around a thousand). Moderately sized setups
(few thousands to tens of thousands connections) typically set the ratio
between 1000 and 5000, allowing 10 to 50 streams per connection at full load.
Large-scale deployments (hundreds of thousands to millions connections) might
use lower values (120 to 200) to support 1.2 to 2 streams per connection on
average at full load.
Contrary to HTTP/2, QUIC is capable to dynamically adjust the number of
concurrent streams during the connection lifetime. However, QUIC flow control
is stricter than HTTP/2, thus it is preferable when using it to specify
values big enough to prevent extra latency on the connection. There is also a
limitation for QUIC listeners with enabled 0-RTT. In this case, the initial
value advertised to the peer will ignore stream elasticity and instead rely
solely on the "tune.quic.fe.stream.max-concurrent" setting. However, the
stream elasticity principle will still be effective past this initial
annoucement during the connection lifetime.
Monitoring the total number of active streams on backends, including queues,
provides a practical indicator of a sustainable target load and helps avoid
over-provisioning.
tune.stick-counters <number>
Sets the number of stick-counters that may be tracked at the same time by a
connection or a request via "track-sc*" actions in "tcp-request" or
@ -8294,10 +8226,7 @@ hash-type <method> <function> <modifier>
none don't hash the key, the key will be used as a hash, this can be
useful to manually hash the key using a converter for that purpose
and let haproxy use the result directly. The operation will
convert the key to a string if it is not already, and parse it as
an integer whose value will be used as the key. Some input key
types might not be relevant here (e.g. IP addresses).
and let haproxy use the result directly.
<modifier> indicates an optional method applied after hashing the key :
@ -9105,9 +9034,7 @@ http-reuse { never | safe | aggressive | always }
- proxy protocol
- TOS and mark socket options
- connection name, determined either by the result of the evaluation of the
"pool-conn-name" expression if present, otherwise by the "sni" expression,
which defaults to "req.hdr(host),field(1,:)", i.e. uses the incoming
request's "Host" header field without the colon nor the port number.
"pool-conn-name" expression if present, otherwise by the "sni" expression
In some occasions, connection lookup or reuse is not performed due to extra
restrictions. This is determined by the reuse strategy specified via the
@ -9181,26 +9108,6 @@ http-reuse { never | safe | aggressive | always }
too few connections are kept open. It may be desirable in this case to adjust
such thresholds or simply to increase the global "maxconn" value.
In some rare cases, when the host name is used to distinguish outgoing TLS
connections (e.g. forward proxy), where most request target different hosts,
the reuse rate will be very low, and the automatic eviction of rarely used
connections will kick in before connections have a chance to be reused,
because the mechanism continuously measures the average number of connections
needed to deliver the service without exhausting resources. In such
situations, setting "pool-low-conn" to a value close to the average expected
number of idle connections may help preserve more connections by encouraging
threads to setup their own instead of trying to pick other threads' and
shrinking the pool of available connections.
If a locally hosted server uses a single certificate (with multiple host
names or wildcards) and operates multiple sites, it may be more effective to
just use "no-sni-auto" on the "server" line to avoid reserving a connection
to a single Host name. This will significantly increase the reuse rate. Some
servers might perform excessive checks between Host and SNI though, resulting
in rejecting subsequent requests, so this option requires preliminary
validation. The default behavior ("sni-auto") is to be safe even with such
servers.
When thread groups are explicitly enabled, it is important to understand that
idle connections are only usable between threads from a same group. As such
it may happen that unfair load between groups leads to more idle connections
@ -9984,7 +9891,7 @@ no option accept-unsafe-violations-in-http-request
When this option is set, the following rules are observed:
* In H1 only, invalid characters, including NULL character, in header name
will not be rejected; however the header will be dropped.
will be accepted;
* In H1 only, NULL character in header value will be accepted;
@ -10049,11 +9956,8 @@ no option accept-unsafe-violations-in-http-response
When this option is set, the following rules are observed:
* In H1 only, status codes longer than 3 digits but whose value fits in 16
bits are not rejected.
* In H1 only, invalid characters, including NULL character, in header name
will not be rejected; however the header will be dropped.
will be accepted;
* In H1 only, NULL character in header value will be accepted;
@ -18909,21 +18813,6 @@ hash-key <key>
better only use values comprised between 1 and this value to
avoid overlap.
id32 The node keys will be derived from the server's numeric
identifier as set from "id" or which defaults to its position
in the server list, but the full 32 bits of the ID will be
used so that there is no collision. This one is not scaled
like "id" is, so it is recommended to either always use it
with a hash function (see "hash-key") or with explicitly
assigned ID values that are evenly distributed over the 32-bit
space.
guid The node keys will be derived from the server's guid, when
available, otherwise they will fall back on "id". The benefit
is that it does not depend on ordering at all, only on an
internal stable identifier that can be replicated across many
load balancers.
addr The node keys will be derived from the server's address, when
available, or else fall back on "id".
@ -18953,13 +18842,9 @@ healthcheck <name>
id <value>
May be used in the following contexts: tcp, http, log
Set a persistent ID for the server. This ID must be a 32-bit positive number
and unique for the proxy. An unused ID will automatically be assigned if
unset. The first assigned value will be 1. This ID is currently only returned
in statistics, and is used to place LB nodes when using consistent hash
algorithms when "hash-key" is set to "id" (the default). In this case, only
the 28 lowest bits of the value are used (i.e. (id % 268435356)), so better
only use values comprised between 1 and this value to avoid overlap.
Set a persistent ID for the server. This ID must be positive and unique for
the proxy. An unused ID will automatically be assigned if unset. The first
assigned value will be 1. This ID is currently only returned in statistics.
idle-ping <delay>
May be used in the following contexts: tcp, http, log
@ -19053,7 +18938,7 @@ downinter <delay>
"inter" setting will have a very limited effect as it will not be able to
reduce the time spent in the queue.
init-state { fully-up | up | down | fully-down | none }
init-state { fully-up | up | down | fully-down }
May be used in the following contexts: tcp, http
May be used in sections : defaults | frontend | listen | backend
@ -19061,25 +18946,20 @@ init-state { fully-up | up | down | fully-down | none }
The "init-state" option sets the initial state of the server:
- when set to 'fully-up', the server is considered immediately available
and, if health checks are enabled for this server, it will be turned to
the DOWN state when ALL health checks fail.
- when set to 'up', the server is considered immediately available and, if
health checks are enabled for this server, it will be turned to the DOWN
state immediately if the next health check fails.
- when set to 'down', the server initially is considered unavailable and,
if health checks are enabled for this server, it can be turned to the UP
state if the next health check succeeds.
and can turn to the DOWN state when ALL health checks fail.
- when set to 'up' (the default), the server is considered immediately
available and will initiate a health check that can turn it to the DOWN
state immediately if it fails.
- when set to 'down', the server initially is considered unavailable and
will initiate a health check that can turn it to the UP state immediately
if it succeeds.
- when set to 'fully-down', the server is initially considered unavailable
and, if health checks are enabled for this server, it will turned to the
UP state when ALL health checks succeed.
- when set to 'none' (the default value), init-state management is
disabled. It can be used to restore the default behavior when this
parameter was inherited from a 'default-server' directive.
and can turn to the UP state when ALL health checks succeed.
The server's init-state is considered when the HAProxy instance is
(re)started, a new server is detected (for example via service discovery /
DNS resolution), a dynamic server is inlived, a server exits maintenance,
etc. This directive cannot be used when the server is tracking another one.
etc.
Examples:
# pass client traffic ONLY to Redis "master" node
@ -19921,13 +19801,11 @@ sni-auto
May be used in the following contexts: tcp, http, log, peers, ring
The "sni-auto" parameter enables the automatic SNI selection, if no value was
already set. It sets the "sni" expression to "req.hdr(host),field(1,:)",
which means that an SNI will be presented with the Host name of the request
that is being sent to the server, but dropping the port number. It is enabled
by default but this parameter may be used as "server" setting to reset any
"no-sni-auto" setting which would have been inherited from "default-server"
directive as default value. It may also be used as "default-server" setting
to reset any previous "default-server" "no-sni-auto" setting.
already set. It is enabled by default but this parameter may be used as
"server" setting to reset any "no-sni-auto" setting which would have been
inherited from "default-server" directive as default value. It may also be
used as "default-server" setting to reset any previous "default-server"
"no-sni-auto" setting.
For HTTPS connections, the selected SNI is based on the request host header
value, if found. Otherwise it remains unset. For other protocols, the option
@ -20277,11 +20155,7 @@ a cache of previous answers, an answer will be considered obsolete after
resolvers <resolvers id>
Creates a new name server list labeled <resolvers id>. As mentioned above,
the special name "default" always exists and will be automatically created if
not explicitly declared; this will be the one internal services such as
httpclient rely on. Declaring a "default" entry will affect how such services
perform their name resolution.
Creates a new name server list labeled <resolvers id>
A resolvers section accept the following parameters:
@ -21237,8 +21111,6 @@ param(name[,delim]) string string
port_only string integer
protobuf(field_number[,field_type]) binary binary
regsub(regex,subst[,flags]) string string
reverse string string
reverse_dom string string
rfc7239_field(field) string string
rfc7239_is_valid string boolean
rfc7239_n2nn string address / str
@ -22736,58 +22608,6 @@ regsub(<regex>,<subst>[,<flags>])
http-request redirect location %[url,'regsub("(foo|bar)([0-9]+)?","\2\1",i)']
http-request redirect location %[url,regsub(\"(foo|bar)([0-9]+)?\",\"\2\1\",i)]
reverse
Reverses the input string byte by byte.
This converter is encoding-agnostic and reverses bytes, not characters; it is
not suitable for reversing human text encoded as UTF-8.
This can turn suffix lookups on the original string into prefix lookups on
the reversed string, allowing the use of indexed prefix matchers such as
"map_beg" on large maps.
Examples:
"example.com" -> "moc.elpmaxe"
"ab cd" -> "dc ba"
# Given a map file where each key contains a reversed hostname:
# moc.elpmaxe.ppa app1
# moc.elpmaxe.bd dbcluster
# Pick a backend based on the domain suffix of the Host header:
use_backend %[req.hdr(host),lower,reverse,map_beg(/etc/haproxy/hosts.map,default)]
reverse_dom
Converts a string containing an FQDN-like hostname into its reversed-label
form. A single trailing dot on the input is ignored. Empty labels cause the
converter to fail.
This converter does not lowercase its input and does not strip any port.
It is meant to be combined with existing converters such as "lower" or
"host_only" when needed.
The trailing-dot policy is intentionally left to the caller. This allows
callers to decide whether they want to match the apex too or only
subdomains.
The reversed-label form is useful for large domain maps because it turns
domain suffix lookups into prefix lookups, allowing the use of indexed prefix
matchers such as "map_beg".
Examples:
"example.com" -> "com.example"
"mail.example.com" -> "com.example.mail"
"example.com." -> "com.example"
# match only subdomains of example.net, not the apex
acl example_net_sub req.hdr(Host),host_only,reverse_dom -m beg net.example.
# match only the apex
acl example_net_apex req.hdr(Host),host_only,reverse_dom -i net.example
# exact-or-subdomain prefix lookup using an explicit dotted form
http-request set-var(txn.rev_host) req.hdr(Host),host_only,reverse_dom,concat(.)
use_backend %[var(txn.rev_host),map_beg(/etc/haproxy/domains.map)]
rfc7239_field(<field>)
Extracts a single field/parameter from RFC 7239 compliant header value input.

View file

@ -1,238 +0,0 @@
HAPROXY CORE PRINCIPLES
0. RULE ZERO: EXCEPTIONS AND JUSTIFICATION
- These rules are mandatory; violations are bugs unless explicitly justified.
- A violation is acceptable if accompanied by a comment explaining WHY the
standard approach was insufficient (e.g., "Performance-critical bypass").
- Reviews should flag unjustified violations but accept commented ones.
1. PROJECT ORGANIZATION
- header files all under "include/", and split between haproxy/<file>-t.h for
type definitions (types, enums, structures), and haproxy/<file>.h for static
definitions and exported symbols. A few imported libs under include/import.
- C source files in src/.
- some API doc in doc/internals/api/ (not always up to date, check date or
version at the top).
2. ENVIRONMENT AND DATA TYPES
- The project targets 32/64-bit POSIX systems (little or big endian).
- Char is signed or unsigned 8-bit, short signed 16-bit, int signed 32-bit.
- Long and pointers always match the native word size. Long long is 64-bit.
- Aliases: uchar (unsigned char), uint (unsigned int), ulong (unsigned long),
ushort (unsigned short), ullong (unsigned long long), llong (long long),
schar (signed char).
- size_t is always the same size as long, but its underlying type is often
uint on 32-bit and ulong on 64-bit. This is a frequent source of build
errors on 32-bit platforms (e.g. passing a size_t where a long* is
expected, or printing one with "%lu"); always cast in printf() (ulong
with "%lu").
- Main platforms are x86_64 and aarch64 with high thread counts (>=64).
- Unaligned accesses are permitted for archs that support them; portable
wrappers in net_helper.h (read_u32(), write_u32() etc).
- signed integer wrapping well-defined via -fwrapv.
- arch-specific asm() statements OK as long as equivalent C-code exists for
generic archs.
- Pointer arithmetics used a lot via container_of(), offset_of(), and void*
casts.
- Floating point not used.
3. MEMORY MANAGEMENT AND POOLS
- Pools are used for runtime allocation; malloc/free are for boot code only.
- pool_alloc() semantics match malloc(); the return must always be tested.
- pool_alloc() and malloc() are not interchangeable: memory obtained from one
must not be released using the other's free function.
- pool_free() semantics match free(); it is a no-op on NULL.
- pool_free() makes the pointer invalid immediately; it must not be touched
or passed to pool_free() again.
- Memory allocated from one pool must be released to the same pool.
- ha_free() calls free() and sets the pointer to NULL before returning.
- my_realloc2() frees the original pointer if the allocation fails.
- never leave dangling pointers in structs after free().
4. BUFFER INVARIANTS (struct buffer)
- Buffers are 4-word inline structs used for data in transit (wrapping,
sliding window).
- Members: area (storage), size (capacity), head (offset), data (count).
- The area pointer is allowed to be NULL when size is zero.
- always true: 0<=data<=size; always true when size>0: 0<=head<size.
- contents start at <head>, for <data> bytes, and may wrap at the end of the
storage area (area+size).
- API (b_*, in buf.h and dynbuf.h) supports empty or unallocated buffers.
- idempotent functions b_alloc() and b_free() use pools to manage the
storage area and check <size> to know if alloc/free still needed.
- a non-contiguous version exists (ncbuf, ncbmbuf), allowing holes anywhere
in data. ncbuf mandates holes of at least 8 bytes, while ncbmbuf relies on
a bitmap of populated places.
- another string API exists, "ist", representing a pointer and a length in a
struct that is returned by inline functions and macros. It is described in
doc/internals/api/ist.txt
- buffers can switch to and from HTX, which is an internal representation of
HTTP elements, with an API supporting header addition/modification/removal,
start-line manipulation, data appending/consumption etc. HTX functions are
all prefixed with "htx_". Between htx_from_buf() and htx_to_buf(), only the
HTX API may be used, not the b_* API.
5. DATA MANIPULATION (CHUNKS, TRASH, LISTS, TREES)
- Chunks use the buffer API but are NOT allowed to wrap.
- Chunks are used for linear operations like chunk_printf().
- Trash is a thread-local temporary buffer; scope stays within the caller.
- trash always the same size as a buffer (global.tune.bufsize).
- get_trash_chunk() provides rotating thread-local trash chunks. Since almost
any function may itself call get_trash_chunk(), a returned chunk is only
guaranteed valid until the next call into another function and must not be
held across such a call. The rotation lets a single function safely use up
to 3 distinct chunks at once for its own data manipulation.
- For longer lived trash chunks, alloc_trash_chunk() is available but must be
released using free_trash_chunk() on leaving.
- standard doubly-linked lists (struct list) are provided via macros LIST_*.
- LIST_INIT() must be used on new heads and elements. LIST_DELETE() only
removes the element and does not reinitialize it, so the idempotent
LIST_DEL_INIT() is generally preferred. Iterators like list_for_each_* are
available, some safe against item removal. See doc/internals/api/list.txt
for details (grep -i "^list_" to list available macros).
- thread-safe doubly-linked lists (struct mt_list) are provided via macros
mt_list_*. They work like lists and use compatible storage, though they may
not be mixed. See doc/internals/api/mt_list.txt (grep -i "^mt_list_" to
list available operations).
- elastic binary trees (ebtree) are used for fast access (O(logN) operations,
O(1) deletion). Idempotent deletion. Main functions are lookup, insert,
delete, first, next, with type-based prefix eb{32,64,st,mb,pt}_*().
- compact elastic binary trees (cebtree) are used for read-mostly focusing on
space savings (O(logN) operations, but higher cost than ebtree). Same ops
as ebtree, with type-based prefix ceb{32,u32,64,u64,s,is}_*.
6. THREAD SYNCHRONIZATION
- Threads are started at boot (one per CPU) and persist for the process life,
arranged in thread groups (tg) by cache locality.
- Each thread has its own polling loop and scheduler. Total parallelism.
- thread_isolate()/thread_release() for total thread isolation (very heavy).
- "tid" always current thread number, "th_ctx" always current thread's context,
"ti" current thread info.
- "tgid" always current tg number, "tg_ctx" current tg context.
- HA_ATOMIC_* for atomic operations on integers and pointers (includes load
and store). DWCAS is available on some platforms but requires an equivalent
fallback on the others (possibly a more complex operation, e.g. emulation
using two or more CAS).
- The _HA_ATOMIC_* version (leading underscore) do not use barriers so these
must be explicit (__ha_barrier_*).
- Atomic loops must use CPU relaxation or exponential back-off.
- For multiple changes at once, threads may use spinlocks (HA_SPIN_LOCK()/
HA_SPIN_UNLOCK/HA_SPIN_TRYLOCK), and upgradable RW locks (HA_RWLOCK_*) if
read accesses dominate.
- No sleeping locks (mutex etc), only spinning/rwlocks/atomic loops.
7. SCHEDULING AND LATENCY
- Latency is critical.
- No runtime filesystem access, no blocking calls, no long loops.
- Complex processing must be split into small steps; the task must yield.
- CPUs are not dedicated to haproxy, high risk of a thread being interrupted
by another process if it works too long, catastrophic if it happens with a
lock held.
- A watchdog kills the process if a task hogs a CPU for > few milliseconds.
- Tasks vs Tasklets: Tasks have tree storage (rq) and timers (wq); tasklets
use list elements instead of rq and are smaller (no wq). Only task.c/h may
distinguish rq vs list access.
- Tasks are aliased to tasklet while they are running (hence why some
functions cast task to tasklets and conversely to access certain fields).
- inter-thread task/tasklet wakeups always safe using the task_* API.
- task/tasklet->state field must always be accessed atomically.
8. ARCHITECTURAL LAYERS (MUX AND STREAMS)
- Naming: Lower layer (multiplexed), attached to the connection uses suffix
'c' (h1c, h2c, qcc, muxc); Upper layer (demultiplexed/application, often a
stream) uses suffix 's' (h1s, h2s, qcs, muxs).
- Application layer stream (struct stream) has two stream connectors (stconn):
front (scf) and back (scb). Responsible for processing requests/responses,
deciding which server to route it, finding a backend connection or creating
one, and exchanging data between the two sides.
- Stream connectors link to a muxs or applet via a stream endpoint descriptor
(sedesc/sd), and exchange data via buffers, which for an HTTP muxs are HTX
buffers containing HTX blocks.
- The sd carries the shared context between layers.
- When a stream detaches from a mux, a new sd is allocated for the stream and
the mux keeps its previous sd: stconn and muxs both always have a valid sd.
- Front connections/streams are tied to the creator thread forever.
- Idle back connections can be stolen via mux->takeover(), but become
thread-bound once a stream attaches. => all streams of a mux are on the
same thread.
- session vs connection vs stream: connection is transport; session lasts for
the client connection's life; stream are request/response pairs.
- applets carry a context specific to the service being executed or the CLI
command in appctx->svcctx, and this one is always zeroed before the handler
is first called.
9. FUNCTION RETURN CONVENTIONS
- Boolean style: Functions named as actions/sentences return 0 (failure) or
non-zero (success).
- Integer style: some syscall-like functions return <0 (error) or >=0 (success).
- Tri-state style, e.g. counts: <0 (error), 0 (no progress), >0 (success).
10. DIAGNOSTICS AND SAFETY
- When DEBUG_STRICT is set, ABORT_NOW() crashes the program immediately, and
BUG_ON(cond[,msg]) crashes the program if the condition is true.
- COUNT_IF() / CHECK_IF() only track if a condition occurs (non-fatal).
- Glitches are counters for uncommon events used to detect hostile behavior.
- strcpy(), strcat() and sprintf() are totally forbidden (the program will
not build).
11. BASIC CODING STYLE
- Linux Kernel-like, but uses tabs for indent, spaces for alignment. Function
definitions have their opening brace on a new line, never on the same line.
- All local variables must be declared at the beginning of the function
block, before any executable statements (gnu89-like).
- Avoid variable shadowing in code blocks.
- Beware of local static and global variables.
- Use const arguments whenever possible.
- Avoid static storage when persistence is not needed.
- Macros in uppercase unless they're used to wrap functions which then get a
leading underscore.
- Explicitly compare against 0 the return of functions that yield an integer
which is not a boolean (e.g. strcmp), unless they return a boolean (e.g.
isalnum) or a pointer (e.g. strchr).
- Unsigned int comparisons to zero never use >0 but !=0 to avoid signedness
mistakes.
- turn non-zero integer to boolean using "!" or "!!".
12. BUILD AND TEST
- Preferred build command:
$ make -j$(nproc) TARGET=linux-glibc OPT_CFLAGS='-std=gnu89 -Os' \
USE_OPENSSL=1 USE_QUIC_OPENSSL_COMPAT=1 USE_QUIC=1 USE_LUA=1
- Individual files can be tested by passing src/file.o as a make argument.
- Compiler warnings are not permitted for new code.
13. COMMIT MESSAGES AND DOCUMENTATION
- Commit messages must follow the project's strict format below. Do not try
to learn better from previous commits, which might be wrong during reviews.
- Structure: <TAG>: <location>: <subject> (max ~70 chars), then blank line,
then description.
- Tags:
- CLEANUP: spelling fixes, refactoring, no new code nor functional change.
- MINOR: new feature or low-impact change, may be backported if needed.
- MEDIUM: new feature or change with moderate severity/impact/risk.
- MAJOR: new feature or change with important severity/impact/risk.
- OPTIM: Performance improvements, may always be reverted if it breaks.
- DOC: Documentation updates or fixes.
- BUG/<severity>: Fixes a bug. Specify if regression or long-standing.
Valid severities are MINOR (low impact), MEDIUM (perf/stability risk
in uncommon configs, MAJOR (most configs), CRITICAL (stability risk
without workaround).
- Regressions: Find original commit via `git blame`; designate using
`git log -1 --format='%h ("%s")'` and version via `git describe --tags`.
- Location: subsystem (stream, tasks, mux-h2, qpack etc).
- Description: Explain technical "WHY", "HOW", and technical impact. Explain
how to trigger the bug for developer testing.
- Backports: only for fixes, mention versions ("Must be backported to 3.0").
- Style: No generic messages like "fix(xxx): blah". Be technically precise.
- Do not mix spelling fixes in comments (not important) with other changes.
However it's preferred to have a single commit for many typo fixes at once.
- Spelling mistakes in user-visible parts (doc, logs, traces, error messages)
must be in their own commit (may need backport).
- One commit per bug.
- Example:
BUG/MEDIUM: sample: fix null pointer dereference in h1_parse_line
When parsing malformed headers, the line buffer was not initialized.
This caused a crash on certain edge cases. Let's fix this by always
initializing the line buffer when first calling the parser. This was
brought by commit 04c9e8f5 ("MINOR: add h1_parse_line") in latest -dev
so no backport is needed.

View file

@ -1,233 +0,0 @@
HAProxy Threat Model & Trust Boundaries
This document defines the security boundaries of HAProxy, explicitly outlining
what does and does not constitute a security vulnerability. Its purpose is to
give reporters, developers and reviewers a single, predictable basis for
judging an issue's real-world impact.
The project's strong preference is to fix issues quickly and in the open.
Public handling gets fixes to users sooner and spares the ecosystem
(distributions in particular) the heavy cost of embargo coordination, which in
practice has rarely served users. Private, coordinated disclosure is reserved
for the few cases whose real-world impact genuinely warrants it, judged from
the severity ordering (section 6) and the mitigations (section 5). An issue
that is technically in scope but contained in practice does not, by itself,
call for an embargo.
These boundaries apply strictly to officially supported, documented builds
running under a sane, production-ready configuration. Security guarantees are
explicitly voided when using opt-in unsafe knobs, undocumented behavior, or
experimental features. A configuration that merely lacks a recommended
hardening step (for instance, no chroot) does not by itself move a
client-triggered bug out of scope; the missing mitigation only widens the
blast radius (sections 5 and 6).
1. ASSETS TO PROTECT
HAProxy sits on the critical path of the services it fronts, so its
availability and the integrity and confidentiality of the configuration and
secrets it holds are all essential to protect. The assets below are not
ranked here; their relative severity is ranked in section 6.
- Integrity and confidentiality of the host and configuration: a compromise
of the network-facing worker must not extend to the filesystem, nor to the
configuration and its dependencies (private keys, Lua scripts, maps,
crt-lists, ACLs). On a properly configured system the default structural
mitigations prevent this, leaving only a compromise of the master process
as a residual path (see section 5).
- Confidentiality of long-lived secrets: TLS private keys and certificates
above all. Unlike transient client data, their disclosure is permanent and
systemic (impersonation and traffic decryption until every key is rotated
and revoked).
- Availability of the proxied service: being on the critical path, keeping
HAProxy serving is paramount. A small, cheap amount of attacker input
must neither consume a disproportionate amount of CPU or memory
(asymmetric DoS, see section 3) nor crash or stall the process.
- Confidentiality and isolation of client data: data belonging to one
connection, stream or client must never leak to another, and process
memory (including uninitialized memory) must never leak to a client.
- Process integrity (memory safety): no RCE, memory corruption or undefined
behaviour (UB) reachable from untrusted input.
- Correct enforcement of the configured policy: access controls, routing and
header manipulations decided by the configuration must not be bypassable
by crafted input.
2. ATTACKER AND ENTRY POINTS
- The reference attacker is an untrusted client able to send arbitrary
bytes to a frontend: raw TCP payloads, HTTP/1, HTTP/2 and HTTP/3 (QUIC)
traffic, and arbitrary TLS handshake records.
- Entry points in scope are therefore the listeners and everything that
parses or transforms client-supplied data: TLS, the HTTP muxes, HTX,
header/URL processing, sample fetches and converters acting on request
data, stick-tables fed by client data, the cache, and the QUIC/H3 stack.
- A secondary untrusted source is the DNS resolver path: even though
nameservers are configured, their answers arrive over UDP and can be
spoofed by an off-path attacker, so the response parser handles
attacker-influenced input.
3. WHAT QUALIFIES AS A SECURITY BUG (IN SCOPE)
- Memory-safety issues (overflow, out-of-bounds, use-after-free, type
confusion, UB) reachable from untrusted client input.
- Cross-client or cross-stream effects: HTTP request smuggling, response
splitting, cache poisoning, and any mixing of data between concurrent
streams or connections (notably in the H2/H3 multiplexers).
- Disclosure of process memory or of another client's data to a client.
- Bypass of a policy that the configuration is meant to enforce (e.g.
defeating an http-request deny/acl through request crafting).
- Asymmetric / algorithmic denial of service: a single or a few cheap
requests causing disproportionate CPU or memory usage (hash-collision
flooding, catastrophic regex backtracking, quadratic parsing, unbounded
allocation, etc). This is distinct from volumetric DoS (see 4).
- Misuse of a third-party library on untrusted input: feeding malformed
client data into OpenSSL, PCRE, Lua, zlib, etc. in a way that corrupts
memory or crashes the process is in scope. A vulnerability inside the
library itself is handled by that library's project, not here.
- Mishandling of spoofable DNS responses: memory corruption, crashes or
cache/state poisoning in the resolver caused by a crafted DNS answer are
in scope, despite nameservers being nominally trusted (see section 2).
4. WHAT DOES NOT QUALIFY (OUT OF SCOPE)
The following do not fall into the security-bug category.
Trusted peers, servers and protocols:
- attacks that require a non-compliant or malicious server: in a reverse
proxy, servers are trusted, or ejected. This covers server-to-client
attacks in general.
- attacks on protocols only used with trusted peers: peers, PROXY protocol,
CIP (NetScaler Client-IP insertion), SOCKS, a local server reached over
an ABNS or UNIX socket, an FCGI server, etc., as well as TLS servers
contacted by the internal httpclient.
- malfunction of a trusted auxiliary service (log server, ring output,
CLI API consumer, etc.).
Privileged or local access (the actor is already trusted):
- any problem triggered through admin access to the CLI.
- anything requiring access to the master CLI.
- anything requiring access to the command line.
- anything requiring write access to the configuration file or any of its
dependencies (Lua scripts, certificates, crt-list, acl, map, etc.).
- anything requiring a configuration running as root, or chrooted to "/"
(i.e. with no effective chroot).
Opt-in unsafe or experimental knobs (the operator disabled a safety):
- anything requiring "experimental-mode on" on the CLI.
- anything requiring "insecure-fork-wanted".
- anything requiring "accept-unsafe-violations-*".
- anything requiring "expose-experimental-directives".
Misconfiguration:
- anything requiring a configuration that emits warnings at boot.
- anything requiring a nonsensical configuration, e.g. a server looping back
to the frontend, non-standard header processing or URL rewriting, or an
excessively large number of headers or excessively large header/body
sizes.
Volumetric or otherwise detectable activity:
- anything requiring such a high and sustained level of activity that it
would be detected and blocked in production (e.g. billions of requests or
connections). This is volumetric DoS, as opposed to the asymmetric DoS of
section 3.
Inherent protocol limitations:
- anything that is a limitation of a standard protocol rather than an
implementation flaw. For example, HTTP/1 has no way to abort a single
transfer without closing the connection, so a client aborting a transfer
will necessarily cause the corresponding server-side connection to be
closed; this is by design of the protocol, not a vulnerability.
Features that are not security boundaries:
- the stats page, including its admin mode, relies on HTTP basic
authentication and was never meant to be a security boundary. Exposing a
public-facing, admin-enabled stats page is therefore not covered.
- configuring a listener to accept the PROXY protocol or CIP from senders
that are not restricted to trusted ones is a misconfiguration: these
headers are believed on trust, so the listener must be reachable only by
the trusted L4/L7 component that prepends them.
Side channels:
- cryptographic and micro-architectural side channels (timing, cache,
speculative execution, etc.) are out of scope. Constant-time handling of
secrets is pursued on a best-effort basis as ordinary hardening where it
clearly matters, but observable timing or resource variations are not
handled as security bugs.
Log integrity:
- escaping of data emitted to logs is a configuration responsibility.
Injection of control characters or forged fields through logged client
data (e.g. when default escaping is disabled, or when a downstream log
consumer mis-parses) is not covered.
5. DEFENSE IN DEPTH (DEFAULT HARDENING)
A correctly deployed HAProxy combines several built-in mitigations that
bound the impact of a successful compromise. These are deliberately taken
into account when assessing the real-world severity of an issue and the
handling it deserves: when one of them contains the practical impact of a
bug, that bug rarely warrants a coordinated embargo and is usually better
fixed quickly and in the open, where users get the fix sooner. They lower
severity, not the obligation to fix: an exploitable memory-safety bug
reachable from client input is still corrected as a bug.
- No fork()/exec() in the worker: the worker never forks nor runs external
programs, so an attacker who achieves code execution has little ability
to spawn a shell or launch persistent background code. ("insecure-fork-
wanted" deliberately disables this and is itself out of scope, see
section 4.)
- chroot and privilege drop: in the sane configuration this document
assumes, the worker drops to an unprivileged user/group and chroots into
an empty, unwritable directory. Injected code therefore has no filesystem
access and very limited means to act on the host.
- Activity watchdog: a thread that stops making progress, e.g. hijacked
into an attacker-controlled loop or otherwise stuck, no longer services
the event loop; the watchdog detects this lack of activity and kills the
process after a few seconds rather than letting it be silently held.
- Master/worker separation: only the worker is exposed to the network and
runs the parsers reachable by clients, and it is the unprivileged,
chrooted process. The master keeps privileges and filesystem access but
has no network exposure. The master must therefore be protected as the
trusted, more privileged component; an attacker is assumed to face only
the worker. The master must under no circumstances be reachable from the
worker (e.g. a master CLI bound to a TCP socket such as localhost is
trivially reachable from compromised worker code and defeats this critical
separation).
6. SEVERITY ORDERING
The worst-case outcomes below are ranked by their realistic impact on a
standard configuration, from most to least severe, and the effort spent
guarding against each is proportional to that severity. The ranking reflects
the master/worker privilege split and the containment provided by the
section-5 mitigations.
1. Remote code execution in the master process. The master is privileged
and has filesystem access, so compromising it defeats every
containment, leaks every secret, and can subvert or take down the
whole service.
2. Chosen disclosure of long-lived secrets, TLS private keys and
certificates above all. Unlike an outage the damage is permanent and
silent: stolen keys allow impersonation, interception and, absent
forward secrecy, decryption of captured traffic, until every affected
key is rotated and revoked across the ecosystem; a restart does not
undo it. "Chosen" sets this rank, not scope: any disclosure of process
memory or of another client's data to a client is in scope (section 3);
this top rank is reserved for a targeted exfiltration, where the
attacker steers the read to a known secret. A leak that cannot be
steered toward a specific secret is still an in-scope disclosure bug,
but ranks far lower - often no worse than the crash such a read tends
to cause first.
3. Crash of the master process. It brings the entire service down and
prevents workers from being respawned: a full but recoverable outage.
4. Crash of the worker process. A transient outage: in-flight connections
are lost and traffic is interrupted for the fraction of a second it
takes to respawn.
5. Remote code execution in the worker process. Contained by no-fork,
chroot, privilege drop and the watchdog, its availability impact is
usually below a worker crash, except in the unlikely case where it
unlocks the chosen disclosure of level 2, which is hard to reach
through the internals from injected code.
6. Policy bypass. Serious, but with no direct availability impact.
7. SECURITY-RELEVANT INVARIANTS AND DEFAULTS
The values below define the conditions HAProxy is designed to operate
within, and may be relied upon by parsing and processing code. A suspected
vulnerability that can only be triggered by conditions outside them
(typically values pushed beyond the stated limits) does not qualify as
security-relevant:
- trash buffers and struct buffer storage are always at least a few kB.
- default buffer size is 16 kB (15 kB max input, as 1 kB is reserved for
rewrites), tunable up to <256 MB.
- default log line is 1 kB, tunable up to <=64 kB.

View file

@ -1,7 +1,7 @@
-----------------------
HAProxy Starter Guide
-----------------------
version 3.5
version 3.4
This document is an introduction to HAProxy for all those who don't know it, as
@ -97,9 +97,6 @@ to the mailing list whose responses are present in these documents.
protocol which is implemented by HAProxy and a number of third party
products.
- security.txt : how to report a security issue, and what does and does not
qualify as a vulnerability.
- README : how to build HAProxy from sources
@ -1689,7 +1686,15 @@ information you might later regret. Since the issue tracker presents itself as
a very long thread, please avoid pasting very long dumps (a few hundreds lines
or more) and attach them instead.
If you believe you may have found a security issue, please refer to the file
doc/security.txt. It explains what does and does not qualify as a vulnerability
in HAProxy, and how to report a genuine one privately. Most suspected issues
turn out to be ordinary bugs that are better reported as described above.
If you've found what you're absolutely certain can be considered a critical
security issue that would put many users in serious trouble if discussed in a
public place, then you can send it with the reproducer to security@haproxy.org.
A small team of trusted developers will receive it and will be able to propose
a fix. We usually don't use embargoes and once a fix is available it gets
merged. In some rare circumstances it can happen that a release is coordinated
with software vendors. Please note that this process usually messes up with
everyone's work, and that rushed up releases can sometimes introduce new bugs,
so it's best avoided unless strictly necessary; as such, there is often little
consideration for reports that needlessly cause such extra burden, and the best
way to see your work credited usually is to provide a working fix, which will
appear in changelogs.

View file

@ -1,7 +1,7 @@
------------------------
HAProxy Management Guide
------------------------
version 3.5
version 3.4
This document describes how to start, stop, manage, and troubleshoot HAProxy,
@ -215,18 +215,6 @@ list of options is :
in foreground and to show incoming and outgoing events. It must never be
used in an init script.
-dA[file] : dump an archive of all dependencies detected at boot time in the
designated file in tar format, immediately after the configuration is done
loading. This is equivalent to "set-dumpable libs", but instead of keeping
the libs in memory, it dumps them into a file. This may be used after a
core dump, in order to provide all necessary libraries to developers to
permit them to exploit the core. This may not be available on all operating
systems. It is highly recommended to use this with the regular
configuration files, and optionally with "-c" when used manually, to make
haproxy immediately exit after the dump, without starting. Example:
$ haproxy -dA/tmp/libs.tar -c -f /etc/haproxy/haproxy.cfg
-dC[key] : dump the configuration file. It is performed after the lines are
tokenized, so comments are stripped and indenting is forced. If a non-zero
key is specified, lines are truncated before sensitive/confidential fields,
@ -3107,40 +3095,37 @@ show events [<sink>] [-w] [-n] [-0]
delimited by a line feed character ('\n' or 10 or 0x0A). It is possible to
change this to the NUL character ('\0' or 0) by passing the "-0" argument.
show fd [-!plcfbsd]* [[<tgid>]/[<fd>] | <fd>]
show fd [-!plcfbsd]* [<fd>]
Dump the list of either all open file descriptors or just the one number <fd>
if specified. The form "<tgid>/<fd>" is also accepted, where either side may
be empty as a wildcard ("/<fd>" for fd <fd> across thread groups, "<tgid>/"
for all fds of <tgid>). The <tgid> is currently parsed but ignored, pending
future support for per-thread-group fd tables. A set of flags may optionally
be passed to restrict the dump only to certain FD types or to omit certain FD
types. When '-' or '!' are encountered, the selection is inverted for the
following characters in the same argument. The inversion is reset before each
argument word delimited by white spaces. Selectable FD types include 'p' for
pipes, 'l' for listeners, 'c' for connections (any type), 'f' for frontend
connections, 'b' for backend connections (any type), 's' for connections to
servers, 'd' for connections to the "dispatch" address or the backend's
transparent address. With this, 'b' is a shortcut for 'sd' and 'c' for 'fb' or
'fsd'. 'c!f' is equivalent to 'b' ("any connections except frontend
connections" are indeed backend connections). This is only aimed at developers
who need to observe internal states in order to debug complex issues such as
abnormal CPU usages. One fd is reported per lines, and for each of them, its
state in the poller using upper case letters for enabled flags and lower case
for disabled flags, using "P" for "polled", "R" for "ready", "A" for "active",
the events status using "H" for "hangup", "E" for "error", "O" for "output",
"P" for "priority" and "I" for "input", a few other flags like "N" for "new"
(just added into the fd cache), "U" for "updated" (received an update in the
fd cache), "L" for "linger_risk", "C" for "cloned", then the cached entry
position, the pointer to the internal owner, the pointer to the I/O callback
and its name when known. When the owner is a connection, the connection flags,
and the target are reported (frontend, proxy or server). When the owner is a
listener, the listener's state and its frontend are reported. There is no
point in using this command without a good knowledge of the internals. It's
worth noting that the output format may evolve over time so this output must
not be parsed by tools designed to be durable. Some internal structure states
may look suspicious to the function listing them, in this case the output line
will be suffixed with an exclamation mark ('!'). This may help find a starting
point when trying to diagnose an incident.
if specified. A set of flags may optionally be passed to restrict the dump
only to certain FD types or to omit certain FD types. When '-' or '!' are
encountered, the selection is inverted for the following characters in the
same argument. The inversion is reset before each argument word delimited by
white spaces. Selectable FD types include 'p' for pipes, 'l' for listeners,
'c' for connections (any type), 'f' for frontend connections, 'b' for backend
connections (any type), 's' for connections to servers, 'd' for connections
to the "dispatch" address or the backend's transparent address. With this,
'b' is a shortcut for 'sd' and 'c' for 'fb' or 'fsd'. 'c!f' is equivalent to
'b' ("any connections except frontend connections" are indeed backend
connections). This is only aimed at developers who need to observe internal
states in order to debug complex issues such as abnormal CPU usages. One fd
is reported per lines, and for each of them, its state in the poller using
upper case letters for enabled flags and lower case for disabled flags, using
"P" for "polled", "R" for "ready", "A" for "active", the events status using
"H" for "hangup", "E" for "error", "O" for "output", "P" for "priority" and
"I" for "input", a few other flags like "N" for "new" (just added into the fd
cache), "U" for "updated" (received an update in the fd cache), "L" for
"linger_risk", "C" for "cloned", then the cached entry position, the pointer
to the internal owner, the pointer to the I/O callback and its name when
known. When the owner is a connection, the connection flags, and the target
are reported (frontend, proxy or server). When the owner is a listener, the
listener's state and its frontend are reported. There is no point in using
this command without a good knowledge of the internals. It's worth noting
that the output format may evolve over time so this output must not be parsed
by tools designed to be durable. Some internal structure states may look
suspicious to the function listing them, in this case the output line will be
suffixed with an exclamation mark ('!'). This may help find a starting point
when trying to diagnose an incident.
show info [typed|json] [desc] [float]
Dump info about haproxy status on current process. If "typed" is passed as an

View file

@ -1,4 +1,4 @@
2026/04/27 Willy Tarreau
2020/03/05 Willy Tarreau
HAProxy Technologies
The PROXY protocol
Versions 1 & 2
@ -31,7 +31,6 @@ Revision history
2025/09/09 - added SSL-related TLVs for key exchange group and signature
scheme (Steven Collison)
2026/01/15 - added SSL client certificate TLV (Simon Ser)
2026/04/27 - clarified UDP usage (Valaphee)
1. Background
@ -176,11 +175,6 @@ The receiver may apply a short timeout and decide to abort the connection if
the protocol header is not seen within a few seconds (at least 3 seconds to
cover a TCP retransmit).
For UDP, the PROXY protocol header and the proxied UDP payload MUST be sent in
the same datagram. The sender MUST NOT split the PROXY protocol header across
multiple UDP datagrams, and the receiver MUST parse the header independently
for each received datagram.
The receiver MUST be configured to only receive the protocol described in this
specification and MUST not try to guess whether the protocol header is present
or not. This means that the protocol explicitly prevents port sharing between

View file

@ -1,40 +0,0 @@
Reporting security issues in HAProxy
------------------------------------
Before reporting anything, please read doc/internals/threat-model.txt. It
defines precisely what is and is not considered a security vulnerability in
HAProxy. A fair number of suspected issues (and most automated or LLM-assisted
findings) fall outside that boundary: they are ordinary bugs, and are best
reported and fixed in public through the usual channels described in the
"Contacts" section of doc/intro.txt.
If, after reading the threat model, you are confident you have found a genuine
security issue that would put many users at risk if discussed in the open, the
security team can be reached at security@haproxy.org, a private list read by a
handful of security officers; anything shared there remains private. Please
include a reproducer, and ideally a proposed and tested patch, as well as a
valid name under which the report can be credited.
Auxiliary tools in dev/ and admin/ are not intended for production use and are
by nature out of the security scope. Please report bugs affecting them via the
regular channels.
We usually don't use embargoes: once a fix is available it simply gets merged.
In rare circumstances a release may be coordinated with software vendors, but
this disrupts everyone's work and rushed releases can introduce new bugs, so it
is avoided unless strictly necessary. As a result, reports that needlessly cause
such extra burden get little consideration, and the most effective and best
credited way to report an issue is to provide a working fix, which will appear
in the changelogs.
Findings produced with the help of AI MUST be accompanied by a working, tested
patch. Such tools routinely report issues that are out of scope (see the
threat model above) or simply not real, and reviewing them by hand wastes the
very time and trust this process depends on. A model-generated report that
arrives without a verified reproducer and a fix will generally not be
processed.
See also:
- doc/internals/threat-model.txt : what qualifies as a vulnerability
- doc/internals/core-principles.txt : the project's design principles
- doc/intro.txt : general contacts and bug reporting

View file

@ -16,6 +16,6 @@ traces
trace applet verbosity complete start now
trace h3 start now
trace quic start now
trace qcm start now
trace qmux start now
trace peers start now
.endif

View file

@ -22,6 +22,7 @@
extern struct userlist *userlist;
struct userlist *auth_find_userlist(char *name);
unsigned int auth_resolve_groups(struct userlist *l, char *groups);
int userlist_postinit();
void userlist_free(struct userlist *ul);
struct pattern *pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill);

View file

@ -156,7 +156,6 @@ struct lbprm_per_tgrp {
* The other ones might take it themselves if needed.
*/
struct lb_ops {
struct list link;
int (*proxy_init)(struct proxy *); /* set up per-proxy LB state at config time; <0=fail */
void (*update_server_eweight)(struct server *); /* to be called after eweight change // srvlock */
void (*set_server_status_up)(struct server *); /* to be called after status changes to UP // srvlock */
@ -167,11 +166,6 @@ struct lb_ops {
void (*proxy_deinit)(struct proxy *); /* to be called when we're destroying the proxy */
void (*server_deinit)(struct server *); /* to be called when we're destroying the server */
int (*server_init)(struct server *); /* initialize a freshly added server (runtime); <0=fail. */
uint32_t algo_prop; /* load balancing algorithm lookup and properties */
struct {
uint32_t mask;
uint32_t match;
} map[VAR_ARRAY];
};
/* LB parameters for all algorithms */

View file

@ -30,10 +30,6 @@
#include <haproxy/stream-t.h>
#include <haproxy/time.h>
extern struct list lb_ops_list;
void lb_ops_register(struct lb_ops *ops);
struct server *get_server_sh(struct proxy *px, const char *addr, int len, const struct server *avoid);
struct server *get_server_uh(struct proxy *px, char *uri, int uri_len, const struct server *avoid);
struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len, const struct server *avoid);

View file

@ -76,7 +76,7 @@
#define CF_WAKE_ONCE 0x10000000 /* pretend there is activity on this channel (one-shoot) */
#define CF_FLT_ANALYZE 0x20000000 /* at least one filter is still analyzing this channel */
/* unused 0x40000000 */
/* unuse 0x40000000 */
#define CF_ISRESP 0x80000000 /* 0 = request channel, 1 = response channel */
/* Masks which define input events for stream analysers */
@ -252,30 +252,27 @@ struct channel {
* without waking the parent up. The special value CHN_INFINITE_FORWARD is
* never decreased nor increased.
*
* The channel's consumed data count (b_data(chn->buf)) says how many bytes may
* be consumed from the visible buffer. This is updated by any buffer_write()
* as well as any data forwarded through the visible buffer. Since the
* ->to_forward attribute applies to data beyond what's already been accounted
* for, an analyser will not see a buffer which has a non-null ->to_forward
* with additional unprocessed data. A producer is responsible for raising the
* consumed count by min(to_forward, available_data) when it injects data into
* the buffer.
* The buf->o parameter says how many bytes may be consumed from the visible
* buffer. This parameter is updated by any buffer_write() as well as any data
* forwarded through the visible buffer. Since the ->to_forward attribute
* applies to data after buf->p, an analyser will not see a buffer which has a
* non-null ->to_forward with buf->i > 0. A producer is responsible for raising
* buf->o by min(to_forward, buf->i) when it injects data into the buffer.
*
* The consumer is responsible for advancing the consumed count (via
* b_ack()) when it sends data from the visible buffer, and for updating
* ->pipe->data when it sends data from the invisible buffer.
* The consumer is responsible for decreasing ->buf->o when it sends data
* from the visible buffer, and ->pipe->data when it sends data from the
* invisible buffer.
*
* A real-world example consists in part in an HTTP response waiting in a
* buffer to be forwarded. We know the header length (300) and the amount of
* data to forward (content-length=9000). The buffer already contains 1000
* bytes of data after the 300 bytes of headers. Thus the caller will set
* the consumed count to 300 indicating that it explicitly wants to send those
* data, and set ->to_forward to 9000 (content-length). This value must be
* normalised immediately after updating ->to_forward : since there are already
* 1300 bytes in the buffer, 300 of which are already counted in the consumed
* count, and that size is smaller than ->to_forward, we must update the
* consumed count to 1300 to flush the whole buffer, and reduce ->to_forward to
* 8000. After that, the producer may
* buf->o to 300 indicating that it explicitly wants to send those data, and
* set ->to_forward to 9000 (content-length). This value must be normalised
* immediately after updating ->to_forward : since there are already 1300 bytes
* in the buffer, 300 of which are already counted in buf->o, and that size
* is smaller than ->to_forward, we must update buf->o to 1300 to flush the
* whole buffer, and reduce ->to_forward to 8000. After that, the producer may
* try to feed the additional data through the invisible buffer using a
* platform-specific method such as splice().
*
@ -294,16 +291,15 @@ struct channel {
* buf->size - global.maxrewrite + ->to_forward.
*
* A buffer may contain up to 5 areas :
* - the data already consumed (acknowledged). These data are located between
* b_lim(b) and b_head(b) ;
* - the data available to process and possibly transform. These data start at
* b_head(b) and may be up to b_data(b) bytes long.
* - the data to preserve. They start at b_head(b) and stop at
* b_lim(b) + b_data(b). The limit between the two solely depends on the
* protocol being analysed.
* - the data waiting to be sent. These data are located between buf->p-o and
* buf->p ;
* - the data to process and possibly transform. These data start at
* buf->p and may be up to ->i bytes long.
* - the data to preserve. They start at ->p and stop at ->p+i. The limit
* between the two solely depends on the protocol being analysed.
* - the spare area : it is the remainder of the buffer, which can be used to
* store new incoming data. It starts at b_lim(b) + b_data(b) and is up to
* b->size - b_data(b) long. It may be limited by global.maxrewrite.
* store new incoming data. It starts at ->p+i and is up to ->size-i-o long.
* It may be limited by global.maxrewrite.
* - the reserved area : this is the area which must not be filled and is
* reserved for possible rewrites ; it is up to global.maxrewrite bytes
* long.

View file

@ -422,7 +422,7 @@ static inline int channel_is_rewritable(const struct channel *chn)
*/
static inline int channel_may_send(const struct channel *chn)
{
return chn_cons(chn)->state >= SC_ST_REQ;
return chn_cons(chn)->state == SC_ST_EST;
}
/* HTX version of channel_may_recv(). Returns non-zero if the channel can still
@ -808,7 +808,7 @@ static inline size_t channel_data(const struct channel *chn)
return (IS_HTX_STRM(chn_strm(chn)) ? htx_used_space(htxbuf(&chn->buf)) : c_data(chn));
}
/* Returns the amount of input data in a channel, taking the HTX streams into
/* Returns the amount of input data in a channel, taking he HTX streams into
* account. This function relies on channel_data().
*/
static inline size_t channel_input_data(const struct channel *chn)
@ -816,6 +816,12 @@ static inline size_t channel_input_data(const struct channel *chn)
return channel_data(chn) - co_data(chn);
}
/* Returns 1 if the channel is empty, taking he HTX streams into account */
static inline size_t channel_empty(const struct channel *chn)
{
return (IS_HTX_STRM(chn) ? htx_is_empty(htxbuf(&chn->buf)) : c_empty(chn));
}
/* Check channel's last_read date against the idle timeer to verify the producer
* is still streaming data or not
*/
@ -855,7 +861,7 @@ static inline void channel_check_xfer(struct channel *chn, size_t xferred)
chn->flags &= ~(CF_STREAMER | CF_STREAMER_FAST);
}
else if (chn->xfer_small >= 2) {
/* if the buffer has been at least half full times,
/* if the buffer has been at least half full twchne,
* we receive faster than we send, so at least it
* is not a "fast streamer".
*/

View file

@ -165,7 +165,9 @@ static forceinline struct buffer *alloc_small_trash_chunk(void)
*/
static forceinline struct buffer *alloc_trash_chunk_sz(size_t size)
{
if (size <= pool_head_trash->size)
if (pool_head_small_trash && size <= pool_head_small_trash->size)
return alloc_small_trash_chunk();
else if (size <= pool_head_trash->size)
return alloc_trash_chunk();
else if (pool_head_large_trash && size <= pool_head_large_trash->size)
return alloc_large_trash_chunk();

View file

@ -583,12 +583,10 @@
* for such array declarations. But it's not the case for clang and other
* compilers.
*/
#ifndef __nonstring
# if __has_attribute(nonstring)
# define __nonstring __attribute__ ((nonstring))
# else
# define __nonstring
# endif
#if __has_attribute(nonstring)
#define __nonstring __attribute__ ((nonstring))
#else
#define __nonstring
#endif
#endif /* _HAPROXY_COMPILER_H */

View file

@ -60,7 +60,7 @@ struct comp_ctx {
struct slz_stream strm;
const void *direct_ptr; /* NULL or pointer to beginning of data */
int direct_len; /* length of direct_ptr if not NULL */
struct buffer queued; /* if not null, data already queued */
struct buffer queued; /* if not NULL, data already queued */
#elif defined(USE_ZLIB)
z_stream strm; /* zlib stream */
void *zlib_deflate_state;

View file

@ -130,8 +130,8 @@ enum {
CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */
CO_FL_QMUX_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
CO_FL_QMUX_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
CO_FL_QSTRM_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
CO_FL_QSTRM_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */
/* These flags indicate whether the Control and Transport layers are initialized */
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */
@ -179,8 +179,6 @@ enum {
/* below we have all handshake flags grouped into one */
CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP | CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV,
CO_FL_WAIT_XPRT = CO_FL_WAIT_L4_CONN | CO_FL_HANDSHAKE | CO_FL_WAIT_L6_CONN,
/* handshake running on top of a layer6 */
CO_FL_WAIT_XPRT_L6 = CO_FL_QMUX_SEND | CO_FL_QMUX_RECV,
CO_FL_SSL_WAIT_HS = 0x08000000, /* wait for an SSL handshake to complete */
@ -215,7 +213,7 @@ static forceinline char *conn_show_flags(char *buf, size_t len, const char *deli
/* flags */
_(CO_FL_SAFE_LIST, _(CO_FL_IDLE_LIST, _(CO_FL_CTRL_READY,
_(CO_FL_REVERSED, _(CO_FL_ACT_REVERSING, _(CO_FL_OPT_MARK, _(CO_FL_OPT_TOS,
_(CO_FL_QMUX_SEND, _(CO_FL_QMUX_RECV,
_(CO_FL_QSTRM_SEND, _(CO_FL_QSTRM_RECV,
_(CO_FL_XPRT_READY, _(CO_FL_WANT_DRAIN, _(CO_FL_WAIT_ROOM, _(CO_FL_SSL_NO_CACHED_INFO, _(CO_FL_EARLY_SSL_HS,
_(CO_FL_EARLY_DATA, _(CO_FL_SOCKS4_SEND, _(CO_FL_SOCKS4_RECV, _(CO_FL_SOCK_RD_SH,
_(CO_FL_SOCK_WR_SH, _(CO_FL_ERROR, _(CO_FL_FDLESS, _(CO_FL_WAIT_L4_CONN,
@ -287,7 +285,7 @@ enum {
CO_ER_SSL_FATAL, /* SSL fatal error during a SSL_read or SSL_write */
CO_ER_QMUX, /* QMux transport parameter exchange failure */
CO_ER_QSTRM, /* QMux transport parameter exchange failure */
CO_ER_REVERSE, /* Error during reverse connect */
@ -351,7 +349,7 @@ enum {
XPRT_SSL = 1,
XPRT_HANDSHAKE = 2,
XPRT_QUIC = 3,
XPRT_QMUX = 4,
XPRT_QSTRM = 4,
XPRT_ENTRIES /* must be last one */
};
@ -675,12 +673,11 @@ struct connection {
};
struct mux_proto_list {
const struct ist mux_proto; /* Mux protocol, to be used with the "proto" directive */
const struct ist token; /* token name and length. Empty is catch-all */
enum proto_proxy_mode mode;
enum proto_proxy_side side;
const struct mux_ops *mux;
const char *alpn; /* Default alpn to set by default when the mux protocol is forced (optional, in binary form) */
int init_xprt;
struct list list;
};

View file

@ -86,10 +86,7 @@ int conn_create_mux(struct connection *conn, int *closed_connection);
int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake);
int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
struct ist mux_proto, int mode);
const struct mux_proto_list *conn_select_mux_fe(const struct connection *conn);
int conn_install_mux_fe(struct connection *conn, void *ctx);
const struct mux_proto_list *conn_select_mux_be(const struct connection *conn);
int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess,
const struct mux_ops *force_mux_ops);
int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *sess);
@ -114,7 +111,6 @@ int conn_reverse(struct connection *conn);
const char *conn_err_code_name(struct connection *c);
const char *conn_err_code_str(struct connection *c);
int xprt_add_hs(struct connection *conn);
int xprt_add_l6hs(struct connection *conn, int xprt);
void register_mux_proto(struct mux_proto_list *list);
static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type);
@ -500,64 +496,6 @@ static inline int conn_install_mux(struct connection *conn, const struct mux_ops
return ret;
}
/* Calculates the approximate number of streams permitted for an already
* established frontend connection based on the number of active connections
* (including this one), the number of already committed streams in the current
* thread group, the limit, and the desired limit (a ratio of which will be
* applied as the budget permits). May return 0 for no limit. The minimum value
* when a limit is set will be 1 as a minimum.
*/
static inline uint conn_calc_max_streams(uint desired)
{
uint per_conn_left;
uint avg_per_conn;
uint conn_curr;
int conn_left;
uint extra;
uint curr;
/* check for infinite */
if (!global.tune.streams_elasticity)
return 0;
/* check for none (0% overcommit) */
if (global.tune.streams_elasticity == 100)
return 1;
if (desired <= 1)
return 1;
conn_curr = _HA_ATOMIC_LOAD(&actconn) - 1;
conn_left = global.hardmaxconn - conn_curr;
if (conn_left <= 0)
return 1;
/* the limit is per process, we're working per group. Since we're
* counting extra streams max, we subtract 100% from elasticity.
*/
extra = (((ullong)global.hardmaxconn * (global.tune.streams_elasticity - 100) / 100));
curr = _HA_ATOMIC_LOAD(&tg_ctx->committed_extra_streams) * global.nbtgroups;
if (curr >= extra)
return 1;
/* this is the average per conn left that we can allocate */
per_conn_left = ((extra - curr) + conn_left - 1) / conn_left;
/* OK so we know we can still allocate (extra - curr) streams per
* tgroup, that will be shared across conn_left connections, but ought
* to be fairly shared between all conn_curr ones. This allows to
* provide at least up to <desired> as long as we leave enough for all
* remaining connections left.
*/
avg_per_conn = ((ullong)(extra - curr) * (desired - 1)) / extra;
/* both values are permitted since they respect the global limit,
* so let's deliver the best option to better serve first conns
* so that the limit degrades smoothly with the number of conns.
*/
return 1 + MAX(per_conn_left, avg_per_conn);
}
/* Retrieves any valid stream connector from this connection, preferably the first
* valid one. The purpose is to be able to figure one other end of a private
* connection for purposes like source binding or proxy protocol header
@ -653,7 +591,7 @@ static inline struct mux_proto_list *get_mux_proto(const struct ist proto)
struct mux_proto_list *item;
list_for_each_entry(item, &mux_proto_list.list, list) {
if (isteq(proto, item->mux_proto))
if (isteq(proto, item->token))
return item;
}
return NULL;
@ -672,7 +610,6 @@ void list_mux_proto(FILE *out);
*/
static inline const struct mux_proto_list *conn_get_best_mux_entry(
const struct ist mux_proto,
const struct ist alpn,
int proto_side, int proto_is_quic, int proto_mode)
{
struct mux_proto_list *item;
@ -681,14 +618,10 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
list_for_each_entry(item, &mux_proto_list.list, list) {
if (!(item->side & proto_side) || !(item->mode & proto_mode) || ((proto_is_quic != 0) != ((item->mux->flags & MX_FL_FRAMED) != 0)))
continue;
if (istlen(mux_proto) && isteq(mux_proto, item->mux_proto)) {
if (istlen(mux_proto) && isteq(mux_proto, item->token)) {
return item;
}
else if (istlen(alpn) && item->alpn &&
strlen(item->alpn) == istlen(alpn) + 1 &&
!memcmp(alpn.ptr, item->alpn + 1, istlen(alpn)))
return item;
else if (!istlen(item->mux_proto)) {
else if (!istlen(item->token)) {
if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode))
fallback = item;
}
@ -705,12 +638,11 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
*/
static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
const struct ist mux_proto,
const struct ist alpn,
int proto_side, int proto_mode)
{
const struct mux_proto_list *item;
item = conn_get_best_mux_entry(mux_proto, alpn, proto_side, proto_is_quic(conn->ctrl), proto_mode);
item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
return item ? item->mux : NULL;
}

View file

@ -59,7 +59,7 @@
#define DEF_MAX_THREADS_PER_GROUP 16
#endif
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 16 times
/* threads enabled, max_threads defaults to long bits for 1 tgroup or 4 times
* long bits if more tgroups are enabled.
*/
#ifndef MAX_THREADS

View file

@ -1,5 +1,5 @@
/*
* include/haproxy/dgram.h
* include/haproxy/proto_dgram.h
* This file provides functions related to DGRAM processing.
*
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>

View file

@ -107,7 +107,7 @@ static inline int b_may_alloc_for_crit(uint crit)
return 0;
/* If the emergency buffers are too low, we won't try to allocate a
* buffer either so that we speed up their release. As a corollary, it
* buffer either so that we speed up their release. As a corrolary, it
* means that we're always allowed to try to fall back to an emergency
* buffer if pool_alloc() fails. The minimum number of available
* emergency buffers for an allocation depends on the queue:
@ -138,7 +138,7 @@ static inline char *__b_get_emergency_buf(void)
/* Ensures that <buf> is allocated, or allocates it. If no memory is available,
* ((char *)1) is assigned instead with a zero size. The allocated buffer is
* returned, or NULL in case no memory is available. Since buffers only contain
* user data, poisoning is always disabled as it brings no benefit and impacts
* user data, poisonning is always disabled as it brings no benefit and impacts
* performance. Due to the difficult buffer_wait management, they are not
* subject to forced allocation failures either. If other waiters are present
* at higher criticality levels, we refrain from allocating.

View file

@ -1,5 +1,5 @@
/*
* include/haproxy/filters-t.h
* include/haproxy/filteers-t.h
* This file defines everything related to stream filters.
*
* Copyright (C) 2015 Qualys Inc., Christopher Faulet <cfaulet@qualys.com>

View file

@ -216,7 +216,6 @@ struct global {
uint max_checks_per_thread; /* if >0, no more than this concurrent checks per thread */
uint ring_queues; /* if >0, #ring queues, otherwise equals #thread groups */
uint cli_max_payload_sz; /* The max payload size for the CLI */
int streams_elasticity; /* percent of advertised streams to connection; 0=no limit */
enum threadgroup_takeover tg_takeover; /* Policy for threadgroup takeover */
} tune;
struct {

View file

@ -61,7 +61,6 @@ extern struct cfgfile fileless_cfg;
/* storage for collected libs */
extern void *lib_storage;
extern size_t lib_size;
extern char *lib_output_file;
struct proxy;
struct server;

View file

@ -98,7 +98,7 @@ enum h1m_state {
#define H1_MF_UPG_WEBSOCKET 0x00008000 // Set for a Websocket upgrade handshake
#define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked"
#define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now)
#define H1_MF_UPG_HDR 0x00040000 // non-empty Upgrapde header found
#define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token
#define H1_MF_NOT_HTTP 0x00080000 // Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted)
/* Mask to use to reset H1M flags when we restart headers parsing.
*
@ -160,7 +160,7 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
int h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value);
void h1_parse_connection_header(struct h1m *h1m, struct ist *value);
void h1_parse_upgrade_header(struct h1m *h1m, struct ist *value);
void h1_parse_upgrade_header(struct h1m *h1m, struct ist value);
void h1_generate_random_ws_input_key(char key_out[25]);
void h1_calculate_ws_output_key(const char *key, char *result);

View file

@ -27,7 +27,7 @@
#include <haproxy/buf-t.h>
#include <haproxy/mux_quic-t.h>
/* H3 unidirectional stream types
/* H3 unidirecational stream types
* Emitted as the first byte on the stream to differentiate it.
*/
#define H3_UNI_S_T_CTRL 0x00

View file

@ -326,50 +326,6 @@ static inline int is_immutable_header(struct ist hdr)
}
}
/* This function parses comma-separated values from <hv> and rewrite it in place,
* skip all occurrences of <value>. It is the caller responsibility to deal with
* empty header value.
*/
static inline void http_remove_header_value(struct ist *hv, struct ist value)
{
char *e, *n, *p;
struct ist word;
word.ptr = hv->ptr - 1; // -1 for next loop's pre-increment
p = hv->ptr;
e = hv->ptr + hv->len;
hv->len = 0;
while (++word.ptr < e) {
/* skip leading delimiter and blanks */
if (HTTP_IS_LWS(*word.ptr))
continue;
n = http_find_hdr_value_end(word.ptr, e); // next comma or end of line
word.len = n - word.ptr;
/* trim trailing blanks */
while (word.len && HTTP_IS_LWS(word.ptr[word.len-1]))
word.len--;
if (isteqi(word, value))
goto skip_val;
if (hv->ptr + hv->len == p) {
/* no rewrite done till now */
hv->len = n - hv->ptr;
}
else {
if (hv->len)
hv->ptr[hv->len++] = ',';
istcat(hv, word, e - hv->ptr);
}
skip_val:
word.ptr = p = n;
}
}
#endif /* _HAPROXY_HTTP_H */
/*

View file

@ -17,7 +17,7 @@ struct httpclient {
struct buffer buf; /* input buffer, raw HTTP */
} res;
struct {
/* callbacks used to send the request, */
/* callbacks used to send the request, */
void (*req_payload)(struct httpclient *hc); /* send a payload */
/* callbacks used to receive the response, if not set, the IO
@ -28,7 +28,7 @@ struct httpclient {
void (*res_end)(struct httpclient *hc); /* end of the response */
} ops;
struct sockaddr_storage *dst; /* destination address */
struct appctx *appctx; /* HTTP client appctx */
struct appctx *appctx; /* HTTPclient appctx */
int timeout_server; /* server timeout in ms */
void *caller; /* ptr of the caller */
unsigned int flags; /* other flags */
@ -50,7 +50,7 @@ struct httpclient {
#define HTTPCLIENT_FS_ENDED 0x00020000 /* the httpclient is stopped */
/* options */
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must use an absolute URI */
#define HTTPCLIENT_O_HTTPPROXY 0x00000001 /* the request must be use an absolute URI */
#define HTTPCLIENT_O_RES_HTX 0x00000002 /* response is stored in HTX */
/* States of the HTTP Client Appctx */
@ -65,4 +65,4 @@ enum {
#define HTTPCLIENT_USERAGENT "HAProxy"
#endif /* !_HAPROXY_HTTPCLIENT_T_H */
#endif /* ! _HAPROXY_HTTCLIENT__T_H */

View file

@ -38,4 +38,4 @@ static inline int httpclient_started(struct httpclient *hc)
return !!(hc->flags & HTTPCLIENT_FS_STARTED);
}
#endif /* !_HAPROXY_HTTPCLIENT_H */
#endif /* ! _HAPROXY_HTTCLIENT_H */

View file

@ -1,5 +1,5 @@
/*
* include/haproxy/http_htx.h
* include/haproxy/http_htx-t.h
* This file defines function prototypes for HTTP manipulation using the
* internal representation.
*

View file

@ -40,7 +40,7 @@
* | HTX | PAYLOADS ==> | | <== HTX_BLKs |
* +-----+---------------+------------------------------+--------------+
* ^
* blocks[] (the beginning of the blocks array)
* blocks[] (the beginning of the bocks array)
*
*
* The blocks part remains linear and sorted. You may think about it as an array
@ -84,7 +84,7 @@
* At the end, if payload wrapping or blocks defragmentation is not enough, some
* free space may be get back with a full defragmentation. This way, the holes in
* the middle are not reusable but count in the available free space. The only
* way to reuse this lost space is to fully defragment the HTX message.
* way to reuse this lost space is to fully defragmenate the HTX message.
*
* - * -
*
@ -113,10 +113,11 @@
* - 0000 = request start-line
* - 0001 = response start-line
* - 0010 = header
* - 0011 = end-of-headers
* - 0100 = data
* - 0101 = trailer
* - 0110 = end-of-trailers
* - 0011 = pseudo-header ou "special" header
* - 0100 = end-of-headers
* - 0101 = data
* - 0110 = trailer
* - 0111 = end-of-trailers
* ...
* - 1111 = unused
*
@ -127,7 +128,7 @@
*/
#define HTX_SL_F_NONE 0x00000000
#define HTX_SL_F_IS_RESP 0x00000001 /* It is the response start-line (unset means the request one) */
#define HTX_SL_F_XFER_LEN 0x00000002 /* The message xfer size can be determined */
#define HTX_SL_F_XFER_LEN 0x00000002 /* The message xfer size can be dertermined */
#define HTX_SL_F_XFER_ENC 0x00000004 /* The transfer-encoding header was found in message */
#define HTX_SL_F_CLEN 0x00000008 /* The content-length header was found in message */
#define HTX_SL_F_CHNK 0x00000010 /* The message payload is chunked */
@ -139,9 +140,8 @@
#define HTX_SL_F_HAS_AUTHORITY 0x00000400 /* The request authority is explicitly specified */
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
#define HTX_SL_F_CONN_UPG 0x00001000 /* The message contains "connection: upgrade" header */
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyless (only for request) */
#define HTX_SL_F_BODYLESS_RESP 0x00002000 /* The response to this message is bodyloess (only for reqyest) */
#define HTX_SL_F_NOT_HTTP 0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
#define HTX_SL_F_UPG_HDR 0x00008000 /* non-empty Upgrapde header found */
/* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the
@ -158,8 +158,7 @@ static forceinline char *hsl_show_flags(char *buf, size_t len, const char *delim
_(HTX_SL_F_CLEN, _(HTX_SL_F_CHNK, _(HTX_SL_F_VER_11,
_(HTX_SL_F_BODYLESS, _(HTX_SL_F_HAS_SCHM, _(HTX_SL_F_SCHM_HTTP,
_(HTX_SL_F_SCHM_HTTPS, _(HTX_SL_F_HAS_AUTHORITY,
_(HTX_SL_F_NORMALIZED_URI, _(HTX_SL_F_CONN_UPG, _(HTX_SL_F_BODYLESS_RESP,
_(HTX_SL_F_NOT_HTTP, _(HTX_SL_F_UPG_HDR))))))))))))))));
_(HTX_SL_F_NORMALIZED_URI, _(HTX_SL_F_CONN_UPG)))))))))))));
/* epilogue */
_(~0U);
return buf;

View file

@ -65,9 +65,7 @@ struct buffer *htx_copy_to_large_buffer(struct buffer *dst, struct buffer *src);
#define HTX_XFER_DEFAULT 0x00000000 /* Default XFER: no partial xfer / remove blocks from source */
#define HTX_XFER_KEEP_SRC_BLKS 0x00000001 /* Don't remove xfer blocks from source messages during xfer */
#define HTX_XFER_PARTIAL_HDRS_COPY 0x00000002 /* Allow partial copy of headers and trailers part */
#define HTX_XFER_HDRS_ONLY 0x00000004 /* Only Transfer header blocks (start-line, header and EOH) */
#define HTX_XFER_NO_METADATA 0x00000008 /* <count> don't include meta-data, only payload */
#define HTX_XFER_HDRS_ONLY 0x00000003 /* Only Transfer header blocks (start-line, header and EOH) */
size_t htx_xfer(struct htx *dst, struct htx *src, size_t count, unsigned int flags);
/* Functions and macros to get parts of the start-line or length of these

View file

@ -76,56 +76,6 @@ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
return result;
}
/* returns non-zero if a*b would overflow an unsigned long, otherwise sets the
* result into res and returns 0.
*/
static inline int mulul_overflow(unsigned long a, unsigned long b, unsigned long *res)
{
/* __builtin_mul_overflow() is gcc >= 5 or clang >= 3.4 */
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
(defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
return __builtin_mul_overflow(a, b, res);
#else
/* portable method involving a division */
if (a && b && a > (~(ulong)0) / b)
return 1;
*res = a * b;
return 0;
#endif
}
/* returns non-zero if a*b would overflow a size_t, otherwise sets the
* result into res and returns 0.
*/
static inline int mulsz_overflow(size_t a, size_t b, size_t *res)
{
/* __builtin_mul_overflow() is gcc >= 5 or clang >= 3.4 */
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
(defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4)))
return __builtin_mul_overflow(a, b, res);
#else
/* portable method involving a division */
if (a && b && a > (~(size_t)0) / b)
return 1;
*res = a * b;
return 0;
#endif
}
/* Computes the size of an array of m*n bytes, taking overflows into account.
* If the multiply would overflow, returns the largest possible size_t so that
* any call to malloc() or equivalent would fail. Otherwise returns the size.
* Note that this implies that even 1*max would not be permitted either.
*/
static inline size_t array_size_or_fail(size_t m, size_t n)
{
size_t size;
if (unlikely(mulsz_overflow(m, n, &size)))
return DISGUISE(~(size_t)0);
return size;
}
/* rotate left a 64-bit integer by <bits:[0-5]> bits */
static inline uint64_t rotl64(uint64_t v, uint8_t bits)
{

View file

@ -31,6 +31,8 @@ struct server;
struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid);
extern const struct lb_ops lb_chash_ops;
#endif /* _HAPROXY_LB_CHASH_H */
/*

View file

@ -30,6 +30,8 @@
struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid);
extern const struct lb_ops lb_fas_ops;
#endif /* _HAPROXY_LB_FAS_H */
/*

View file

@ -30,6 +30,8 @@
struct server *fwlc_get_next_server(struct proxy *p, struct server *srvtoavoid);
extern const struct lb_ops lb_fwlc_ops;
#endif /* _HAPROXY_LB_FWLC_H */
/*

View file

@ -30,6 +30,8 @@
struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid);
extern const struct lb_ops lb_fwrr_ops;
#endif /* _HAPROXY_LB_FWRR_H */
/*

View file

@ -30,6 +30,8 @@
struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid);
struct server *map_get_server_hash(struct proxy *px, unsigned int hash);
extern const struct lb_ops lb_map_ops;
#endif /* _HAPROXY_LB_MAP_H */
/*

View file

@ -29,4 +29,6 @@
struct server *ss_get_server(struct proxy *px);
extern const struct lb_ops lb_ss_ops;
#endif /* _HAPROXY_LB_SS_H */

View file

@ -278,7 +278,7 @@ struct connack {
} user_props[MQTT_PROP_USER_PROPERTY_ENTRIES];
uint8_t wildcard_subscription_available;
uint8_t subscription_identifiers_available;
uint8_t shared_subscription_available;
uint8_t shared_subsription_available;
uint16_t server_keepalive;
struct ist response_information;
struct ist server_reference;

View file

@ -53,7 +53,6 @@ struct qcc {
struct list frms; /* prepared frames related to flow-control */
uint64_t ms_bidi_init; /* max initial sub-ID of bidi stream allowed for the peer */
uint64_t ms_bidi_rel; /* max relative sub-ID of bidi stream allowed for the peer */
uint64_t ms_bidi; /* max sub-ID of bidi stream allowed for the peer */
uint64_t cl_bidi_r; /* total count of closed remote bidi stream since last MAX_STREAMS emission */
@ -90,12 +89,12 @@ struct qcc {
struct quic_pacer pacer; /* engine used to pace emission */
int paced_sent_ctr; /* counter for when emission is interrupted due to pacing */
};
/* qmux */
struct buffer qmux_buf;
/* qstrm */
struct buffer qstrm_buf;
};
} tx;
struct {
struct buffer qmux_buf;
struct buffer qstrm_buf;
uint64_t rlen; /* last record length read */
} rx;
@ -180,7 +179,7 @@ struct qcs {
struct {
union {
struct qc_stream_desc *stream; /* quic */
struct buffer qmux_buf; /* qmux */
struct buffer qstrm_buf; /* qstrm */
};
struct quic_fctl fc; /* stream flow control applied on sending */
struct quic_frame *msd_frm; /* MAX_STREAM_DATA frame prepared */
@ -286,11 +285,9 @@ static forceinline char *qcc_show_flags(char *buf, size_t len, const char *delim
/* flags */
_(QC_CF_ERRL,
_(QC_CF_ERRL_DONE,
_(QC_CF_IS_BACK,
_(QC_CF_CONN_FULL,
_(QC_CF_CONN_SHUT,
_(QC_CF_ERR_CONN,
_(QC_CF_WAIT_HS)))))));
_(QC_CF_WAIT_HS)))));
/* epilogue */
_(~0U);
return buf;
@ -333,8 +330,7 @@ static forceinline char *qcs_show_flags(char *buf, size_t len, const char *delim
_(QC_SF_HREQ_RECV,
_(QC_SF_TO_STOP_SENDING,
_(QC_SF_UNKNOWN_PL_LENGTH,
_(QC_SF_RECV_RESET,
_(QC_SF_EOI_SUSPENDED)))))))))))));
_(QC_SF_RECV_RESET))))))))))));
/* epilogue */
_(~0U);
return buf;

View file

@ -10,7 +10,6 @@
#include <haproxy/connection.h>
#include <haproxy/list.h>
#include <haproxy/mux_quic-t.h>
#include <haproxy/quic_tune.h>
#include <haproxy/stconn.h>
#include <haproxy/h3.h>
@ -54,7 +53,7 @@ int qcc_recv_max_streams(struct qcc *qcc, uint64_t max, int bidi);
int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t final_size);
int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err);
static inline int qcm_stream_rx_bufsz(void)
static inline int qmux_stream_rx_bufsz(void)
{
return global.tune.bufsize - NCB_RESERVED_SZ;
}
@ -129,9 +128,6 @@ static inline void qcs_wait_http_req(struct qcs *qcs)
BUG_ON_HOT(qcs->flags & QC_SF_HREQ_RECV);
qcs->flags |= QC_SF_HREQ_RECV;
++qcc->nb_hreq;
/* On BE side avail_streams cb should prevent opening of too many concurrent streams. */
BUG_ON(conn_is_back(qcc->conn) && qcc->nb_hreq > quic_tune.be.stream_max_concurrent);
}
void qcc_show_quic(struct qcc *qcc);

View file

@ -0,0 +1,10 @@
#ifndef _HAPROXY_MUX_QUIC_QSTRM_H
#define _HAPROXY_MUX_QUIC_QSTRM_H
#include <haproxy/mux_quic.h>
int qcc_qstrm_recv(struct qcc *qcc);
int qcc_qstrm_send_frames(struct qcc *qcc, struct list *frms);
#endif /* _HAPROXY_MUX_QUIC_QSTRM_H */

View file

@ -24,7 +24,7 @@
/* The principle is to be able to change the type of a pointer by pointing
* it directly to an object type. The object type indicates the format of the
* structure holding the type, and this is used to retrieve the pointer to the
* structure holing the type, and this is used to retrieve the pointer to the
* beginning of the structure. Doing so saves us from having to maintain both
* a pointer and a type for elements such as connections which can point to
* various types of objects.

View file

@ -92,8 +92,8 @@ int protocol_resume_all(void);
int protocol_enable_all(void);
/* returns the protocol associated to family <family> with proto_type among the
* supported protocol types, and index <alt> (0 or 1) selecting between the two
* possible entries per (family, proto_type), or NULL if not found.
* supported protocol types, and ctrl_type of either SOCK_STREAM or SOCK_DGRAM
* depending on the requested values, or NULL if not found.
*/
static inline struct protocol *protocol_lookup(int family, enum proto_type proto_type, int alt)
{

View file

@ -96,7 +96,7 @@ void proxy_capture_error(struct proxy *proxy, int is_back,
void (*show)(struct buffer *, const struct error_snapshot *));
void proxy_adjust_all_maxconn(void);
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
struct proxy *cli_find_backend(struct appctx *appctx, const char *arg);
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
void free_stick_rules(struct list *rules);
void free_server_rules(struct list *srules);

View file

@ -1,10 +0,0 @@
#ifndef _HAPROXY_QCM_QMUX_H
#define _HAPROXY_QCM_QMUX_H
#include <haproxy/mux_quic.h>
int qcc_qmux_recv(struct qcc *qcc);
int qcc_qmux_send_frames(struct qcc *qcc, struct list *frms);
#endif /* _HAPROXY_QCM_QMUX_H */

View file

@ -1,5 +1,5 @@
#ifndef _HAPROXY_QCM_HTTP_H
#define _HAPROXY_QCM_HTTP_H
#ifndef _HAPROXY_MUX_QUIC_HTTP_H
#define _HAPROXY_MUX_QUIC_HTTP_H
#ifdef USE_QUIC
@ -17,4 +17,4 @@ size_t qcs_http_reset_buf(struct qcs *qcs, struct buffer *buf, size_t count);
#endif /* USE_QUIC */
#endif /* _HAPROXY_QCM_HTTP_H */
#endif /* _HAPROXY_MUX_QUIC_HTTP_H */

View file

@ -1,5 +1,5 @@
#ifndef _HAPROXY_QCM_TRACE_H
#define _HAPROXY_QCM_TRACE_H
#ifndef _HAPROXY_QMUX_TRACE_H
#define _HAPROXY_QMUX_TRACE_H
#ifdef USE_QUIC
@ -10,10 +10,10 @@
struct qcc;
struct qcs;
extern struct trace_source trace_qcm;
#define TRACE_SOURCE &trace_qcm
extern struct trace_source trace_qmux;
#define TRACE_SOURCE &trace_qmux
static const struct trace_event qcm_trace_events[] = {
static const struct trace_event qmux_trace_events[] = {
#define QMUX_EV_QCC_NEW (1ULL << 0)
{ .mask = QMUX_EV_QCC_NEW , .name = "qcc_new", .desc = "new QUIC connection" },
#define QMUX_EV_QCC_RECV (1ULL << 1)
@ -72,9 +72,9 @@ struct qcs_build_stream_trace_arg {
uint64_t offset;
};
void qcm_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
void qcm_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc);
void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs);
#endif /* USE_QUIC */
#endif /* _HAPROXY_QCM_TRACE_H */
#endif /* _HAPROXY_QMUX_TRACE_H */

View file

@ -43,14 +43,6 @@
#define QPACK_DEC_INST_SCCL 0x40 // Stream Cancellation
#define QPACK_DEC_INST_SACK 0x80 // Section Acknowledgment
/* Encoded field line bitmasks (shared between encoder and decoder) */
#define QPACK_EFL_BITMASK 0xf0
#define QPACK_LFL_WPBNM 0x00 // Literal field line with post-base name reference
#define QPACK_IFL_WPBI 0x10 // Indexed field line with post-based index
#define QPACK_LFL_WLN_BIT 0x20 // Literal field line with literal name
#define QPACK_LFL_WNR_BIT 0x40 // Literal field line with name reference
#define QPACK_IFL_BIT 0x80 // Indexed field line
/* RFC 9204 6. Error Handling */
enum qpack_err {
QPACK_ERR_DECOMPRESSION_FAILED = 0x200,

View file

@ -93,30 +93,24 @@ static inline struct ist qpack_get_value(const struct qpack_dht *dht, const stru
return ret;
}
/* takes an absolute idx (including static table offset), returns the associated name */
/* takes an idx, returns the associated name */
static inline struct ist qpack_idx_to_name(const struct qpack_dht *dht, uint32_t idx)
{
const struct qpack_dte *dte;
if (idx < QPACK_SHT_SIZE)
return ist("### ERR ###"); /* static table entries not accessible via dht */
dte = qpack_get_dte(dht, idx - QPACK_SHT_SIZE);
dte = qpack_get_dte(dht, idx);
if (!dte)
return ist("### ERR ###"); // error
return qpack_get_name(dht, dte);
}
/* takes an absolute idx (including static table offset), returns the associated value */
/* takes an idx, returns the associated value */
static inline struct ist qpack_idx_to_value(const struct qpack_dht *dht, uint32_t idx)
{
const struct qpack_dte *dte;
if (idx < QPACK_SHT_SIZE)
return ist("### ERR ###"); /* static table entries not accessible via dht */
dte = qpack_get_dte(dht, idx - QPACK_SHT_SIZE);
dte = qpack_get_dte(dht, idx);
if (!dte)
return ist("### ERR ###"); // error

View file

@ -42,7 +42,7 @@ struct pendconn {
};
struct queue {
struct eb_root head; /* queued pendconns */
struct eb_root head; /* queued pendconnds */
struct proxy *px; /* the proxy we're waiting for, never NULL in queue */
struct server *sv; /* the server we are waiting for, may be NULL if don't care */
__decl_thread(HA_SPINLOCK_T lock); /* for manipulations in the tree */

View file

@ -135,8 +135,6 @@ static inline void in46un_to_addr(const union sockaddr_in46 *src,
in6->sin6_family = AF_INET6;
in6->sin6_addr = src->in6.sin6_addr;
in6->sin6_port = src->in6.sin6_port;
in6->sin6_flowinfo = src->in6.sin6_flowinfo;
in6->sin6_scope_id = src->in6.sin6_scope_id;
break;
default:

View file

@ -1,5 +1,5 @@
/*
* include/haproxy/resolvers-t.h
* include/haproxy/dns-t.h
* This file provides structures and types for DNS.
*
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
@ -114,7 +114,7 @@ struct resolv_answer_item {
char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
int16_t type; /* question type */
int16_t class; /* query class */
uint32_t ttl; /* response TTL */
int32_t ttl; /* response TTL */
int16_t priority; /* SRV type priority */
uint16_t weight; /* SRV type weight */
uint16_t port; /* SRV type port */
@ -281,7 +281,7 @@ enum {
* matching preference was found.
*/
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
* OR provided IP found and preference is not matched and an IP
* OR provided IP found and preference is not match and an IP
* matching preference was found.
*/
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */

View file

@ -1,5 +1,5 @@
/*
* include/haproxy/resolvers.h
* include/haproxy/dns.h
* This file provides functions related to DNS protocol
*
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>

View file

@ -111,8 +111,7 @@ enum srv_initaddr {
* at start up time.
*/
enum srv_init_state {
SRV_INIT_STATE_NONE = 0,
SRV_INIT_STATE_FULLY_DOWN, /* the server should initially be considered DOWN until it passes all health checks. Please keep set to zero. */
SRV_INIT_STATE_FULLY_DOWN = 0, /* the server should initially be considered DOWN until it passes all health checks. Please keep set to zero. */
SRV_INIT_STATE_DOWN, /* the server should initially be considered DOWN until it passes one health check. */
SRV_INIT_STATE_UP, /* the server should initially be considered UP, but will go DOWN if it fails one health check. */
SRV_INIT_STATE_FULLY_UP, /* the server should initially be considered UP, but will go DOWN if it fails all health checks. */
@ -249,9 +248,7 @@ struct pid_list {
/* srv methods of computing chash keys */
enum srv_hash_key {
SRV_HASH_KEY_ID = 0, /* derived from server puid, 28 LSB used */
SRV_HASH_KEY_ID32, /* derived from server puid, 32 bits used */
SRV_HASH_KEY_GUID, /* derived from server guid */
SRV_HASH_KEY_ID = 0, /* derived from server puid */
SRV_HASH_KEY_ADDR, /* derived from server address */
SRV_HASH_KEY_ADDR_PORT /* derived from server address and port */
};
@ -279,8 +276,6 @@ struct srv_per_thread {
struct ceb_root *idle_conns; /* Shareable idle connections */
struct ceb_root *safe_conns; /* Safe idle connections */
struct ceb_root *avail_conns; /* Connections in use, but with still new streams available */
struct server *srv; /* Back-pointer to the server */
struct eb32_node idle_node; /* When to next do cleanup in the idle connections */
#ifdef USE_QUIC
struct ist quic_retry_token;
#endif
@ -331,7 +326,6 @@ enum renegotiate_mode {
struct path_parameters {
__decl_thread(HA_RWLOCK_T param_lock);
char nego_alpn[MAX_ALPN_SIZE];
int64_t srv_hash;
#ifdef USE_QUIC
struct quic_early_transport_params tps;
#endif
@ -403,6 +397,7 @@ struct server {
* thread, and generally at the same time.
*/
THREAD_ALIGN();
struct eb32_node idle_node; /* When to next do cleanup in the idle connections */
unsigned int curr_idle_conns; /* Current number of orphan idling connections, both the idle and the safe lists */
unsigned int curr_idle_nb; /* Current number of connections in the idle list */
unsigned int curr_safe_nb; /* Current number of connections in the safe list */

View file

@ -41,9 +41,9 @@
#include <haproxy/tools.h>
__decl_thread(extern HA_SPINLOCK_T idle_conn_srv_lock);
extern struct idle_conns idle_conns[MAX_THREADS];
extern struct task *idle_conn_task[MAX_THREADS];
extern struct eb_root idle_conn_srv[MAX_THREADS];
extern struct task *idle_conn_task;
extern struct mt_list servers_list;
extern struct dict server_key_dict;
@ -278,35 +278,6 @@ static inline void srv_adm_set_ready(struct server *s)
srv_clr_admin_flag(s, SRV_ADMF_FMAINT);
}
static inline void srv_set_init_state(struct server *srv)
{
/* no init-state configured or the server is already disabled: don't eval init-state */
if (srv->init_state == SRV_INIT_STATE_NONE ||
srv->next_admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT))
return;
if (srv->init_state == SRV_INIT_STATE_FULLY_UP) {
/* initially UP, when all checks fail to bring server DOWN */
srv->next_state = SRV_ST_RUNNING;
srv->check.health = srv->check.rise + srv->check.fall - 1;
}
else if (srv->init_state == SRV_INIT_STATE_UP) {
/* initially UP, when one check fails check brings server DOWN */
srv->next_state = SRV_ST_RUNNING;
srv->check.health = srv->check.rise;
}
else if (srv->init_state == SRV_INIT_STATE_DOWN) {
/* initially DOWN, when one check is successful bring server UP */
srv->next_state = SRV_ST_STOPPED;
srv->check.health = srv->check.rise - 1;
}
else if (srv->init_state == SRV_INIT_STATE_FULLY_DOWN) {
/* initially DOWN, when all checks are successful bring server UP */
srv->next_state = SRV_ST_STOPPED;
srv->check.health = 0;
}
}
/* appends an initaddr method to the existing list. Returns 0 on failure. */
static inline int srv_append_initaddr(unsigned int *list, enum srv_initaddr addr)
{

View file

@ -50,7 +50,7 @@ struct certificate_ocsp {
int refcount_store; /* Number of ckch_store that reference this certificate_ocsp */
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
struct buffer response;
unsigned long expire;
long expire;
X509 *issuer;
STACK_OF(X509) *chain;
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */

View file

@ -736,6 +736,7 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
when = tick_first(when, task->expire);
task->expire = when;
task_drop_running(task, 0);
if (!task_in_wq(task) || tick_is_lt(task->expire, task->wq.key)) {
if (likely(caller)) {
caller = HA_ATOMIC_XCHG(&task->caller, caller);
@ -746,7 +747,6 @@ static inline void _task_schedule(struct task *task, int when, const struct ha_c
}
__task_queue(task, &tg_ctx->timers);
}
task_drop_running(task, 0);
HA_RWLOCK_WRUNLOCK(TASK_WQ_LOCK, &wq_lock);
} else
#endif

View file

@ -138,7 +138,6 @@ struct tgroup_ctx {
struct eb_root timers; /* wait queue (sorted timers tree, global, accessed under wq_lock) */
uint niced_tasks; /* number of niced tasks in this group's run queues */
uint committed_extra_streams; /* sum of extra front streams committed by muxes in this group */
/* pad to cache line (64B) */
char __pad[0]; /* unused except to check remaining room */

View file

@ -188,12 +188,4 @@ struct file_name_node {
char name[VAR_ARRAY]; /* storage, used with cebus_*() */
};
/* a pair of uint64_t. It's purposely arranged in little endian to help
* being vectorized on modern processors.
*/
struct uint64_pair {
uint64_t l;
uint64_t h;
};
#endif /* _HAPROXY_TOOLS_T_H */

View file

@ -826,7 +826,7 @@ static inline int get_addr_len(const struct sockaddr_storage *addr)
return 0;
}
/* set port in network byte order (use htons() before calling) */
/* set port in host byte order */
static inline int set_net_port(struct sockaddr_storage *addr, int port)
{
switch (addr->ss_family) {
@ -840,7 +840,7 @@ static inline int set_net_port(struct sockaddr_storage *addr, int port)
return 0;
}
/* set port in host byte order */
/* set port in network byte order */
static inline int set_host_port(struct sockaddr_storage *addr, int port)
{
switch (addr->ss_family) {
@ -1154,8 +1154,6 @@ void *get_sym_curr_addr(const char *name);
void *get_sym_next_addr(const char *name);
int dump_libs(struct buffer *output, int with_addr);
void collect_libs(void);
void free_collected_libs(void);
int copy_libs_to_file(void);
/* Note that this may result in opening libgcc() on first call, so it may need
* to have been called once before chrooting.
@ -1290,27 +1288,11 @@ static inline void _ha_aligned_free(void *ptr)
int parse_dotted_uints(const char *s, unsigned int **nums, size_t *sz);
/* PRNG */
struct uint64_pair _ha_random64_pair_hashed(void);
void ha_generate_uuid_v4(struct buffer *output);
void ha_generate_uuid_v7(struct buffer *output);
void ha_random_seed(const unsigned char *seed, size_t len);
void ha_random_seed_thread(void);
void ha_random_jump128(uint32_t dist);
void ha_random_jump192(uint32_t dist);
void ha_random_jump96(uint32_t dist);
uint64_t ha_random64(void);
uint64_t ha_random64_internal(void);
/* Returns a pair of uint64_t randoms hashed so as not to disclose the internal
* PRNG state.
*/
static inline void ha_random64_pair_hashed(uint64_t *l, uint64_t *h)
{
struct uint64_pair ret = _ha_random64_pair_hashed();
*l = ret.l;
*h = ret.h;
}
static inline uint32_t ha_random32()
{

View file

@ -166,7 +166,6 @@ struct trace_ctx {
struct trace_source {
/* source definition */
const struct ist name;
const struct ist alias;
const char *desc;
const struct trace_event *known_events;
struct list source_link; // element in list of known trace sources

View file

@ -34,8 +34,6 @@
#define _TRC_LOC(f,l) __TRC_LOC(f, ":", l)
#define __TRC_LOC(f,c,l) f c #l
#if defined(USE_TRACE)
/* truncate a macro arg list to exactly 5 args and replace missing ones with NULL.
* The first one (a0) is always ignored.
*/
@ -141,23 +139,8 @@
&trace_no_cb, ist2(_msg, _msg_len)); \
} \
} while (0)
#else
# define TRACE_ENABLED(level, mask, args...) 0
# define TRACE(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_ERROR(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_USER(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_DATA(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_PROTO(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_STATE(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_DEVEL(msg, mask, args...) do { /* do nothing */ } while(0)
# define TRACE_ENTER(mask, args...) do { /* do nothing */ } while(0)
# define TRACE_LEAVE(mask, args...) do { /* do nothing */ } while(0)
# define TRACE_POINT(mask, args...) do { /* do nothing */ } while(0)
# define TRACE_PRINTF(level, args...) do { /* do nothing */ } while(0)
# define TRACE_PRINTF_LOC(level, args...) do { /* do nothing */ } while(0)
#endif
#if defined (USE_TRACE) && (defined(DEBUG_DEV) || defined(DEBUG_FULL))
#if defined(DEBUG_DEV) || defined(DEBUG_FULL)
# define DBG_TRACE(msg, mask, args...) TRACE(msg, mask, ##args)
# define DBG_TRACE_ERROR(msg, mask, args...) TRACE_ERROR(msg, mask, ##args)
# define DBG_TRACE_USER(msg, mask, args...) TRACE_USER(msg, mask, ##args)

View file

@ -33,7 +33,7 @@
#ifdef CONFIG_PRODUCT_BRANCH
#define PRODUCT_BRANCH CONFIG_PRODUCT_BRANCH
#else
#define PRODUCT_BRANCH "3.5"
#define PRODUCT_BRANCH "3.4"
#endif
#ifdef CONFIG_PRODUCT_STATUS

View file

@ -1,14 +0,0 @@
#ifndef _HAPROXY_XPRT_QMUX_H
#define _HAPROXY_XPRT_QMUX_H
#include <stddef.h>
struct buffer;
struct quic_transport_params;
const struct quic_transport_params *xprt_qmux_lparams(const void *context);
const struct quic_transport_params *xprt_qmux_rparams(const void *context);
size_t xprt_qmux_xfer_rxbuf(void *context, struct buffer *out);
#endif /* _HAPROXY_XPRT_QMUX_H */

View file

@ -0,0 +1,9 @@
#ifndef _HAPROXY_XPRT_QSTRM_H
#define _HAPROXY_XPRT_QSTRM_H
const struct quic_transport_params *xprt_qstrm_lparams(const void *context);
const struct quic_transport_params *xprt_qstrm_rparams(const void *context);
size_t xprt_qstrm_xfer_rxbuf(const void *context, struct buffer *out);
#endif /* _HAPROXY_XPRT_QSTRM_H */

View file

@ -29,7 +29,7 @@ syslog S3 -level notice {
syslog S4 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 failed.+reason: Layer4 connection problem.+info: \"ECONNREFUSED returned by OS.*\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv4 failed.+reason: Layer4 connection problem.+info: \"Connection refused\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
} -start
server s1 {

View file

@ -1,77 +0,0 @@
varnishtest "Health-checks: some external check tests"
feature ignore_unknown_macro
#REGTEST_TYPE=slow
server s1 {
rxreq
expect req.method == GET
expect req.url == /health
expect req.proto == HTTP/1.1
txresp
} -start
syslog S1 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded, reason: External check passed, code: 0"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded, reason: External check passed, code: 0"
} -start
syslog S2 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be[0-9]/srv succeeded.*code: 200"
} -start
haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif
external-check
insecure-fork-wanted
healthcheck http-health
type httpchk
http-check send meth GET uri /health ver HTTP/1.1
defaults
mode http
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
option log-health-checks
backend be1
log ${S1_addr}:${S1_port} len 2048 local0
option external-check
external-check command /bin/true
server srv ${h1_li1_addr}:${h1_li1_port} check inter 100ms rise 1 fall 1
defaults
mode http
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
option external-check
external-check command /bin/true
option log-health-checks
backend be2
log ${S1_addr}:${S1_port} len 2048 local0
server srv ${h1_li1_addr}:${h1_li1_port} check inter 100ms rise 1 fall 1
backend be3
log ${S2_addr}:${S2_port} len 2048 local0
option external-check
external-check command /bin/true
server srv ${s1_addr}:${s1_port} check inter 100ms rise 1 fall 1 healthcheck http-health
listen li1
mode http
bind "fd@${li1}"
http-request return status 200
} -start
syslog S1 -wait
syslog S2 -wait

View file

@ -144,7 +144,7 @@ syslog S2 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9] succeeded"
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv[0-9]+ succeeded"
recv

View file

@ -7,12 +7,12 @@ feature ignore_unknown_macro
syslog S1 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*ECONNREFUSED returned by OS.* at step 2 of tcp-check.*connect port 1"
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.*Connection refused at step 2 of tcp-check.*connect port 1"
} -start
syslog S2 -level notice {
recv
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*ECONNREFUSED returned by OS.* at step 1 of tcp-check.*connect port 1"
expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv1 failed.*Connection refused at step 1 of tcp-check.*connect port 1"
} -start
server s1 {

View file

@ -1,41 +0,0 @@
varnishtest "reverse converter test"
feature ignore_unknown_macro
server s1 {
rxreq
txresp -hdr "Connection: close"
} -repeat 4 -start
haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif
defaults
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
frontend fe
bind "fd@${fe}"
http-request return status 200 hdr X-Reverse "%[str(example.com),reverse]" hdr X-Reverse2 "%[str(ab cd),reverse]" hdr X-Reverse3 "%[str(example.com),reverse,concat(.)]" hdr X-Reverse4 "%[str(),reverse]"
default_backend be
backend be
server s1 ${s1_addr}:${s1_port}
} -start
client c1 -connect ${h1_fe_sock} {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.x-reverse == "moc.elpmaxe"
expect resp.http.x-reverse2 == "dc ba"
expect resp.http.x-reverse3 == "moc.elpmaxe."
expect resp.http.x-reverse4 == "<undef>"
} -run

View file

@ -1,2 +0,0 @@
com.example. example
com.example.mail. mail

View file

@ -1,94 +0,0 @@
varnishtest "reverse_dom converter test"
feature ignore_unknown_macro
server s1 {
rxreq
txresp -hdr "Connection: close"
} -repeat 8 -start
haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif
defaults
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
frontend fe
bind "fd@${fe}"
http-request set-var(txn.rev_const) str(MaIl.EXAMPLE.com),reverse_dom
http-request set-var(txn.rev_host) req.hdr(Host),host_only,reverse_dom if { req.hdr(Host) -m found }
http-request set-var(txn.rev_host_dot) var(txn.rev_host),concat(.) if { var(txn.rev_host) -m found }
http-request set-var(txn.route) var(txn.rev_host_dot),map_beg(${testdir}/reverse_dom.map,miss) if { var(txn.rev_host_dot) -m found }
http-request set-var(txn.sub_only) str(no)
http-request set-var(txn.sub_only) str(yes) if { var(txn.rev_host) -m beg com.example. }
http-request return status 200 hdr X-Rev-Const "%[var(txn.rev_const)]" hdr X-Rev-Host "%[var(txn.rev_host)]" hdr X-Route "%[var(txn.route)]" hdr X-Sub-Only "%[var(txn.sub_only)]"
default_backend be
backend be
server s1 ${s1_addr}:${s1_port}
} -start
client c1 -connect ${h1_fe_sock} {
txreq -url "/" -hdr "Host: example.com"
rxresp
expect resp.status == 200
expect resp.http.x-rev-const == "com.EXAMPLE.MaIl"
expect resp.http.x-rev-host == "com.example"
expect resp.http.x-route == "example"
expect resp.http.x-sub-only == "no"
txreq -url "/" -hdr "Host: mail.example.com"
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "com.example.mail"
expect resp.http.x-route == "mail"
expect resp.http.x-sub-only == "yes"
txreq -url "/" -hdr "Host: example.com."
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "com.example"
expect resp.http.x-route == "example"
expect resp.http.x-sub-only == "no"
txreq -url "/" -hdr "Host: localhost"
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "localhost"
expect resp.http.x-route == "miss"
expect resp.http.x-sub-only == "no"
txreq -url "/" -hdr "Host: badexample.com"
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "com.badexample"
expect resp.http.x-route == "miss"
expect resp.http.x-sub-only == "no"
txreq -url "/" -hdr "Host: foo..bar"
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "<undef>"
expect resp.http.x-route == "<undef>"
txreq -url "/" -hdr "Host: .example.com"
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "<undef>"
expect resp.http.x-route == "<undef>"
txreq -url "/" -hdr "Host: ."
rxresp
expect resp.status == 200
expect resp.http.x-rev-host == "<undef>"
expect resp.http.x-route == "<undef>"
} -run

View file

@ -146,7 +146,7 @@ client c1 -connect ${hap_fe1_sock} {
} -run
# missing websocket key
client c2_1 -connect ${hap_fe1_sock} {
client c2 -connect ${hap_fe1_sock} {
txreq \
-req "GET" \
-url "/" \
@ -158,19 +158,6 @@ client c2_1 -connect ${hap_fe1_sock} {
expect resp.status == 400
} -run
client c2_2 -connect ${hap_fe1_sock} {
txreq \
-req "GET" \
-url "/" \
-hdr "host: 127.0.0.1" \
-hdr "connection: upgrade" \
-hdr "upgrade: proto1, websocket, proto2" \
-hdr "upgrade: proto3"
rxresp
expect resp.status == 400
} -run
# missing key on server side
client c3 -connect ${hap_fe2_sock} {
txreq \

View file

@ -9,7 +9,7 @@ haproxy h1 -conf {
thread-groups 1
.endif
tune.lua.openlibs string
tune.lua.openlibs none
tune.lua.bool-sample-conversion normal
lua-load ${testdir}/h_txn_get_priv.lua

View file

@ -42,7 +42,7 @@ haproxy h1 -conf {
thread-groups 1
.endif
tune.lua.openlibs string
tune.lua.openlibs none
tune.lua.bool-sample-conversion normal
lua-load ${testdir}/lua_httpclient.lua

View file

@ -14,7 +14,7 @@ haproxy h1 -conf {
thread-groups 1
.endif
tune.lua.openlibs string
tune.lua.openlibs none
tune.lua.bool-sample-conversion normal
lua-load ${testdir}/lua_socket.lua

View file

@ -10,7 +10,7 @@ haproxy h1 -conf {
thread-groups 1
.endif
tune.lua.openlibs string,table
tune.lua.openlibs none
tune.lua.bool-sample-conversion normal
lua-load ${testdir}/txn_get_priv.lua
lua-load ${testdir}/txn_get_priv-print_r.lua

Some files were not shown because too many files have changed in this diff Show more