mirror of
https://github.com/haproxy/haproxy.git
synced 2026-06-11 01:41:49 -04:00
Compare commits
No commits in common. "master" and "v3.4-dev11" have entirely different histories.
master
...
v3.4-dev11
229 changed files with 1487 additions and 4861 deletions
18
.cirrus.yml
Normal file
18
.cirrus.yml
Normal 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)
|
||||
38
.github/workflows/freebsd.yml
vendored
38
.github/workflows/freebsd.yml
vendored
|
|
@ -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
|
||||
2
.github/workflows/illumos.yml
vendored
2
.github/workflows/illumos.yml
vendored
|
|
@ -2,7 +2,7 @@ name: Illumos
|
|||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 3 * * 1"
|
||||
- cron: "0 0 25 * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
|
|
|||
2
BRANCHES
2
BRANCHES
|
|
@ -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
324
CHANGELOG
|
|
@ -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
14
INSTALL
|
|
@ -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 :
|
||||
|
|
|
|||
85
Makefile
85
Makefile
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
[](https://github.com/haproxy/haproxy/actions/workflows/illumos.yml)
|
||||
[](https://github.com/haproxy/haproxy/actions/workflows/netbsd.yml)
|
||||
[](https://github.com/haproxy/haproxy/actions/workflows/cross-zoo.yml)
|
||||
[](https://github.com/haproxy/haproxy/actions/workflows/freebsd.yml)
|
||||
[](https://cirrus-ci.com/github/haproxy/haproxy/)
|
||||
[](https://github.com/haproxy/haproxy/actions/workflows/vtest.yml)
|
||||
|
||||

|
||||
|
|
|
|||
2
VERDATE
2
VERDATE
|
|
@ -1,2 +1,2 @@
|
|||
$Format:%ci$
|
||||
2026/06/03
|
||||
2026/05/08
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
3.5-dev0
|
||||
3.4-dev11
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 $@ $<
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -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:
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
10
include/haproxy/mux_quic_qstrm.h
Normal file
10
include/haproxy/mux_quic_qstrm.h
Normal 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 */
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
9
include/haproxy/xprt_qstrm.h
Normal file
9
include/haproxy/xprt_qstrm.h
Normal 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 */
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
com.example. example
|
||||
com.example.mail. mail
|
||||
|
|
@ -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
|
||||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue