Compare commits

..

1 Commits

Author SHA1 Message Date
Frederic Lecaille
25b668d59a MINOR: stream: Add address filtering to "show sess" CLI command
This patch adds these four options to "show sess" CLI command:

  - fsrc <addr> to show only stream with <addr> as source address
  - fdst <addr> to show only stream with <addr> as destination address
  - bsrc <addr> to show only stream with <addr> as source address
  - bdst <addr> to show only stream with <addr> as destination address

The addresses are made of at least one parameter between the IP address and the
port for instance as follows:

  fsrc [::]:12345 # a port without address for an IPv6 address
  bsrc :12S45     # same as previous but for an IPv4 address
  bdst 10.10.10.10:12345
  fdst [::1]:12345

Only one option may be used by direction (source or destination). Indeed, at
this time only two sockaddr_storage structs have been added to the CLI I/O handler
context. This context has to be allocated because its size is for now on greater than
APPLET_MAX_SVCCTX bytes. This is done from new pool_head_show_sess_ctx() static
pool. ->src and ->dst new sockaddr_storage members are added to show_sess_ctx
struct to store these two addresses. CLI_SHOWSESS_F_NULL_SRC may be used when
the address stored into ->src is null. Same thing for CLI_SHOWSESS_F_NULL_DST
and ->dst. New CLI_SHOWSESS_F_[F|B](SRC|DST) new CLI context flags have been
added to identify the option used (at most two) on the CLI command line.

This patch also implements cli_sess_sk_to_be_skipped() to identify the
streams which must be skipped and not dumped by "show sess" depending on the
->src and ->dst addresses which have been parsed from fsrc, fdst, bsrc and
bdst new options. This is the role cli_parse_show_sess() modified by this
patch to parse these addresses calling str2sa_range().

cli_io_handler_dump_sess() is modified to call cli_sess_sk_to_be_skipped()
if one of the four CLI_SHOWSESS_F_[F|B](SRC|DST) new flags have been set
on the CLI I/O handler context flags for "show sess" command. The connection
is retrieved by strm_orig() for frontend connections if CLI_SHOWSESS_F_FSRC or
CLI_SHOWSESS_F_FDST have been set. sc_conn(strm->scb()) is called for
backend connections if CLI_SHOWSESS_F_BSRC or CLI_SHOWSESS_F_BDST have been set.
Then the current stream to be dumped is potentially skipped by cli_sess_sk_to_be_skipped()
by address direction.
2025-05-23 19:55:35 +02:00
141 changed files with 2253 additions and 3452 deletions

View File

@ -5,8 +5,97 @@ on:
- cron: "0 0 * * 4"
workflow_dispatch:
permissions:
contents: read
jobs:
test:
uses: ./.github/workflows/aws-lc-template.yml
with:
command: "from matrix import determine_latest_aws_lc_fips; print(determine_latest_aws_lc_fips(''))"
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "from matrix import determine_latest_aws_lc_fips; print(determine_latest_aws_lc_fips(''))")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1

View File

@ -1,103 +0,0 @@
name: AWS-LC template
on:
workflow_call:
inputs:
command:
required: true
type: string
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "${{ inputs.command }}")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1

View File

@ -5,8 +5,97 @@ on:
- cron: "0 0 * * 4"
workflow_dispatch:
permissions:
contents: read
jobs:
test:
uses: ./.github/workflows/aws-lc-template.yml
with:
command: "from matrix import determine_latest_aws_lc; print(determine_latest_aws_lc(''))"
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "from matrix import determine_latest_aws_lc; print(determine_latest_aws_lc(''))")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1

View File

@ -1,89 +1,6 @@
ChangeLog :
===========
2025/06/11 : 3.3-dev1
- BUILD: tools: properly define ha_dump_backtrace() to avoid a build warning
- DOC: config: Fix a typo in 2.7 (Name format for maps and ACLs)
- REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+ (5)
- REGTESTS: Remove REQUIRE_VERSION=2.3 from all tests
- REGTESTS: Remove REQUIRE_VERSION=2.4 from all tests
- REGTESTS: Remove tests with REQUIRE_VERSION_BELOW=2.4
- REGTESTS: Remove support for REQUIRE_VERSION and REQUIRE_VERSION_BELOW
- MINOR: server: group postinit server tasks under _srv_postparse()
- MINOR: stats: add stat_col flags
- MINOR: stats: add ME_NEW_COMMON() helper
- MINOR: proxy: collect per-capability stat in proxy_cond_disable()
- MINOR: proxy: add a true list containing all proxies
- MINOR: log: only run postcheck_log_backend() checks on backend
- MEDIUM: proxy: use global proxy list for REGISTER_POST_PROXY_CHECK() hook
- MEDIUM: server: automatically add server to proxy list in new_server()
- MEDIUM: server: add and use srv_init() function
- BUG/MAJOR: leastconn: Protect tree_elt with the lbprm lock
- BUG/MEDIUM: check: Requeue healthchecks on I/O events to handle check timeout
- CLEANUP: applet: Update comment for applet_put* functions
- DEBUG: check: Add the healthcheck's expiration date in the trace messags
- BUG/MINOR: mux-spop: Fix null-pointer deref on SPOP stream allocation failure
- CLEANUP: sink: remove useless cleanup in sink_new_from_logger()
- MAJOR: counters: add shared counters base infrastructure
- MINOR: counters: add shared counters helpers to get and drop shared pointers
- MINOR: counters: add common struct and flags to {fe,be}_counters_shared
- MEDIUM: counters: manage shared counters using dedicated helpers
- CLEANUP: counters: merge some common counters between {fe,be}_counters_shared
- MINOR: counters: add local-only internal rates to compute some maxes
- MAJOR: counters: dispatch counters over thread groups
- BUG/MEDIUM: cli: Properly parse empty lines and avoid crashed
- BUG/MINOR: config: emit warning for empty args only in discovery mode
- BUG/MINOR: config: fix arg number reported on empty arg warning
- BUG/MINOR: quic: Missing SSL session object freeing
- MINOR: applet: Add API functions to manipulate input and output buffers
- MINOR: applet: Add API functions to get data from the input buffer
- CLEANUP: applet: Simplify a bit comments for applet_put* functions
- MEDIUM: hlua: Update TCP applet functions to use the new applet API
- BUG/MEDIUM: fd: Use the provided tgid in fd_insert() to get tgroup_info
- BUG/MINIR: h1: Fix doc of 'accept-unsafe-...-request' about URI parsing
2025/05/28 : 3.3-dev0
- MINOR: version: mention that it's development again
2025/05/28 : 3.2.0
- MINOR: promex: Add agent check status/code/duration metrics
- MINOR: ssl: support strict-sni in ssl-default-bind-options
- MINOR: ssl: also provide the "tls-tickets" bind option
- MINOR: server: define CLI I/O handler for "add server"
- MINOR: server: implement "add server help"
- MINOR: server: use stress mode for "add server help"
- BUG/MEDIUM: server: fix crash after duplicate GUID insertion
- BUG/MEDIUM: server: fix potential null-deref after previous fix
- MINOR: config: list recently added sections with -dKcfg
- BUG/MAJOR: cache: Crash because of wrong cache entry deleted
- DOC: configuration: fix the example in crt-store
- DOC: config: clarify the wording around single/double quotes
- DOC: config: clarify the legacy cookie and header captures
- DOC: config: fix alphabetical ordering of layer 7 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 6 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 5 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 4 sample fetch functions
- DOC: config: fix alphabetical ordering of internal sample fetch functions
- BUG/MINOR: h3: Set HTX flags corresponding to the scheme found in the request
- BUG/MEDIUM: h3: Declare absolute URI as normalized when a :authority is found
- DOC: config: mention in bytes_in and bytes_out that they're read on input
- DOC: config: clarify the basics of ACLs (call point, multi-valued etc)
- REGTESTS: Make the script testing conditional set-var compatible with Vtest2
- REGTESTS: Explicitly allow failing shell commands in some scripts
- MINOR: listeners: Add support for a label on bind line
- BUG/MEDIUM: cli/ring: Properly handle shutdown in "show event" I/O handler
- BUG/MEDIUM: hlua: Properly detect shudowns for TCP applets based on the new API
- BUG/MEDIUM: hlua: Fix getline() for TCP applets to work with applet's buffers
- BUG/MEDIUM: hlua: Fix receive API for TCP applets to properly handle shutdowns
- CI: vtest: Rely on VTest2 to run regression tests
- CI: vtest: Fix the build script to properly work on MaOS
- CI: combine AWS-LC and AWS-LC-FIPS by template
- BUG/MEDIUM: httpclient: Throw an error if an lua httpclient instance is reused
- DOC: hlua: Add a note to warn user about httpclient object reuse
- DOC: hlua: fix a few typos in HTTPMessage.set_body_len() documentation
- DEV: patchbot: prepare for new version 3.3-dev
- MINOR: version: mention that it's 3.2 LTS now.
2025/05/21 : 3.2-dev17
- DOC: configuration: explicit multi-choice on bind shards option
- BUG/MINOR: sink: detect and warn when using "send-proxy" options with ring servers

View File

@ -984,7 +984,7 @@ OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \
src/lb_fas.o src/clock.o src/sock_inet.o src/ev_select.o \
src/lb_map.o src/shctx.o src/mworker-prog.o src/hpack-dec.o \
src/arg.o src/signal.o src/fix.o src/dynbuf.o src/guid.o \
src/cfgparse-tcp.o src/lb_ss.o src/chunk.o src/counters.o \
src/cfgparse-tcp.o src/lb_ss.o src/chunk.o \
src/cfgparse-unix.o src/regex.o src/fcgi.o src/uri_auth.o \
src/eb64tree.o src/eb32tree.o src/eb32sctree.o src/lru.o \
src/limits.o src/ebimtree.o src/wdt.o src/hpack-tbl.o \

View File

@ -1,2 +1,2 @@
$Format:%ci$
2025/06/11
2025/05/21

View File

@ -1 +1 @@
3.3-dev1
3.2-dev17

View File

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

View File

@ -1,29 +0,0 @@
ENDINPUT
BEGININSTRUCTION
You are an AI assistant that follows instruction extremely well. Help as much
as you can, responding to a single question using a single response.
The developer wants to know if he needs to backport the patch above to fix
maintenance branches, for which branches, and what possible dependencies might
be mentioned in the commit message. Carefully study the commit message and its
backporting instructions if any (otherwise it should probably not be backported),
then provide a very concise and short summary that will help the developer decide
to backport it, or simply to skip it.
Start by explaining in one or two sentences what you recommend for this one and why.
Finally, based on your analysis, give your general conclusion as "Conclusion: X"
where X is a single word among:
- "yes", if you recommend to backport the patch right now either because
it explicitly states this or because it's a fix for a bug that affects
a maintenance branch (3.2 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:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
-----------------------
HAProxy Starter Guide
-----------------------
version 3.3
version 3.2
This document is an introduction to HAProxy for all those who don't know it, as

View File

@ -893,9 +893,7 @@ Core class
**context**: init, task, action
This function returns a new object of a *httpclient* class. An *httpclient*
object must be used to process one and only one request. It must never be
reused to process several requests.
This function returns a new object of a *httpclient* class.
:returns: A :ref:`httpclient_class` object.
@ -2583,9 +2581,7 @@ HTTPClient class
.. js:class:: HTTPClient
The httpclient class allows issue of outbound HTTP requests through a simple
API without the knowledge of HAProxy internals. Any instance must be used to
process one and only one request. It must never be reused to process several
requests.
API without the knowledge of HAProxy internals.
.. js:function:: HTTPClient.get(httpclient, request)
.. js:function:: HTTPClient.head(httpclient, request)
@ -3920,25 +3916,21 @@ AppletTCP class
*size* is missing, the function tries to read all the content of the stream
until the end. An optional timeout may be specified in milliseconds. In this
case the function will return no longer than this delay, with the amount of
available data, or nil if there is no data. An empty string is returned if the
connection is closed.
available data (possibly none).
:param class_AppletTCP applet: An :ref:`applettcp_class`
:param integer size: the required read size.
:returns: return nil if the timeout has expired and no data was available but
can still be received. Otherwise, a string is returned, possibly an empty
string if the connection is closed.
:returns: always return a string, the string can be empty if the connection is
closed.
.. js:function:: AppletTCP.try_receive(applet)
Reads available data from the TCP stream and returns immediately. Returns a
string containing read bytes or nil if no bytes are available at that time. An
empty string is returned if the connection is closed.
string containing read bytes that may possibly be empty if no bytes are
available at that time.
:param class_AppletTCP applet: An :ref:`applettcp_class`
:returns: return nil if no data was available but can still be
received. Otherwise, a string is returned, possibly an empty string if the
connection is closed.
:returns: always return a string, the string can be empty.
.. js:function:: AppletTCP.send(appletmsg)
@ -4625,10 +4617,10 @@ HTTPMessage class
added with the "chunked" value. In both cases, all existing "Content-Length"
and "Transfer-Encoding" headers are removed.
This function should be used in the filter context to be able to alter the
payload of the HTTP message. The internal state of the HTTP message is updated
This fnuction should be used in the filter context to be able to alter the
payload of the HTTP message. The internal state fo the HTTP message is updated
accordingly. :js:func:`HTTPMessage.add_header()` or
:js:func:`HTTPMessage.set_header()` functions must be used in that case.
:js:func:`HTTPMessage.set_header()` functions must to be used in that case.
:param class_httpmessage http_msg: The manipulated HTTP message.
:param type length: The new payload length to set. It can be an integer or

View File

@ -1,7 +1,7 @@
------------------------
HAProxy Management Guide
------------------------
version 3.3
version 3.2
This document describes how to start, stop, manage, and troubleshoot HAProxy,
@ -3402,6 +3402,19 @@ show sess [<id> | all | help] [<options>*]
analysis. It is only displayed if it was captured.
- susp only show streams considered as suspicious by the developers
based on criteria that may in time or vary along versions.
- fsrc [<addr>][:<port>] only show streams with <addr> as optional source
frontent address and <port> as optional port.
- fdst [<addr>][:<port>] only show streams with <addr> as optional destination
frontent address and <port> as optional port.
- bsrc [<addr>][:<port>] only show streams with <addr> as optional source
backend address and <port> as optional port.
- bdst [<addr>][:<port>] only show streams with <addr> as optional destination
backend address and <port> as optional port.
Note that for fsrc, fdst, bsrc and bdst options, at least one parameter must
be provided (the addresse or the port). Only one address may be used by
direction (only one option between fdst and bdst, and only one option between
fsrc and bsrc).
show stat [domain <resolvers|proxy>] [{<iid>|<proxy>} <type> <sid>] \
[typed|json] [desc] [up|no-maint]

View File

@ -215,7 +215,7 @@ function handler(applet)
local input = applet:receive(1, delay)
if input then
if input == "" or input == "q" then
if input == "q" then
game_over = true
elseif input == "\27" then
local a = applet:receive(1, delay)

View File

@ -282,92 +282,6 @@ static inline void applet_expect_data(struct appctx *appctx)
se_fl_clr(appctx->sedesc, SE_FL_EXP_NO_DATA);
}
/* Returns the buffer containing data pushed to the applet by the stream. For
* applets using its own buffers it is the appctx input buffer. For legacy
* applet, it is the output channel buffer.
*/
static inline struct buffer *applet_get_inbuf(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return &appctx->inbuf;
else
return sc_ob(appctx_sc(appctx));
}
/* Returns the buffer containing data pushed by the applets to the stream. For
* applets using its own buffer it is the appctx output buffer. For legacy
* applet, it is the input channel buffer.
*/
static inline struct buffer *applet_get_outbuf(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return &appctx->outbuf;
else
return sc_ib(appctx_sc(appctx));
}
/* Returns the amount of data in the input buffer (see applet_get_inbuf) */
static inline size_t applet_input_data(const struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return b_data(&appctx->inbuf);
else
return co_data(sc_oc(appctx_sc(appctx)));
}
/* Skips <len> bytes from the input buffer (see applet_get_inbuf).
*
* This is useful when data have been read directly from the buffer. It is
* illegal to call this function with <len> causing a wrapping at the end of the
* buffer. It's the caller's responsibility to ensure that <len> is never larger
* than available ouput data.
*/
static inline void applet_skip_input(struct appctx *appctx, size_t len)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
b_del(&appctx->inbuf, len);
else
co_skip(sc_oc(appctx_sc(appctx)), len);
}
/* Removes all bytes from the input buffer (see applet_get_inbuf).
*/
static inline void applet_reset_input(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
b_reset(&appctx->inbuf);
applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
}
else
co_skip(sc_oc(appctx_sc(appctx)), co_data(sc_oc(appctx_sc(appctx))));
}
/* Returns the amout of space available at the output buffer (see applet_get_outbuf).
*/
static inline size_t applet_output_room(const struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return b_room(&appctx->outbuf);
else
return channel_recv_max(sc_ic(appctx_sc(appctx)));
}
/*Indicates that the applet have more data to deliver and it needs more room in
* the output buffer to do so (see applet_get_outbuf).
*
* For applets using its own buffers, <room_needed> is not used and only
* <appctx> flags are updated. For legacy applets, the amount of free space
* required must be specified. In this last case, it is the caller
* responsibility to be sure <room_needed> is valid.
*/
static inline void applet_need_room(struct appctx *appctx, size_t room_needed)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
applet_have_more_data(appctx);
else
sc_need_room(appctx_sc(appctx), room_needed);
}
/* Should only be used via wrappers applet_putchk() / applet_putchk_stress(). */
static inline int _applet_putchk(struct appctx *appctx, struct buffer *chunk,
int stress)
@ -404,10 +318,9 @@ static inline int _applet_putchk(struct appctx *appctx, struct buffer *chunk,
return ret;
}
/* writes chunk <chunk> into the applet output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
/* writes chunk <chunk> into the input channel of the stream attached to this
* appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full error.
* See ci_putchk() for the list of return codes.
*/
static inline int applet_putchk(struct appctx *appctx, struct buffer *chunk)
{
@ -420,10 +333,9 @@ static inline int applet_putchk_stress(struct appctx *appctx, struct buffer *chu
return _applet_putchk(appctx, chunk, 1);
}
/* writes <len> chars from <blk> into the applet output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
/* writes <len> chars from <blk> into the input channel of the stream attached
* to this appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full
* error. See ci_putblk() for the list of return codes.
*/
static inline int applet_putblk(struct appctx *appctx, const char *blk, int len)
{
@ -455,11 +367,10 @@ static inline int applet_putblk(struct appctx *appctx, const char *blk, int len)
return ret;
}
/* writes chars from <str> up to the trailing zero (excluded) into the applet
* output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
/* writes chars from <str> up to the trailing zero (excluded) into the input
* channel of the stream attached to this appctx's endpoint, and marks the
* SC_FL_NEED_ROOM on a channel full error. See ci_putstr() for the list of
* return codes.
*/
static inline int applet_putstr(struct appctx *appctx, const char *str)
{
@ -492,10 +403,9 @@ static inline int applet_putstr(struct appctx *appctx, const char *str)
return ret;
}
/* writes character <chr> into the applet's output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
/* writes character <chr> into the input channel of the stream attached to this
* appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full error.
* See ci_putchr() for the list of return codes.
*/
static inline int applet_putchr(struct appctx *appctx, char chr)
{
@ -528,283 +438,6 @@ static inline int applet_putchr(struct appctx *appctx, char chr)
return ret;
}
static inline int applet_may_get(const struct appctx *appctx, size_t len)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (len > b_data(&appctx->inbuf)) {
if (se_fl_test(appctx->sedesc, SE_FL_SHW))
return -1;
return 0;
}
}
else {
const struct stconn *sc = appctx_sc(appctx);
if ((sc->flags & SC_FL_SHUT_DONE) || len > co_data(sc_oc(sc))) {
if (sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED))
return -1;
return 0;
}
}
return 1;
}
/* Gets one char from the applet input buffer (see appet_get_inbuf),
*
* Return values :
* 1 : number of bytes read, equal to requested size.
* =0 : not enough data available. <c> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getchar(const struct appctx *appctx, char *c)
{
int ret;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
return ret;
*c = ((appctx->flags & APPCTX_FL_INOUT_BUFS)
? *(b_head(&appctx->inbuf))
: *(co_head(sc_oc(appctx_sc(appctx)))));
return 1;
}
/* Copies one full block of data from the applet input buffer (see
* appet_get_inbuf).
*
* <len> bytes are capied, starting at the offset <offset>.
*
* Return values :
* >0 : number of bytes read, equal to requested size.
* =0 : not enough data available. <blk> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getblk(const struct appctx *appctx, char *blk, int len, int offset)
{
const struct buffer *buf;
int ret;
ret = applet_may_get(appctx, len+offset);
if (ret <= 0)
return ret;
buf = ((appctx->flags & APPCTX_FL_INOUT_BUFS)
? &appctx->inbuf
: sc_ob(appctx_sc(appctx)));
return b_getblk(buf, blk, len, offset);
}
/* Gets one text block representing a word from the applet input buffer (see
* appet_get_inbuf).
*
* The separator is waited for as long as some data can still be received and the
* destination is not full. Otherwise, the string may be returned as is, without
* the separator.
*
* Return values :
* >0 : number of bytes read. Includes the separator if present before len or end.
* =0 : no separator before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getword(const struct appctx *appctx, char *str, int len, char sep)
{
const struct buffer *buf;
char *p;
size_t input, max = len;
int ret = 0;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
goto out;
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
buf = &appctx->inbuf;
input = b_data(buf);
}
else {
struct stconn *sc = appctx_sc(appctx);
buf = sc_ob(sc);
input = co_data(sc_oc(sc));
}
if (max > input) {
max = input;
str[max-1] = 0;
}
p = b_head(buf);
while (max) {
*str++ = *p;
ret++;
max--;
if (*p == sep)
goto out;
p = b_next(buf, p);
}
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (ret < len && (ret < input || b_room(buf)) &&
!se_fl_test(appctx->sedesc, SE_FL_SHW))
ret = 0;
}
else {
struct stconn *sc = appctx_sc(appctx);
if (ret < len && (ret < input || channel_may_recv(sc_oc(sc))) &&
!(sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)))
ret = 0;
}
out:
if (max)
*str = 0;
return ret;
}
/* Gets one text block representing a line from the applet input buffer (see
* appet_get_inbuf).
*
* The '\n' is waited for as long as some data can still be received and the
* destination is not full. Otherwise, the string may be returned as is, without
* the '\n'.
*
* Return values :
* >0 : number of bytes read. Includes the \n if present before len or end.
* =0 : no '\n' before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getline(const struct appctx *appctx, char *str, int len)
{
return applet_getword(appctx, str, len, '\n');
}
/* Gets one or two blocks of data at once from the applet input buffer (see appet_get_inbuf),
*
* Data are not copied.
*
* Return values :
* >0 : number of blocks filled (1 or 2). blk1 is always filled before blk2.
* =0 : not enough data available. <blk*> are left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getblk_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2)
{
const struct buffer *buf;
size_t max;
int ret;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
return ret;
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
buf = &appctx->inbuf;
max = b_data(buf);
}
else {
struct stconn *sc = appctx_sc(appctx);
buf = sc_ob(sc);
max = co_data(sc_oc(sc));
}
return b_getblk_nc(buf, blk1, len1, blk2, len2, 0, max);
}
/* Gets one or two blocks of text representing a word from the applet input
* buffer (see appet_get_inbuf).
*
* Data are not copied. The separator is waited for as long as some data can
* still be received and the destination is not full. Otherwise, the string may
* be returned as is, without the separator.
*
* Return values :
* >0 : number of bytes read. Includes the separator if present before len or end.
* =0 : no separator before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getword_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2, char sep)
{
int ret;
size_t l;
ret = applet_getblk_nc(appctx, blk1, len1, blk2, len2);
if (unlikely(ret <= 0))
return ret;
for (l = 0; l < *len1 && (*blk1)[l] != sep; l++);
if (l < *len1 && (*blk1)[l] == sep) {
*len1 = l + 1;
return 1;
}
if (ret >= 2) {
for (l = 0; l < *len2 && (*blk2)[l] != sep; l++);
if (l < *len2 && (*blk2)[l] == sep) {
*len2 = l + 1;
return 2;
}
}
/* If we have found no LF and the buffer is full or the SC is shut, then
* the resulting string is made of the concatenation of the pending
* blocks (1 or 2).
*/
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (b_full(&appctx->inbuf) || se_fl_test(appctx->sedesc, SE_FL_SHW))
return ret;
}
else {
struct stconn *sc = appctx_sc(appctx);
if (!channel_may_recv(sc_oc(sc)) || sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED))
return ret;
}
/* No LF yet and not shut yet */
return 0;
}
/* Gets one or two blocks of text representing a line from the applet input
* buffer (see appet_get_inbuf).
*
* Data are not copied. The '\n' is waited for as long as some data can still be
* received and the destination is not full. Otherwise, the string may be
* returned as is, without the '\n'.
*
* Return values :
* >0 : number of bytes read. Includes the \n if present before len or end.
* =0 : no '\n' before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getline_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2)
{
return applet_getword_nc(appctx, blk1, len1, blk2, len2, '\n');
}
#endif /* _HAPROXY_APPLET_H */
/*

View File

@ -86,7 +86,7 @@ static inline int be_usable_srv(struct proxy *be)
/* set the time of last session on the backend */
static inline void be_set_sess_last(struct proxy *be)
{
HA_ATOMIC_STORE(&be->be_counters.shared->tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
be->be_counters.last_sess = ns_to_sec(now_ns);
}
/* This function returns non-zero if the designated server will be

View File

@ -25,144 +25,108 @@
#include <haproxy/freq_ctr-t.h>
#define COUNTERS_SHARED_F_NONE 0x0000
#define COUNTERS_SHARED_F_LOCAL 0x0001 // shared counter struct is actually process-local
// common to fe_counters_shared and be_counters_shared
#define COUNTERS_SHARED \
struct { \
uint16_t flags; /* COUNTERS_SHARED_F flags */\
};
#define COUNTERS_SHARED_TG \
struct { \
unsigned long last_change; /* last time, when the state was changed */\
long long srv_aborts; /* aborted responses during DATA phase caused by the server */\
long long cli_aborts; /* aborted responses during DATA phase caused by the client */\
long long internal_errors; /* internal processing errors */\
long long failed_rewrites; /* failed rewrites (warning) */\
long long bytes_out; /* number of bytes transferred from the server to the client */\
long long bytes_in; /* number of bytes transferred from the client to the server */\
long long denied_resp; /* blocked responses because of security concerns */\
long long denied_req; /* blocked requests because of security concerns */\
long long cum_sess; /* cumulated number of accepted connections */\
/* compression counters, index 0 for requests, 1 for responses */\
long long comp_in[2]; /* input bytes fed to the compressor */\
long long comp_out[2]; /* output bytes emitted by the compressor */\
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */\
struct freq_ctr sess_per_sec; /* sessions per second on this server */\
}
// for convenience (generic pointer)
struct counters_shared {
COUNTERS_SHARED;
struct {
COUNTERS_SHARED_TG;
} *tg[MAX_TGROUPS];
};
/* counters used by listeners and frontends */
struct fe_counters_shared_tg {
COUNTERS_SHARED_TG;
long long denied_sess; /* denied session requests (tcp-req-sess rules) */
long long denied_conn; /* denied connection requests (tcp-req-conn rules) */
long long intercepted_req; /* number of monitoring or stats requests intercepted by the frontend */
long long cum_conn; /* cumulated number of received connections */
struct freq_ctr conn_per_sec; /* received connections per second on the frontend */
struct freq_ctr req_per_sec; /* HTTP requests per second on the frontend */
long long cum_sess_ver[3]; /* cumulated number of h1/h2/h3 sessions */
union {
struct {
long long cum_req[4]; /* cumulated number of processed other/h1/h2/h3 requests */
long long cache_hits; /* cache hits */
long long cache_lookups;/* cache lookups */
long long comp_rsp; /* number of compressed responses */
long long rsp[6]; /* http response codes */
} http;
} p; /* protocol-specific stats */
long long failed_req; /* failed requests (eg: invalid or timeout) */
};
struct fe_counters_shared {
COUNTERS_SHARED;
struct fe_counters_shared_tg *tg[MAX_TGROUPS];
};
struct fe_counters {
struct fe_counters_shared *shared; /* shared counters */
unsigned int conn_max; /* max # of active sessions */
long long cum_conn; /* cumulated number of received connections */
long long cum_sess; /* cumulated number of accepted connections */
long long cum_sess_ver[3]; /* cumulated number of h1/h2/h3 sessions */
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
struct freq_ctr _sess_per_sec; /* sessions per second on this frontend, used to compute sps_max (internal use only) */
struct freq_ctr _conn_per_sec; /* connections per second on this frontend, used to compute cps_max (internal use only) */
long long bytes_in; /* number of bytes transferred from the client to the server */
long long bytes_out; /* number of bytes transferred from the server to the client */
/* compression counters, index 0 for requests, 1 for responses */
long long comp_in[2]; /* input bytes fed to the compressor */
long long comp_out[2]; /* output bytes emitted by the compressor */
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */
long long denied_req; /* blocked requests because of security concerns */
long long denied_resp; /* blocked responses because of security concerns */
long long failed_req; /* failed requests (eg: invalid or timeout) */
long long denied_conn; /* denied connection requests (tcp-req-conn rules) */
long long denied_sess; /* denied session requests (tcp-req-sess rules) */
long long failed_rewrites; /* failed rewrites (warning) */
long long internal_errors; /* internal processing errors */
long long cli_aborts; /* aborted responses during DATA phase caused by the client */
long long srv_aborts; /* aborted responses during DATA phase caused by the server */
long long intercepted_req; /* number of monitoring or stats requests intercepted by the frontend */
union {
struct {
unsigned int rps_max; /* maximum of new HTTP requests second observed */
struct freq_ctr _req_per_sec; /* HTTP requests per second on the frontend, only used to compute rps_max */
} http;
} p; /* protocol-specific stats */
};
struct be_counters_shared_tg {
COUNTERS_SHARED_TG;
long long cum_lbconn; /* cumulated number of sessions processed by load balancing (BE only) */
long long connect; /* number of connection establishment attempts */
long long reuse; /* number of connection reuses */
unsigned long last_sess; /* last session time */
long long failed_checks, failed_hana; /* failed health checks and health analyses for servers */
long long down_trans; /* up->down transitions */
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
long long cache_hits; /* cache hits */
long long cache_lookups;/* cache lookups */
long long cum_req[4]; /* cumulated number of processed other/h1/h2/h3 requests */
long long comp_rsp; /* number of compressed responses */
unsigned int rps_max; /* maximum of new HTTP requests second observed */
long long rsp[6]; /* http response codes */
long long cache_lookups;/* cache lookups */
long long cache_hits; /* cache hits */
} http;
} p; /* protocol-specific stats */
long long redispatches; /* retried and redispatched connections (BE only) */
long long retries; /* retried and redispatched connections (BE only) */
long long failed_resp; /* failed responses (BE only) */
long long failed_conns; /* failed connect() attempts (BE only) */
};
struct freq_ctr sess_per_sec; /* sessions per second on this server */
struct freq_ctr req_per_sec; /* HTTP requests per second on the frontend */
struct freq_ctr conn_per_sec; /* received connections per second on the frontend */
struct be_counters_shared {
COUNTERS_SHARED;
struct be_counters_shared_tg *tg[MAX_TGROUPS];
unsigned long last_change; /* last time, when the state was changed */
};
/* counters used by servers and backends */
struct be_counters {
struct be_counters_shared *shared; /* shared counters */
unsigned int conn_max; /* max # of active sessions */
long long cum_sess; /* cumulated number of accepted connections */
long long cum_lbconn; /* cumulated number of sessions processed by load balancing (BE only) */
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
unsigned int nbpend_max; /* max number of pending connections with no server assigned yet */
unsigned int cur_sess_max; /* max number of currently active sessions */
struct freq_ctr _sess_per_sec; /* sessions per second on this frontend, used to compute sps_max (internal use only) */
long long bytes_in; /* number of bytes transferred from the client to the server */
long long bytes_out; /* number of bytes transferred from the server to the client */
/* compression counters, index 0 for requests, 1 for responses */
long long comp_in[2]; /* input bytes fed to the compressor */
long long comp_out[2]; /* output bytes emitted by the compressor */
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */
long long denied_req; /* blocked requests because of security concerns */
long long denied_resp; /* blocked responses because of security concerns */
long long connect; /* number of connection establishment attempts */
long long reuse; /* number of connection reuses */
long long failed_conns; /* failed connect() attempts (BE only) */
long long failed_resp; /* failed responses (BE only) */
long long cli_aborts; /* aborted responses during DATA phase caused by the client */
long long srv_aborts; /* aborted responses during DATA phase caused by the server */
long long retries; /* retried and redispatched connections (BE only) */
long long redispatches; /* retried and redispatched connections (BE only) */
long long failed_rewrites; /* failed rewrites (warning) */
long long internal_errors; /* internal processing errors */
long long failed_checks, failed_hana; /* failed health checks and health analyses for servers */
long long down_trans; /* up->down transitions */
unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
unsigned int qtime_max, ctime_max, dtime_max, ttime_max; /* maximum of conn_time, queue_time, data_time, total_time observed */
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
long long comp_rsp; /* number of compressed responses */
unsigned int rps_max; /* maximum of new HTTP requests second observed */
long long rsp[6]; /* http response codes */
long long cache_lookups;/* cache lookups */
long long cache_hits; /* cache hits */
} http;
} p; /* protocol-specific stats */
struct freq_ctr sess_per_sec; /* sessions per second on this server */
unsigned long last_sess; /* last session time */
unsigned long last_change; /* last time, when the state was changed */
};
#endif /* _HAPROXY_COUNTERS_T_H */

View File

@ -1,102 +0,0 @@
/*
* include/haproxy/counters.h
* objects counters management
*
* Copyright 2025 HAProxy Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_COUNTERS_H
# define _HAPROXY_COUNTERS_H
#include <stddef.h>
#include <haproxy/counters-t.h>
#include <haproxy/guid-t.h>
struct fe_counters_shared *counters_fe_shared_get(const struct guid_node *guid);
struct be_counters_shared *counters_be_shared_get(const struct guid_node *guid);
void counters_fe_shared_drop(struct fe_counters_shared *counters);
void counters_be_shared_drop(struct be_counters_shared *counters);
/* time oriented helper: get last time (relative to current time) on a given
* <scounter> array, for <elem> member (one member per thread group) which is
* assumed to be unsigned long type.
*
* wrapping is handled by taking the lowest diff between now and last counter.
* But since wrapping is expected once every ~136 years (starting 01/01/1970),
* perhaps it's not worth the extra CPU cost.. let's see.
*/
#define COUNTERS_SHARED_LAST_OFFSET(scounters, type, offset) \
({ \
unsigned long last = HA_ATOMIC_LOAD((type *)((char *)scounters[0] + offset));\
unsigned long now_seconds = ns_to_sec(now_ns); \
int it; \
\
for (it = 1; it < global.nbtgroups; it++) { \
unsigned long cur = HA_ATOMIC_LOAD((type *)((char *)scounters[it] + offset));\
if ((now_seconds - cur) < (now_seconds - last)) \
last = cur; \
} \
last; \
})
#define COUNTERS_SHARED_LAST(scounters, elem) \
({ \
int offset = offsetof(typeof(**scounters), elem); \
unsigned long last = COUNTERS_SHARED_LAST_OFFSET(scounters, typeof(scounters[0]->elem), offset); \
\
last; \
})
/* generic unsigned integer addition for all <elem> members from
* <scounters> array (one member per thread group)
* <rfunc> is function taking pointer as parameter to read from the memory
* location pointed to scounters[it].elem
*/
#define COUNTERS_SHARED_TOTAL_OFFSET(scounters, type, offset, rfunc) \
({ \
uint64_t __ret = 0; \
int it; \
\
for (it = 0; it < global.nbtgroups; it++) \
__ret += rfunc((type *)((char *)scounters[it] + offset)); \
__ret; \
})
#define COUNTERS_SHARED_TOTAL(scounters, elem, rfunc) \
({ \
int offset = offsetof(typeof(**scounters), elem); \
uint64_t __ret = COUNTERS_SHARED_TOTAL_OFFSET(scounters, typeof(scounters[0]->elem), offset, rfunc);\
\
__ret; \
})
/* same as COUNTERS_SHARED_TOTAL but with <rfunc> taking 2 extras arguments:
* <arg1> and <arg2>
*/
#define COUNTERS_SHARED_TOTAL_ARG2(scounters, elem, rfunc, arg1, arg2) \
({ \
uint64_t __ret = 0; \
int it; \
\
for (it = 0; it < global.nbtgroups; it++) \
__ret += rfunc(&scounters[it]->elem, arg1, arg2); \
__ret; \
})
#endif /* _HAPROXY_COUNTERS_H */

View File

@ -499,7 +499,6 @@ static inline long fd_clr_running(int fd)
static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), int tgid, unsigned long thread_mask)
{
extern void sock_conn_iocb(int);
struct tgroup_info *tginfo = &ha_tgroup_info[tgid - 1];
int newstate;
/* conn_fd_handler should support edge-triggered FDs */
@ -529,7 +528,7 @@ static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), int tgid
BUG_ON(fdtab[fd].state != 0);
BUG_ON(tgid < 1 || tgid > MAX_TGROUPS);
thread_mask &= tginfo->threads_enabled;
thread_mask &= tg->threads_enabled;
BUG_ON(thread_mask == 0);
fd_claim_tgid(fd, tgid);

View File

@ -244,7 +244,7 @@ struct listener {
struct fe_counters *counters; /* statistics counters */
struct mt_list wait_queue; /* link element to make the listener wait for something (LI_LIMITED) */
char *name; /* listener's name */
char *label; /* listener's label */
unsigned int thr_conn[MAX_THREADS_PER_GROUP]; /* number of connections per thread for the group */
struct list by_fe; /* chaining in frontend's list of listeners */

View File

@ -202,7 +202,7 @@ struct qcc_app_ops {
/* Initialize <qcs> stream app context or leave it to NULL if rejected. */
int (*attach)(struct qcs *qcs, void *conn_ctx);
/* Convert received HTTP payload to HTX. Returns amount of decoded bytes from <b> or a negative error code. */
/* Convert received HTTP payload to HTX. */
ssize_t (*rcv_buf)(struct qcs *qcs, struct buffer *b, int fin);
/* Convert HTX to HTTP payload for sending. */
@ -232,7 +232,7 @@ struct qcc_app_ops {
#define QC_CF_ERRL 0x00000001 /* fatal error detected locally, connection should be closed soon */
#define QC_CF_ERRL_DONE 0x00000002 /* local error properly handled, connection can be released */
#define QC_CF_IS_BACK 0x00000004 /* backend side */
/* unused 0x00000004 */
#define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */
/* unused 0x00000010 */
#define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */

View File

@ -311,10 +311,6 @@ struct proxy {
char flags; /* bit field PR_FL_* */
enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */
char cap; /* supported capabilities (PR_CAP_*) */
/* 4-bytes hole */
struct list global_list; /* list member for global proxy list */
unsigned int maxconn; /* max # of active streams on the frontend */
int options; /* PR_O_REDISP, PR_O_TRANSP, ... */

View File

@ -33,7 +33,6 @@
#include <haproxy/thread.h>
extern struct proxy *proxies_list;
extern struct list proxies;
extern struct eb_root used_proxy_id; /* list of proxy IDs in use */
extern unsigned int error_snapshot_id; /* global ID assigned to each error then incremented */
extern struct eb_root proxy_by_name; /* tree of proxies sorted by name */
@ -136,24 +135,22 @@ static inline void proxy_reset_timeouts(struct proxy *proxy)
/* increase the number of cumulated connections received on the designated frontend */
static inline void proxy_inc_fe_conn_ctr(struct listener *l, struct proxy *fe)
{
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_conn);
_HA_ATOMIC_INC(&fe->fe_counters.cum_conn);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_conn);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->conn_per_sec, 1);
_HA_ATOMIC_INC(&l->counters->cum_conn);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.cps_max,
update_freq_ctr(&fe->fe_counters._conn_per_sec, 1));
update_freq_ctr(&fe->fe_counters.conn_per_sec, 1));
}
/* increase the number of cumulated connections accepted by the designated frontend */
static inline void proxy_inc_fe_sess_ctr(struct listener *l, struct proxy *fe)
{
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_sess);
_HA_ATOMIC_INC(&fe->fe_counters.cum_sess);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->sess_per_sec, 1);
_HA_ATOMIC_INC(&l->counters->cum_sess);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.sps_max,
update_freq_ctr(&fe->fe_counters._sess_per_sec, 1));
update_freq_ctr(&fe->fe_counters.sess_per_sec, 1));
}
/* increase the number of cumulated HTTP sessions on the designated frontend.
@ -163,21 +160,20 @@ static inline void proxy_inc_fe_cum_sess_ver_ctr(struct listener *l, struct prox
unsigned int http_ver)
{
if (http_ver == 0 ||
http_ver > sizeof(fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver) / sizeof(*fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver))
http_ver > sizeof(fe->fe_counters.cum_sess_ver) / sizeof(*fe->fe_counters.cum_sess_ver))
return;
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver[http_ver - 1]);
_HA_ATOMIC_INC(&fe->fe_counters.cum_sess_ver[http_ver - 1]);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_sess_ver[http_ver - 1]);
_HA_ATOMIC_INC(&l->counters->cum_sess_ver[http_ver - 1]);
}
/* increase the number of cumulated streams on the designated backend */
static inline void proxy_inc_be_ctr(struct proxy *be)
{
_HA_ATOMIC_INC(&be->be_counters.shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&be->be_counters.shared->tg[tgid - 1]->sess_per_sec, 1);
_HA_ATOMIC_INC(&be->be_counters.cum_sess);
HA_ATOMIC_UPDATE_MAX(&be->be_counters.sps_max,
update_freq_ctr(&be->be_counters._sess_per_sec, 1));
update_freq_ctr(&be->be_counters.sess_per_sec, 1));
}
/* increase the number of cumulated requests on the designated frontend.
@ -187,15 +183,14 @@ static inline void proxy_inc_be_ctr(struct proxy *be)
static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe,
unsigned int http_ver)
{
if (http_ver >= sizeof(fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req) / sizeof(*fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req))
if (http_ver >= sizeof(fe->fe_counters.p.http.cum_req) / sizeof(*fe->fe_counters.p.http.cum_req))
return;
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req[http_ver]);
_HA_ATOMIC_INC(&fe->fe_counters.p.http.cum_req[http_ver]);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->p.http.cum_req[http_ver]);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->req_per_sec, 1);
_HA_ATOMIC_INC(&l->counters->p.http.cum_req[http_ver]);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1));
update_freq_ctr(&fe->fe_counters.req_per_sec, 1));
}
/* Returns non-zero if the proxy is configured to retry a request if we got that status, 0 otherwise */

View File

@ -228,9 +228,6 @@ struct quic_version {
extern const struct quic_version quic_versions[];
extern const size_t quic_versions_nb;
extern const struct quic_version *preferred_version;
extern const struct quic_version *quic_version_draft_29;
extern const struct quic_version *quic_version_1;
extern const struct quic_version *quic_version_2;
/* unused: 0x01 */
/* Flag the packet number space as requiring an ACK frame to be sent. */
@ -308,7 +305,6 @@ struct qcc_app_ops;
/* Number of received bytes. */ \
uint64_t rx; \
} bytes; \
size_t max_udp_payload; \
/* First DCID used by client on its Initial packet. */ \
struct quic_cid odcid; \
/* DCID of our endpoint - not updated when a new DCID is used */ \
@ -319,7 +315,7 @@ struct qcc_app_ops;
* with a connection \
*/ \
struct eb_root *cids; \
enum obj_type *target; \
struct listener *li; /* only valid for frontend connections */ \
/* Idle timer task */ \
struct task *idle_timer_task; \
unsigned int idle_expire; \
@ -460,7 +456,6 @@ struct quic_conn_closed {
#define QUIC_FL_CONN_HPKTNS_DCD (1U << 16) /* Handshake packet number space discarded */
#define QUIC_FL_CONN_PEER_VALIDATED_ADDR (1U << 17) /* Peer address is considered as validated for this connection. */
#define QUIC_FL_CONN_NO_TOKEN_RCVD (1U << 18) /* Client dit not send any token */
#define QUIC_FL_CONN_SCID_RECEIVED (1U << 19) /* (client only: first Initial received. */
/* gap here */
#define QUIC_FL_CONN_TO_KILL (1U << 24) /* Unusable connection, to be killed */
#define QUIC_FL_CONN_TX_TP_RECEIVED (1U << 25) /* Peer transport parameters have been received (used for the transmitting part) */

View File

@ -69,8 +69,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
struct quic_connection_id *conn_id,
struct sockaddr_storage *local_addr,
struct sockaddr_storage *peer_addr,
int token, void *owner,
struct connection *conn);
int server, int token, void *owner);
int quic_build_post_handshake_frames(struct quic_conn *qc);
const struct quic_version *qc_supported_version(uint32_t version);
int quic_peer_validated_addr(struct quic_conn *qc);
@ -164,22 +163,6 @@ static inline void quic_free_ncbuf(struct ncbuf *ncbuf)
*ncbuf = NCBUF_NULL;
}
/* Return the address of the QUIC counters attached to the proxy of
* the owner of the connection whose object type address is <o> for
* listener and servers, or NULL for others object type.
*/
static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
{
struct proxy *p;
struct listener *l = objt_listener(o);
struct server *s = objt_server(o);
p = l ? l->bind_conf->frontend :
s ? s->proxy : NULL;
return p ? EXTRA_COUNTERS_GET(p->extra_counters_fe, m) : NULL;
}
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
void quic_set_tls_alert(struct quic_conn *qc, int alert);

View File

@ -26,7 +26,7 @@
#include <haproxy/quic_rx-t.h>
int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
enum obj_type *obj_type);
struct listener *li);
int qc_treat_rx_pkts(struct quic_conn *qc);
int qc_parse_hd_form(struct quic_rx_packet *pkt,
unsigned char **pos, const unsigned char *end);

View File

@ -33,7 +33,6 @@
#include <haproxy/connection-t.h>
#include <haproxy/fd-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/obj_type.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_sock-t.h>
@ -79,8 +78,7 @@ static inline char qc_test_fd(struct quic_conn *qc)
*/
static inline int qc_fd(struct quic_conn *qc)
{
/* TODO: check this: For backends, qc->fd is always initialized */
return qc_test_fd(qc) ? qc->fd : __objt_listener(qc->target)->rx.fd;
return qc_test_fd(qc) ? qc->fd : qc->li->rx.fd;
}
/* Try to increment <l> handshake current counter. If listener limit is

View File

@ -34,8 +34,7 @@
#include <haproxy/ssl_sock-t.h>
int ssl_quic_initial_ctx(struct bind_conf *bind_conf);
SSL_CTX *ssl_quic_srv_new_ssl_ctx(void);
int qc_alloc_ssl_sock_ctx(struct quic_conn *qc, struct connection *conn);
int qc_alloc_ssl_sock_ctx(struct quic_conn *qc);
int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx);
int quic_ssl_set_tls_cbs(SSL *ssl);

View File

@ -26,9 +26,6 @@ int qc_lstnr_params_init(struct quic_conn *qc,
const unsigned char *dcid, size_t dcidlen,
const unsigned char *scid, size_t scidlen,
const struct quic_cid *token_odcid);
void qc_srv_params_init(struct quic_conn *qc,
const struct quic_transport_params *srv_params,
const unsigned char *scid, size_t scidlen);
/* Dump <cid> transport parameter connection ID value if present (non null length).
* Used only for debugging purposes.

View File

@ -171,7 +171,6 @@ enum srv_init_state {
#define SRV_F_DEFSRV_USE_SSL 0x4000 /* default-server uses SSL */
#define SRV_F_DELETED 0x8000 /* srv is deleted but not yet purged */
#define SRV_F_STRICT_MAXCONN 0x10000 /* maxconn is to be strictly enforced, as a limit of outbound connections */
#define SRV_F_CHECKED 0x20000 /* set once server was postparsed */
/* configured server options for send-proxy (server->pp_opts) */
#define SRV_PP_V1 0x0001 /* proxy protocol version 1 */
@ -478,9 +477,6 @@ struct server {
char *alpn_str; /* ALPN protocol string */
int alpn_len; /* ALPN protocol string length */
} ssl_ctx;
#ifdef USE_QUIC
struct quic_transport_params quic_params; /* QUIC transport parameters */
#endif
struct resolv_srvrq *srvrq; /* Pointer representing the DNS SRV requeest, if any */
struct list srv_rec_item; /* to attach server to a srv record item */
struct list ip_rec_item; /* to attach server to a A or AAAA record item */

View File

@ -73,7 +73,7 @@ struct server *new_server(struct proxy *proxy);
void srv_take(struct server *srv);
struct server *srv_drop(struct server *srv);
void srv_free_params(struct server *srv);
int srv_init(struct server *srv);
int srv_init_per_thr(struct server *srv);
void srv_set_ssl(struct server *s, int use_ssl);
const char *srv_adm_st_chg_cause(enum srv_adm_st_chg_cause cause);
const char *srv_op_st_chg_cause(enum srv_op_st_chg_cause cause);
@ -181,16 +181,15 @@ const struct mux_ops *srv_get_ws_proto(struct server *srv);
/* increase the number of cumulated streams on the designated server */
static inline void srv_inc_sess_ctr(struct server *s)
{
_HA_ATOMIC_INC(&s->counters.shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&s->counters.shared->tg[tgid - 1]->sess_per_sec, 1);
_HA_ATOMIC_INC(&s->counters.cum_sess);
HA_ATOMIC_UPDATE_MAX(&s->counters.sps_max,
update_freq_ctr(&s->counters._sess_per_sec, 1));
update_freq_ctr(&s->counters.sess_per_sec, 1));
}
/* set the time of last session on the designated server */
static inline void srv_set_sess_last(struct server *s)
{
HA_ATOMIC_STORE(&s->counters.shared->tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
s->counters.last_sess = ns_to_sec(now_ns);
}
/* returns the current server throttle rate between 0 and 100% */
@ -320,39 +319,6 @@ static inline int srv_is_transparent(const struct server *srv)
(srv->flags & SRV_F_MAPPORTS);
}
/* Detach server from proxy list. It is supported to call this
* even if the server is not yet in the list
* Must be called under thread isolation or when it is safe to assume
* that the parent proxy doesn't is not skimming through the server list
*/
static inline void srv_detach(struct server *srv)
{
struct proxy *px = srv->proxy;
if (px->srv == srv)
px->srv = srv->next;
else {
struct server *prev;
for (prev = px->srv; prev && prev->next != srv; prev = prev->next)
;
BUG_ON(!prev);
prev->next = srv->next;
}
}
static inline int srv_is_quic(const struct server *srv)
{
#ifdef USE_QUIC
return srv->addr_type.proto_type == PROTO_TYPE_DGRAM &&
srv->addr_type.xprt_type == PROTO_TYPE_STREAM;
#else
return 0;
#endif
}
#endif /* _HAPROXY_SERVER_H */
/*

View File

@ -28,11 +28,9 @@
#include <haproxy/api.h>
#include <haproxy/connection-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/protocol-t.h>
#include <haproxy/sock-t.h>
int sock_create_server_socket(struct connection *conn, struct proxy *be,
enum proto_type proto_type, int sock_type, int *stream_err);
int sock_create_server_socket(struct connection *conn, struct proxy *be, int *stream_err);
void sock_enable(struct receiver *rx);
void sock_disable(struct receiver *rx);
void sock_unbind(struct receiver *rx);

View File

@ -62,7 +62,7 @@ struct ckch_inst *ckch_inst_new();
int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, int is_default, struct ckch_inst **ckchi, char **err);
int ckch_inst_new_load_srv_store(const char *path, struct ckch_store *ckchs,
struct ckch_inst **ckchi, char **err, int is_quic);
struct ckch_inst **ckchi, char **err);
int ckch_inst_rebuild(struct ckch_store *ckch_store, struct ckch_inst *ckchi,
struct ckch_inst **new_inst, char **err);

View File

@ -342,11 +342,6 @@ enum stat_idx_info {
ST_I_INF_MAX
};
/* Flags for stat_col.flags */
#define STAT_COL_FL_NONE 0x00
#define STAT_COL_FL_GENERIC 0x01 /* stat is generic if set */
#define STAT_COL_FL_SHARED 0x02 /* stat may be shared between co-processes if set */
/* Represent an exposed statistic. */
struct stat_col {
const char *name; /* short name, used notably in CSV headers */
@ -355,8 +350,8 @@ struct stat_col {
uint32_t type; /* combination of field_nature and field_format */
uint8_t cap; /* mask of stats_domain_px_cap to restrain metrics to an object types subset */
/* 1 byte hole */
uint16_t flags; /* STAT_COL_FL_* flags */
uint8_t generic; /* bit set if generic */
/* 2 bytes hole */
/* used only for generic metrics */
struct {

View File

@ -79,7 +79,7 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f,
/* Returns true if <col> is fully defined, false if only used as name-desc. */
static inline int stcol_is_generic(const struct stat_col *col)
{
return col->flags & STAT_COL_FL_GENERIC;
return col->generic;
}
static inline enum field_format stcol_format(const struct stat_col *col)

View File

@ -362,8 +362,8 @@ static inline void stream_choose_redispatch(struct stream *s)
s->scb->state = SC_ST_REQ;
} else {
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->retries);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->retries);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.retries);
_HA_ATOMIC_INC(&s->be->be_counters.retries);
s->scb->state = SC_ST_ASS;
}

View File

@ -33,7 +33,7 @@
#ifdef CONFIG_PRODUCT_BRANCH
#define PRODUCT_BRANCH CONFIG_PRODUCT_BRANCH
#else
#define PRODUCT_BRANCH "3.3"
#define PRODUCT_BRANCH "3.2"
#endif
#ifdef CONFIG_PRODUCT_STATUS

View File

@ -14,7 +14,7 @@ See also: doc/regression-testing.txt
* vtest compilation *
$ git clone https://github.com/vtest/VTest2
$ git clone https://github.com/vtest/VTest
$ cd VTest

View File

@ -1,5 +1,6 @@
vtest "Test for balance URI"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.3
server s1 {
rxreq

View File

@ -2,6 +2,8 @@ varnishtest "Caching rules test"
# A response will not be cached unless it has an explicit age (Cache-Control max-age of s-maxage, Expires) or a validator (Last-Modified, or ETag)
# A response will not be cached either if it has an Age header that is either invalid (should be an integer) or greater than its max age.
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "Expires support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "If-Modified-Since support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "If-None-Match support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "A successful unsafe method (POST for instance) on a cached entry must disable it."
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "Vary support"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "Check the Accept-Encoding processing implemented in the Vary mechanism"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -6,6 +6,7 @@ feature ignore_unknown_macro
# The first health-checks passed tests are checked for all these servers
# thanks to syslog messages.
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd
#REGTEST_TYPE=slow

View File

@ -1,6 +1,7 @@
varnishtest "Health-checks"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd,osx,generic
#REGTEST_TYPE=slow

View File

@ -1,6 +1,7 @@
varnishtest "Health-check test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd
#REGTEST_TYPE=slow

View File

@ -1,5 +1,6 @@
varnishtest "Health-checks: http-check send test"
#REGTEST_TYPE=slow
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
# This script tests HTTP health-checks and more particularly the "http-check

View File

@ -5,6 +5,8 @@ feature cmd "$HAPROXY_PROGRAM -cc 'feature(TPROXY)'"
# as private and should only be reused for requests of the same session.
# This is similar to the http-reuse never mode
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -1,4 +1,5 @@
varnishtest "Test the http-reuse with special connection parameters"
#REQUIRE_VERSION=2.4
#REQUIRE_OPTIONS=OPENSSL
feature ignore_unknown_macro

View File

@ -4,6 +4,8 @@ varnishtest "Test the proper interaction between http-reuse and dispatch mode"
# reused for requests of the same session
# This is similar to the http-reuse never mode
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -1,5 +1,7 @@
varnishtest "Check that the TLVs are properly validated"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
# We need one HAProxy for each test, because apparently the connection by

View File

@ -1,5 +1,7 @@
varnishtest "Test connection upgrades from TCP to HTTP"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,4 +1,5 @@
varnishtest "fix converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro

View File

@ -1,4 +1,5 @@
varnishtest "iif converter Test"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro

View File

@ -1,4 +1,5 @@
varnishtest "JSON Query converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro

View File

@ -1,4 +1,5 @@
varnishtest "mqtt converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
@ -234,4 +235,4 @@ client c3_31_1 -connect ${h1_fe1_sock} {
# Valid MQTT 3.1 CONNECT packet (id: test_sub - username: test - passwd: passwd)
sendhex "102400064d514973647003c200000008746573745f7375620004746573740006706173737764"
recv 4
} -run
} -run

View File

@ -1,5 +1,7 @@
varnishtest "url_enc converter test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,6 @@
varnishtest "Filtering test with several filters and random forwarding (via trace filter)"
#REQUIRE_VERSION=2.4
#REQUIRE_OPTION=ZLIB|SLZ
#REGTEST_TYPE=slow

View File

@ -2,7 +2,7 @@ varnishtest "HTTP request tests: H1 request target parsing"
feature ignore_unknown_macro
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.0-dev0)'"
#REQUIRE_VERSION=3.0
haproxy h1 -conf {
global

View File

@ -1,6 +1,8 @@
varnishtest "A test to be sure payload is skipped for bodyless responses"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp \

View File

@ -5,6 +5,8 @@ feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(FAST-FORWARD)'"
feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(SPLICE)'"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp \

View File

@ -0,0 +1,61 @@
varnishtest "cannot add the HTX EOM block because the buffer is full"
feature ignore_unknown_macro
#REQUIRE_VERSION_BELOW=2.4
#REGTEST_TYPE=devel
# This test checks that an HTTP message is properly processed when we failed to
# add the HTX EOM block in an HTX message during the parsing because the buffer
# is full. Some space must be released in the buffer to make it possible. This
# requires an extra pass in the H1 multiplexer. Here, we must be sure the mux is
# called while there is no more incoming data.
server s1 {
rxreq
expect req.bodylen == 15200
txresp -bodylen 15220
} -start
syslog S -level info {
recv
expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\""
} -start
haproxy h1 -conf {
global
tune.bufsize 16384
tune.maxrewrite 1024
defaults
mode http
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
backend be1
tcp-response inspect-delay 100ms
tcp-response content accept if { res.len gt 15272 }
tcp-response content reject
http-response deny if { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
server srv1 ${s1_addr}:${s1_port}
frontend fe1
option httplog
option http-buffer-request
log ${S_addr}:${S_port} local0 debug err
bind "fd@${fe1}"
http-request deny if ! { req.body_len eq 15200 } or { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
use_backend be1
} -start
haproxy h1 -cli {
send "trace h1 sink stderr; trace h1 level developer; trace h1 verbosity complete; trace h1 start now"
}
client c1 -connect ${h1_fe1_sock} {
txreq -bodylen 15200
rxresp
expect resp.status == 200
expect resp.bodylen == 15220
} -run

View File

@ -1,6 +1,7 @@
varnishtest "A test for the wait-for-body HTTP action"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=slow
server s1 {

View File

@ -8,6 +8,8 @@ varnishtest "h1/h2 support for protocol upgrade test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# http/1.1 server
server srv_h1 {
rxreq

View File

@ -12,6 +12,8 @@ varnishtest "WebSocket test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# valid websocket server
server s1 {
rxreq

View File

@ -1,4 +1,5 @@
varnishtest "Test IPv4/IPv6 except param for the forwardfor and originalto options"
#REQUIRE_VERSION=2.4
# This config tests the except parameter for the HTTP forwardfor and originalto
# options.

View File

@ -1,4 +1,5 @@
varnishtest "normalize-uri tests"
#REQUIRE_VERSION=2.4
# This reg-test tests the http-request normalize-uri action.

View File

@ -2,6 +2,8 @@ varnishtest "http-request set-timeout test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server srv_h1 -repeat 9 {
rxreq
txresp

View File

@ -1,6 +1,8 @@
varnishtest "Verify logging of relative/absolute URI path"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp -hdr "Connection: close"

View File

@ -49,7 +49,6 @@ client c1 -connect ${h1_frt_sock} -repeat 100 {
syslog Slog -wait
shell {
set +e
ss -pt | grep CLOSE-WAIT.*haproxy.*pid=${h1_pid}
exit $((!$?))
}

View File

@ -1,5 +1,6 @@
varnishtest "Lua: txn:get_priv() scope"
#REQUIRE_OPTIONS=LUA,OPENSSL
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=bug
feature ignore_unknown_macro

View File

@ -355,8 +355,8 @@ client c9 -connect ${h1_mainfe_sock} {
} -run
client c10 -connect ${h1_mainfe_sock} {
txreq -url "/converter" -hdr "User-Agent: c10" -hdr "X-Cust: foobar"
txreq -url "/converter" -hdr "X-Cust: foobar"
rxresp
expect resp.status == 200
expect resp.http.x-var == "proc.req_len=52 sess.x_cust=foobar"
expect resp.http.x-var == "proc.req_len=35 sess.x_cust=foobar"
} -run

View File

@ -1,5 +1,7 @@
varnishtest "Hash validity test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,7 @@
varnishtest "ub64dec sample fetche Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -2,6 +2,8 @@ varnishtest "Add server via cli"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp

View File

@ -5,6 +5,8 @@ varnishtest "Delete server via cli"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# static server
server s1 -repeat 3 {
rxreq

View File

@ -3,6 +3,7 @@ varnishtest "Set server ssl via CLI"
feature ignore_unknown_macro
# for "set server <srv> ssl"
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=devel
#REQUIRE_OPTIONS=OPENSSL

View File

@ -6,6 +6,7 @@ varnishtest "Delete server via cli and update certificates"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#REQUIRE_OPTIONS=OPENSSL
feature cmd "command -v socat"

View File

@ -47,7 +47,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 1"
@ -78,7 +77,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 2"
@ -109,7 +107,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 3"
@ -141,7 +138,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 4"
@ -173,7 +169,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 5"
@ -205,7 +200,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 6"
@ -238,7 +232,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 7"
@ -270,7 +263,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 8"
@ -303,7 +295,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 9"
@ -336,7 +327,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 10"
@ -369,7 +359,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 11"
@ -402,7 +391,6 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 12"

View File

@ -15,6 +15,7 @@
# This should be backported to 1.8
#REGTEST_TYPE=bug
#REQUIRE_VERSION=2.4
varnishtest "stick-tables: Test expirations when used with table_*"

View File

@ -6,6 +6,8 @@ feature ignore_unknown_macro
# do the job they are supposed to do.
# If we remove one of the "stick on" rule, this script fails.
#REQUIRE_VERSION=2.4
server s_not_used_1 {}
server s_not_used_2 {}
server s_not_used_3 {}

View File

@ -2,7 +2,7 @@
set -eux
curl -fsSL https://github.com/vtest/VTest2/archive/main.tar.gz -o VTest.tar.gz
curl -fsSL https://github.com/wlallemand/VTest/archive/refs/heads/haproxy-sd_notify.tar.gz -o VTest.tar.gz
mkdir ../vtest
tar xvf VTest.tar.gz -C ../vtest --strip-components=1
# Special flags due to: https://github.com/vtest/VTest/issues/12
@ -24,7 +24,7 @@ set -e
# temporarily detect Apple Silicon (it's using /opt/homebrew instead of /usr/local)
#
if test -f /opt/homebrew/include/pcre2.h; then
make -j${CPUS} FLAGS="-O2 -s -Wall" INCS="-I. -Isrc -Ilib -I/usr/local/include -I/opt/homebrew/include -pthread"
make -j${CPUS} FLAGS="-O2 -s -Wall" INCS="-Isrc -Ilib -I/usr/local/include -I/opt/homebrew/include -pthread"
else
make -j${CPUS} FLAGS="-O2 -s -Wall"
fi

View File

@ -52,6 +52,10 @@ _help()
#REQUIRE_SERVICE=prometheus-exporter
#REQUIRE_SERVICES=prometheus-exporter,foo
# To define a range of versions that a test can run with:
#REQUIRE_VERSION=0.0
#REQUIRE_VERSION_BELOW=99.9
Configure environment variables to set the haproxy and vtest binaries to use
setenv HAPROXY_PROGRAM /usr/local/sbin/haproxy
setenv VTEST_PROGRAM /usr/local/bin/vtest
@ -120,13 +124,15 @@ _findtests() {
set -- $(grep '^#[0-9A-Z_]*=' "$i")
IFS="$OLDIFS"
require_options="";
require_version=""; require_version_below=""; require_options="";
require_services=""; exclude_targets=""; regtest_type=""
requiredoption=""; requiredservice=""; excludedtarget="";
while [ $# -gt 0 ]; do
v="$1"; v="${v#*=}"
case "$1" in
"#REQUIRE_VERSION="*) require_version="$v" ;;
"#REQUIRE_VERSION_BELOW="*) require_version_below="$v" ;;
"#REQUIRE_OPTIONS="*) require_options="$v" ;;
"#REQUIRE_SERVICES="*) require_services="$v" ;;
"#EXCLUDE_TARGETS="*) exclude_targets="$v" ;;
@ -165,6 +171,21 @@ _findtests() {
IFS=","; set -- $require_services; IFS=$OLDIFS; require_services="$*"
IFS=","; set -- $exclude_targets; IFS=$OLDIFS; exclude_targets="$*"
if [ -n "$require_version" ]; then
if [ $(_version "$HAPROXY_VERSION") -lt $(_version "$require_version") ]; then
echo " Skip $i because option haproxy is version: $HAPROXY_VERSION"
echo " REASON: this test requires at least version: $require_version"
skiptest=1
fi
fi
if [ -n "$require_version_below" ]; then
if [ $(_version "$HAPROXY_VERSION") -ge $(_version "$require_version_below") ]; then
echo " Skip $i because option haproxy is version: $HAPROXY_VERSION"
echo " REASON: this test requires a version below: $require_version_below"
skiptest=1
fi
fi
for excludedtarget in $exclude_targets; do
if [ "$excludedtarget" = "$TARGET" ]; then
echo " Skip $i because haproxy is compiled for the excluded target $TARGET"

View File

@ -27,7 +27,6 @@
#include <haproxy/backend.h>
#include <haproxy/channel.h>
#include <haproxy/check.h>
#include <haproxy/counters.h>
#include <haproxy/frontend.h>
#include <haproxy/global.h>
#include <haproxy/hash.h>
@ -825,8 +824,8 @@ int assign_server(struct stream *s)
goto out;
}
else if (srv != prev_srv) {
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->cum_lbconn);
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->cum_lbconn);
_HA_ATOMIC_INC(&s->be->be_counters.cum_lbconn);
_HA_ATOMIC_INC(&srv->counters.cum_lbconn);
}
s->target = &srv->obj_type;
}
@ -1000,11 +999,11 @@ int assign_server_and_queue(struct stream *s)
s->txn->flags |= TX_CK_DOWN;
}
s->flags |= SF_REDISP;
_HA_ATOMIC_INC(&prev_srv->counters.shared->tg[tgid - 1]->redispatches);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->redispatches);
_HA_ATOMIC_INC(&prev_srv->counters.redispatches);
_HA_ATOMIC_INC(&s->be->be_counters.redispatches);
} else {
_HA_ATOMIC_INC(&prev_srv->counters.shared->tg[tgid - 1]->retries);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->retries);
_HA_ATOMIC_INC(&prev_srv->counters.retries);
_HA_ATOMIC_INC(&s->be->be_counters.retries);
}
}
}
@ -1992,9 +1991,7 @@ int connect_server(struct stream *s)
/* set the correct protocol on the output stream connector */
if (srv) {
struct protocol *proto = protocol_lookup(srv_conn->dst->ss_family, srv->addr_type.proto_type, srv->alt_proto);
if (conn_prepare(srv_conn, proto, srv->xprt)) {
if (conn_prepare(srv_conn, protocol_lookup(srv_conn->dst->ss_family, PROTO_TYPE_STREAM, srv->alt_proto), srv->xprt)) {
conn_free(srv_conn);
return SF_ERR_INTERNAL;
}
@ -2020,13 +2017,9 @@ int connect_server(struct stream *s)
srv_conn->ctx = s->scb;
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
/* Delay mux initialization if SSL and ALPN/NPN is set. Note
* that this is skipped in TCP mode as we only want mux-pt
* anyway.
*/
if (!srv ||
(srv->use_ssl != 1 || (!(srv->ssl_ctx.alpn_str) && !(srv->ssl_ctx.npn_str)) ||
!IS_HTX_STRM(s)))
srv->mux_proto || !IS_HTX_STRM(s)))
#endif
init_mux = 1;
@ -2091,13 +2084,13 @@ int connect_server(struct stream *s)
s->scb->flags |= SC_FL_NOLINGER;
if (s->flags & SF_SRV_REUSED) {
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->reuse);
_HA_ATOMIC_INC(&s->be->be_counters.reuse);
if (srv)
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->reuse);
_HA_ATOMIC_INC(&srv->counters.reuse);
} else {
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->connect);
_HA_ATOMIC_INC(&s->be->be_counters.connect);
if (srv)
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->connect);
_HA_ATOMIC_INC(&srv->counters.connect);
}
err = do_connect_server(s, srv_conn);
@ -2286,8 +2279,8 @@ int srv_redispatch_connect(struct stream *s)
s->conn_err_type = STRM_ET_QUEUE_ERR;
}
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&srv->counters.failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
return 1;
case SRV_STATUS_NOSRV:
@ -2296,7 +2289,7 @@ int srv_redispatch_connect(struct stream *s)
s->conn_err_type = STRM_ET_CONN_ERR;
}
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
return 1;
case SRV_STATUS_QUEUED:
@ -2325,8 +2318,8 @@ int srv_redispatch_connect(struct stream *s)
if (srv)
srv_set_sess_last(srv);
if (srv)
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&srv->counters.failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
/* release other streams waiting for this server */
if (may_dequeue_tasks(srv, s->be))
@ -2400,8 +2393,8 @@ void back_try_conn_req(struct stream *s)
if (srv)
srv_set_sess_last(srv);
if (srv)
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&srv->counters.failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
/* release other streams waiting for this server */
sess_change_server(s, NULL);
@ -2467,8 +2460,8 @@ void back_try_conn_req(struct stream *s)
pendconn_cond_unlink(s->pend_pos);
if (srv)
_HA_ATOMIC_INC(&srv->counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&srv->counters.failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
sc_abort(sc);
sc_shutdown(sc);
req->flags |= CF_WRITE_TIMEOUT;
@ -2723,8 +2716,8 @@ void back_handle_st_cer(struct stream *s)
}
if (objt_server(s->target))
_HA_ATOMIC_INC(&objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_conns);
_HA_ATOMIC_INC(&objt_server(s->target)->counters.failed_conns);
_HA_ATOMIC_INC(&s->be->be_counters.failed_conns);
sess_change_server(s, NULL);
if (may_dequeue_tasks(objt_server(s->target), s->be))
process_srv_queue(objt_server(s->target));
@ -2756,8 +2749,8 @@ void back_handle_st_cer(struct stream *s)
s->conn_err_type = STRM_ET_CONN_OTHER;
if (objt_server(s->target))
_HA_ATOMIC_INC(&objt_server(s->target)->counters.shared->tg[tgid - 1]->internal_errors);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->internal_errors);
_HA_ATOMIC_INC(&objt_server(s->target)->counters.internal_errors);
_HA_ATOMIC_INC(&s->be->be_counters.internal_errors);
sess_change_server(s, NULL);
if (may_dequeue_tasks(objt_server(s->target), s->be))
process_srv_queue(objt_server(s->target));
@ -2894,8 +2887,8 @@ void back_handle_st_rdy(struct stream *s)
*/
void set_backend_down(struct proxy *be)
{
HA_ATOMIC_STORE(&be->be_counters.shared->tg[tgid - 1]->last_change, ns_to_sec(now_ns));
_HA_ATOMIC_INC(&be->be_counters.shared->tg[tgid - 1]->down_trans);
be->be_counters.last_change = ns_to_sec(now_ns);
_HA_ATOMIC_INC(&be->be_counters.down_trans);
if (!(global.mode & MODE_STARTING)) {
ha_alert("%s '%s' has no server available!\n", proxy_type_str(be), be->id);
@ -2967,12 +2960,10 @@ no_cookie:
}
int be_downtime(struct proxy *px) {
unsigned long last_change = COUNTERS_SHARED_LAST(px->be_counters.shared->tg, last_change);
if (px->lbprm.tot_weight && last_change < ns_to_sec(now_ns)) // ignore negative time
if (px->lbprm.tot_weight && px->be_counters.last_change < ns_to_sec(now_ns)) // ignore negative time
return px->down_time;
return ns_to_sec(now_ns) - last_change + px->down_time;
return ns_to_sec(now_ns) - px->be_counters.last_change + px->down_time;
}
/*
@ -3410,7 +3401,7 @@ smp_fetch_be_sess_rate(const struct arg *args, struct sample *smp, const char *k
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = COUNTERS_SHARED_TOTAL(px->be_counters.shared->tg, sess_per_sec, read_freq_ctr);
smp->data.u.sint = read_freq_ctr(&px->be_counters.sess_per_sec);
return 1;
}
@ -3593,7 +3584,7 @@ smp_fetch_srv_sess_rate(const struct arg *args, struct sample *smp, const char *
{
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = COUNTERS_SHARED_TOTAL(args->data.srv->counters.shared->tg, sess_per_sec, read_freq_ctr);
smp->data.u.sint = read_freq_ctr(&args->data.srv->counters.sess_per_sec);
return 1;
}

View File

@ -493,7 +493,7 @@ static struct eb32_node *insert_entry(struct cache *cache, struct cache_tree *tr
if (last_clear_ts == date.tv_sec) {
/* Too many entries for this primary key, clear the
* one that was inserted. */
release_entry_locked(tree, new_entry);
release_entry_locked(tree, entry);
return NULL;
}
@ -503,7 +503,7 @@ static struct eb32_node *insert_entry(struct cache *cache, struct cache_tree *tr
* the newly inserted one. */
entry = container_of(prev, struct cache_entry, eb);
entry->last_clear_ts = date.tv_sec;
release_entry_locked(tree, new_entry);
release_entry_locked(tree, entry);
return NULL;
}
}
@ -2133,9 +2133,9 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
return ACT_RET_CONT;
if (px == strm_fe(s))
_HA_ATOMIC_INC(&px->fe_counters.shared->tg[tgid - 1]->p.http.cache_lookups);
_HA_ATOMIC_INC(&px->fe_counters.p.http.cache_lookups);
else
_HA_ATOMIC_INC(&px->be_counters.shared->tg[tgid - 1]->p.http.cache_lookups);
_HA_ATOMIC_INC(&px->be_counters.p.http.cache_lookups);
cache_tree = get_cache_tree_from_hash(cache, read_u32(s->txn->cache_hash));
@ -2222,9 +2222,9 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
should_send_notmodified_response(cache, htxbuf(&s->req.buf), res);
if (px == strm_fe(s))
_HA_ATOMIC_INC(&px->fe_counters.shared->tg[tgid - 1]->p.http.cache_hits);
_HA_ATOMIC_INC(&px->fe_counters.p.http.cache_hits);
else
_HA_ATOMIC_INC(&px->be_counters.shared->tg[tgid - 1]->p.http.cache_hits);
_HA_ATOMIC_INC(&px->be_counters.p.http.cache_hits);
return ACT_RET_CONT;
} else {
s->target = NULL;

View File

@ -49,7 +49,6 @@
#include <haproxy/check.h>
#include <haproxy/chunk.h>
#include <haproxy/clock.h>
#include <haproxy/counters.h>
#ifdef USE_CPU_AFFINITY
#include <haproxy/cpuset.h>
#include <haproxy/cpu_topo.h>
@ -2066,31 +2065,28 @@ next_line:
goto next_line;
}
if ((global.mode & MODE_DISCOVERY)) {
/* Only print empty arg warning in discovery mode to prevent double display. */
for (check_arg = 0; check_arg < arg; check_arg++) {
if (!*args[check_arg]) {
size_t newpos;
for (check_arg = 0; check_arg < arg; check_arg++) {
if (!*args[check_arg]) {
size_t newpos;
/* if an empty arg was found, its pointer should be in <errptr>, except
* for rare cases such as '\x00' etc. We need to check errptr in any case
* and if it's not set, we'll fall back to args's position in the output
* string instead (less accurate but still useful).
*/
if (!errptr) {
newpos = args[check_arg] - outline;
if (newpos >= strlen(line))
newpos = 0; // impossible to report anything, start at the beginning.
errptr = line + newpos;
}
/* sanitize input line in-place */
newpos = sanitize_for_printing(line, errptr - line, 80);
ha_warning("parsing [%s:%d]: argument number %d at position %d is empty and marks the end of the "
"argument list; all subsequent arguments will be ignored:\n %s\n %*s\n",
file, linenum, check_arg, (int)(errptr - thisline + 1), line, (int)(newpos + 1), "^");
break;
/* if an empty arg was found, its pointer should be in <errptr>, except
* for rare cases such as '\x00' etc. We need to check errptr in any case
* and if it's not set, we'll fall back to args's position in the output
* string instead (less accurate but still useful).
*/
if (!errptr) {
newpos = args[check_arg] - outline;
if (newpos >= strlen(line))
newpos = 0; // impossible to report anything, start at the beginning.
errptr = line + newpos;
}
/* sanitize input line in-place */
newpos = sanitize_for_printing(line, errptr - line, 80);
ha_warning("parsing [%s:%d]: argument number %d at position %d is empty and marks the end of the "
"argument list; all subsequent arguments will be ignored:\n %s\n %*s\n",
file, linenum, check_arg + 1, (int)(errptr - thisline + 1), line, (int)(newpos+1), "^");
break;
}
}
@ -2821,13 +2817,28 @@ int check_config_validity()
/*
* we must finish to initialize certain things on the servers,
* as some of the fields may be accessed soon
* as some of the per_thr/per_tgrp fields may be accessed soon
*/
MT_LIST_FOR_EACH_ENTRY_LOCKED(newsrv, &servers_list, global_list, back) {
if (srv_init(newsrv) & ERR_CODE) {
if (srv_init_per_thr(newsrv) == -1) {
ha_alert("parsing [%s:%d] : failed to allocate per-thread lists for server '%s'.\n",
newsrv->conf.file, newsrv->conf.line, newsrv->id);
cfgerr++;
continue;
}
/* initialize idle conns lists */
if (newsrv->max_idle_conns != 0) {
newsrv->curr_idle_thr = calloc(global.nbthread, sizeof(*newsrv->curr_idle_thr));
if (!newsrv->curr_idle_thr) {
ha_alert("parsing [%s:%d] : failed to allocate idle connection tasks for server '%s'.\n",
newsrv->conf.file, newsrv->conf.line, newsrv->id);
cfgerr++;
continue;
}
}
}
/* starting to initialize the main proxies list */
@ -3767,8 +3778,6 @@ out_uri_auth_compat:
((newsrv->flags & SRV_F_DEFSRV_USE_SSL) && newsrv->use_ssl != 1)) {
if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv)
cfgerr += xprt_get(XPRT_SSL)->prepare_srv(newsrv);
else if (xprt_get(XPRT_QUIC) && xprt_get(XPRT_QUIC)->prepare_srv)
cfgerr += xprt_get(XPRT_QUIC)->prepare_srv(newsrv);
}
if ((newsrv->flags & SRV_F_FASTOPEN) &&
@ -4115,13 +4124,6 @@ out_uri_auth_compat:
int mode = conn_pr_mode_to_proto_mode(curproxy->mode);
const struct mux_proto_list *mux_ent;
if (srv_is_quic(newsrv)) {
if (!newsrv->mux_proto) {
/* Force QUIC as mux-proto on server with quic addresses, similarly to bind on FE side. */
newsrv->mux_proto = get_mux_proto(ist("quic"));
}
}
if (!newsrv->mux_proto)
continue;
@ -4271,15 +4273,6 @@ init_proxies_list_stage2:
/* enable separate counters */
if (curproxy->options2 & PR_O2_SOCKSTAT) {
listener->counters = calloc(1, sizeof(*listener->counters));
if (listener->counters) {
listener->counters->shared = counters_fe_shared_get(&listener->guid);
if (!listener->counters->shared) {
ha_free(&listener->counters);
ha_alert("config: %s '%s': out of memory.\n",
proxy_type_str(curproxy), curproxy->id);
}
}
if (!listener->name)
memprintf(&listener->name, "sock-%d", listener->luid);
}

View File

@ -34,7 +34,6 @@
#include <haproxy/cfgparse.h>
#include <haproxy/check.h>
#include <haproxy/chunk.h>
#include <haproxy/counters.h>
#include <haproxy/dgram.h>
#include <haproxy/dynbuf.h>
#include <haproxy/extcheck.h>
@ -195,11 +194,10 @@ static void check_trace(enum trace_level level, uint64_t mask,
((check->type == PR_O2_EXT_CHK) ? 'E' : (check->state & CHK_ST_AGENT ? 'A' : 'H')),
srv->id);
chunk_appendf(&trace_buf, " status=%d/%d %s exp=%d",
chunk_appendf(&trace_buf, " status=%d/%d %s",
(check->health >= check->rise) ? check->health - check->rise + 1 : check->health,
(check->health >= check->rise) ? check->fall : check->rise,
(check->health >= check->rise) ? (srv->uweight ? "UP" : "DRAIN") : "DOWN",
(check->task->expire ? TICKS_TO_MS(check->task->expire - now_ms) : 0));
(check->health >= check->rise) ? (srv->uweight ? "UP" : "DRAIN") : "DOWN");
}
else
chunk_appendf(&trace_buf, " : [EMAIL]");
@ -516,7 +514,7 @@ void set_server_check_status(struct check *check, short status, const char *desc
if ((!(check->state & CHK_ST_AGENT) ||
(check->status >= HCHK_STATUS_L57DATA)) &&
(check->health > 0)) {
_HA_ATOMIC_INC(&s->counters.shared->tg[tgid - 1]->failed_checks);
_HA_ATOMIC_INC(&s->counters.failed_checks);
report = 1;
check->health--;
if (check->health < check->rise)
@ -744,7 +742,7 @@ void __health_adjust(struct server *s, short status)
HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
HA_ATOMIC_STORE(&s->consecutive_errors, 0);
_HA_ATOMIC_INC(&s->counters.shared->tg[tgid - 1]->failed_hana);
_HA_ATOMIC_INC(&s->counters.failed_hana);
if (s->check.fastinter) {
/* timer might need to be advanced, it might also already be
@ -996,7 +994,6 @@ int httpchk_build_status_header(struct server *s, struct buffer *buf)
"UP %d/%d", "UP",
"NOLB %d/%d", "NOLB",
"no check" };
unsigned long last_change = COUNTERS_SHARED_LAST(s->counters.shared->tg, last_change);
if (!(s->check.state & CHK_ST_ENABLED))
sv_state = 6;
@ -1034,9 +1031,9 @@ int httpchk_build_status_header(struct server *s, struct buffer *buf)
s->queueslength);
if ((s->cur_state == SRV_ST_STARTING) &&
ns_to_sec(now_ns) < last_change + s->slowstart &&
ns_to_sec(now_ns) >= last_change) {
ratio = MAX(1, 100 * (ns_to_sec(now_ns) - last_change) / s->slowstart);
ns_to_sec(now_ns) < s->counters.last_change + s->slowstart &&
ns_to_sec(now_ns) >= s->counters.last_change) {
ratio = MAX(1, 100 * (ns_to_sec(now_ns) - s->counters.last_change) / s->slowstart);
chunk_appendf(buf, "; throttle=%d%%", ratio);
}
@ -1091,11 +1088,6 @@ int wake_srv_chk(struct stconn *sc)
ret = -1;
task_wakeup(check->task, TASK_WOKEN_IO);
}
else {
/* Check in progress. Queue it to eventually handle timeout
* update */
task_queue(check->task);
}
if (check->server)
HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);

View File

@ -987,18 +987,12 @@ int cli_parse_cmdline(struct appctx *appctx)
continue;
}
if (!len)
goto process_cmdline;
/* The end of the command line was reached. Change the trailing \r, if any,
* by a null byte. For the command line, the trailing \r and \n are removed,
* but we conserve them for payload mode.
*/
if (str[len-1] == '\r') {
if (str[len-1] == '\r')
str[--len] = '\0';
if (!len)
goto process_cmdline;
}
/*
* Look for the "payload start" pattern at the end of a
@ -1061,7 +1055,6 @@ int cli_parse_cmdline(struct appctx *appctx)
}
}
process_cmdline:
if (!(appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)) {
appctx->st0 = CLI_ST_PROCESS_CMDLINE;
break;
@ -1423,8 +1416,7 @@ static int cli_io_handler_show_fd(struct appctx *appctx)
#if defined(USE_QUIC)
else if (fdt.iocb == quic_conn_sock_fd_iocb) {
qc = fdtab[fd].owner;
li = qc ? objt_listener(qc->target) : NULL;
sv = qc ? objt_server(qc->target) : NULL;
li = qc ? qc->li : NULL;
xprt_ctx = qc ? qc->xprt_ctx : NULL;
conn = qc ? qc->conn : NULL;
xprt = conn ? conn->xprt : NULL; // in fact it's &ssl_quic
@ -3690,6 +3682,8 @@ int mworker_cli_attach_server(char **errmsg)
else
memprintf(&msg, "old-%d", child->pid);
newsrv->next = mworker_proxy->srv;
mworker_proxy->srv = newsrv;
newsrv->conf.file = strdup(msg);
newsrv->id = strdup(msg);
newsrv->conf.line = 0;

View File

@ -1,100 +0,0 @@
/*
* objects counters management
*
* Copyright 2025 HAProxy Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <haproxy/atomic.h>
#include <haproxy/clock.h>
#include <haproxy/counters.h>
#include <haproxy/global.h>
#include <haproxy/time.h>
static void _counters_shared_drop(void *counters)
{
struct counters_shared *shared = counters;
int it = 0;
if (!shared)
return;
/* memory was allocated using calloc(), simply free it */
while (it < global.nbtgroups) {
free(shared->tg[it]);
it += 1;
}
free(counters);
}
/* release a shared fe counters struct */
void counters_fe_shared_drop(struct fe_counters_shared *counters)
{
_counters_shared_drop(counters);
}
/* release a shared be counters struct */
void counters_be_shared_drop(struct be_counters_shared *counters)
{
_counters_shared_drop(counters);
}
/* retrieved shared counters pointer for a given <guid> object
* <size> hint is expected to reflect the actual tg member size (fe/be)
* if <guid> is not set, then sharing is disabled
* Returns the pointer on success or NULL on failure
*/
static void*_counters_shared_get(const struct guid_node *guid, size_t size)
{
struct counters_shared *shared;
uint last_change;
int it = 0;
/* no shared memory for now, simply allocate a memory block
* for the counters (zero-initialized), ignore guid
*/
shared = calloc(1, sizeof(*shared));
if (!shared)
return NULL;
if (!guid->node.key)
shared->flags |= COUNTERS_SHARED_F_LOCAL;
while (it < global.nbtgroups) {
shared->tg[it] = calloc(1, size);
if (!shared->tg[it]) {
_counters_shared_drop(shared);
return NULL;
}
it += 1;
}
last_change = ns_to_sec(now_ns);
/* only set one group, only latest value is considered */
HA_ATOMIC_STORE(&shared->tg[0]->last_change, last_change);
return shared;
}
/* retrieve shared fe counters pointer for a given <guid> object */
struct fe_counters_shared *counters_fe_shared_get(const struct guid_node *guid)
{
return _counters_shared_get(guid, sizeof(struct fe_counters_shared_tg));
}
/* retrieve shared be counters pointer for a given <guid> object */
struct be_counters_shared *counters_be_shared_get(const struct guid_node *guid)
{
return _counters_shared_get(guid, sizeof(struct be_counters_shared_tg));
}

View File

@ -446,12 +446,12 @@ static int fcgi_flt_http_headers(struct stream *s, struct filter *filter, struct
goto end;
rewrite_err:
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
hdr_rule_err:
node = ebpt_first(&hdr_rules);
while (node) {

View File

@ -393,14 +393,14 @@ comp_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
if (st->comp_ctx[dir] && st->comp_ctx[dir]->cur_lvl > 0) {
update_freq_ctr(&global.comp_bps_in, consumed);
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.shared->tg[tgid - 1]->comp_in[dir], consumed);
_HA_ATOMIC_ADD(&s->be->be_counters.shared->tg[tgid - 1]->comp_in[dir], consumed);
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.comp_in[dir], consumed);
_HA_ATOMIC_ADD(&s->be->be_counters.comp_in[dir], consumed);
update_freq_ctr(&global.comp_bps_out, to_forward);
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.shared->tg[tgid - 1]->comp_out[dir], to_forward);
_HA_ATOMIC_ADD(&s->be->be_counters.shared->tg[tgid - 1]->comp_out[dir], to_forward);
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.comp_out[dir], to_forward);
_HA_ATOMIC_ADD(&s->be->be_counters.comp_out[dir], to_forward);
} else {
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.shared->tg[tgid - 1]->comp_byp[dir], consumed);
_HA_ATOMIC_ADD(&s->be->be_counters.shared->tg[tgid - 1]->comp_byp[dir], consumed);
_HA_ATOMIC_ADD(&strm_fe(s)->fe_counters.comp_byp[dir], consumed);
_HA_ATOMIC_ADD(&s->be->be_counters.comp_byp[dir], consumed);
}
return to_forward;
@ -419,9 +419,9 @@ comp_http_end(struct stream *s, struct filter *filter,
goto end;
if (strm_fe(s)->mode == PR_MODE_HTTP)
_HA_ATOMIC_INC(&strm_fe(s)->fe_counters.shared->tg[tgid - 1]->p.http.comp_rsp);
_HA_ATOMIC_INC(&strm_fe(s)->fe_counters.p.http.comp_rsp);
if ((s->flags & SF_BE_ASSIGNED) && (s->be->mode == PR_MODE_HTTP))
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->p.http.comp_rsp);
_HA_ATOMIC_INC(&s->be->be_counters.p.http.comp_rsp);
end:
return 1;
}

View File

@ -26,7 +26,6 @@
#include <haproxy/arg.h>
#include <haproxy/chunk.h>
#include <haproxy/connection.h>
#include <haproxy/counters.h>
#include <haproxy/fd.h>
#include <haproxy/frontend.h>
#include <haproxy/global.h>
@ -261,7 +260,7 @@ smp_fetch_fe_req_rate(const struct arg *args, struct sample *smp, const char *kw
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = COUNTERS_SHARED_TOTAL(px->fe_counters.shared->tg, req_per_sec, read_freq_ctr);
smp->data.u.sint = read_freq_ctr(&px->fe_counters.req_per_sec);
return 1;
}
@ -281,7 +280,7 @@ smp_fetch_fe_sess_rate(const struct arg *args, struct sample *smp, const char *k
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = COUNTERS_SHARED_TOTAL(px->fe_counters.shared->tg, sess_per_sec, read_freq_ctr);
smp->data.u.sint = read_freq_ctr(&px->fe_counters.sess_per_sec);
return 1;
}

View File

@ -36,7 +36,6 @@
#include <haproxy/qmux_http.h>
#include <haproxy/qpack-dec.h>
#include <haproxy/qpack-enc.h>
#include <haproxy/quic_conn.h>
#include <haproxy/quic_enc.h>
#include <haproxy/quic_fctl.h>
#include <haproxy/quic_frame.h>
@ -680,12 +679,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
goto out;
}
flags |= HTX_SL_F_HAS_SCHM;
if (isteqi(list[hdr_idx].v, ist("http")))
flags |= HTX_SL_F_SCHM_HTTP;
else if (isteqi(list[hdr_idx].v, ist("https")))
flags |= HTX_SL_F_SCHM_HTTPS;
else if (!http_validate_scheme(list[hdr_idx].v)) {
if (!http_validate_scheme(list[hdr_idx].v)) {
TRACE_ERROR("invalid scheme pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
h3s->err = H3_ERR_MESSAGE_ERROR;
qcc_report_glitch(h3c->qcc, 1);
@ -778,7 +772,6 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
if (!istlen(scheme)) {
/* No scheme (CONNECT), use :authority only. */
uri = authority;
flags |= HTX_SL_F_HAS_AUTHORITY;
}
else if (isttest(authority)) {
/* Use absolute URI form as :authority is present. */
@ -787,20 +780,6 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
istcat(&uri, authority, trash.size);
if (!isteq(path, ist("*")))
istcat(&uri, path, trash.size);
flags |= HTX_SL_F_HAS_AUTHORITY;
if (flags & (HTX_SL_F_SCHM_HTTP|HTX_SL_F_SCHM_HTTPS)) {
/* we don't know if it was originally an absolute or a
* relative request because newer versions of HTTP use
* the absolute URI format by default, which we call
* the normalized URI format internally. This is the
* strongly recommended way of sending a request for
* a regular client, so we cannot distinguish this
* from a request intended for a proxy. For other
* schemes however there is no doubt.
*/
flags |= HTX_SL_F_NORMALIZED_URI;
}
}
else {
/* Use origin URI form. */
@ -1385,13 +1364,9 @@ static ssize_t h3_parse_settings_frm(struct h3c *h3c, const struct buffer *buf,
/* Transcode HTTP/3 payload received in buffer <b> to HTX data for stream
* <qcs>. If <fin> is set, it indicates that no more data will arrive after.
*
* It may be necessary to call this function with an empty input buffer to
* signal a standalone FIN.
*
* Returns the amount of decoded bytes from <b> or a negative error code. A
* null value can be returned even if input buffer is not empty, meaning that
* transcoding cannot be performed due to partial HTTP/3 content. Receive
* operation may be called later with newer data available.
* Returns the count of consumed bytes or a negative error code. If 0 is
* returned, stream data is incomplete, decoding should be call again later
* with more content.
*/
static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
{
@ -1691,13 +1666,6 @@ static int h3_encode_header(struct buffer *buf,
return qpack_encode_header(buf, n, v_strip);
}
/* Convert a HTX status-line and associated headers stored into <htx> into a
* HTTP/3 HEADERS response frame. HTX blocks are removed up to end-of-trailer
* included.
*
* Returns the amount of consumed bytes from <htx> buffer or a negative error
* code.
*/
static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
{
int err;
@ -1852,15 +1820,15 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
}
/* Convert a series of HTX trailer blocks from <htx> buffer into <qcs> buffer
* as a HTTP/3 HEADERS frame. Forbidden trailers are skipped. HTX trailer
* blocks are removed from <htx> up to end-of-trailer included.
* as a H3 HEADERS frame. H3 forbidden trailers are skipped. HTX trailer blocks
* are removed from <htx> until EOT is found and itself removed.
*
* If only a EOT HTX block is present without trailer, no H3 frame is produced.
* Caller is responsible to emit an empty QUIC STREAM frame to signal the end
* of the stream.
*
* Returns the amount of consumed bytes from <htx> buffer or a negative error
* code.
* Returns the size of HTX blocks removed. A negative error code is returned in
* case of a fatal error which should caused a connection closure.
*/
static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
{
@ -2032,9 +2000,9 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
* underlying HTX area via <buf> as this will be used if zero-copy can be
* performed.
*
* Returns the amount of consumed bytes from <htx> buffer, which corresponds to
* the length sum of encoded frames payload. A negative error code is returned
* in case of a fatal error which should caused a connection closure.
* Returns the total bytes of encoded HTTP/3 payload. This corresponds to the
* total bytes of HTX block removed. A negative error code is returned in case
* of a fatal error which should caused a connection closure.
*/
static int h3_resp_data_send(struct qcs *qcs, struct htx *htx,
struct buffer *buf, size_t count)
@ -2159,14 +2127,6 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx,
return -1;
}
/* Transcode HTX data from <buf> of length <count> into HTTP/3 frame for <qcs>
* stream instance. Successfully transcoded HTX blocks are removed from input
* buffer.
*
* Returns the amount of consumed bytes from <buf>. In case of error,
* connection is flagged and transcoding is interrupted. The returned value is
* unchanged though.
*/
static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count)
{
size_t total = 0;
@ -2533,6 +2493,7 @@ static int h3_send_goaway(struct h3c *h3c)
static int h3_init(struct qcc *qcc)
{
struct h3c *h3c;
const struct listener *li = __objt_listener(qcc->conn->target);
TRACE_ENTER(H3_EV_H3C_NEW, qcc->conn);
@ -2549,7 +2510,9 @@ static int h3_init(struct qcc *qcc)
h3c->id_goaway = 0;
qcc->ctx = h3c;
h3c->prx_counters = qc_counters(qcc->conn->target, &h3_stats_module);
h3c->prx_counters =
EXTRA_COUNTERS_GET(li->bind_conf->frontend->extra_counters_fe,
&h3_stats_module);
LIST_INIT(&h3c->buf_wait.list);
TRACE_LEAVE(H3_EV_H3C_NEW, qcc->conn);

View File

@ -75,7 +75,6 @@
#include <haproxy/cli.h>
#include <haproxy/clock.h>
#include <haproxy/connection.h>
#include <haproxy/counters.h>
#ifdef USE_CPU_AFFINITY
#include <haproxy/cpuset.h>
#include <haproxy/cpu_topo.h>
@ -816,10 +815,10 @@ static void sig_dump_state(struct sig_handler *sh)
send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
while (s) {
chunk_printf(&trash,
"SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %llu tot.",
"SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
p->id, s->id,
(s->cur_state != SRV_ST_STOPPED) ? "UP" : "DOWN",
s->cur_sess, s->queueslength, (ullong)COUNTERS_SHARED_TOTAL(s->counters.shared->tg, cum_sess, HA_ATOMIC_LOAD));
s->cur_sess, s->queueslength, s->counters.cum_sess);
ha_warning("%s\n", trash.area);
send_log(p, LOG_NOTICE, "%s\n", trash.area);
s = s->next;
@ -828,21 +827,21 @@ static void sig_dump_state(struct sig_handler *sh)
/* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
if (!p->srv) {
chunk_printf(&trash,
"SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %llu+%llu.",
"SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id,
p->feconn, p->beconn, p->totpend, p->queueslength, (ullong)COUNTERS_SHARED_TOTAL(p->fe_counters.shared->tg, cum_conn, HA_ATOMIC_LOAD), (ullong)COUNTERS_SHARED_TOTAL(p->be_counters.shared->tg, cum_sess, HA_ATOMIC_LOAD));
p->feconn, p->beconn, p->totpend, p->queueslength, p->fe_counters.cum_conn, p->be_counters.cum_sess);
} else if (p->srv_act == 0) {
chunk_printf(&trash,
"SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %llu+%llu.",
"SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id,
(p->srv_bck) ? "is running on backup servers" : "has no server available",
p->feconn, p->beconn, p->totpend, p->queueslength, (ullong)COUNTERS_SHARED_TOTAL(p->fe_counters.shared->tg, cum_conn, HA_ATOMIC_LOAD), (ullong)COUNTERS_SHARED_TOTAL(p->be_counters.shared->tg, cum_sess, HA_ATOMIC_LOAD));
p->feconn, p->beconn, p->totpend, p->queueslength, p->fe_counters.cum_conn, p->be_counters.cum_sess);
} else {
chunk_printf(&trash,
"SIGHUP: Proxy %s has %d active servers and %d backup servers available."
" Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %llu+%llu.",
" Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id, p->srv_act, p->srv_bck,
p->feconn, p->beconn, p->totpend, p->queueslength, (ullong)COUNTERS_SHARED_TOTAL(p->fe_counters.shared->tg, cum_conn, HA_ATOMIC_LOAD), (ullong)COUNTERS_SHARED_TOTAL(p->be_counters.shared->tg, cum_sess, HA_ATOMIC_LOAD));
p->feconn, p->beconn, p->totpend, p->queueslength, p->fe_counters.cum_conn, p->be_counters.cum_sess);
}
ha_warning("%s\n", trash.area);
send_log(p, LOG_NOTICE, "%s\n", trash.area);
@ -2102,7 +2101,7 @@ static void step_init_2(int argc, char** argv)
clock_adjust_now_offset();
ready_date = date;
list_for_each_entry(px, &proxies, global_list) {
for (px = proxies_list; px; px = px->next) {
struct server *srv;
struct post_proxy_check_fct *ppcf;
struct post_server_check_fct *pscf;

View File

@ -5299,20 +5299,20 @@ __LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
{
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
struct stconn *sc = appctx_sc(luactx->appctx);
int ret;
const char *blk1 = NULL;
size_t len1 = 0;
const char *blk2 = NULL;
size_t len2 = 0;
const char *blk1;
size_t len1;
const char *blk2;
size_t len2;
/* Read the maximum amount of data available. */
ret = applet_getline_nc(luactx->appctx, &blk1, &len1, &blk2, &len2);
ret = co_getline_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
/* Data not yet available. return yield. */
if (ret == 0) {
applet_need_more_data(luactx->appctx);
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
return 0;
}
/* End of data: commit the total strings and return. */
@ -5327,10 +5327,10 @@ __LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KC
/* don't check the max length read and don't check. */
luaL_addlstring(&luactx->b, blk1, len1);
if (len2)
luaL_addlstring(&luactx->b, blk2, len2);
luaL_addlstring(&luactx->b, blk2, len2);
applet_skip_input(luactx->appctx, len1+len2);
/* Consume input channel output buffer data. */
co_skip(sc_oc(sc), len1 + len2);
luaL_pushresult(&luactx->b);
return 1;
}
@ -5352,22 +5352,26 @@ __LJMP static int hlua_applet_tcp_getline(lua_State *L)
__LJMP static int hlua_applet_tcp_recv_try(lua_State *L)
{
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
struct stconn *sc = appctx_sc(luactx->appctx);
size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
int exp_date = MAY_LJMP(luaL_checkinteger(L, 3));
int ret;
const char *blk1 = NULL;
size_t len1 = 0;
const char *blk2 = NULL;
size_t len2 = 0;
const char *blk1;
size_t len1;
const char *blk2;
size_t len2;
/* Read the maximum amount of data available. */
ret = applet_getblk_nc(luactx->appctx, &blk1, &len1, &blk2, &len2);
if (luactx->appctx->flags & APPCTX_FL_INOUT_BUFS)
ret = b_getblk_nc(&luactx->appctx->inbuf, &blk1, &len1, &blk2, &len2, 0, b_data(&luactx->appctx->inbuf));
else
ret = co_getblk_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
/* Data not yet available. return yield. */
if (ret == 0) {
if (tick_is_expired(exp_date, now_ms)) {
/* return the result. */
lua_pushnil(L);
luaL_pushresult(&luactx->b);
return 1;
}
@ -5392,9 +5396,11 @@ __LJMP static int hlua_applet_tcp_recv_try(lua_State *L)
* the end of data stream.
*/
luaL_addlstring(&luactx->b, blk1, len1);
if (len2)
luaL_addlstring(&luactx->b, blk2, len2);
applet_skip_input(luactx->appctx, len1+len2);
luaL_addlstring(&luactx->b, blk2, len2);
if (luactx->appctx->flags & APPCTX_FL_INOUT_BUFS)
b_del(&luactx->appctx->inbuf, len1 + len2);
else
co_skip(sc_oc(sc), len1 + len2);
if (tick_is_expired(exp_date, now_ms)) {
/* return the result. */
@ -5414,14 +5420,15 @@ __LJMP static int hlua_applet_tcp_recv_try(lua_State *L)
len -= len1;
/* Copy the second block. */
if (len2) {
if (len2 > len)
len2 = len;
luaL_addlstring(&luactx->b, blk2, len2);
len -= len2;
}
if (len2 > len)
len2 = len;
luaL_addlstring(&luactx->b, blk2, len2);
len -= len2;
applet_skip_input(luactx->appctx, len1+len2);
if (luactx->appctx->flags & APPCTX_FL_INOUT_BUFS)
b_del(&luactx->appctx->inbuf, len1 + len2);
else
co_skip(sc_oc(sc), len1 + len2);
/* If there is no other data available, yield waiting for new data. */
if (len > 0 && !tick_is_expired(exp_date, now_ms)) {
@ -5504,7 +5511,7 @@ __LJMP static int hlua_applet_tcp_try_recv(lua_State *L)
lua_pushinteger(L, -1);
/* set the expiration date (mandatory arg but not relevant here) */
lua_pushinteger(L, now_ms);
lua_pushinteger(L, TICK_ETERNITY);
/* Initialise the string catenation. */
luaL_buffinit(L, &luactx->b);
@ -5530,10 +5537,15 @@ __LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KCont
struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
int l = MAY_LJMP(luaL_checkinteger(L, 3));
struct stconn *sc = appctx_sc(luactx->appctx);
struct channel *chn = sc_ic(sc);
int max;
/* Get the max amount of data which can be written */
max = applet_output_room(luactx->appctx);
if (luactx->appctx->flags & APPCTX_FL_INOUT_BUFS)
max = b_room(&luactx->appctx->outbuf);
else
max = channel_recv_max(chn);
if (max > (len - l))
max = len - l;
@ -5550,7 +5562,10 @@ __LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KCont
* applet, and returns a yield.
*/
if (l < len) {
applet_need_room(luactx->appctx, applet_output_room(luactx->appctx) + 1);
if (luactx->appctx->flags & APPCTX_FL_INOUT_BUFS)
applet_have_more_data(luactx->appctx);
else
sc_need_room(sc, channel_recv_max(chn) + 1);
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
}
@ -8277,12 +8292,6 @@ __LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
hlua_hc = hlua_checkhttpclient(L, 1);
/* An HTTPclient instance must never process more that one request. So
* at this stage, it must never have been started.
*/
if (httpclient_started(hlua_hc->hc))
WILL_LJMP(luaL_error(L, "httpclient instance cannot be reused. It must process at most one request"));
lua_pushnil(L); /* first key */
while (lua_next(L, 2)) {
if (strcmp(lua_tostring(L, -2), "dst") == 0) {
@ -9021,7 +9030,7 @@ __LJMP static int hlua_txn_done(lua_State *L)
/* let's log the request time */
s->logs.request_ts = now_ns;
if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.shared->tg[tgid - 1]->intercepted_req);
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
}
done:
@ -11212,7 +11221,10 @@ out:
if (yield)
return;
applet_reset_input(ctx);
if (ctx->flags & APPCTX_FL_INOUT_BUFS)
b_reset(&ctx->inbuf);
else
co_skip(sc_oc(sc), co_data(sc_oc(sc)));
return;
error:
@ -14690,6 +14702,12 @@ static void hlua_deinit()
lua_close(hlua_states[thr]);
}
srv_drop(socket_tcp);
#ifdef USE_OPENSSL
srv_drop(socket_ssl);
#endif
free_proxy(socket_proxy);
}

View File

@ -6,15 +6,13 @@
#include <haproxy/dynbuf.h>
#include <haproxy/htx.h>
#include <haproxy/http.h>
#include <haproxy/istbuf.h>
#include <haproxy/mux_quic.h>
#include <haproxy/qmux_http.h>
#include <haproxy/qmux_trace.h>
#include <haproxy/quic_utils.h>
#include <haproxy/trace.h>
/* HTTP/0.9 request -> HTX. */
static ssize_t hq_interop_rcv_buf_req(struct qcs *qcs, struct buffer *b, int fin)
static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
{
struct htx *htx;
struct htx_sl *sl;
@ -94,74 +92,12 @@ static ssize_t hq_interop_rcv_buf_req(struct qcs *qcs, struct buffer *b, int fin
return b_data(b);
}
/* HTTP/0.9 response -> HTX. */
static ssize_t hq_interop_rcv_buf_res(struct qcs *qcs, struct buffer *b, int fin)
{
ssize_t ret = 0;
struct htx *htx;
struct htx_sl *sl;
struct buffer *htx_buf;
const struct stream *strm = __sc_strm(qcs->sd->sc);
const unsigned int flags = HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN;
size_t htx_sent;
htx_buf = qcc_get_stream_rxbuf(qcs);
BUG_ON(!htx_buf);
htx = htx_from_buf(htx_buf);
if (htx_is_empty(htx) && !strm->res.total) {
/* First data transfer, add HTX response start-line first. */
sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags,
ist("HTTP/1.0"), ist("200"), ist(""));
BUG_ON(!sl);
if (fin && !b_data(b))
sl->flags |= HTX_SL_F_BODYLESS;
htx_add_endof(htx, HTX_BLK_EOH);
}
if (!b_data(b)) {
if (fin && quic_stream_is_bidi(qcs->id)) {
if (qcs_http_handle_standalone_fin(qcs)) {
htx_to_buf(htx, htx_buf);
return -1;
}
}
}
else {
BUG_ON(b_data(b) > htx_free_data_space(htx)); /* TODO */
BUG_ON(b_head(b) + b_data(b) > b_wrap(b)); /* TODO */
htx_sent = htx_add_data(htx, ist2(b_head(b), b_data(b)));
BUG_ON(htx_sent < b_data(b)); /* TODO */
ret = htx_sent;
if (fin && b_data(b) == htx_sent)
htx->flags |= HTX_FL_EOM;
}
htx_to_buf(htx, htx_buf);
return ret;
}
/* Returns the amount of decoded bytes from <b> or a negative error code. */
static ssize_t hq_interop_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
{
/* hq-interop parser does not support buffer wrapping. */
BUG_ON(b_data(b) != b_contig_data(b, 0));
return !(qcs->qcc->flags & QC_CF_IS_BACK) ?
hq_interop_rcv_buf_req(qcs, b, fin) :
hq_interop_rcv_buf_res(qcs, b, fin);
}
/* Returns the amount of consumed bytes from <buf>. */
static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf,
size_t count)
{
enum htx_blk_type btype;
struct htx *htx = NULL;
struct htx_blk *blk;
struct htx_sl *sl = NULL;
int32_t idx;
uint32_t bsize, fsize;
struct buffer *res = NULL;
@ -177,25 +113,9 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf,
btype = htx_get_blk_type(blk);
fsize = bsize = htx_get_blksz(blk);
BUG_ON(btype == HTX_BLK_REQ_SL);
switch (btype) {
case HTX_BLK_REQ_SL:
res = qcc_get_stream_txbuf(qcs, &err, 0);
if (!res) {
BUG_ON(err); /* TODO */
goto end;
}
BUG_ON_HOT(sl); /* Only one start-line expected */
sl = htx_get_blk_ptr(htx, blk);
/* Only GET supported for HTTP/0.9. */
b_putist(res, ist("GET "));
b_putist(res, htx_sl_req_uri(sl));
b_putist(res, ist(" HTTP/0.9\r\n"));
htx_remove_blk(htx, blk);
total += fsize;
break;
case HTX_BLK_DATA:
res = qcc_get_stream_txbuf(qcs, &err, 0);
if (!res) {

View File

@ -116,13 +116,13 @@ static enum act_return http_action_set_req_line(struct act_rule *rule, struct pr
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
@ -386,13 +386,13 @@ static enum act_return http_action_normalize_uri(struct act_rule *rule, struct p
goto leave;
fail_rewrite:
_HA_ATOMIC_ADD(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites, 1);
_HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_ADD(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites, 1);
_HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_ADD(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites, 1);
_HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
if (objt_server(s->target))
_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites, 1);
_HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
@ -562,13 +562,13 @@ static enum act_return http_action_replace_uri(struct act_rule *rule, struct pro
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
@ -642,13 +642,13 @@ static enum act_return action_http_set_status(struct act_rule *rule, struct prox
struct session *sess, struct stream *s, int flags)
{
if (http_res_set_status(rule->arg.http.i, rule->arg.http.str, s) == -1) {
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW)) {
if (!(s->flags & SF_ERR_MASK))
@ -717,10 +717,10 @@ static enum act_return http_action_reject(struct act_rule *rule, struct proxy *p
s->req.analysers &= AN_REQ_FLT_END;
s->res.analysers &= AN_RES_FLT_END;
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->denied_req);
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->denied_req);
_HA_ATOMIC_INC(&s->be->be_counters.denied_req);
_HA_ATOMIC_INC(&sess->fe->fe_counters.denied_req);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->denied_req);
_HA_ATOMIC_INC(&sess->listener->counters->denied_req);
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
@ -1281,7 +1281,7 @@ static enum act_return http_action_auth(struct act_rule *rule, struct proxy *px,
req->analysers &= AN_REQ_FLT_END;
if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.shared->tg[tgid - 1]->intercepted_req);
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL;
@ -1449,13 +1449,13 @@ static enum act_return http_action_set_header(struct act_rule *rule, struct prox
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(msg->flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
@ -1581,13 +1581,13 @@ static enum act_return http_action_replace_header(struct act_rule *rule, struct
goto leave;
fail_rewrite:
_HA_ATOMIC_INC(&sess->fe->fe_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites);
if (s->flags & SF_BE_ASSIGNED)
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&sess->listener->counters->shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites);
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->failed_rewrites);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites);
if (!(msg->flags & HTTP_MSGF_SOFT_RW)) {
ret = ACT_RET_ERR;
@ -2315,7 +2315,7 @@ static enum act_return http_action_return(struct act_rule *rule, struct proxy *p
req->analysers &= AN_REQ_FLT_END;
if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.shared->tg[tgid - 1]->intercepted_req);
_HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
}
return ACT_RET_ABRT;

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