Merge ~lucaskanashiro/ubuntu/+source/haproxy:kinetic-mre into ubuntu/+source/haproxy:ubuntu/kinetic-devel

Proposed by Lucas Kanashiro
Status: Merged
Approved by: git-ubuntu bot
Approved revision: not available
Merge reported by: Lucas Kanashiro
Merged at revision: 7e46924b5a654ab811b04f3b8f1bee1eca8b7388
Proposed branch: ~lucaskanashiro/ubuntu/+source/haproxy:kinetic-mre
Merge into: ubuntu/+source/haproxy:ubuntu/kinetic-devel
Diff against target: 6773 lines (+2423/-819)
114 files modified
.cirrus.yml (+1/-1)
.github/matrix.py (+10/-7)
.github/workflows/compliance.yml (+2/-2)
.github/workflows/cross-zoo.yml (+110/-0)
.github/workflows/vtest.yml (+5/-2)
.github/workflows/windows.yml (+2/-1)
CHANGELOG (+190/-0)
Makefile (+7/-3)
SUBVERS (+1/-1)
VERDATE (+2/-2)
VERSION (+1/-1)
addons/promex/README (+2/-0)
addons/promex/service-prometheus.c (+30/-1)
addons/wurfl/dummy/wurfl/wurfl.h (+10/-5)
debian/changelog (+20/-0)
debian/patches/reproducible.patch (+1/-3)
debian/patches/series (+0/-3)
dev/null (+0/-145)
doc/configuration.txt (+282/-224)
doc/intro.txt (+1/-1)
doc/management.txt (+4/-0)
doc/proxy-protocol.txt (+1/-1)
include/haproxy/buf.h (+1/-1)
include/haproxy/bug.h (+2/-0)
include/haproxy/http.h (+2/-0)
include/haproxy/listener-t.h (+11/-2)
include/haproxy/listener.h (+11/-5)
include/haproxy/peers-t.h (+1/-0)
include/haproxy/pool.h (+2/-2)
include/haproxy/server.h (+9/-5)
include/haproxy/sink.h (+2/-0)
include/haproxy/ssl_sock-t.h (+11/-7)
include/haproxy/ssl_sock.h (+23/-0)
include/haproxy/stats-t.h (+2/-0)
include/haproxy/stream.h (+1/-1)
include/haproxy/task.h (+2/-1)
include/haproxy/tcpcheck-t.h (+1/-0)
include/haproxy/tools.h (+3/-2)
include/import/ebmbtree.h (+53/-0)
reg-tests/cache/if-modified-since.vtc (+4/-1)
reg-tests/cache/if-none-match.vtc (+4/-0)
reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc (+8/-3)
reg-tests/checks/pgsql-check.vtc (+16/-0)
reg-tests/checks/smtp-check.vtc (+6/-2)
reg-tests/contrib/prometheus.vtc (+4/-3)
reg-tests/converter/digest.vtc (+1/-1)
reg-tests/converter/hmac.vtc (+1/-1)
reg-tests/converter/iif.vtc (+1/-1)
reg-tests/converter/json_query.vtc (+1/-1)
reg-tests/http-messaging/h1_host_normalization.vtc (+276/-0)
reg-tests/http-messaging/http_request_buffer.vtc (+18/-1)
reg-tests/http-rules/restrict_req_hdr_names.vtc (+62/-0)
reg-tests/log/log_forward.vtc (+57/-0)
reg-tests/mailers/healthcheckmail.vtc (+1/-1)
reg-tests/ssl/log_forward_ssl.vtc (+60/-0)
reg-tests/startup/automatic_maxconn.vtc (+102/-0)
reg-tests/startup/common.pem (+117/-0)
scripts/announce-release (+12/-11)
src/backend.c (+0/-1)
src/cache.c (+17/-17)
src/cfgparse-listen.c (+4/-2)
src/cfgparse-ssl.c (+7/-7)
src/cfgparse.c (+52/-5)
src/check.c (+7/-0)
src/dns.c (+1/-1)
src/ev_epoll.c (+2/-2)
src/ev_evports.c (+2/-4)
src/ev_kqueue.c (+2/-2)
src/ev_poll.c (+2/-1)
src/fcgi-app.c (+1/-1)
src/fcgi.c (+6/-2)
src/fd.c (+3/-3)
src/flt_http_comp.c (+21/-21)
src/flt_spoe.c (+22/-9)
src/h1.c (+92/-15)
src/h1_htx.c (+3/-0)
src/haproxy.c (+10/-2)
src/hlua.c (+8/-3)
src/hlua_fcn.c (+3/-0)
src/hpack-dec.c (+10/-0)
src/http.c (+32/-0)
src/http_act.c (+2/-0)
src/http_ana.c (+20/-14)
src/http_fetch.c (+6/-5)
src/http_htx.c (+14/-25)
src/listener.c (+45/-16)
src/log.c (+11/-5)
src/mux_fcgi.c (+14/-8)
src/mux_h1.c (+26/-13)
src/mux_h2.c (+24/-10)
src/mworker.c (+4/-2)
src/pattern.c (+6/-6)
src/peers.c (+41/-25)
src/pool.c (+12/-12)
src/proto_tcp.c (+9/-6)
src/proto_udp.c (+8/-5)
src/protocol.c (+3/-3)
src/proxy.c (+32/-16)
src/regex.c (+9/-5)
src/resolvers.c (+29/-10)
src/ring.c (+11/-1)
src/server.c (+5/-6)
src/signal.c (+3/-0)
src/sink.c (+46/-15)
src/ssl_crtlist.c (+5/-0)
src/ssl_sample.c (+3/-0)
src/ssl_sock.c (+17/-11)
src/stats.c (+20/-5)
src/stick_table.c (+29/-17)
src/stream.c (+22/-12)
src/stream_interface.c (+28/-4)
src/tcpcheck.c (+37/-6)
src/time.c (+1/-0)
src/tools.c (+4/-3)
Reviewer Review Type Date Requested Status
git-ubuntu bot Approve
Andreas Hasenack Approve
Canonical Server Reporter Pending
Review via email: mp+439425@code.launchpad.net

Description of the change

MRE update to version 2.4.22 (LP: #2012557). Some patches were removed (applied by upstream) and others refreshed.

the proposed package is available in this PPA:

https://launchpad.net/~lucaskanashiro/+archive/ubuntu/ha-stack

autopkgtest summary:

autopkgtest [18:52:16]: @@@@@@@@@@@@@@@@@@@@ summary
cli PASS
proxy-localhost PASS
proxy-ssl-termination PASS
proxy-ssl-pass-through PASS

To post a comment you must log in.
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

This needs rebasing, security released 2.4.18-1ubuntu1.3

Revision history for this message
Lucas Kanashiro (lucaskanashiro) wrote :

Thanks for checking Andreas, the rebase is done.

Revision history for this message
Andreas Hasenack (ahasenack) :
review: Needs Information
Revision history for this message
Lucas Kanashiro (lucaskanashiro) :
Revision history for this message
Andreas Hasenack (ahasenack) :
Revision history for this message
Lucas Kanashiro (lucaskanashiro) :
Revision history for this message
Lucas Kanashiro (lucaskanashiro) :
Revision history for this message
Andreas Hasenack (ahasenack) :
Revision history for this message
Lucas Kanashiro (lucaskanashiro) wrote :

Version string fixed.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

haha, gotta love version strings :)

+1

review: Approve
Revision history for this message
git-ubuntu bot (git-ubuntu-bot) wrote :

Approvers: lucaskanashiro, ahasenack
Uploaders: lucaskanashiro, ahasenack
MP auto-approved

review: Approve
Revision history for this message
Lucas Kanashiro (lucaskanashiro) wrote :

Thanks Andreas. Package uploaded:

Uploading haproxy_2.4.22-0ubuntu0.22.10.1.dsc
Uploading haproxy_2.4.22.orig.tar.gz
Uploading haproxy_2.4.22-0ubuntu0.22.10.1.debian.tar.xz
Uploading haproxy_2.4.22-0ubuntu0.22.10.1_source.changes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.cirrus.yml b/.cirrus.yml
2index e754f83..deace96 100644
3--- a/.cirrus.yml
4+++ b/.cirrus.yml
5@@ -1,7 +1,7 @@
6 FreeBSD_task:
7 freebsd_instance:
8 matrix:
9- image_family: freebsd-13-0
10+ image_family: freebsd-13-1
11 only_if: $CIRRUS_BRANCH =~ 'master|next'
12 install_script:
13 - pkg update -f && pkg upgrade -y && pkg install -y openssl git gmake lua53 socat pcre
14diff --git a/.github/matrix.py b/.github/matrix.py
15index 264a3d2..abd6caf 100644
16--- a/.github/matrix.py
17+++ b/.github/matrix.py
18@@ -10,6 +10,7 @@ import json
19 import sys
20 import urllib.request
21 import re
22+from os import environ
23
24 if len(sys.argv) == 2:
25 build_type = sys.argv[1]
26@@ -40,7 +41,7 @@ def determine_latest_openssl(ssl):
27 if "openssl-" in name:
28 if name > latest_tag:
29 latest_tag = name
30- return "OPENSSL={}".format(latest_tag[8:])
31+ return "OPENSSL_VERSION={}".format(latest_tag[8:])
32
33 def determine_latest_libressl(ssl):
34 libressl_download_list = urllib.request.urlopen("http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/")
35@@ -48,7 +49,7 @@ def determine_latest_libressl(ssl):
36 decoded_line = line.decode("utf-8")
37 if "libressl-" in decoded_line and ".tar.gz.asc" in decoded_line:
38 l = re.split("libressl-|.tar.gz.asc", decoded_line)[1]
39- return "LIBRESSL={}".format(l)
40+ return "LIBRESSL_VERSION={}".format(l)
41
42 def clean_compression(compression):
43 return compression.replace("USE_", "").lower()
44@@ -67,7 +68,7 @@ matrix = []
45
46 # Ubuntu
47
48-os = "ubuntu-latest"
49+os = "ubuntu-20.04"
50 TARGET = "linux-glibc"
51 for CC in ["gcc", "clang"]:
52 matrix.append(
53@@ -125,8 +126,8 @@ for CC in ["gcc", "clang"]:
54 for ssl in [
55 "stock",
56 "OPENSSL_VERSION=1.0.2u",
57- "OPENSSL_VERSION=latest",
58- "LIBRESSL_VERSION=latest",
59+ "OPENSSL_VERSION=3.0.2",
60+ "LIBRESSL_VERSION=3.5.3",
61 # "BORINGSSL=yes",
62 ]:
63 flags = ["USE_OPENSSL=1"]
64@@ -155,7 +156,7 @@ for CC in ["gcc", "clang"]:
65
66 # ASAN
67
68-os = "ubuntu-latest"
69+os = "ubuntu-20.04"
70 TARGET = "linux-glibc"
71 for CC in ["gcc","clang"]:
72 matrix.append(
73@@ -207,4 +208,6 @@ for CC in ["clang"]:
74
75 print(json.dumps(matrix, indent=4, sort_keys=True))
76
77-print("::set-output name=matrix::{}".format(json.dumps({"include": matrix})))
78+if environ.get('GITHUB_OUTPUT') is not None:
79+ with open(environ.get('GITHUB_OUTPUT'), 'a') as f:
80+ print("matrix={}".format(json.dumps({"include": matrix})), file=f)
81diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml
82index 66bc154..a11f0fa 100644
83--- a/.github/workflows/compliance.yml
84+++ b/.github/workflows/compliance.yml
85@@ -24,7 +24,7 @@ jobs:
86 curl -fsSL https://github.com/summerwind/h2spec/releases/download/${H2SPEC_VERSION}/h2spec_linux_amd64.tar.gz -o h2spec.tar.gz
87 tar xvf h2spec.tar.gz
88 sudo install -m755 h2spec /usr/local/bin/h2spec
89- echo "::set-output name=version::${H2SPEC_VERSION}"
90+ echo "version=${H2SPEC_VERSION}" >> $GITHUB_OUTPUT
91 - name: Compile HAProxy with ${{ matrix.CC }}
92 run: |
93 make -j$(nproc) all \
94@@ -47,7 +47,7 @@ jobs:
95 fi
96 echo "::endgroup::"
97 haproxy -vv
98- echo "::set-output name=version::$(haproxy -v |awk 'NR==1{print $3}')"
99+ echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
100 - name: Launch HAProxy ${{ steps.show-version.outputs.version }}
101 run: haproxy -f .github/h2spec.config -D
102 - name: Run h2spec ${{ steps.install-h2spec.outputs.version }}
103diff --git a/.github/workflows/cross-zoo.yml b/.github/workflows/cross-zoo.yml
104new file mode 100644
105index 0000000..e2a5816
106--- /dev/null
107+++ b/.github/workflows/cross-zoo.yml
108@@ -0,0 +1,110 @@
109+#
110+# this is naamed "zoo" after OpenSSL "cross zoo pipeline"
111+#
112+name: Cross Compile
113+
114+on:
115+ schedule:
116+ - cron: "0 0 21 * *"
117+
118+permissions:
119+ contents: read
120+
121+jobs:
122+ cross-compilation:
123+ strategy:
124+ matrix:
125+ platform: [
126+ {
127+ arch: aarch64-linux-gnu,
128+ libs: libc6-dev-arm64-cross,
129+ target: linux-aarch64
130+ }, {
131+ arch: alpha-linux-gnu,
132+ libs: libc6.1-dev-alpha-cross,
133+ target: linux-alpha-gcc
134+ }, {
135+ arch: arm-linux-gnueabi,
136+ libs: libc6-dev-armel-cross,
137+ target: linux-armv4
138+ }, {
139+ arch: arm-linux-gnueabihf,
140+ libs: libc6-dev-armhf-cross,
141+ target: linux-armv4
142+ }, {
143+ arch: hppa-linux-gnu,
144+ libs: libc6-dev-hppa-cross,
145+ target: -static linux-generic32
146+ }, {
147+ arch: m68k-linux-gnu,
148+ libs: libc6-dev-m68k-cross,
149+ target: -static -m68040 linux-latomic
150+ }, {
151+ arch: mips-linux-gnu,
152+ libs: libc6-dev-mips-cross,
153+ target: -static linux-mips32
154+ }, {
155+ arch: mips64-linux-gnuabi64,
156+ libs: libc6-dev-mips64-cross,
157+ target: -static linux64-mips64
158+ }, {
159+ arch: mipsel-linux-gnu,
160+ libs: libc6-dev-mipsel-cross,
161+ target: linux-mips32
162+ }, {
163+ arch: powerpc64le-linux-gnu,
164+ libs: libc6-dev-ppc64el-cross,
165+ target: linux-ppc64le
166+ }, {
167+ arch: riscv64-linux-gnu,
168+ libs: libc6-dev-riscv64-cross,
169+ target: linux64-riscv64
170+ }, {
171+ arch: s390x-linux-gnu,
172+ libs: libc6-dev-s390x-cross,
173+ target: linux64-s390x
174+ }, {
175+ arch: sh4-linux-gnu,
176+ libs: libc6-dev-sh4-cross,
177+ target: no-async linux-latomic
178+ }, {
179+ arch: hppa-linux-gnu,
180+ libs: libc6-dev-hppa-cross,
181+ target: linux-generic32,
182+ }, {
183+ arch: m68k-linux-gnu,
184+ libs: libc6-dev-m68k-cross,
185+ target: -mcfv4e linux-latomic
186+ }, {
187+ arch: mips-linux-gnu,
188+ libs: libc6-dev-mips-cross,
189+ target: linux-mips32
190+ }, {
191+ arch: mips64-linux-gnuabi64,
192+ libs: libc6-dev-mips64-cross,
193+ target: linux64-mips64
194+ }, {
195+ arch: sparc64-linux-gnu,
196+ libs: libc6-dev-sparc64-cross,
197+ target: linux64-sparcv9
198+ }
199+ ]
200+ runs-on: ubuntu-latest
201+ steps:
202+ - name: install packages
203+ run: |
204+ sudo apt-get update
205+ sudo apt-get -yq --force-yes install \
206+ gcc-${{ matrix.platform.arch }} \
207+ ${{ matrix.platform.libs }}
208+ - uses: actions/checkout@v2
209+
210+
211+ - name: install quictls
212+ run: |
213+ QUICTLS_EXTRA_ARGS="--cross-compile-prefix=${{ matrix.platform.arch }}- ${{ matrix.platform.target }}" QUICTLS=yes scripts/build-ssl.sh
214+
215+ - name: Build
216+ run: |
217+ make ERR=1 CC=${{ matrix.platform.arch }}-gcc TARGET=linux-glibc USE_LIBCRYPT= USE_OPENSSL=1 USE_QUIC=1 USE_PROMEX=1 SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include ADDLIB="-Wl,-rpath,${HOME}/opt/lib"
218+
219diff --git a/.github/workflows/vtest.yml b/.github/workflows/vtest.yml
220index ea39662..781a2b3 100644
221--- a/.github/workflows/vtest.yml
222+++ b/.github/workflows/vtest.yml
223@@ -50,7 +50,7 @@ jobs:
224 - name: Generate cache key
225 id: generate-cache-key
226 run: |
227- echo "::set-output name=key::$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')"
228+ echo "key=$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')" >> $GITHUB_OUTPUT
229
230 - name: Cache SSL libs
231 if: ${{ matrix.ssl && matrix.ssl != 'stock' && matrix.ssl != 'BORINGSSL=yes' && matrix.ssl != 'QUICTLS=yes' }}
232@@ -114,6 +114,9 @@ jobs:
233 run: make -C addons/wurfl/dummy
234 - name: Compile HAProxy with ${{ matrix.CC }}
235 run: |
236+ echo "::group::Show compiler's version"
237+ echo | ${{ matrix.CC }} -v
238+ echo "::endgroup::"
239 echo "::group::Show platform specific defines"
240 echo | ${{ matrix.CC }} -dM -xc -E -
241 echo "::endgroup::"
242@@ -138,7 +141,7 @@ jobs:
243 fi
244 echo "::endgroup::"
245 haproxy -vv
246- echo "::set-output name=version::$(haproxy -v |awk 'NR==1{print $3}')"
247+ echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
248 - name: Install problem matcher for VTest
249 # This allows one to more easily see which tests fail.
250 run: echo "::add-matcher::.github/vtest.json"
251diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
252index 58283ff..022c7f6 100644
253--- a/.github/workflows/windows.yml
254+++ b/.github/workflows/windows.yml
255@@ -56,9 +56,10 @@ jobs:
256 TARGET=${{ matrix.TARGET }} \
257 CC=${{ matrix.CC }} \
258 DEBUG="-DDEBUG_STRICT -DDEBUG_MEMORY_POOLS -DDEBUG_POOL_INTEGRITY" \
259+ DEBUG_CFLAGS="-g -Wno-deprecated-declarations" \
260 ${{ join(matrix.FLAGS, ' ') }}
261 - name: Show HAProxy version
262 id: show-version
263 run: |
264 ./haproxy -vv
265- echo "::set-output name=version::$(./haproxy -v |awk 'NR==1{print $3}')"
266+ echo "version=$(./haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
267diff --git a/CHANGELOG b/CHANGELOG
268index f9eec74..d59309f 100644
269--- a/CHANGELOG
270+++ b/CHANGELOG
271@@ -1,6 +1,196 @@
272 ChangeLog :
273 ===========
274
275+2023/02/14 : 2.4.22
276+ - BUG/MINOR: fcgi-app: prevent 'use-fcgi-app' in default section
277+ - BUG/MEDIUM: ssl: wrong eviction from the session cache tree
278+ - BUG/MINOR: ssl/crt-list: warn when a line is malformated
279+ - BUG/MEDIUM: stick-table: do not leave entries in end of window during purge
280+ - BUG/MEDIUM: cache: use the correct time reference when comparing dates
281+ - DOC: config: fix option spop-check proxy compatibility
282+ - DOC: config: 'http-send-name-header' option may be used in default section
283+ - DOC: proxy-protocol: fix wrong byte in provided example
284+ - BUG/MEDIUM: stconn: Schedule a shutw on shutr if data must be sent first
285+ - CI: github: don't warn on deprecated openssl functions on windows
286+ - BUG/CRITICAL: http: properly reject empty http header field names
287+
288+2023/01/27 : 2.4.21
289+ - BUG/MINOR: http-htx: Don't consider an URI as normalized after a set-uri action
290+ - BUG/MEDIIM: stconn: Flush output data before forwarding close to write side
291+ - CI: github: change "ubuntu-latest" to "ubuntu-20.04"
292+ - BUILD: peers: peers-t.h depends on stick-table-t.h
293+ - BUG/MINOR: resolvers: Don't wait periodic resolution on healthcheck failure
294+ - BUG/MEDIUM: ssl: Verify error codes can exceed 63
295+ - BUG/MINOR: ssl: Fix potential overflow
296+ - BUG/MEDIUM: mworker: fix segv in early failure of mworker mode with peers
297+ - BUG/MINOR: promex: create haproxy_backend_agg_server_status
298+ - MINOR: promex: introduce haproxy_backend_agg_check_status
299+ - DOC: promex: Add missing backend metrics
300+ - BUG/MAJOR: fcgi: Fix uninitialized reserved bytes
301+ - REGTESTS: fix the race conditions in iff.vtc
302+ - REGTESTS: startup: check maxconn computation
303+ - BUG/MEDIUM: resolvers: Use tick_first() to update the resolvers task timeout
304+ - LICENSE: wurfl: clarify the dummy library license.
305+ - BUG/MINOR: ssl: Fix memory leak of find_chain in ssl_sock_load_cert_chain
306+ - BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream flag set
307+ - BUG/MINOR: pool/stats: Use ullong to report total pool usage in bytes in stats
308+ - BUILD: makefile: build the features list dynamically
309+ - BUILD: makefile: sort the features list
310+ - BUG/MINOR: http-fetch: Only fill txn status during prefetch if not already set
311+ - BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is realigned
312+ - REGTEST: fix the race conditions in json_query.vtc
313+ - REGTEST: fix the race conditions in digest.vtc
314+ - REGTEST: fix the race conditions in hmac.vtc
315+ - BUG/MINOR: http: Memory leak of http redirect rules' format string
316+ - CLEANUP: htx: fix a typo in an error message of http_str_to_htx
317+ - BUG/MINOR: h1-htx: Remove flags about protocol upgrade on non-101 responses
318+ - BUG/MINOR: resolvers: Wait the resolution execution for a do_resolv action
319+ - BUG/MINOR: promex: Don't forget to consume the request on error
320+ - BUG/MINOR: http-ana: Report SF_FINST_R flag on error waiting the request body
321+ - BUG/MINOR: http-fetch: Don't block HTTP sample fetch eval in HTTP_MSG_ERROR state
322+ - BUG/MINOR: http-ana: make set-status also update txn->status
323+ - BUG/MINOR: listeners: fix suspend/resume of inherited FDs
324+ - DOC: config: fix wrong section number for "protocol prefixes"
325+ - DOC: config: fix aliases for protocol prefixes "udp4@" and "udp6@"
326+ - BUG/MINOR: mux-fcgi: Correctly set pathinfo
327+ - DOC: config: fix "Address formats" chapter syntax
328+ - BUG/MINOR: listener: close tiny race between resume_listener() and stopping
329+ - BUG/MINOR: mux-h2: add missing traces on failed headers decoding
330+ - BUILD: hpack: include global.h for the trash that is needed in debug mode
331+ - BUG/MINOR: sink: free the forwarding task on exit
332+
333+2022/12/09 : 2.4.20
334+ - BUG/MINOR: checks: update pgsql regex on auth packet
335+ - DOC: config: Fix pgsql-check documentation to make user param mandatory
336+ - BUG/MEDIUM: lua: Don't crash in hlua_lua2arg_check on failure
337+ - BUG/MEDIUM: lua: handle stick table implicit arguments right.
338+ - BUILD: h1: silence an initiialized warning with gcc-4.7 and -Os
339+ - BUG/MINOR: http-fetch: Update method after a prefetch in smp_fetch_meth()
340+ - BUILD: http_fetch: silence an uninitiialized warning with gcc-4/5/6 at -Os
341+ - BUG/MINOR: mux-h1: Account consumed output data on synchronous connection error
342+ - MINOR: smtpchk: Update expect rule to fully match replies to EHLO commands
343+ - BUG/MINOR: smtpchk: SMTP Service check should gracefully close SMTP transaction
344+ - BUG/MINOR: backend: only enforce turn-around state when not redispatching
345+ - DOC: configuration: missing 'if' in tcp-request content example
346+ - BUG/MAJOR: stick-tables: do not try to index a server name for applets
347+ - BUG/MINOR: server: make sure "show servers state" hides private bits
348+ - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in matrix.py
349+ - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in workflow definition
350+ - BUG/MINOR: log: Preserve message facility when the log target is a ring buffer
351+ - BUG/MINOR: ring: Properly parse connect timeout
352+ - BUG/MEDIUM: compression: handle rewrite errors when updating response headers
353+ - BUG/MINOR: sink: Only use backend capability for the sink proxies
354+ - BUG/MINOR: sink: Set default connect/server timeout for implicit ring buffers
355+ - CI: SSL: use proper version generating when "latest" semantic is used
356+ - CI: SSL: temporarily stick to LibreSSL=3.5.3
357+ - BUG/MINOR: stick-table: Use server_id instead of std_t_sint in process_store_rules()
358+ - DOC: management: add forgotten "show startup-logs"
359+ - BUG/MAJOR: stick-table: don't process store-response rules for applets
360+ - BUG/MEDIUM: stick-table: fix a race condition when updating the expiration task
361+ - BUG/MINOR: log: fixing bug in tcp syslog_io_handler Octet-Counting
362+ - CI: add monthly gcc cross compile jobs
363+ - BUG/MINOR: ssl: Memory leak of AUTHORITY_KEYID struct when loading issuer
364+ - BUG/MINOR: ssl: ocsp structure not freed properly in case of error
365+ - CI: switch to the "latest" LibreSSL
366+ - CI: emit the compiler's version in the build reports
367+ - BUG/MEDIUM: wdt/clock: properly handle early task hangs
368+ - BUG/MINOR: http-htx: Fix error handling during parsing http replies
369+ - BUG/MINOR: resolvers: Set port before IP address when processing SRV records
370+ - BUG/MINOR: mux-fcgi: Be sure to send empty STDING record in case of zero-copy
371+ - BUG/MEDIUM: mux-fcgi: Avoid value length overflow when it doesn't fit at once
372+ - BUG/MINOR: mux-h1: Do not send a last null chunk on body-less answers
373+ - REG-TESTS: cache: Remove T-E header for 304-Not-Modified responses
374+ - DOC: config: fix alphabetical ordering of global section
375+ - BUG/MEDIUM: ring: fix creation of server in uninitialized ring
376+ - BUG/MINOR: pool/cli: use ullong to report total pool usage in bytes
377+ - BUG/MEDIUM: listener: Fix race condition when updating the global mngmt task
378+ - BUG/MINOR: http_ana/txn: don't re-initialize txn and req var lists
379+ - BUG/MINOR: ssl: don't initialize the keylog callback when not required
380+ - BUG/MEDIUM: peers: messages about unkown tables not correctly ignored
381+ - BUILD: peers: Remove unused variables
382+ - BUG/MINOR: server/idle: at least use atomic stores when updating max_used_conns
383+ - BUILD: listener: fix build warning on global_listener_rwlock without threads
384+ - BUG/MINOR: cfgparse-listen: fix ebpt_next_dup pointer dereference on proxy "from" inheritance
385+ - BUG/MINOR: log: fix parse_log_message rfc5424 size check
386+ - BUG/MINOR: http-htx: Don't consider an URI as normalized after a set-uri action
387+ - BUILD: http-htx: Silent build error about a possible NULL start-line
388+ - BUG/MINOR: mux-h1: Fix handling of 408-Request-Time-Out
389+ - Revert "BUG/MINOR: http-htx: Don't consider an URI as normalized after a set-uri action"
390+ - DOC: config: provide some configuration hints for "http-reuse"
391+ - DOC: config: clarify the fact that SNI should not be used in HTTP scenarios
392+ - DOC: config: mention that a single monitor-uri rule is supported
393+ - DOC: config: explain how default matching method for ACL works
394+ - DOC: config: clarify the fact that "retries" is not just for connections
395+ - DOC: config: clarify the -m dir and -m dom pattern matching methods
396+ - SCRIPTS: announce-release: add a link to the data plane API
397+ - Revert "CI: switch to the "latest" LibreSSL"
398+ - Revert "CI: determine actual OpenSSL version dynamically"
399+
400+2022/09/28 : 2.4.19
401+ - BUG/MEDIUM: mworker: use default maxconn in wait mode
402+ - MINOR: http: Add function to get port part of a host
403+ - MINOR: http: Add function to detect default port
404+ - BUG/MEDIUM: h1: Improve authority validation for CONNCET request
405+ - MINOR: http-htx: Use new HTTP functions for the scheme based normalization
406+ - MINOR: ebtree: add ebmb_lookup_shorter() to pursue lookups
407+ - BUG/MEDIUM: pattern: only visit equivalent nodes when skipping versions
408+ - MINOR: peers: Use a dedicated reconnect timeout when stopping the local peer
409+ - BUG/MEDIUM: peers: limit reconnect attempts of the old process on reload
410+ - BUG/MINOR: peers: Use right channel flag to consider the peer as connected
411+ - BUG/MEDIUM: dns: Properly initialize new DNS session
412+ - MINOR: server: Constify source server to copy its settings
413+ - REORG: server: Export srv_settings_cpy() function
414+ - BUG/MEDIUM: proxy: Perform a custom copy for default server settings
415+ - BUG/MINOR: ring/cli: fix a race condition between the writer and the reader
416+ - BUG/MINOR: sink: fix a race condition between the writer and the reader
417+ - BUILD: cfgparse: always defined _GNU_SOURCE for sched.h and crypt.h
418+ - BUG/MEDIUM: poller: use fd_delete() to release the poller pipes
419+ - BUG/MEDIUM: task: relax one thread consistency check in task_unlink_wq()
420+ - BUILD: debug: silence warning on gcc-5
421+ - BUG/MEDIUM: ring: fix too lax 'size' parser
422+ - BUILD: http: silence an uninitialized warning affecting gcc-5
423+ - BUG/MEDIUM: http-ana: fix crash or wrong header deletion by http-restrict-req-hdr-names
424+ - BUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle
425+ - BUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized
426+ - BUG/MAJOR: mworker: fix infinite loop on master with no proxies.
427+ - BUG/MINOR: resolvers: return the correct value in resolvers_finalize_config()
428+ - BUG/MINOR: tcpcheck: Disable QUICKACK only if data should be sent after connect
429+ - REGTESTS: Fix prometheus script to perform HTTP health-checks
430+ - DOC: configuration: do-resolve doesn't work with a port in the string
431+ - BUG/MEDIUM: spoe: Properly update streams waiting for a ACK in async mode
432+ - BUG/MEDIUM: peers: Add connect and server timeut to peers proxy
433+ - BUG/MEDIUM: peers: Don't use resync timer when local resync is in progress
434+ - BUG/MEDIUM: peers: Don't start resync on reload if local peer is not up-to-date
435+ - BUG/MINOR: hlua: Rely on CF_EOI to detect end of message in HTTP applets
436+ - BUG/MINOR: tcpcheck: Disable QUICKACK for default tcp-check (with no rule)
437+ - BUG/MEDIUM: mux-h1: do not refrain from signaling errors after end of input
438+ - REGTESTS: http_request_buffer: Add a barrier to not mix up log messages
439+ - BUG/MEDIUM: mux-h1: always use RST to kill idle connections in pools
440+ - BUG/MINOR: mux-h2: fix the "show fd" dest buffer for the subscriber
441+ - BUG/MINOR: mux-h1: fix the "show fd" dest buffer for the subscriber
442+ - BUG/MINOR: mux-fcgi: fix the "show fd" dest buffer for the subscriber
443+ - BUG/MINOR: regex: Properly handle PCRE2 lib compiled without JIT support
444+ - BUILD: makefile: enable crypt(3) for NetBSD
445+ - BUG/MINOR: h1: Support headers case adjustment for TCP proxies
446+ - BUG/MINOR: task: always reset a new tasklet's call date
447+ - BUG/MINOR: signals/poller: set the poller timeout to 0 when there are signals
448+ - BUG/MINOR: signals/poller: ensure wakeup from signals
449+ - CI: cirrus-ci: bump FreeBSD image to 13-1
450+ - BUG/MEDIUM: proxy: ensure pause_proxy() and resume_proxy() own PROXY_LOCK
451+ - MINOR: listener: small API change
452+ - BUG/MINOR: stats: fixing stat shows disabled frontend status as 'OPEN'
453+ - REGTESTS: healthcheckmail: Relax matching on the healthcheck log message
454+ - REGTESTS: log: test the log-forward feature
455+ - BUG/MEDIUM: sink: bad init sequence on tcp sink from a ring.
456+ - REGTESTS: ssl/log: test the log-forward with SSL
457+ - DOC: fix TOC in starter guide for subsection 3.3.8. Statistics
458+ - BUG/MEDIUM: captures: free() an error capture out of the proxy lock
459+ - BUILD: fd: fix a build warning on the DWCAS
460+ - SCRIPTS: announce-release: update some URLs to https
461+ - BUG/MINOR: log: improper behavior when escaping log data
462+ - REGTESTS: 4be_1srv_smtpchk_httpchk_layer47errors: Return valid SMTP replies
463+ - BUG/MEDIUM: resolvers: Remove aborted resolutions from query_ids tree
464+
465 2022/07/27 : 2.4.18
466 - CI: determine actual LibreSSL version dynamically
467 - MEDIUM: http-ana: Add a proxy option to restrict chars in request header names
468diff --git a/Makefile b/Makefile
469index c0a6a27..40c2b10 100644
470--- a/Makefile
471+++ b/Makefile
472@@ -423,8 +423,8 @@ endif
473 # NetBSD 8 and above
474 ifeq ($(TARGET),netbsd)
475 set_target_defaults = $(call default_opts, \
476- USE_POLL USE_TPROXY USE_THREAD USE_KQUEUE USE_ACCEPT4 USE_CLOSEFROM \
477- USE_GETADDRINFO)
478+ USE_POLL USE_TPROXY USE_LIBCRYPT USE_THREAD USE_KQUEUE USE_ACCEPT4 \
479+ USE_CLOSEFROM USE_GETADDRINFO)
480 endif
481
482 # AIX 5.1 only
483@@ -524,7 +524,11 @@ ignore_implicit = $(if $(subst environment,,$(origin $(1))), \
484 # is used to report a list of all flags which were used to build this version.
485 # Do not assign anything to it.
486 BUILD_OPTIONS := $(foreach opt,$(use_opts),$(call ignore_implicit,$(opt)))
487-BUILD_FEATURES := $(foreach opt,$(patsubst USE_%,%,$(use_opts)),$(if $(USE_$(opt)),+$(opt),-$(opt)))
488+
489+# Make a list of all known features with +/- prepended depending on their
490+# activation status. Must be a macro so that dynamically enabled ones are
491+# evaluated with their current status.
492+BUILD_FEATURES = $(foreach opt,$(patsubst USE_%,%,$(sort $(use_opts))),$(if $(USE_$(opt)),+$(opt),-$(opt)))
493
494 # All USE_* options have their equivalent macro defined in the code (some might
495 # possibly be unused though)
496diff --git a/SUBVERS b/SUBVERS
497index 994ee02..f042fd0 100644
498--- a/SUBVERS
499+++ b/SUBVERS
500@@ -1,2 +1,2 @@
501--1d80f18
502+-f8e3218
503
504diff --git a/VERDATE b/VERDATE
505index 6a4d254..d8a3372 100644
506--- a/VERDATE
507+++ b/VERDATE
508@@ -1,2 +1,2 @@
509-2022-07-27 15:10:44 +0200
510-2022/07/27
511+2023-02-14 16:57:13 +0100
512+2023/02/14
513diff --git a/VERSION b/VERSION
514index cc2ff5a..76cb51e 100644
515--- a/VERSION
516+++ b/VERSION
517@@ -1 +1 @@
518-2.4.18
519+2.4.22
520diff --git a/addons/promex/README b/addons/promex/README
521index e41ebdc..4e29e23 100644
522--- a/addons/promex/README
523+++ b/addons/promex/README
524@@ -286,6 +286,8 @@ See prometheus export for the description of each field.
525 | haproxy_backend_max_total_time_seconds |
526 | haproxy_backend_internal_errors_total |
527 | haproxy_backend_uweight |
528+| haproxy_backend_agg_server_status |
529+| haproxy_backend_agg_check_status |
530 +-----------------------------------------------------+
531
532 * Server metrics
533diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c
534index b267f98..d31b666 100644
535--- a/addons/promex/service-prometheus.c
536+++ b/addons/promex/service-prometheus.c
537@@ -289,6 +289,8 @@ const struct promex_metric promex_st_metrics[ST_F_TOTAL_FIELDS] = {
538 [ST_F_NEED_CONN_EST] = { .n = IST("need_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) },
539 [ST_F_UWEIGHT] = { .n = IST("uweight"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) },
540 [ST_F_AGG_SRV_CHECK_STATUS] = { .n = IST("agg_server_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) },
541+ [ST_F_AGG_SRV_STATUS ] = { .n = IST("agg_server_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) },
542+ [ST_F_AGG_CHECK_STATUS] = { .n = IST("agg_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) },
543 };
544
545 /* Description of overridden stats fields */
546@@ -792,6 +794,7 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
547 double secs;
548 enum promex_back_state bkd_state;
549 enum promex_srv_state srv_state;
550+ enum healthcheck_status srv_check_status;
551
552 for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
553 if (!(promex_st_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
554@@ -800,6 +803,8 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
555 while (appctx->ctx.stats.obj1) {
556 struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
557 unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
558+ unsigned int srv_check_count[HCHK_STATUS_SIZE] = { 0 };
559+ const char *check_state;
560
561 px = appctx->ctx.stats.obj1;
562
563@@ -814,7 +819,8 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
564 return -1;
565
566 switch (appctx->st2) {
567- case ST_F_AGG_SRV_CHECK_STATUS:
568+ case ST_F_AGG_SRV_CHECK_STATUS: // DEPRECATED
569+ case ST_F_AGG_SRV_STATUS:
570 if (!px->srv)
571 goto next_px;
572 sv = px->srv;
573@@ -833,6 +839,28 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
574 }
575 appctx->ctx.stats.st_code = 0;
576 goto next_px;
577+ case ST_F_AGG_CHECK_STATUS:
578+ if (!px->srv)
579+ goto next_px;
580+ sv = px->srv;
581+ while (sv) {
582+ srv_check_status = sv->check.status;
583+ srv_check_count[srv_check_status] += 1;
584+ sv = sv->next;
585+ }
586+ for (; appctx->ctx.stats.st_code < HCHK_STATUS_SIZE; appctx->ctx.stats.st_code++) {
587+ if (get_check_status_result(appctx->ctx.stats.st_code) < CHK_RES_FAILED)
588+ continue;
589+ val = mkf_u32(FO_STATUS, srv_check_count[appctx->ctx.stats.st_code]);
590+ check_state = get_check_status_info(appctx->ctx.stats.st_code);
591+ labels[1].name = ist("state");
592+ labels[1].value = ist(check_state);
593+ if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
594+ &val, labels, &out, max))
595+ goto full;
596+ }
597+ appctx->ctx.stats.st_code = 0;
598+ goto next_px;
599 case ST_F_STATUS:
600 bkd_state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0);
601 for (; appctx->ctx.stats.st_code < PROMEX_BACK_STATE_COUNT; appctx->ctx.stats.st_code++) {
602@@ -1547,6 +1575,7 @@ static void promex_appctx_handle_io(struct appctx *appctx)
603 res->flags |= CF_READ_NULL;
604 si_shutr(si);
605 si_shutw(si);
606+ goto out;
607 }
608
609 struct applet promex_applet = {
610diff --git a/addons/wurfl/dummy/wurfl/wurfl.h b/addons/wurfl/dummy/wurfl/wurfl.h
611index 3b450fc..7659561 100644
612--- a/addons/wurfl/dummy/wurfl/wurfl.h
613+++ b/addons/wurfl/dummy/wurfl/wurfl.h
614@@ -4,11 +4,16 @@
615 * Copyright (c) ScientiaMobile, Inc.
616 * http://www.scientiamobile.com
617 *
618- * This software package is the property of ScientiaMobile Inc. and is licensed
619- * commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor).
620- * If you represent the Licensee, please refer to the licensing agreement which has been signed
621- * between the two parties. If you do not represent the Licensee, you are not authorized to use
622- * this software in any way.
623+ * This software package is the property of ScientiaMobile Inc. and is distributed under
624+ * a dual licensing scheme:
625+ *
626+ * 1) commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor).
627+ * If you represent the Licensee, please refer to the licensing agreement which has been signed
628+ * between the two parties. If you do not represent the Licensee, you are not authorized to use
629+ * this software in any way.
630+ *
631+ * 2) LGPL when used in the context of the HAProxy project with the purpose of testing compatibility
632+ * of HAProxy with ScientiaMobile software.
633 *
634 */
635
636diff --git a/debian/changelog b/debian/changelog
637index 02ccd97..ca7af92 100644
638--- a/debian/changelog
639+++ b/debian/changelog
640@@ -1,3 +1,23 @@
641+haproxy (2.4.22-0ubuntu0.22.10.1) kinetic; urgency=medium
642+
643+ * New upstream release (LP: #2012557).
644+ - Major and critical bug fixes according to the upstream changelog:
645+ + BUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized
646+ + BUG/MAJOR: mworker: fix infinite loop on master with no proxies.
647+ + BUG/MAJOR: stick-tables: do not try to index a server name for applets
648+ + BUG/MAJOR: stick-table: don't process store-response rules for applets
649+ + BUG/MAJOR: fcgi: Fix uninitialized reserved bytes
650+ + BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is realigned
651+ + BUG/CRITICAL: http: properly reject empty http header field names
652+ - Remove patches applied by upstream in debian/patches:
653+ + CVE-2023-0056.patch
654+ + CVE-2023-25725.patch
655+ + CVE-2023-0836.patch
656+ - Refresh existing patches in debian/patches:
657+ + reproducible.patch
658+
659+ -- Lucas Kanashiro <kanashiro@ubuntu.com> Wed, 22 Mar 2023 18:39:05 -0300
660+
661 haproxy (2.4.18-1ubuntu1.3) kinetic-security; urgency=medium
662
663 * SECURITY UPDATE: information leak via uninitialized bytes
664diff --git a/debian/patches/CVE-2023-0056.patch b/debian/patches/CVE-2023-0056.patch
665deleted file mode 100644
666index dd8b02d..0000000
667--- a/debian/patches/CVE-2023-0056.patch
668+++ /dev/null
669@@ -1,38 +0,0 @@
670-From 827a6299e6995c5c3ba620d8b7cbacdaef67f2c4 Mon Sep 17 00:00:00 2001
671-From: Christopher Faulet <cfaulet@haproxy.com>
672-Date: Thu, 22 Dec 2022 09:47:01 +0100
673-Subject: [PATCH] BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream
674- flag set
675-
676-As state in RFC9113#8.1, HEADERS frame with the ES flag set that carries an
677-informational status code is malformed. However, there is no test on this
678-condition.
679-
680-On 2.4 and higher, it is hard to predict consequences of this bug because
681-end of the message is only reported with a flag. But on 2.2 and lower, it
682-leads to a crash because there is an unexpected extra EOM block at the end
683-of an interim response.
684-
685-Now, when a ES flag is detected on a HEADERS frame for an interim message, a
686-stream error is sent (RST_STREAM/PROTOCOL_ERROR).
687-
688-This patch should solve the issue #1972. It should be backported as far as
689-2.0.
690----
691- src/mux_h2.c | 5 +++++
692- 1 file changed, 5 insertions(+)
693-
694---- a/src/mux_h2.c
695-+++ b/src/mux_h2.c
696-@@ -4940,6 +4940,11 @@ next_frame:
697- *flags |= H2_SF_HEADERS_RCVD;
698-
699- if (h2c->dff & H2_F_HEADERS_END_STREAM) {
700-+ if (msgf & H2_MSGF_RSP_1XX) {
701-+ /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */
702-+ TRACE_STATE("invalid interim response with ES flag!", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
703-+ goto fail;
704-+ }
705- /* no more data are expected for this message */
706- htx->flags |= HTX_FL_EOM;
707- }
708diff --git a/debian/patches/CVE-2023-0836.patch b/debian/patches/CVE-2023-0836.patch
709deleted file mode 100644
710index f708696..0000000
711--- a/debian/patches/CVE-2023-0836.patch
712+++ /dev/null
713@@ -1,47 +0,0 @@
714-From f988992d16f45ef03d5bbb024a1042ed8123e4c5 Mon Sep 17 00:00:00 2001
715-From: Youfu Zhang <zhangyoufu@gmail.com>
716-Date: Fri, 9 Dec 2022 19:15:48 +0800
717-Subject: [PATCH] BUG/MAJOR: fcgi: Fix uninitialized reserved bytes
718-
719-The output buffer is not zero-initialized. If we don't clear reserved
720-bytes, fcgi requests sent to backend will leak sensitive data.
721-
722-This patch must be backported as far as 2.2.
723-
724-(cherry picked from commit 2e6bf0a2722866ae0128a4392fa2375bd1f03ff8)
725-Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
726-(cherry picked from commit db03179fee55c60a92ce6b86a0f04dbb9ba0328b)
727-Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
728----
729- src/fcgi.c | 8 ++++++--
730- 1 file changed, 6 insertions(+), 2 deletions(-)
731-
732-diff --git a/src/fcgi.c b/src/fcgi.c
733-index dcf2db2..1d1a82b 100644
734---- a/src/fcgi.c
735-+++ b/src/fcgi.c
736-@@ -47,7 +47,7 @@ int fcgi_encode_record_hdr(struct buffer *out, const struct fcgi_header *h)
737- out->area[len++] = ((h->len >> 8) & 0xff);
738- out->area[len++] = (h->len & 0xff);
739- out->area[len++] = h->padding;
740-- len++; /* rsv */
741-+ out->area[len++] = 0; /* rsv */
742-
743- out->data = len;
744- return 1;
745-@@ -94,7 +94,11 @@ int fcgi_encode_begin_request(struct buffer *out, const struct fcgi_begin_reques
746- out->area[len++] = ((r->role >> 8) & 0xff);
747- out->area[len++] = (r->role & 0xff);
748- out->area[len++] = r->flags;
749-- len += 5; /* rsv */
750-+ out->area[len++] = 0; /* rsv */
751-+ out->area[len++] = 0;
752-+ out->area[len++] = 0;
753-+ out->area[len++] = 0;
754-+ out->area[len++] = 0;
755-
756- out->data = len;
757- return 1;
758---
759-1.7.10.4
760-
761diff --git a/debian/patches/CVE-2023-25725.patch b/debian/patches/CVE-2023-25725.patch
762deleted file mode 100644
763index 1897223..0000000
764--- a/debian/patches/CVE-2023-25725.patch
765+++ /dev/null
766@@ -1,145 +0,0 @@
767-From a6c7ac9d51248a641f456906549120d3f6387049 Mon Sep 17 00:00:00 2001
768-From: Willy Tarreau <w@1wt.eu>
769-Date: Thu, 9 Feb 2023 21:36:54 +0100
770-Subject: BUG/CRITICAL: http: properly reject empty http header field names
771-
772-The HTTP header parsers surprizingly accepts empty header field names,
773-and this is a leftover from the original code that was agnostic to this.
774-
775-When muxes were introduced, for H2 first, the HPACK decompressor needed
776-to feed headers lists, and since empty header names were strictly
777-forbidden by the protocol, the lists of headers were purposely designed
778-to be terminated by an empty header field name (a principle that is
779-similar to H1's empty line termination). This principle was preserved
780-and generalized to other protocols migrated to muxes (H1/FCGI/H3 etc)
781-without anyone ever noticing that the H1 parser was still able to deliver
782-empty header field names to this list. In addition to this it turns out
783-that the HPACK decompressor, despite a comment in the code, may
784-successfully decompress an empty header field name, and this mistake
785-was propagated to the QPACK decompressor as well.
786-
787-The impact is that an empty header field name may be used to truncate
788-the list of headers and thus make some headers disappear. While for
789-H2/H3 the impact is limited as haproxy sees a request with missing
790-headers, and headers are not used to delimit messages, in the case of
791-HTTP/1, the impact is significant because the presence (and sometimes
792-contents) of certain sensitive headers is detected during the parsing.
793-Thus, some of these headers may be seen, marked as present, their value
794-extracted, but never delivered to upper layers and obviously not
795-forwarded to the other side either. This can have for consequence that
796-certain important header fields such as Connection, Upgrade, Host,
797-Content-length, Transfer-Encoding etc are possibly seen as different
798-between what haproxy uses to parse/forward/route and what is observed
799-in http-request rules and of course, forwarded. One direct consequence
800-is that it is possible to exploit this property in HTTP/1 to make
801-affected versions of haproxy forward more data than is advertised on
802-the other side, and bypass some access controls or routing rules by
803-crafting extraneous requests. Note, however, that responses to such
804-requests will normally not be passed back to the client, but this can
805-still cause some harm.
806-
807-This specific risk can be mostly worked around in configuration using
808-the following rule that will rely on the bug's impact to precisely
809-detect the inconsistency between the known body size and the one
810-expected to be advertised to the server (the rule works from 2.0 to
811-2.8-dev):
812-
813- http-request deny if { fc_http_major 1 } !{ req.body_size 0 } !{ req.hdr(content-length) -m found } !{ req.hdr(transfer-encoding) -m found } !{ method CONNECT }
814-
815-This will exclusively block such carefully crafted requests delivered
816-over HTTP/1. HTTP/2 and HTTP/3 do not need content-length, and a body
817-that arrives without being announced with a content-length will be
818-forwarded using transfer-encoding, hence will not cause discrepancies.
819-In HAProxy 2.0 in legacy mode ("no option http-use-htx"), this rule will
820-simply have no effect but will not cause trouble either.
821-
822-A clean solution would consist in modifying the loops iterating over
823-these headers lists to check the header name's pointer instead of its
824-length (since both are zero at the end of the list), but this requires
825-to touch tens of places and it's very easy to miss one. Functions such
826-as htx_add_header(), htx_add_trailer(), htx_add_all_headers() would be
827-good starting points for such a possible future change.
828-
829-Instead the current fix focuses on blocking empty headers where they
830-are first inserted, hence in the H1/HPACK/QPACK decoders. One benefit
831-of the current solution (for H1) is that it allows "show errors" to
832-report a precise diagnostic when facing such invalid HTTP/1 requests,
833-with the exact location of the problem and the originating address:
834-
835- $ printf "GET / HTTP/1.1\r\nHost: localhost\r\n:empty header\r\n\r\n" | nc 0 8001
836- HTTP/1.1 400 Bad request
837- Content-length: 90
838- Cache-Control: no-cache
839- Connection: close
840- Content-Type: text/html
841-
842- <html><body><h1>400 Bad request</h1>
843- Your browser sent an invalid request.
844- </body></html>
845-
846- $ socat /var/run/haproxy.stat <<< "show errors"
847- Total events captured on [10/Feb/2023:16:29:37.530] : 1
848-
849- [10/Feb/2023:16:29:34.155] frontend decrypt (#2): invalid request
850- backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:31092
851- buffer starts at 0 (including 0 out), 16334 free,
852- len 50, wraps at 16336, error at position 33
853- H1 connection flags 0x00000000, H1 stream flags 0x00000810
854- H1 msg state MSG_HDR_NAME(17), H1 msg flags 0x00001410
855- H1 chunk len 0 bytes, H1 body len 0 bytes :
856-
857- 00000 GET / HTTP/1.1\r\n
858- 00016 Host: localhost\r\n
859- 00033 :empty header\r\n
860- 00048 \r\n
861-
862-I want to address sincere and warm thanks for their great work to the
863-team composed of the following security researchers who found the issue
864-together and reported it: Bahruz Jabiyev, Anthony Gavazzi, and Engin
865-Kirda from Northeastern University, Kaan Onarlioglu from Akamai
866-Technologies, Adi Peleg and Harvey Tuch from Google. And kudos to Amaury
867-Denoyelle from HAProxy Technologies for spotting that the HPACK and
868-QPACK decoders would let this pass despite the comment explicitly
869-saying otherwise.
870-
871-This fix must be backported as far as 2.0. The QPACK changes can be
872-dropped before 2.6. In 2.0 there is also the equivalent code for legacy
873-mode, which doesn't suffer from the list truncation, but it would better
874-be fixed regardless.
875----
876- src/h1.c | 4 ++++
877- src/hpack-dec.c | 9 +++++++++
878- src/qpack-dec.c | 9 +++++++++
879- 3 files changed, 22 insertions(+)
880-
881---- a/src/h1.c
882-+++ b/src/h1.c
883-@@ -706,6 +706,10 @@ int h1_headers_to_hdr_list(char *start,
884-
885- if (likely(*ptr == ':')) {
886- col = ptr - start;
887-+ if (col <= sol) {
888-+ state = H1_MSG_HDR_NAME;
889-+ goto http_msg_invalid;
890-+ }
891- EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP);
892- }
893-
894---- a/src/hpack-dec.c
895-+++ b/src/hpack-dec.c
896-@@ -419,6 +419,15 @@ int hpack_decode_frame(struct hpack_dht
897- /* <name> and <value> are correctly filled here */
898- }
899-
900-+ /* We must not accept empty header names (forbidden by the spec and used
901-+ * as a list termination).
902-+ */
903-+ if (!name.len) {
904-+ hpack_debug_printf("##ERR@%d##\n", __LINE__);
905-+ ret = -HPACK_ERR_INVALID_ARGUMENT;
906-+ goto leave;
907-+ }
908-+
909- /* here's what we have here :
910- * - name.len > 0
911- * - value is filled with either const data or data allocated from tmp
912diff --git a/debian/patches/reproducible.patch b/debian/patches/reproducible.patch
913index bbc95b8..e499a79 100644
914--- a/debian/patches/reproducible.patch
915+++ b/debian/patches/reproducible.patch
916@@ -1,8 +1,6 @@
917-diff --git a/Makefile b/Makefile
918-index 566bdb26a3e7..8603dea25c21 100644
919 --- a/Makefile
920 +++ b/Makefile
921-@@ -975,7 +975,7 @@ src/haproxy.o: src/haproxy.c $(DEP)
922+@@ -995,7 +995,7 @@
923 -DBUILD_ARCH='"$(strip $(ARCH))"' \
924 -DBUILD_CPU='"$(strip $(CPU))"' \
925 -DBUILD_CC='"$(strip $(CC))"' \
926diff --git a/debian/patches/series b/debian/patches/series
927index 25260a8..276b0d5 100644
928--- a/debian/patches/series
929+++ b/debian/patches/series
930@@ -4,6 +4,3 @@ haproxy.service-add-documentation.patch
931 # applied during the build process:
932 # debianize-dconv.patch
933 reproducible.patch
934-CVE-2023-0056.patch
935-CVE-2023-25725.patch
936-CVE-2023-0836.patch
937diff --git a/doc/configuration.txt b/doc/configuration.txt
938index 5d4c052..0c23dd1 100644
939--- a/doc/configuration.txt
940+++ b/doc/configuration.txt
941@@ -3,7 +3,7 @@
942 Configuration Manual
943 ----------------------
944 version 2.4
945- 2022/07/27
946+ 2023/02/14
947
948
949 This document covers the configuration language as implemented in the version
950@@ -965,32 +965,36 @@ of them have command-line equivalents.
951 The following keywords are supported in the "global" section :
952
953 * Process management and security
954+ - 51degrees-cache-size
955+ - 51degrees-data-file
956+ - 51degrees-property-name-list
957+ - 51degrees-property-separator
958 - ca-base
959 - chroot
960- - crt-base
961 - cpu-map
962+ - crt-base
963 - daemon
964 - default-path
965 - description
966 - deviceatlas-json-file
967 - deviceatlas-log-level
968- - deviceatlas-separator
969 - deviceatlas-properties-cookie
970+ - deviceatlas-separator
971 - expose-experimental-directives
972 - external-check
973 - gid
974 - group
975- - hard-stop-after
976 - h1-case-adjust
977 - h1-case-adjust-file
978+ - h2-workaround-bogus-websocket-clients
979+ - hard-stop-after
980 - insecure-fork-wanted
981 - insecure-setuid-wanted
982 - issuers-chain-path
983- - h2-workaround-bogus-websocket-clients
984 - localpeer
985 - log
986- - log-tag
987 - log-send-hostname
988+ - log-tag
989 - lua-load
990 - lua-load-per-thread
991 - lua-prepend-path
992@@ -1003,13 +1007,9 @@ The following keywords are supported in the "global" section :
993 - pp2-never-send-local
994 - presetenv
995 - resetenv
996- - uid
997- - ulimit-n
998- - user
999 - set-dumpable
1000 - set-var
1001 - setenv
1002- - stats
1003 - ssl-default-bind-ciphers
1004 - ssl-default-bind-ciphersuites
1005 - ssl-default-bind-curves
1006@@ -1020,25 +1020,25 @@ The following keywords are supported in the "global" section :
1007 - ssl-dh-param-file
1008 - ssl-server-verify
1009 - ssl-skip-self-issued-ca
1010+ - stats
1011+ - strict-limits
1012+ - uid
1013+ - ulimit-n
1014 - unix-bind
1015 - unsetenv
1016- - 51degrees-data-file
1017- - 51degrees-property-name-list
1018- - 51degrees-property-separator
1019- - 51degrees-cache-size
1020+ - user
1021+ - wurfl-cache-size
1022 - wurfl-data-file
1023 - wurfl-information-list
1024 - wurfl-information-list-separator
1025- - wurfl-cache-size
1026- - strict-limits
1027
1028 * Performance tuning
1029 - busy-polling
1030 - max-spread-checks
1031+ - maxcompcpuusage
1032+ - maxcomprate
1033 - maxconn
1034 - maxconnrate
1035- - maxcomprate
1036- - maxcompcpuusage
1037 - maxpipes
1038 - maxsessrate
1039 - maxsslconn
1040@@ -1046,16 +1046,16 @@ The following keywords are supported in the "global" section :
1041 - maxzlibmem
1042 - no-memory-trimming
1043 - noepoll
1044- - nokqueue
1045 - noevports
1046- - nopoll
1047- - nosplice
1048 - nogetaddrinfo
1049+ - nokqueue
1050+ - nopoll
1051 - noreuseport
1052+ - nosplice
1053 - profiling.tasks
1054- - spread-checks
1055 - server-state-base
1056 - server-state-file
1057+ - spread-checks
1058 - ssl-engine
1059 - ssl-mode-async
1060 - tune.buffers.limit
1061@@ -1074,9 +1074,9 @@ The following keywords are supported in the "global" section :
1062 - tune.idletimer
1063 - tune.lua.forced-yield
1064 - tune.lua.maxmem
1065+ - tune.lua.service-timeout
1066 - tune.lua.session-timeout
1067 - tune.lua.task-timeout
1068- - tune.lua.service-timeout
1069 - tune.maxaccept
1070 - tune.maxpollevents
1071 - tune.maxrewrite
1072@@ -1092,13 +1092,13 @@ The following keywords are supported in the "global" section :
1073 - tune.sndbuf.client
1074 - tune.sndbuf.server
1075 - tune.ssl.cachesize
1076+ - tune.ssl.capture-cipherlist-size
1077+ - tune.ssl.default-dh-param
1078+ - tune.ssl.force-private-cache
1079 - tune.ssl.keylog
1080 - tune.ssl.lifetime
1081- - tune.ssl.force-private-cache
1082 - tune.ssl.maxrecord
1083- - tune.ssl.default-dh-param
1084 - tune.ssl.ssl-ctx-cache-size
1085- - tune.ssl.capture-cipherlist-size
1086 - tune.vars.global-max-size
1087 - tune.vars.proc-max-size
1088 - tune.vars.reqres-max-size
1089@@ -1115,6 +1115,36 @@ The following keywords are supported in the "global" section :
1090 3.1. Process management and security
1091 ------------------------------------
1092
1093+51degrees-data-file <file path>
1094+ The path of the 51Degrees data file to provide device detection services. The
1095+ file should be unzipped and accessible by HAProxy with relevant permissions.
1096+
1097+ Please note that this option is only available when HAProxy has been
1098+ compiled with USE_51DEGREES.
1099+
1100+51degrees-property-name-list [<string> ...]
1101+ A list of 51Degrees property names to be load from the dataset. A full list
1102+ of names is available on the 51Degrees website:
1103+ https://51degrees.com/resources/property-dictionary
1104+
1105+ Please note that this option is only available when HAProxy has been
1106+ compiled with USE_51DEGREES.
1107+
1108+51degrees-property-separator <char>
1109+ A char that will be appended to every property value in a response header
1110+ containing 51Degrees results. If not set that will be set as ','.
1111+
1112+ Please note that this option is only available when HAProxy has been
1113+ compiled with USE_51DEGREES.
1114+
1115+51degrees-cache-size <number>
1116+ Sets the size of the 51Degrees converter cache to <number> entries. This
1117+ is an LRU cache which reminds previous device detections and their results.
1118+ By default, this cache is disabled.
1119+
1120+ Please note that this option is only available when HAProxy has been
1121+ compiled with USE_51DEGREES.
1122+
1123 ca-base <dir>
1124 Assigns a default directory to fetch SSL CA certificates and CRLs from when a
1125 relative path is used with "ca-file", "ca-verify-file" or "crl-file"
1126@@ -1267,6 +1297,13 @@ default-path { current | config | parent | origin <path> }
1127 paths. A robust approach could consist in prefixing all files names with
1128 their respective site name, or in doing so at the directory level.
1129
1130+description <text>
1131+ Add a text that describes the instance.
1132+
1133+ Please note that it is required to escape certain characters (# for example)
1134+ and this text is inserted into a html page so you should avoid using
1135+ "<" and ">" characters.
1136+
1137 deviceatlas-json-file <path>
1138 Sets the path of the DeviceAtlas JSON data file to be loaded by the API.
1139 The path must be a valid JSON data file and accessible by HAProxy process.
1140@@ -1275,15 +1312,15 @@ deviceatlas-log-level <value>
1141 Sets the level of information returned by the API. This directive is
1142 optional and set to 0 by default if not set.
1143
1144-deviceatlas-separator <char>
1145- Sets the character separator for the API properties results. This directive
1146- is optional and set to | by default if not set.
1147-
1148 deviceatlas-properties-cookie <name>
1149 Sets the client cookie's name used for the detection if the DeviceAtlas
1150 Client-side component was used during the request. This directive is optional
1151 and set to DAPROPS by default if not set.
1152
1153+deviceatlas-separator <char>
1154+ Sets the character separator for the API properties results. This directive
1155+ is optional and set to | by default if not set.
1156+
1157 expose-experimental-directives
1158 This statement must appear before using directives tagged as experimental or
1159 the config file will be rejected.
1160@@ -1309,22 +1346,6 @@ group <group name>
1161 Similar to "gid" but uses the GID of group name <group name> from /etc/group.
1162 See also "gid" and "user".
1163
1164-hard-stop-after <time>
1165- Defines the maximum time allowed to perform a clean soft-stop.
1166-
1167- Arguments :
1168- <time> is the maximum time (by default in milliseconds) for which the
1169- instance will remain alive when a soft-stop is received via the
1170- SIGUSR1 signal.
1171-
1172- This may be used to ensure that the instance will quit even if connections
1173- remain opened during a soft-stop (for example with long timeouts for a proxy
1174- in tcp mode). It applies both in TCP and HTTP mode.
1175-
1176- Example:
1177- global
1178- hard-stop-after 30s
1179-
1180 h1-case-adjust <from> <to>
1181 Defines the case adjustment to apply, when enabled, to the header name
1182 <from>, to change it to <to> before sending it to HTTP/1 clients or
1183@@ -1374,6 +1395,33 @@ h1-case-adjust-file <hdrs-file>
1184 See "h1-case-adjust", "option h1-case-adjust-bogus-client" and
1185 "option h1-case-adjust-bogus-server".
1186
1187+h2-workaround-bogus-websocket-clients
1188+ This disables the announcement of the support for h2 websockets to clients.
1189+ This can be use to overcome clients which have issues when implementing the
1190+ relatively fresh RFC8441, such as Firefox 88. To allow clients to
1191+ automatically downgrade to http/1.1 for the websocket tunnel, specify h2
1192+ support on the bind line using "alpn" without an explicit "proto" keyword. If
1193+ this statement was previously activated, this can be disabled by prefixing
1194+ the keyword with "no'.
1195+
1196+hard-stop-after <time>
1197+ Defines the maximum time allowed to perform a clean soft-stop.
1198+
1199+ Arguments :
1200+ <time> is the maximum time (by default in milliseconds) for which the
1201+ instance will remain alive when a soft-stop is received via the
1202+ SIGUSR1 signal.
1203+
1204+ This may be used to ensure that the instance will quit even if connections
1205+ remain opened during a soft-stop (for example with long timeouts for a proxy
1206+ in tcp mode). It applies both in TCP and HTTP mode.
1207+
1208+ Example:
1209+ global
1210+ hard-stop-after 30s
1211+
1212+ See also: grace
1213+
1214 insecure-fork-wanted
1215 By default HAProxy tries hard to prevent any thread and process creation
1216 after it starts. Doing so is particularly important when using Lua files of
1217@@ -1421,15 +1469,6 @@ issuers-chain-path <dir>
1218 "issuers-chain-path" directory. All other certificates with the same issuer
1219 will share the chain in memory.
1220
1221-h2-workaround-bogus-websocket-clients
1222- This disables the announcement of the support for h2 websockets to clients.
1223- This can be use to overcome clients which have issues when implementing the
1224- relatively fresh RFC8441, such as Firefox 88. To allow clients to
1225- automatically downgrade to http/1.1 for the websocket tunnel, specify h2
1226- support on the bind line using "alpn" without an explicit "proto" keyword. If
1227- this statement was previously activated, this can be disabled by prefixing
1228- the keyword with "no'.
1229-
1230 localpeer <name>
1231 Sets the local instance's peer name. It will be ignored if the "-L"
1232 command line argument is specified or if used after "peers" section
1233@@ -1762,6 +1801,26 @@ server-state-file <file>
1234 configuration. See also "server-state-base" and "show servers state",
1235 "load-server-state-from-file" and "server-state-file-name"
1236
1237+set-dumpable
1238+ This option is better left disabled by default and enabled only upon a
1239+ developer's request. If it has been enabled, it may still be forcibly
1240+ disabled by prefixing it with the "no" keyword. It has no impact on
1241+ performance nor stability but will try hard to re-enable core dumps that were
1242+ possibly disabled by file size limitations (ulimit -f), core size limitations
1243+ (ulimit -c), or "dumpability" of a process after changing its UID/GID (such
1244+ as /proc/sys/fs/suid_dumpable on Linux). Core dumps might still be limited by
1245+ the current directory's permissions (check what directory the file is started
1246+ from), the chroot directory's permission (it may be needed to temporarily
1247+ disable the chroot directive or to move it to a dedicated writable location),
1248+ or any other system-specific constraint. For example, some Linux flavours are
1249+ notorious for replacing the default core file with a path to an executable
1250+ not even installed on the system (check /proc/sys/kernel/core_pattern). Often,
1251+ simply writing "core", "core.%p" or "/var/log/core/core.%p" addresses the
1252+ issue. When trying to enable this option waiting for a rare issue to
1253+ re-appear, it's often a good idea to first try to obtain such a dump by
1254+ issuing, for example, "kill -11" to the "haproxy" process and verify that it
1255+ leaves a core where expected when dying.
1256+
1257 set-var <var-name> <expr>
1258 Sets the process-wide variable '<var-name>' to the result of the evaluation
1259 of the sample expression <expr>. The variable '<var-name>' may only be a
1260@@ -1785,26 +1844,6 @@ setenv <name> <value>
1261 the configuration file sees the new value. See also "presetenv", "resetenv",
1262 and "unsetenv".
1263
1264-set-dumpable
1265- This option is better left disabled by default and enabled only upon a
1266- developer's request. If it has been enabled, it may still be forcibly
1267- disabled by prefixing it with the "no" keyword. It has no impact on
1268- performance nor stability but will try hard to re-enable core dumps that were
1269- possibly disabled by file size limitations (ulimit -f), core size limitations
1270- (ulimit -c), or "dumpability" of a process after changing its UID/GID (such
1271- as /proc/sys/fs/suid_dumpable on Linux). Core dumps might still be limited by
1272- the current directory's permissions (check what directory the file is started
1273- from), the chroot directory's permission (it may be needed to temporarily
1274- disable the chroot directive or to move it to a dedicated writable location),
1275- or any other system-specific constraint. For example, some Linux flavours are
1276- notorious for replacing the default core file with a path to an executable
1277- not even installed on the system (check /proc/sys/kernel/core_pattern). Often,
1278- simply writing "core", "core.%p" or "/var/log/core/core.%p" addresses the
1279- issue. When trying to enable this option waiting for a rare issue to
1280- re-appear, it's often a good idea to first try to obtain such a dump by
1281- issuing, for example, "kill -11" to the "haproxy" process and verify that it
1282- leaves a core where expected when dying.
1283-
1284 ssl-default-bind-ciphers <ciphers>
1285 This setting is only available when support for OpenSSL was built in. It sets
1286 the default string describing the list of cipher algorithms ("cipher suite")
1287@@ -1995,6 +2034,10 @@ ssl-skip-self-issued-ca
1288 certificates. It's useless for BoringSSL, .issuer is ignored because ocsp
1289 bits does not need it. Requires at least OpenSSL 1.0.2.
1290
1291+stats maxconn <connections>
1292+ By default, the stats socket is limited to 10 concurrent connections. It is
1293+ possible to change this value with "stats maxconn".
1294+
1295 stats socket [<address:port>|<path>] [param*]
1296 Binds a UNIX socket to <path> or a TCPv4/v6 address to <address:port>.
1297 Connections to this socket will return various statistics outputs and even
1298@@ -2011,9 +2054,12 @@ stats timeout <timeout, in milliseconds>
1299 to change this value with "stats timeout". The value must be passed in
1300 milliseconds, or be suffixed by a time unit among { us, ms, s, m, h, d }.
1301
1302-stats maxconn <connections>
1303- By default, the stats socket is limited to 10 concurrent connections. It is
1304- possible to change this value with "stats maxconn".
1305+strict-limits
1306+ Makes process fail at startup when a setrlimit fails. HAProxy tries to set the
1307+ best setrlimit according to what has been calculated. If it fails, it will
1308+ emit a warning. This option is here to guarantee an explicit failure of
1309+ HAProxy when those limits fail. It is enabled by default. It may still be
1310+ forcibly disabled by prefixing it with the "no" keyword.
1311
1312 uid <number>
1313 Changes the process's user ID to <number>. It is recommended that the user ID
1314@@ -2061,42 +2107,14 @@ node <name>
1315 nodes, it becomes easy to immediately spot what server is handling the
1316 traffic.
1317
1318-description <text>
1319- Add a text that describes the instance.
1320-
1321- Please note that it is required to escape certain characters (# for example)
1322- and this text is inserted into a html page so you should avoid using
1323- "<" and ">" characters.
1324-
1325-51degrees-data-file <file path>
1326- The path of the 51Degrees data file to provide device detection services. The
1327- file should be unzipped and accessible by HAProxy with relevant permissions.
1328-
1329- Please note that this option is only available when HAProxy has been
1330- compiled with USE_51DEGREES.
1331-
1332-51degrees-property-name-list [<string> ...]
1333- A list of 51Degrees property names to be load from the dataset. A full list
1334- of names is available on the 51Degrees website:
1335- https://51degrees.com/resources/property-dictionary
1336-
1337- Please note that this option is only available when HAProxy has been
1338- compiled with USE_51DEGREES.
1339-
1340-51degrees-property-separator <char>
1341- A char that will be appended to every property value in a response header
1342- containing 51Degrees results. If not set that will be set as ','.
1343-
1344- Please note that this option is only available when HAProxy has been
1345- compiled with USE_51DEGREES.
1346-
1347-51degrees-cache-size <number>
1348- Sets the size of the 51Degrees converter cache to <number> entries. This
1349- is an LRU cache which reminds previous device detections and their results.
1350- By default, this cache is disabled.
1351+wurfl-cache-size <size>
1352+ Sets the WURFL Useragent cache size. For faster lookups, already processed user
1353+ agents are kept in a LRU cache :
1354+ - "0" : no cache is used.
1355+ - <size> : size of lru cache in elements.
1356
1357- Please note that this option is only available when HAProxy has been
1358- compiled with USE_51DEGREES.
1359+ Please note that this option is only available when HAProxy has been compiled
1360+ with USE_WURFL=1.
1361
1362 wurfl-data-file <file path>
1363 The path of the WURFL data file to provide device detection services. The
1364@@ -2152,22 +2170,6 @@ wurfl-patch-file [<file path>]
1365 Please note that this option is only available when HAProxy has been compiled
1366 with USE_WURFL=1.
1367
1368-wurfl-cache-size <size>
1369- Sets the WURFL Useragent cache size. For faster lookups, already processed user
1370- agents are kept in a LRU cache :
1371- - "0" : no cache is used.
1372- - <size> : size of lru cache in elements.
1373-
1374- Please note that this option is only available when HAProxy has been compiled
1375- with USE_WURFL=1.
1376-
1377-strict-limits
1378- Makes process fail at startup when a setrlimit fails. HAProxy tries to set the
1379- best setrlimit according to what has been calculated. If it fails, it will
1380- emit a warning. This option is here to guarantee an explicit failure of
1381- HAProxy when those limits fail. It is enabled by default. It may still be
1382- forcibly disabled by prefixing it with the "no" keyword.
1383-
1384 3.2. Performance tuning
1385 -----------------------
1386
1387@@ -2204,6 +2206,24 @@ max-spread-checks <delay in milliseconds>
1388 even if the servers' check intervals are larger. When servers run with
1389 shorter intervals, their intervals will be respected though.
1390
1391+maxcompcpuusage <number>
1392+ Sets the maximum CPU usage HAProxy can reach before stopping the compression
1393+ for new requests or decreasing the compression level of current requests.
1394+ It works like 'maxcomprate' but measures CPU usage instead of incoming data
1395+ bandwidth. The value is expressed in percent of the CPU used by HAProxy. A
1396+ value of 100 disable the limit. The default value is 100. Setting a lower
1397+ value will prevent the compression work from slowing the whole process down
1398+ and from introducing high latencies.
1399+
1400+maxcomprate <number>
1401+ Sets the maximum per-process input compression rate to <number> kilobytes
1402+ per second. For each session, if the maximum is reached, the compression
1403+ level will be decreased during the session. If the maximum is reached at the
1404+ beginning of a session, the session will not compress at all. If the maximum
1405+ is not reached, the compression level will be increased up to
1406+ tune.comp.maxlevel. A value of zero means there is no limit, this is the
1407+ default value.
1408+
1409 maxconn <number>
1410 Sets the maximum per-process number of concurrent connections to <number>. It
1411 is equivalent to the command-line argument "-n". Proxies will stop accepting
1412@@ -2229,25 +2249,6 @@ maxconnrate <number>
1413 value close to its expected share. Also, lowering tune.maxaccept can improve
1414 fairness.
1415
1416-maxcomprate <number>
1417- Sets the maximum per-process input compression rate to <number> kilobytes
1418- per second. For each session, if the maximum is reached, the compression
1419- level will be decreased during the session. If the maximum is reached at the
1420- beginning of a session, the session will not compress at all. If the maximum
1421- is not reached, the compression level will be increased up to
1422- tune.comp.maxlevel. A value of zero means there is no limit, this is the
1423- default value.
1424-
1425-maxcompcpuusage <number>
1426- Sets the maximum CPU usage HAProxy can reach before stopping the compression
1427- for new requests or decreasing the compression level of current requests.
1428- It works like 'maxcomprate' but measures CPU usage instead of incoming data
1429- bandwidth. The value is expressed in percent of the CPU used by HAProxy. In
1430- case of multiple processes (nbproc > 1), each process manages its individual
1431- usage. A value of 100 disable the limit. The default value is 100. Setting
1432- a lower value will prevent the compression work from slowing the whole
1433- process down and from introducing high latencies.
1434-
1435 maxpipes <number>
1436 Sets the maximum per-process number of pipes to <number>. Currently, pipes
1437 are only used by kernel-based tcp splicing. Since a pipe contains two file
1438@@ -2323,17 +2324,21 @@ noepoll
1439 equivalent to the command-line argument "-de". The next polling system
1440 used will generally be "poll". See also "nopoll".
1441
1442-nokqueue
1443- Disables the use of the "kqueue" event polling system on BSD. It is
1444- equivalent to the command-line argument "-dk". The next polling system
1445- used will generally be "poll". See also "nopoll".
1446-
1447 noevports
1448 Disables the use of the event ports event polling system on SunOS systems
1449 derived from Solaris 10 and later. It is equivalent to the command-line
1450 argument "-dv". The next polling system used will generally be "poll". See
1451 also "nopoll".
1452
1453+nogetaddrinfo
1454+ Disables the use of getaddrinfo(3) for name resolving. It is equivalent to
1455+ the command line argument "-dG". Deprecated gethostbyname(3) will be used.
1456+
1457+nokqueue
1458+ Disables the use of the "kqueue" event polling system on BSD. It is
1459+ equivalent to the command-line argument "-dk". The next polling system
1460+ used will generally be "poll". See also "nopoll".
1461+
1462 nopoll
1463 Disables the use of the "poll" event polling system. It is equivalent to the
1464 command-line argument "-dp". The next polling system used will be "select".
1465@@ -2341,6 +2346,10 @@ nopoll
1466 platforms supported by HAProxy. See also "nokqueue", "noepoll" and
1467 "noevports".
1468
1469+noreuseport
1470+ Disables the use of SO_REUSEPORT - see socket(7). It is equivalent to the
1471+ command line argument "-dR".
1472+
1473 nosplice
1474 Disables the use of kernel tcp splicing between sockets on Linux. It is
1475 equivalent to the command line argument "-dS". Data will then be copied
1476@@ -2351,14 +2360,6 @@ nosplice
1477 case of doubt. See also "option splice-auto", "option splice-request" and
1478 "option splice-response".
1479
1480-nogetaddrinfo
1481- Disables the use of getaddrinfo(3) for name resolving. It is equivalent to
1482- the command line argument "-dG". Deprecated gethostbyname(3) will be used.
1483-
1484-noreuseport
1485- Disables the use of SO_REUSEPORT - see socket(7). It is equivalent to the
1486- command line argument "-dR".
1487-
1488 profiling.memory { on | off }
1489 Enables ('on') or disables ('off') per-function memory profiling. This will
1490 keep usage statistics of malloc/calloc/realloc/free calls anywhere in the
1491@@ -2604,18 +2605,18 @@ tune.lua.session-timeout <timeout>
1492 counts only the pure Lua runtime. If the Lua does a sleep, the sleep is
1493 not taken in account. The default timeout is 4s.
1494
1495-tune.lua.task-timeout <timeout>
1496- Purpose is the same as "tune.lua.session-timeout", but this timeout is
1497- dedicated to the tasks. By default, this timeout isn't set because a task may
1498- remain alive during of the lifetime of HAProxy. For example, a task used to
1499- check servers.
1500-
1501 tune.lua.service-timeout <timeout>
1502 This is the execution timeout for the Lua services. This is useful for
1503 preventing infinite loops or spending too much time in Lua. This timeout
1504 counts only the pure Lua runtime. If the Lua does a sleep, the sleep is
1505 not taken in account. The default timeout is 4s.
1506
1507+tune.lua.task-timeout <timeout>
1508+ Purpose is the same as "tune.lua.session-timeout", but this timeout is
1509+ dedicated to the tasks. By default, this timeout isn't set because a task may
1510+ remain alive during of the lifetime of HAProxy. For example, a task used to
1511+ check servers.
1512+
1513 tune.maxaccept <number>
1514 Sets the maximum number of consecutive connections a process may accept in a
1515 row before switching to other work. In single process mode, higher numbers
1516@@ -2756,6 +2757,26 @@ tune.ssl.cachesize <number>
1517 pre-allocated upon startup and are shared between all processes if "nbproc"
1518 is greater than 1. Setting this value to 0 disables the SSL session cache.
1519
1520+tune.ssl.capture-cipherlist-size <number>
1521+ Sets the maximum size of the buffer used for capturing client hello cipher
1522+ list, extensions list, elliptic curves list and elliptic curve point
1523+ formats. If the value is 0 (default value) the capture is disabled,
1524+ otherwise a buffer is allocated for each SSL/TLS connection.
1525+
1526+tune.ssl.default-dh-param <number>
1527+ Sets the maximum size of the Diffie-Hellman parameters used for generating
1528+ the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The
1529+ final size will try to match the size of the server's RSA (or DSA) key (e.g,
1530+ a 2048 bits temporary DH key for a 2048 bits RSA key), but will not exceed
1531+ this maximum value. Only 1024 or higher values are allowed. Higher values
1532+ will increase the CPU load, and values greater than 1024 bits are not
1533+ supported by Java 7 and earlier clients. This value is not used if static
1534+ Diffie-Hellman parameters are supplied either directly in the certificate
1535+ file or by using the ssl-dh-param-file parameter.
1536+ If there is neither a default-dh-param nor a ssl-dh-param-file defined, and
1537+ if the server's PEM file of a given frontend does not specify its own DH
1538+ parameters, then DHE ciphers will be unavailable for this frontend.
1539+
1540 tune.ssl.force-private-cache
1541 This option disables SSL session cache sharing between all processes. It
1542 should normally not be used since it will force many renegotiations due to
1543@@ -2824,28 +2845,12 @@ tune.ssl.maxrecord <number>
1544 best value. HAProxy will automatically switch to this setting after an idle
1545 stream has been detected (see tune.idletimer above).
1546
1547-tune.ssl.default-dh-param <number>
1548- Sets the maximum size of the Diffie-Hellman parameters used for generating
1549- the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The
1550- final size will try to match the size of the server's RSA (or DSA) key (e.g,
1551- a 2048 bits temporary DH key for a 2048 bits RSA key), but will not exceed
1552- this maximum value. Default value if 2048. Only 1024 or higher values are
1553- allowed. Higher values will increase the CPU load, and values greater than
1554- 1024 bits are not supported by Java 7 and earlier clients. This value is not
1555- used if static Diffie-Hellman parameters are supplied either directly
1556- in the certificate file or by using the ssl-dh-param-file parameter.
1557-
1558 tune.ssl.ssl-ctx-cache-size <number>
1559 Sets the size of the cache used to store generated certificates to <number>
1560 entries. This is a LRU cache. Because generating a SSL certificate
1561 dynamically is expensive, they are cached. The default cache size is set to
1562 1000 entries.
1563
1564-tune.ssl.capture-cipherlist-size <number>
1565- Sets the maximum size of the buffer used for capturing client-hello cipher
1566- list. If the value is 0 (default value) the capture is disabled, otherwise
1567- a buffer is allocated for each SSL/TLS connection.
1568-
1569 tune.vars.global-max-size <size>
1570 tune.vars.proc-max-size <size>
1571 tune.vars.reqres-max-size <size>
1572@@ -3619,7 +3624,7 @@ http-error X X X X
1573 http-request - X X X
1574 http-response - X X X
1575 http-reuse X - X X
1576-http-send-name-header - - X X
1577+http-send-name-header X - X X
1578 id - X X X
1579 ignore-persist - - X X
1580 load-server-state-from-file X - X X
1581@@ -3677,7 +3682,7 @@ option socket-stats (*) X X X -
1582 option splice-auto (*) X X X X
1583 option splice-request (*) X X X X
1584 option splice-response (*) X X X X
1585-option spop-check - - - X
1586+option spop-check X - X X
1587 option srvtcpka (*) X - X X
1588 option ssl-hello-chk X - X X
1589 -- keyword -------------------------- defaults - frontend - listen -- backend -
1590@@ -6162,7 +6167,8 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> :
1591 based on information found in the request (IE a Host header).
1592 If this action is used to find the server's IP address (using the
1593 "set-dst" action), then the server IP address in the backend must be set
1594- to 0.0.0.0.
1595+ to 0.0.0.0. The do-resolve action takes an host-only parameter, any port must
1596+ be removed from the string.
1597
1598 Example:
1599 resolvers mydns
1600@@ -6177,7 +6183,7 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> :
1601
1602 frontend fe
1603 bind 10.42.0.1:80
1604- http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower
1605+ http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower,regsub(:[0-9]*$,)
1606 http-request capture var(txn.myip) len 40
1607
1608 # return 503 when the variable is not set,
1609@@ -6814,9 +6820,11 @@ http-request set-uri <fmt> [ { if | unless } <condition> ]
1610
1611 This rewrites the request URI with the result of the evaluation of format
1612 string <fmt>. The scheme, authority, path and query string are all replaced
1613- at once. This can be used to rewrite hosts in front of proxies, or to
1614- perform complex modifications to the URI such as moving parts between the
1615- path and the query string.
1616+ at once. This can be used to rewrite hosts in front of proxies, or to perform
1617+ complex modifications to the URI such as moving parts between the path and
1618+ the query string. If an absolute URI is set, it will be sent as is to
1619+ HTTP/1.1 servers. If it is not the desired behavior, the host, the path
1620+ and/or the query string should be set separately.
1621 See also "http-request set-path" and "http-request set-query".
1622
1623 http-request set-var(<var-name>) <expr> [ { if | unless } <condition> ]
1624@@ -7541,7 +7549,26 @@ http-reuse { never | safe | aggressive | always }
1625 because almost no new connection will be established while idle connections
1626 remain available. This is particularly true with the "always" strategy.
1627
1628- See also : "option http-keep-alive", "server maxconn"
1629+ The rules to decide to keep an idle connection opened or to close it after
1630+ processing are also governed by the "tune.pool-low-fd-ratio" (default: 20%)
1631+ and "tune.pool-high-fd-ratio" (default: 25%). These correspond to the
1632+ percentage of total file descriptors spent in idle connections above which
1633+ haproxy will respectively refrain from keeping a connection opened after a
1634+ response, and actively kill idle connections. Some setups using a very high
1635+ ratio of idle connections, either because of too low a global "maxconn", or
1636+ due to a lot of HTTP/2 or HTTP/3 traffic on the frontend (few connections)
1637+ but HTTP/1 connections on the backend, may observe a lower reuse rate because
1638+ too few connections are kept open. It may be desirable in this case to adjust
1639+ such thresholds or simply to increase the global "maxconn" value.
1640+
1641+ Similarly, when thread groups are explicitly enabled, it is important to
1642+ understand that idle connections are only usable between threads from a same
1643+ group. As such it may happen that unfair load between groups leads to more
1644+ idle connections being needed, causing a lower reuse rate. The same solution
1645+ may then be applied (increase global "maxconn" or increase pool ratios).
1646+
1647+ See also : "option http-keep-alive", "server maxconn", "thread-groups",
1648+ "tune.pool-high-fd-ratio", "tune.pool-low-fd-ratio"
1649
1650
1651 http-send-name-header [<header>]
1652@@ -8073,7 +8100,9 @@ monitor-uri <uri>
1653 Monitor requests are processed very early, just after the request is parsed
1654 and even before any "http-request". The only rulesets applied before are the
1655 tcp-request ones. They cannot be logged either, and it is the intended
1656- purpose. They are only used to report HAProxy's health to an upper component,
1657+ purpose. Only one URI may be configured for monitoring; when multiple
1658+ "monitor-uri" statements are present, the last one will define the URI to
1659+ be used. They are only used to report HAProxy's health to an upper component,
1660 nothing more. However, it is possible to add any number of conditions using
1661 "monitor fail" and ACLs so that the result can be adjusted to whatever check
1662 can be imagined (most often the number of available servers in a backend).
1663@@ -9350,7 +9379,7 @@ no option persist
1664 See also : "option redispatch", "retries", "force-persist"
1665
1666
1667-option pgsql-check [ user <username> ]
1668+option pgsql-check user <username>
1669 Use PostgreSQL health checks for server testing
1670 May be used in sections : defaults | frontend | listen | backend
1671 yes | no | yes | yes
1672@@ -9610,7 +9639,7 @@ no option splice-response
1673 option spop-check
1674 Use SPOP health checks for server testing
1675 May be used in sections : defaults | frontend | listen | backend
1676- no | no | no | yes
1677+ yes | no | yes | yes
1678 Arguments : none
1679
1680 It is possible to test that the server correctly talks SPOP protocol instead
1681@@ -10175,24 +10204,26 @@ redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
1682
1683
1684 retries <value>
1685- Set the number of retries to perform on a server after a connection failure
1686+ Set the number of retries to perform on a server after a failure
1687 May be used in sections: defaults | frontend | listen | backend
1688 yes | no | yes | yes
1689 Arguments :
1690- <value> is the number of times a connection attempt should be retried on
1691- a server when a connection either is refused or times out. The
1692- default value is 3.
1693+ <value> is the number of times a request or connection attempt should be
1694+ retried on a server after a failure.
1695
1696- It is important to understand that this value applies to the number of
1697- connection attempts, not full requests. When a connection has effectively
1698- been established to a server, there will be no more retry.
1699+ By default, retries apply only to new connection attempts. However, when
1700+ the "retry-on" directive is used, other conditions might trigger a retry
1701+ (e.g. empty response, undesired status code), and each of them will count
1702+ one attempt, and when the total number attempts reaches the value here, an
1703+ error will be returned.
1704
1705 In order to avoid immediate reconnections to a server which is restarting,
1706 a turn-around timer of min("timeout connect", one second) is applied before
1707- a retry occurs.
1708+ a retry occurs on the same server.
1709
1710- When "option redispatch" is set, the last retry may be performed on another
1711- server even if a cookie references a different server.
1712+ When "option redispatch" is set, some retries may be performed on another
1713+ server even if a cookie references a different server. By default this will
1714+ only be the last retry unless an argument is passed to "option redispatch".
1715
1716 See also : "option redispatch"
1717
1718@@ -12423,7 +12454,7 @@ tcp-request content <action> [{if | unless} <condition>]
1719 evaluated.
1720
1721 Example:
1722- tcp-request content use-service lua.deny { src -f /etc/haproxy/blacklist.lst }
1723+ tcp-request content use-service lua.deny if { src -f /etc/haproxy/blacklist.lst }
1724
1725 Example:
1726
1727@@ -14986,8 +15017,10 @@ sni <expression>
1728 The "sni" parameter evaluates the sample fetch expression, converts it to a
1729 string and uses the result as the host name sent in the SNI TLS extension to
1730 the server. A typical use case is to send the SNI received from the client in
1731- a bridged HTTPS scenario, using the "ssl_fc_sni" sample fetch for the
1732- expression, though alternatives such as req.hdr(host) can also make sense. If
1733+ a bridged TCP/SSL scenario, using the "ssl_fc_sni" sample fetch for the
1734+ expression. THIS MUST NOT BE USED FOR HTTPS, where req.hdr(host) should be
1735+ used instead, since SNI in HTTPS must always match the Host field and clients
1736+ are allowed to use different host names over the same connection). If
1737 "verify required" is set (which is the recommended setting), the resulting
1738 name will also be matched against the server certificate's names. See the
1739 "verify" directive for more details. If you want to set a SNI for health
1740@@ -15679,7 +15712,11 @@ possible to convert the sample to lowercase before matching, like this :
1741 All ACL-specific criteria imply a default matching method. Most often, these
1742 criteria are composed by concatenating the name of the original sample fetch
1743 method and the matching method. For example, "hdr_beg" applies the "beg" match
1744-to samples retrieved using the "hdr" fetch method. Since all ACL-specific
1745+to samples retrieved using the "hdr" fetch method. This matching method is only
1746+usable when the keyword is used alone, without any converter. In case any such
1747+converter were to be applied after such an ACL keyword, the default matching
1748+method from the ACL keyword is simply ignored since what will matter for the
1749+matching is the output type of the last converter. Since all ACL-specific
1750 criteria rely on a sample fetch method, it is always possible instead to use
1751 the original sample fetch method and the explicit matching method using "-m".
1752
1753@@ -15805,13 +15842,24 @@ different forms :
1754 - suffix match (-m end) : the patterns are compared with the end of the
1755 extracted string, and the ACL matches if any of them matches.
1756
1757- - subdir match (-m dir) : the patterns are looked up inside the extracted
1758- string, delimited with slashes ("/"), and the ACL matches if any of them
1759- matches.
1760-
1761- - domain match (-m dom) : the patterns are looked up inside the extracted
1762- string, delimited with dots ("."), and the ACL matches if any of them
1763- matches.
1764+ - subdir match (-m dir) : the patterns are looked up anywhere inside the
1765+ extracted string, delimited with slashes ("/"), the beginning or the end
1766+ of the string. The ACL matches if any of them matches. As such, the string
1767+ "/images/png/logo/32x32.png", would match "/images", "/images/png",
1768+ "images/png", "/png/logo", "logo/32x32.png" or "32x32.png" but not "png"
1769+ nor "32x32".
1770+
1771+ - domain match (-m dom) : the patterns are looked up anywhere inside the
1772+ extracted string, delimited with dots ("."), colons (":"), slashes ("/"),
1773+ question marks ("?"), the beginning or the end of the string. This is made
1774+ to be used with URLs. Leading and trailing delimiters in the pattern are
1775+ ignored. The ACL matches if any of them matches. As such, in the example
1776+ string "http://www1.dc-eu.example.com:80/blah", the patterns "http",
1777+ "www1", ".www1", "dc-eu", "example", "com", "80", "dc-eu.example",
1778+ "blah", ":www1:", "dc-eu.example:80" would match, but not "eu" nor "dc".
1779+ Using it to match domain suffixes for filtering or routing is generally
1780+ not a good idea, as the routing could easily be fooled by prepending the
1781+ matching prefix in front of another domain for example.
1782
1783 String matching applies to verbatim strings as they are passed, with the
1784 exception of the backslash ("\") which makes it possible to escape some
1785@@ -18860,6 +18908,16 @@ ssl_fc_sni : string
1786 requires that the SSL library is built with support for TLS extensions
1787 enabled (check haproxy -vv).
1788
1789+ CAUTION! Except under very specific conditions, it is normally not correct to
1790+ use this field as a substitute for the HTTP "Host" header field. For example,
1791+ when forwarding an HTTPS connection to a server, the SNI field must be set
1792+ from the HTTP Host header field using "req.hdr(host)" and not from the front
1793+ SNI value. The reason is that SNI is solely used to select the certificate
1794+ the server side will present, and that clients are then allowed to send
1795+ requests with different Host values as long as they match the names in the
1796+ certificate. As such, "ssl_fc_sni" should normally not be used as an argument
1797+ to the "sni" server keyword, unless the backend works in TCP mode.
1798+
1799 ACL derivatives :
1800 ssl_fc_sni_end : suffix match
1801 ssl_fc_sni_reg : regex match
1802@@ -22093,8 +22151,8 @@ Optionally, a prefix could be used to force the address family and/or the
1803 socket type and the transport method.
1804
1805
1806-11.1 Address family prefixes
1807-----------------------------
1808+11.1. Address family prefixes
1809+-----------------------------
1810
1811 'abns@<name>' following <name> is an abstract namespace (Linux only).
1812
1813@@ -22129,8 +22187,8 @@ socket type and the transport method.
1814 start by slash '/'.
1815
1816
1817-11.2 Socket type prefixes
1818--------------------------
1819+11.2. Socket type prefixes
1820+--------------------------
1821
1822 Previous "Address family prefixes" can also be prefixed to force the socket
1823 type and the transport method. The default depends of the statement using
1824@@ -22139,7 +22197,7 @@ This is the case for "log" statement where the default is syslog over UDP
1825 but we could force to use syslog over TCP.
1826
1827 Those prefixes were designed for internal purpose and users should
1828-instead use aliases of the next section "11.5.3 Protocol prefixes".
1829+instead use aliases of the next section "11.3 Protocol prefixes".
1830
1831 If users need one those prefixes to perform what they expect because
1832 they can not configure the same using the protocol prefixes, they should
1833@@ -22152,8 +22210,8 @@ report this to the maintainers.
1834 to "datagram".
1835
1836
1837-11.3 Protocol prefixes
1838-----------------------
1839+11.3. Protocol prefixes
1840+-----------------------
1841
1842 'tcp@<address>[:port1[-port2]]' following <address> is considered as an IPv4
1843 or IPv6 address depending of the syntax but
1844@@ -22190,14 +22248,14 @@ report this to the maintainers.
1845 method is forced to "datagram". Depending on
1846 the statement using this address, a port or
1847 port range can or must be specified.
1848- It is considered as an alias of 'stream+ipv4@'.
1849+ It is considered as an alias of 'dgram+ipv4@'.
1850
1851 'udp6@<address>[:port1[-port2]]' following <address> is always considered as
1852 an IPv6 address but socket type and transport
1853 method is forced to "datagram". Depending on
1854 the statement using this address, a port or
1855 port range can or must be specified.
1856- It is considered as an alias of 'stream+ipv4@'.
1857+ It is considered as an alias of 'dgram+ipv4@'.
1858
1859 'uxdg@<path>' following string is considered as a unix socket <path> but
1860 transport method is forced to "datagram". It is considered as
1861diff --git a/doc/intro.txt b/doc/intro.txt
1862index 325ba76..d6e8648 100644
1863--- a/doc/intro.txt
1864+++ b/doc/intro.txt
1865@@ -41,6 +41,7 @@ Summary
1866 3.3.5. Load balancing
1867 3.3.6. Stickiness
1868 3.3.7. Logging
1869+3.3.8. Statistics
1870 3.4. Standard features
1871 3.4.1. Sampling and converting information
1872 3.4.2. Maps
1873@@ -50,7 +51,6 @@ Summary
1874 3.4.6. Formatted strings
1875 3.4.7. HTTP rewriting and redirection
1876 3.4.8. Server protection
1877-3.4.9. Statistics
1878 3.5. Advanced features
1879 3.5.1. Management
1880 3.5.2. System-specific capabilities
1881diff --git a/doc/management.txt b/doc/management.txt
1882index 56e4f66..56f119e 100644
1883--- a/doc/management.txt
1884+++ b/doc/management.txt
1885@@ -2919,6 +2919,10 @@ show ssl crt-list [-n] [<filename>]
1886 ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com
1887 ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
1888
1889+show startup-logs
1890+ Dump all messages emitted during the startup of the current haproxy process,
1891+ each startup-logs buffer is unique to its haproxy worker.
1892+
1893 show table
1894 Dump general information on all known stick-tables. Their name is returned
1895 (the name of the proxy which holds them), their type (currently zero, always
1896diff --git a/doc/proxy-protocol.txt b/doc/proxy-protocol.txt
1897index 4d49d5c..fac0331 100644
1898--- a/doc/proxy-protocol.txt
1899+++ b/doc/proxy-protocol.txt
1900@@ -500,7 +500,7 @@ protocol. Identifying the protocol version is easy :
1901 - if the incoming byte count is 16 or above and the 13 first bytes match
1902 the protocol signature block followed by the protocol version 2 :
1903
1904- \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02
1905+ \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x20
1906
1907 - otherwise, if the incoming byte count is 8 or above, and the 5 first
1908 characters match the US-ASCII representation of "PROXY" then the protocol
1909diff --git a/include/haproxy/buf.h b/include/haproxy/buf.h
1910index 6cfd9d3..fc7b6fb 100644
1911--- a/include/haproxy/buf.h
1912+++ b/include/haproxy/buf.h
1913@@ -445,7 +445,7 @@ static inline void b_slow_realign(struct buffer *b, char *swap, size_t output)
1914
1915 /* process output data in two steps to cover wrapping */
1916 if (block1 > b_size(b) - b_head_ofs(b)) {
1917- block2 = b_size(b) - b_head_ofs(b);
1918+ block2 = b_peek_ofs(b, block1);
1919 block1 -= block2;
1920 }
1921 memcpy(swap + b_size(b) - output, b_head(b), block1);
1922diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h
1923index a2a9f6d..445dd7c 100644
1924--- a/include/haproxy/bug.h
1925+++ b/include/haproxy/bug.h
1926@@ -42,8 +42,10 @@ static inline __attribute((always_inline)) void ha_crash_now(void)
1927 #if __GNUC_PREREQ__(5, 0)
1928 #pragma GCC diagnostic push
1929 #pragma GCC diagnostic ignored "-Warray-bounds"
1930+#if __GNUC_PREREQ__(6, 0)
1931 #pragma GCC diagnostic ignored "-Wnull-dereference"
1932 #endif
1933+#endif
1934 *(volatile char *)1 = 0;
1935 #if __GNUC_PREREQ__(5, 0)
1936 #pragma GCC diagnostic pop
1937diff --git a/include/haproxy/http.h b/include/haproxy/http.h
1938index d0f3fd2..8a86cb6 100644
1939--- a/include/haproxy/http.h
1940+++ b/include/haproxy/http.h
1941@@ -36,6 +36,8 @@ extern const uint8_t http_char_classes[256];
1942 enum http_meth_t find_http_meth(const char *str, const int len);
1943 int http_get_status_idx(unsigned int status);
1944 const char *http_get_reason(unsigned int status);
1945+struct ist http_get_host_port(const struct ist host);
1946+int http_is_default_port(const struct ist schm, const struct ist port);
1947 int http_validate_scheme(const struct ist schm);
1948 struct ist http_get_scheme(const struct ist uri);
1949 struct ist http_get_authority(const struct ist uri, int no_userinfo);
1950diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h
1951index c350290..476e65a 100644
1952--- a/include/haproxy/listener-t.h
1953+++ b/include/haproxy/listener-t.h
1954@@ -156,12 +156,21 @@ struct ssl_bind_conf {
1955 #endif
1956 };
1957
1958+/*
1959+ * In OpenSSL 3.0.0, the biggest verify error code's value is 94 and on the
1960+ * latest 1.1.1 it already reaches 79 so we need to size the ca/crt-ignore-err
1961+ * arrays accordingly. If the max error code increases, the arrays might need to
1962+ * be resized.
1963+ */
1964+#define SSL_MAX_VFY_ERROR_CODE 94
1965+#define IGNERR_BF_SIZE ((SSL_MAX_VFY_ERROR_CODE >> 6) + 1)
1966+
1967 /* "bind" line settings */
1968 struct bind_conf {
1969 #ifdef USE_OPENSSL
1970 struct ssl_bind_conf ssl_conf; /* ssl conf for ctx setting */
1971- unsigned long long ca_ignerr; /* ignored verify errors in handshake if depth > 0 */
1972- unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */
1973+ unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */
1974+ unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */
1975 SSL_CTX *initial_ctx; /* SSL context for initial negotiation */
1976 SSL_CTX *default_ctx; /* SSL context of first/default certificate */
1977 struct ssl_bind_conf *default_ssl_conf; /* custom SSL conf of default_ctx */
1978diff --git a/include/haproxy/listener.h b/include/haproxy/listener.h
1979index 3fb078f..bb502c6 100644
1980--- a/include/haproxy/listener.h
1981+++ b/include/haproxy/listener.h
1982@@ -39,23 +39,29 @@ void listener_set_state(struct listener *l, enum li_state st);
1983 * closes upon SHUT_WR and refuses to rebind. So a common validation path
1984 * involves SHUT_WR && listen && SHUT_RD. In case of success, the FD's polling
1985 * is disabled. It normally returns non-zero, unless an error is reported.
1986+ * It will need to operate under the proxy's lock. The caller is
1987+ * responsible for indicating in lpx whether the proxy locks is
1988+ * already held (non-zero) or not (zero) so that the function picks it.
1989 */
1990-int pause_listener(struct listener *l);
1991+int pause_listener(struct listener *l, int lpx);
1992
1993 /* This function tries to resume a temporarily disabled listener.
1994 * The resulting state will either be LI_READY or LI_FULL. 0 is returned
1995 * in case of failure to resume (eg: dead socket).
1996+ * It will need to operate under the proxy's lock. The caller is
1997+ * responsible for indicating in lpx whether the proxy locks is
1998+ * already held (non-zero) or not (zero) so that the function picks it.
1999 */
2000-int resume_listener(struct listener *l);
2001+int resume_listener(struct listener *l, int lpx);
2002
2003 /*
2004 * This function completely stops a listener. It will need to operate under the
2005- * proxy's lock, the protocol's lock, and the listener's lock. The caller is
2006- * responsible for indicating in lpx, lpr, lli whether the respective locks are
2007+ * proxy's lock and the protocol's lock. The caller is
2008+ * responsible for indicating in lpx, lpr whether the respective locks are
2009 * already held (non-zero) or not (zero) so that the function picks the missing
2010 * ones, in this order.
2011 */
2012-void stop_listener(struct listener *l, int lpx, int lpr, int lli);
2013+void stop_listener(struct listener *l, int lpx, int lpr);
2014
2015 /* This function adds the specified listener's file descriptor to the polling
2016 * lists if it is in the LI_LISTEN state. The listener enters LI_READY or
2017diff --git a/include/haproxy/peers-t.h b/include/haproxy/peers-t.h
2018index ee9d905..93920fd 100644
2019--- a/include/haproxy/peers-t.h
2020+++ b/include/haproxy/peers-t.h
2021@@ -31,6 +31,7 @@
2022
2023 #include <haproxy/api-t.h>
2024 #include <haproxy/dict-t.h>
2025+#include <haproxy/stick_table-t.h>
2026 #include <haproxy/thread-t.h>
2027
2028
2029diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h
2030index 9264998..0547dcb 100644
2031--- a/include/haproxy/pool.h
2032+++ b/include/haproxy/pool.h
2033@@ -55,8 +55,8 @@ void pool_free_nocache(struct pool_head *pool, void *ptr);
2034 void dump_pools_to_trash();
2035 void dump_pools(void);
2036 int pool_total_failures();
2037-unsigned long pool_total_allocated();
2038-unsigned long pool_total_used();
2039+unsigned long long pool_total_allocated();
2040+unsigned long long pool_total_used();
2041 void pool_flush(struct pool_head *pool);
2042 void pool_gc(struct pool_head *pool_ctx);
2043 struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags);
2044diff --git a/include/haproxy/server.h b/include/haproxy/server.h
2045index c927de3..fdb285c 100644
2046--- a/include/haproxy/server.h
2047+++ b/include/haproxy/server.h
2048@@ -45,6 +45,7 @@ extern struct dict server_key_dict;
2049 int srv_downtime(const struct server *s);
2050 int srv_lastsession(const struct server *s);
2051 int srv_getinter(const struct check *check);
2052+void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl);
2053 int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, const struct proxy *defproxy, int parse_flags);
2054 int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater);
2055 const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater);
2056@@ -254,18 +255,21 @@ static inline enum srv_initaddr srv_get_next_initaddr(unsigned int *list)
2057
2058 static inline void srv_use_conn(struct server *srv, struct connection *conn)
2059 {
2060- unsigned int curr;
2061+ unsigned int curr, prev;
2062
2063 curr = _HA_ATOMIC_ADD_FETCH(&srv->curr_used_conns, 1);
2064
2065+
2066 /* It's ok not to do that atomically, we don't need an
2067 * exact max.
2068 */
2069- if (srv->max_used_conns < curr)
2070- srv->max_used_conns = curr;
2071+ prev = HA_ATOMIC_LOAD(&srv->max_used_conns);
2072+ if (prev < curr)
2073+ HA_ATOMIC_STORE(&srv->max_used_conns, curr);
2074
2075- if (srv->est_need_conns < curr)
2076- srv->est_need_conns = curr;
2077+ prev = HA_ATOMIC_LOAD(&srv->est_need_conns);
2078+ if (prev < curr)
2079+ HA_ATOMIC_STORE(&srv->est_need_conns, curr);
2080 }
2081
2082 static inline void conn_delete_from_tree(struct ebmb_node *node)
2083diff --git a/include/haproxy/sink.h b/include/haproxy/sink.h
2084index 51d507c..a9f8099 100644
2085--- a/include/haproxy/sink.h
2086+++ b/include/haproxy/sink.h
2087@@ -28,6 +28,8 @@
2088
2089 extern struct list sink_list;
2090
2091+extern struct proxy *sink_proxies_list;
2092+
2093 struct sink *sink_find(const char *name);
2094 struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt, int fd);
2095 ssize_t __sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
2096diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h
2097index 974b836..35270ca 100644
2098--- a/include/haproxy/ssl_sock-t.h
2099+++ b/include/haproxy/ssl_sock-t.h
2100@@ -52,16 +52,20 @@
2101 #define SSL_SOCK_SEND_UNLIMITED 0x00000004
2102 #define SSL_SOCK_RECV_HEARTBEAT 0x00000008
2103
2104-/* bits 0xFFFF0000 are reserved to store verify errors */
2105+/* bits 0xFFFFFF00 are reserved to store verify errors.
2106+ * The CA en CRT error codes will be stored on 7 bits each
2107+ * (since the max verify error code does not exceed 127)
2108+ * and the CA error depth will be stored on 4 bits.
2109+ */
2110
2111 /* Verify errors macros */
2112-#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 63) ? 63 : e) << (16))
2113-#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (6+16))
2114-#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 63) ? 63 : e) << (4+6+16))
2115+#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 127) ? 127 : e) << (8))
2116+#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (7+8))
2117+#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 127) ? 127 : e) << (4+7+8))
2118
2119-#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (16)) & 63)
2120-#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15)
2121-#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63)
2122+#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (8)) & 127)
2123+#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (7+8)) & 15)
2124+#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+7+8)) & 127)
2125
2126 /* ssl_methods flags for ssl options */
2127 #define MC_SSL_O_ALL 0x0000
2128diff --git a/include/haproxy/ssl_sock.h b/include/haproxy/ssl_sock.h
2129index c68425a..9db4ec4 100644
2130--- a/include/haproxy/ssl_sock.h
2131+++ b/include/haproxy/ssl_sock.h
2132@@ -149,6 +149,29 @@ int ssl_sock_is_ssl(struct connection *conn)
2133 return 1;
2134 }
2135
2136+static inline int cert_ignerr_bitfield_get(const unsigned long long *bitfield, int bit_index)
2137+{
2138+ int byte_index = bit_index >> 6;
2139+ int val = 0;
2140+
2141+ if (byte_index < IGNERR_BF_SIZE)
2142+ val = bitfield[byte_index] & (1ULL << (bit_index & 0x3F));
2143+
2144+ return val != 0;
2145+}
2146+
2147+static inline void cert_ignerr_bitfield_set(unsigned long long *bitfield, int bit_index)
2148+{
2149+ int byte_index = bit_index >> 6;
2150+
2151+ if (byte_index < IGNERR_BF_SIZE)
2152+ bitfield[byte_index] |= (1ULL << (bit_index & 0x3F));
2153+}
2154+
2155+static inline void cert_ignerr_bitfield_set_all(unsigned long long *bitfield)
2156+{
2157+ memset(bitfield, -1, IGNERR_BF_SIZE*sizeof(*bitfield));
2158+}
2159
2160 #endif /* USE_OPENSSL */
2161 #endif /* _HAPROXY_SSL_SOCK_H */
2162diff --git a/include/haproxy/stats-t.h b/include/haproxy/stats-t.h
2163index 17641f5..920a311 100644
2164--- a/include/haproxy/stats-t.h
2165+++ b/include/haproxy/stats-t.h
2166@@ -443,7 +443,9 @@ enum stat_field {
2167 ST_F_USED_CONN_CUR,
2168 ST_F_NEED_CONN_EST,
2169 ST_F_UWEIGHT,
2170+ ST_F_AGG_SRV_STATUS,
2171 ST_F_AGG_SRV_CHECK_STATUS,
2172+ ST_F_AGG_CHECK_STATUS,
2173
2174 /* must always be the last one */
2175 ST_F_TOTAL_FIELDS
2176diff --git a/include/haproxy/stream.h b/include/haproxy/stream.h
2177index 1ec87b1..5a61c20 100644
2178--- a/include/haproxy/stream.h
2179+++ b/include/haproxy/stream.h
2180@@ -337,7 +337,7 @@ static inline void stream_choose_redispatch(struct stream *s)
2181 ((s->be->conn_retries - si->conn_retries) %
2182 (s->be->conn_retries + 1 + s->be->redispatch_after) == 0))) ||
2183 (!(s->flags & SF_DIRECT) && s->be->srv_act > 1 &&
2184- ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR)))) {
2185+ ((s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_HI)))) {
2186 sess_change_server(s, NULL);
2187 if (may_dequeue_tasks(objt_server(s->target), s->be))
2188 process_srv_queue(objt_server(s->target), 0);
2189diff --git a/include/haproxy/task.h b/include/haproxy/task.h
2190index d31c893..b3ffdf2 100644
2191--- a/include/haproxy/task.h
2192+++ b/include/haproxy/task.h
2193@@ -281,7 +281,7 @@ static inline struct task *task_unlink_wq(struct task *t)
2194
2195 if (likely(task_in_wq(t))) {
2196 locked = t->state & TASK_SHARED_WQ;
2197- BUG_ON(!locked && t->thread_mask != tid_bit);
2198+ BUG_ON(!locked && t->thread_mask != tid_bit && !(global.mode & MODE_STOPPING));
2199 if (locked)
2200 HA_RWLOCK_WRLOCK(TASK_WQ_LOCK, &wq_lock);
2201 __task_unlink_wq(t);
2202@@ -526,6 +526,7 @@ static inline void tasklet_init(struct tasklet *t)
2203 t->process = NULL;
2204 t->tid = -1;
2205 #ifdef DEBUG_TASK
2206+ t->call_date = 0;
2207 t->debug.caller_idx = 0;
2208 #endif
2209 LIST_INIT(&t->list);
2210diff --git a/include/haproxy/tcpcheck-t.h b/include/haproxy/tcpcheck-t.h
2211index 29cb4cc..439fe18 100644
2212--- a/include/haproxy/tcpcheck-t.h
2213+++ b/include/haproxy/tcpcheck-t.h
2214@@ -35,6 +35,7 @@
2215 #define TCPCHK_OPT_DEFAULT_CONNECT 0x0008 /* Do a connect using server params */
2216 #define TCPCHK_OPT_IMPLICIT 0x0010 /* Implicit connect */
2217 #define TCPCHK_OPT_SOCKS4 0x0020 /* check the connection via socks4 proxy */
2218+#define TCPCHK_OPT_HAS_DATA 0x0040 /* data should be sent after conncetion */
2219
2220 enum tcpcheck_send_type {
2221 TCPCHK_SEND_UNDEF = 0, /* Send is not parsed. */
2222diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h
2223index a95844a..30b6bfa 100644
2224--- a/include/haproxy/tools.h
2225+++ b/include/haproxy/tools.h
2226@@ -406,7 +406,8 @@ char *encode_chunk(char *start, char *stop,
2227
2228 /*
2229 * Tries to prefix characters tagged in the <map> with the <escape>
2230- * character. The input <string> must be zero-terminated. The result will
2231+ * character. The input <string> is processed until string_stop
2232+ * is reached or NULL-byte is encountered. The result will
2233 * be stored between <start> (included) and <stop> (excluded). This
2234 * function will always try to terminate the resulting string with a '\0'
2235 * before <stop>, and will return its position if the conversion
2236@@ -414,7 +415,7 @@ char *encode_chunk(char *start, char *stop,
2237 */
2238 char *escape_string(char *start, char *stop,
2239 const char escape, const long *map,
2240- const char *string);
2241+ const char *string, const char *string_stop);
2242
2243 /*
2244 * Tries to prefix characters tagged in the <map> with the <escape>
2245diff --git a/include/import/ebmbtree.h b/include/import/ebmbtree.h
2246index f99c16b..2d63ed1 100644
2247--- a/include/import/ebmbtree.h
2248+++ b/include/import/ebmbtree.h
2249@@ -118,6 +118,59 @@ struct ebmb_node *ebmb_lookup_longest(struct eb_root *root, const void *x);
2250 struct ebmb_node *ebmb_lookup_prefix(struct eb_root *root, const void *x, unsigned int pfx);
2251 struct ebmb_node *ebmb_insert_prefix(struct eb_root *root, struct ebmb_node *new, unsigned int len);
2252
2253+/* start from a valid leaf and find the next matching prefix that's either a
2254+ * duplicate, or immediately shorter than the node's current one and still
2255+ * matches it. The purpose is to permit a caller that is not satisfied with a
2256+ * result provided by ebmb_lookup_longest() to evaluate the next matching
2257+ * entry. Given that shorter keys are necessarily attached to nodes located
2258+ * above the current one, it's sufficient to restart from the current leaf and
2259+ * go up until we find a shorter prefix, or a non-matching one.
2260+ */
2261+static inline struct ebmb_node *ebmb_lookup_shorter(struct ebmb_node *start)
2262+{
2263+ eb_troot_t *t = start->node.leaf_p;
2264+ struct ebmb_node *node;
2265+
2266+ /* first, chcek for duplicates */
2267+ node = ebmb_next_dup(start);
2268+ if (node)
2269+ return node;
2270+
2271+ while (1) {
2272+ if (eb_gettag(t) == EB_LEFT) {
2273+ /* Walking up from left branch. We must ensure that we never
2274+ * walk beyond root.
2275+ */
2276+ if (unlikely(eb_clrtag((eb_untag(t, EB_LEFT))->b[EB_RGHT]) == NULL))
2277+ return NULL;
2278+ node = container_of(eb_root_to_node(eb_untag(t, EB_LEFT)), struct ebmb_node, node);
2279+ } else {
2280+ /* Walking up from right branch, so we cannot be below
2281+ * root. However, if we end up on a node with an even
2282+ * and positive bit, this is a cover node, which mandates
2283+ * that the left branch only contains cover values, so we
2284+ * must descend it.
2285+ */
2286+ node = container_of(eb_root_to_node(eb_untag(t, EB_RGHT)), struct ebmb_node, node);
2287+ if (node->node.bit > 0 && !(node->node.bit & 1))
2288+ return ebmb_entry(eb_walk_down(t, EB_LEFT), struct ebmb_node, node);
2289+ }
2290+
2291+ /* Note that <t> cannot be NULL at this stage */
2292+ t = node->node.node_p;
2293+
2294+ /* this is a node attached to a deeper (and possibly different)
2295+ * leaf, not interesting for us.
2296+ */
2297+ if (node->node.pfx >= start->node.pfx)
2298+ continue;
2299+
2300+ if (check_bits(start->key, node->key, 0, node->node.pfx) == 0)
2301+ break;
2302+ }
2303+ return node;
2304+}
2305+
2306 /* The following functions are less likely to be used directly, because their
2307 * code is larger. The non-inlined version is preferred.
2308 */
2309diff --git a/reg-tests/cache/if-modified-since.vtc b/reg-tests/cache/if-modified-since.vtc
2310index 8ae1cce..387fc7e 100644
2311--- a/reg-tests/cache/if-modified-since.vtc
2312+++ b/reg-tests/cache/if-modified-since.vtc
2313@@ -62,6 +62,10 @@ haproxy h1 -conf {
2314 server www ${s1_addr}:${s1_port}
2315 http-response cache-store my_cache
2316
2317+ # Remove Transfer-Encoding header because of a vtest issue with
2318+ # 304-Not-Modified responses
2319+ http-after-response del-header transfer-encoding if { status eq 304 }
2320+
2321 cache my_cache
2322 total-max-size 3
2323 max-age 20
2324@@ -149,4 +153,3 @@ client c1 -connect ${h1_fe_sock} {
2325 expect resp.bodylen == 0
2326
2327 } -run
2328-
2329diff --git a/reg-tests/cache/if-none-match.vtc b/reg-tests/cache/if-none-match.vtc
2330index ba3336a..bc7d67b 100644
2331--- a/reg-tests/cache/if-none-match.vtc
2332+++ b/reg-tests/cache/if-none-match.vtc
2333@@ -47,6 +47,10 @@ haproxy h1 -conf {
2334 server www ${s1_addr}:${s1_port}
2335 http-response cache-store my_cache
2336
2337+ # Remove Transfer-Encoding header because of a vtest issue with
2338+ # 304-Not-Modified responses
2339+ http-after-response del-header transfer-encoding if { status eq 304 }
2340+
2341 cache my_cache
2342 total-max-size 3
2343 max-age 20
2344diff --git a/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc b/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc
2345index f9f37a1..ea72701 100644
2346--- a/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc
2347+++ b/reg-tests/checks/4be_1srv_smtpchk_httpchk_layer47errors.vtc
2348@@ -8,7 +8,7 @@ barrier b cond 3
2349
2350 syslog S1 -level notice {
2351 recv
2352- expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 succeeded.+reason: Layer7 check passed.+code: 2(20|48).+check duration: [[:digit:]]+ms.+status: 1/1 UP."
2353+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 succeeded.+reason: Layer7 check passed.+code: 221.+check duration: [[:digit:]]+ms.+status: 1/1 UP."
2354 barrier b sync
2355 recv
2356 expect ~ "Health check for server be1/srv1 failed.+reason: Layer7 timeout.+check duration: [[:digit:]]+ms.+status: 0/1 DOWN"
2357@@ -36,12 +36,17 @@ server s1 {
2358 send "2"
2359 send "2"
2360 send "0"
2361- send "\r\n\r\n"
2362+ send "\r\n"
2363 recv 16
2364 send "2"
2365 send "4"
2366 send "8"
2367- send "\r\n\r\n"
2368+ send "\r\n"
2369+ recv 6
2370+ send "2"
2371+ send "2"
2372+ send "1"
2373+ send " ok\r\n"
2374 } -start
2375
2376 server s2 {
2377diff --git a/reg-tests/checks/pgsql-check.vtc b/reg-tests/checks/pgsql-check.vtc
2378index 968a18c..05c5a71 100644
2379--- a/reg-tests/checks/pgsql-check.vtc
2380+++ b/reg-tests/checks/pgsql-check.vtc
2381@@ -23,6 +23,11 @@ server s3 {
2382 send "Not a PostgreSQL response"
2383 } -start
2384
2385+server s4 {
2386+ recv 23
2387+ sendhex "52000000170000000A534352414D2D5348412D3235360000"
2388+} -start
2389+
2390 syslog S1 -level notice {
2391 recv
2392 expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+info: \"PostgreSQL server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2393@@ -38,6 +43,10 @@ syslog S3 -level notice {
2394 expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be3/srv failed, reason: Layer7 wrong status.+info: \"PostgreSQL unknown error\".+check duration: [[:digit:]]+ms, status: 0/1 DOWN."
2395 } -start
2396
2397+syslog S4 -level notice {
2398+ recv
2399+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be4/srv succeeded, reason: Layer7 check passed.+info: \"PostgreSQL server is ok\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2400+} -start
2401
2402 haproxy h1 -conf {
2403 defaults
2404@@ -64,6 +73,12 @@ haproxy h1 -conf {
2405 option pgsql-check user postgres
2406 server srv ${s3_addr}:${s3_port} check inter 1s rise 1 fall 1
2407
2408+ backend be4
2409+ log ${S4_addr}:${S4_port} daemon
2410+ option log-health-checks
2411+ option pgsql-check user postgres
2412+ server srv ${s4_addr}:${s4_port} check inter 1s rise 1 fall 1
2413+
2414 listen pgsql1
2415 bind "fd@${pgsql}"
2416 tcp-request inspect-delay 100ms
2417@@ -75,3 +90,4 @@ haproxy h1 -conf {
2418 syslog S1 -wait
2419 syslog S2 -wait
2420 syslog S3 -wait
2421+syslog S4 -wait
2422diff --git a/reg-tests/checks/smtp-check.vtc b/reg-tests/checks/smtp-check.vtc
2423index 29d0ddb..9d8bb8a 100644
2424--- a/reg-tests/checks/smtp-check.vtc
2425+++ b/reg-tests/checks/smtp-check.vtc
2426@@ -10,6 +10,8 @@ server s1 {
2427 send "220 smtp-check.vtc SMTP Server\r\n"
2428 recv 16
2429 send "250 smtp-check.vtc\r\n"
2430+ recv 6
2431+ send "221 smtp-check.vtc closing\r\n"
2432 } -start
2433
2434 server s2 {
2435@@ -18,6 +20,8 @@ server s2 {
2436 send "250-smtp-check.vtc\r\n"
2437 send "250-KEYWORD\r\n"
2438 send "250 LAST KEYWORD\r\n"
2439+ recv 6
2440+ send "221 smtp-check.vtc closing\r\n"
2441 } -start
2442
2443 server s3 {
2444@@ -36,12 +40,12 @@ server s5 {
2445
2446 syslog S1 -level notice {
2447 recv
2448- expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+code: 250.+info: \"smtp-check.vtc\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2449+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv succeeded, reason: Layer7 check passed.+code: 221.+info: \"smtp-check.vtc closing\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2450 } -start
2451
2452 syslog S2 -level notice {
2453 recv
2454- expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv succeeded, reason: Layer7 check passed.+code: 250.+info: \"smtp-check.vtc\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2455+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be2/srv succeeded, reason: Layer7 check passed.+code: 221.+info: \"smtp-check.vtc closing\".+check duration: [[:digit:]]+ms, status: 1/1 UP."
2456 } -start
2457
2458 syslog S3 -level notice {
2459diff --git a/reg-tests/contrib/prometheus.vtc b/reg-tests/contrib/prometheus.vtc
2460index ebe0b87..766db47 100644
2461--- a/reg-tests/contrib/prometheus.vtc
2462+++ b/reg-tests/contrib/prometheus.vtc
2463@@ -8,12 +8,12 @@ feature ignore_unknown_macro
2464 server s1 {
2465 rxreq
2466 txresp
2467-} -repeat 2 -start
2468+} -start
2469
2470 server s2 {
2471 rxreq
2472 txresp
2473-} -repeat 2 -start
2474+} -start
2475
2476 haproxy h1 -conf {
2477 defaults
2478@@ -33,8 +33,9 @@ haproxy h1 -conf {
2479
2480 backend be
2481 stick-table type ip size 1m expire 10s store http_req_rate(10s)
2482+ option httpchk
2483 server s1 ${s1_addr}:${s1_port}
2484- server s2 ${s2_addr}:${s2_port} check maxqueue 10 maxconn 12 pool-max-conn 42
2485+ server s2 ${s2_addr}:${s2_port} check inter 5s maxqueue 10 maxconn 12 pool-max-conn 42
2486 } -start
2487
2488 client c1 -connect ${h1_stats_sock} {
2489diff --git a/reg-tests/converter/digest.vtc b/reg-tests/converter/digest.vtc
2490index a14f1cc..511daca 100644
2491--- a/reg-tests/converter/digest.vtc
2492+++ b/reg-tests/converter/digest.vtc
2493@@ -7,7 +7,7 @@ feature ignore_unknown_macro
2494
2495 server s1 {
2496 rxreq
2497- txresp
2498+ txresp -hdr "Connection: close"
2499 } -repeat 2 -start
2500
2501 haproxy h1 -conf {
2502diff --git a/reg-tests/converter/hmac.vtc b/reg-tests/converter/hmac.vtc
2503index f9d9d35..391e04a 100644
2504--- a/reg-tests/converter/hmac.vtc
2505+++ b/reg-tests/converter/hmac.vtc
2506@@ -7,7 +7,7 @@ feature ignore_unknown_macro
2507
2508 server s1 {
2509 rxreq
2510- txresp
2511+ txresp -hdr "Connection: close"
2512 } -repeat 2 -start
2513
2514 haproxy h1 -conf {
2515diff --git a/reg-tests/converter/iif.vtc b/reg-tests/converter/iif.vtc
2516index 22414e0..3a6d6a6 100644
2517--- a/reg-tests/converter/iif.vtc
2518+++ b/reg-tests/converter/iif.vtc
2519@@ -5,7 +5,7 @@ feature ignore_unknown_macro
2520
2521 server s1 {
2522 rxreq
2523- txresp
2524+ txresp -hdr "Connection: close"
2525 } -repeat 3 -start
2526
2527 haproxy h1 -conf {
2528diff --git a/reg-tests/converter/json_query.vtc b/reg-tests/converter/json_query.vtc
2529index b420942..9db77eb 100644
2530--- a/reg-tests/converter/json_query.vtc
2531+++ b/reg-tests/converter/json_query.vtc
2532@@ -5,7 +5,7 @@ feature ignore_unknown_macro
2533
2534 server s1 {
2535 rxreq
2536- txresp
2537+ txresp -hdr "Connection: close"
2538 } -repeat 8 -start
2539
2540 haproxy h1 -conf {
2541diff --git a/reg-tests/http-messaging/h1_host_normalization.vtc b/reg-tests/http-messaging/h1_host_normalization.vtc
2542new file mode 100644
2543index 0000000..6ea32d2
2544--- /dev/null
2545+++ b/reg-tests/http-messaging/h1_host_normalization.vtc
2546@@ -0,0 +1,276 @@
2547+varnishtest "H1 authority validation and host normalizarion based on the scheme (rfc3982 6.3.2) or the method (connect)"
2548+
2549+#REQUIRE_VERSION=2.4
2550+feature ignore_unknown_macro
2551+
2552+syslog S1 -level info {
2553+ # C1
2554+ recv
2555+ expect ~ "^.* uri: GET http://toto:poue@hostname/c1 HTTP/1.1; host: {hostname}$"
2556+
2557+ # C2
2558+ recv
2559+ expect ~ "^.* uri: GET http://hostname:8080/c2 HTTP/1.1; host: {hostname:8080}$"
2560+
2561+ # C3
2562+ recv
2563+ expect ~ "^.* uri: GET https://hostname/c3 HTTP/1.1; host: {hostname}$"
2564+
2565+ # C4
2566+ recv
2567+ expect ~ "^.* uri: GET https://hostname:80/c4 HTTP/1.1; host: {hostname:80}$"
2568+
2569+ # C5
2570+ recv
2571+ expect ~ "^.* uri: CONNECT hostname:80 HTTP/1.1; host: {hostname}$"
2572+ recv
2573+ expect ~ "^.* uri: CONNECT hostname:80 HTTP/1.1; host: {hostname}$"
2574+
2575+ # C6
2576+ recv
2577+ expect ~ "^.* uri: CONNECT hostname:443 HTTP/1.1; host: {hostname}$"
2578+ recv
2579+ expect ~ "^.* uri: CONNECT hostname:443 HTTP/1.1; host: {hostname}$"
2580+
2581+ recv
2582+ expect ~ "^.* uri: CONNECT hostname:8443 HTTP/1.1; host: {hostname:8443}$"
2583+} -start
2584+
2585+haproxy h1 -conf {
2586+ defaults
2587+ mode http
2588+ timeout connect 1s
2589+ timeout client 1s
2590+ timeout server 1s
2591+
2592+ frontend fe
2593+ bind "fd@${fe}"
2594+
2595+ http-request capture req.hdr(host) len 512
2596+ log-format "uri: %r; host: %hr"
2597+ log ${S1_addr}:${S1_port} len 2048 local0 debug err
2598+
2599+ http-request return status 200
2600+} -start
2601+
2602+# default port 80 with http scheme => should be normalized
2603+# Be sure userinfo are skipped
2604+client c1 -connect ${h1_fe_sock} {
2605+ txreq \
2606+ -req "GET" \
2607+ -url "http://toto:poue@hostname:80/c1" \
2608+ -hdr "host: hostname:80"
2609+
2610+ rxresp
2611+ expect resp.status == 200
2612+} -run
2613+
2614+# port 8080 with http scheme => no normalization
2615+client c2 -connect ${h1_fe_sock} {
2616+ txreq \
2617+ -req "GET" \
2618+ -url "http://hostname:8080/c2" \
2619+ -hdr "host: hostname:8080"
2620+
2621+ rxresp
2622+ expect resp.status == 200
2623+} -run
2624+
2625+# default port 443 with https scheme => should be normalized
2626+client c3 -connect ${h1_fe_sock} {
2627+ txreq \
2628+ -req "GET" \
2629+ -url "https://hostname:443/c3" \
2630+ -hdr "host: hostname:443"
2631+
2632+ rxresp
2633+ expect resp.status == 200
2634+} -run
2635+
2636+# port 80 with https scheme => no normalization
2637+client c4 -connect ${h1_fe_sock} {
2638+ txreq \
2639+ -req "GET" \
2640+ -url "https://hostname:80/c4" \
2641+ -hdr "host: hostname:80"
2642+
2643+ rxresp
2644+ expect resp.status == 200
2645+} -run
2646+
2647+# CONNECT on port 80 => should be normalized
2648+client c5 -connect ${h1_fe_sock} {
2649+ txreq \
2650+ -req "CONNECT" \
2651+ -url "hostname:80" \
2652+ -hdr "host: hostname:80"
2653+
2654+ rxresp
2655+ expect resp.status == 200
2656+} -run
2657+client c5 -connect ${h1_fe_sock} {
2658+
2659+ txreq \
2660+ -req "CONNECT" \
2661+ -url "hostname:80" \
2662+ -hdr "host: hostname"
2663+
2664+ rxresp
2665+ expect resp.status == 200
2666+} -run
2667+
2668+# CONNECT on port 443 => should be normalized
2669+client c6 -connect ${h1_fe_sock} {
2670+ txreq \
2671+ -req "CONNECT" \
2672+ -url "hostname:443" \
2673+ -hdr "host: hostname:443"
2674+
2675+ rxresp
2676+ expect resp.status == 200
2677+} -run
2678+client c6 -connect ${h1_fe_sock} {
2679+ txreq \
2680+ -req "CONNECT" \
2681+ -url "hostname:443" \
2682+ -hdr "host: hostname"
2683+
2684+ rxresp
2685+ expect resp.status == 200
2686+} -run
2687+
2688+# CONNECT on port non-default port => no normalization
2689+client c7 -connect ${h1_fe_sock} {
2690+ txreq \
2691+ -req "CONNECT" \
2692+ -url "hostname:8443" \
2693+ -hdr "host: hostname:8443"
2694+
2695+ rxresp
2696+ expect resp.status == 200
2697+} -run
2698+
2699+# host miss-match => error
2700+client c8 -connect ${h1_fe_sock} {
2701+ txreq \
2702+ -req "GET" \
2703+ -url "http://hostname1/" \
2704+ -hdr "host: hostname2"
2705+
2706+ rxresp
2707+ expect resp.status == 400
2708+} -run
2709+
2710+# port miss-match => error
2711+client c9 -connect ${h1_fe_sock} {
2712+ txreq \
2713+ -req "GET" \
2714+ -url "http://hostname:80/" \
2715+ -hdr "host: hostname:81"
2716+
2717+ rxresp
2718+ expect resp.status == 400
2719+} -run
2720+
2721+# no host port with a non-default port in abs-uri => error
2722+client c10 -connect ${h1_fe_sock} {
2723+ txreq \
2724+ -req "GET" \
2725+ -url "http://hostname:8080/" \
2726+ -hdr "host: hostname"
2727+
2728+ rxresp
2729+ expect resp.status == 400
2730+} -run
2731+
2732+# non-default host port with a default in abs-uri => error
2733+client c11 -connect ${h1_fe_sock} {
2734+ txreq \
2735+ -req "GET" \
2736+ -url "http://hostname/" \
2737+ -hdr "host: hostname:81"
2738+
2739+ rxresp
2740+ expect resp.status == 400
2741+} -run
2742+
2743+# miss-match between host headers => error
2744+client c12 -connect ${h1_fe_sock} {
2745+ txreq \
2746+ -req "GET" \
2747+ -url "http://hostname1/" \
2748+ -hdr "host: hostname1" \
2749+ -hdr "host: hostname2"
2750+
2751+ rxresp
2752+ expect resp.status == 400
2753+} -run
2754+
2755+# miss-match between host headers but with a normalization => error
2756+client c13 -connect ${h1_fe_sock} {
2757+ txreq \
2758+ -req "GET" \
2759+ -url "http://hostname1/" \
2760+ -hdr "host: hostname1:80" \
2761+ -hdr "host: hostname1"
2762+
2763+ rxresp
2764+ expect resp.status == 400
2765+} -run
2766+
2767+# CONNECT authoriy without port => error
2768+client c14 -connect ${h1_fe_sock} {
2769+ txreq \
2770+ -req "CONNECT" \
2771+ -url "hostname" \
2772+ -hdr "host: hostname"
2773+
2774+ rxresp
2775+ expect resp.status == 400
2776+} -run
2777+
2778+# host miss-match with CONNECT => error
2779+client c15 -connect ${h1_fe_sock} {
2780+ txreq \
2781+ -req "CONNECT" \
2782+ -url "hostname1:80" \
2783+ -hdr "host: hostname2:80"
2784+
2785+ rxresp
2786+ expect resp.status == 400
2787+} -run
2788+
2789+# port miss-match with CONNECT => error
2790+client c16 -connect ${h1_fe_sock} {
2791+ txreq \
2792+ -req "CONNECT" \
2793+ -url "hostname:80" \
2794+ -hdr "host: hostname:443"
2795+
2796+ rxresp
2797+ expect resp.status == 400
2798+} -run
2799+
2800+# no host port with non-default port in CONNECT authority => error
2801+client c17 -connect ${h1_fe_sock} {
2802+ txreq \
2803+ -req "CONNECT" \
2804+ -url "hostname:8080" \
2805+ -hdr "host: hostname"
2806+
2807+ rxresp
2808+ expect resp.status == 400
2809+} -run
2810+
2811+# no authority => error
2812+client c18 -connect ${h1_fe_sock} {
2813+ txreq \
2814+ -req "CONNECT" \
2815+ -url "/" \
2816+ -hdr "host: hostname"
2817+
2818+ rxresp
2819+ expect resp.status == 400
2820+} -run
2821+
2822+syslog S1 -wait
2823diff --git a/reg-tests/http-messaging/http_request_buffer.vtc b/reg-tests/http-messaging/http_request_buffer.vtc
2824index f1cec1a..e712e32 100644
2825--- a/reg-tests/http-messaging/http_request_buffer.vtc
2826+++ b/reg-tests/http-messaging/http_request_buffer.vtc
2827@@ -9,6 +9,8 @@ feature ignore_unknown_macro
2828 # thanks to "http-buffer-request". If this was the case, c2 client
2829 # could not connect to s1 server and this would lead to make this test fail.
2830
2831+barrier b1 cond 2 -cyclic
2832+
2833 server s1 {
2834 rxreq
2835 expect req.bodylen == 257
2836@@ -23,11 +25,17 @@ server s1 {
2837
2838 syslog S -level info {
2839 recv
2840- expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 fe1/<NOSRV> .* 408 .* - - cD-- .* .* \"GET /this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url HTTP/1\\.1\""
2841+ expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 fe1/<NOSRV> .* 408 .* - - cR-- .* .* \"GET /this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url HTTP/1\\.1\""
2842+ barrier b1 sync
2843+
2844 recv
2845 expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\""
2846+ barrier b1 sync
2847+
2848 recv
2849 expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\""
2850+ barrier b1 sync
2851+
2852 recv
2853 expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* -1 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\""
2854 } -start
2855@@ -88,6 +96,9 @@ client c1 -connect ${h1_fe1_sock} {
2856 expect resp.status == 408
2857 } -run
2858
2859+# Wait matching on log message
2860+barrier b1 sync
2861+
2862 # Payload is fully sent
2863 # ==> Request must be sent to the server. A 200 must be received
2864 client c2 -connect ${h1_fe1_sock} {
2865@@ -96,6 +107,9 @@ client c2 -connect ${h1_fe1_sock} {
2866 expect resp.status == 200
2867 } -run
2868
2869+# Wait matching on log message
2870+barrier b1 sync
2871+
2872 # Payload is fully sent in 2 steps (with a small delay, smaller than the client
2873 # timeout) and splitted on a chunk size.
2874 # ==> Request must be sent to the server. A 200 must be received
2875@@ -107,6 +121,9 @@ client c3 -connect ${h1_fe2_sock} {
2876 expect resp.status == 200
2877 } -run
2878
2879+# Wait matching on log message
2880+barrier b1 sync
2881+
2882 # Last CRLF of the request payload is missing but payload is sent in 2 steps
2883 # (with a small delay, smaller than the client timeout) and splitted on a chunk
2884 # size. The client aborts before sending the last CRLF.
2885diff --git a/reg-tests/http-rules/restrict_req_hdr_names.vtc b/reg-tests/http-rules/restrict_req_hdr_names.vtc
2886index 57bc7e1..b493c84 100644
2887--- a/reg-tests/http-rules/restrict_req_hdr_names.vtc
2888+++ b/reg-tests/http-rules/restrict_req_hdr_names.vtc
2889@@ -35,6 +35,32 @@ server s5 {
2890 txresp
2891 } -start
2892
2893+server s6 {
2894+ rxreq
2895+ expect req.http.x_my_hdr_with_lots_of_underscores == <undef>
2896+ txresp
2897+} -start
2898+
2899+server s7 {
2900+ rxreq
2901+ expect req.http.x_my_hdr-1 == <undef>
2902+ expect req.http.x-my-hdr-2 == on
2903+ txresp
2904+} -start
2905+
2906+server s8 {
2907+ rxreq
2908+ expect req.http.x-my_hdr-1 == <undef>
2909+ expect req.http.x-my_hdr-2 == <undef>
2910+ txresp
2911+} -start
2912+
2913+server s9 {
2914+ rxreq
2915+ expect req.http.x-my-hdr-with-trailing-underscore_ == <undef>
2916+ txresp
2917+} -start
2918+
2919 haproxy h1 -conf {
2920 defaults
2921 mode http
2922@@ -50,6 +76,10 @@ haproxy h1 -conf {
2923 use_backend be-fcgi1 if { path /req4 }
2924 use_backend be-fcgi2 if { path /req5 }
2925 use_backend be-fcgi3 if { path /req6 }
2926+ use_backend be-http4 if { path /req7 }
2927+ use_backend be-http5 if { path /req8 }
2928+ use_backend be-http6 if { path /req9 }
2929+ use_backend be-http7 if { path /req10 }
2930
2931 backend be-http1
2932 server s1 ${s1_addr}:${s1_port}
2933@@ -72,6 +102,22 @@ haproxy h1 -conf {
2934 backend be-fcgi3
2935 option http-restrict-req-hdr-names reject
2936
2937+ backend be-http4
2938+ option http-restrict-req-hdr-names delete
2939+ server s6 ${s6_addr}:${s6_port}
2940+
2941+ backend be-http5
2942+ option http-restrict-req-hdr-names delete
2943+ server s7 ${s7_addr}:${s7_port}
2944+
2945+ backend be-http6
2946+ option http-restrict-req-hdr-names delete
2947+ server s8 ${s8_addr}:${s8_port}
2948+
2949+ backend be-http7
2950+ option http-restrict-req-hdr-names delete
2951+ server s9 ${s9_addr}:${s9_port}
2952+
2953 defaults
2954 mode http
2955 timeout connect 1s
2956@@ -114,6 +160,22 @@ client c1 -connect ${h1_fe1_sock} {
2957 txreq -req GET -url /req6 -hdr "X-my_hdr: on"
2958 rxresp
2959 expect resp.status == 403
2960+
2961+ txreq -req GET -url /req7 -hdr "X_my_hdr_with_lots_of_underscores: on"
2962+ rxresp
2963+ expect resp.status == 200
2964+
2965+ txreq -req GET -url /req8 -hdr "X_my_hdr-1: on" -hdr "X-my-hdr-2: on"
2966+ rxresp
2967+ expect resp.status == 200
2968+
2969+ txreq -req GET -url /req9 -hdr "X-my_hdr-1: on" -hdr "X-my_hdr-2: on"
2970+ rxresp
2971+ expect resp.status == 200
2972+
2973+ txreq -req GET -url /req10 -hdr "X-my-hdr-with-trailing-underscore_: on"
2974+ rxresp
2975+ expect resp.status == 200
2976 } -run
2977
2978 client c2 -connect ${h1_fe2_sock} {
2979diff --git a/reg-tests/log/log_forward.vtc b/reg-tests/log/log_forward.vtc
2980new file mode 100644
2981index 0000000..3977f4c
2982--- /dev/null
2983+++ b/reg-tests/log/log_forward.vtc
2984@@ -0,0 +1,57 @@
2985+varnishtest "Test the TCP load-forward"
2986+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.3-dev1)'"
2987+feature ignore_unknown_macro
2988+
2989+server s1 {
2990+ rxreq
2991+ txresp
2992+} -repeat 500 -start
2993+
2994+syslog Slg1 -level info {
2995+ recv
2996+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c1 HTTP/1.1\""
2997+} -repeat 50 -start
2998+
2999+haproxy h1 -conf {
3000+ defaults
3001+ mode http
3002+ option httplog
3003+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
3004+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
3005+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
3006+
3007+ frontend fe1
3008+ bind "fd@${fe_1}"
3009+ log 127.0.0.1:1514 local0
3010+# log ${Slg1_addr}:${Slg1_port} local0
3011+ default_backend be
3012+
3013+ backend be
3014+ server app1 ${s1_addr}:${s1_port}
3015+
3016+ ring myring
3017+ description "My local buffer"
3018+ format rfc5424
3019+ maxlen 1200
3020+ size 32764
3021+ timeout connect 5s
3022+ timeout server 10s
3023+ # syslog tcp server
3024+ server mysyslogsrv 127.0.0.1:2514
3025+
3026+ log-forward syslog2tcp
3027+ dgram-bind 127.0.0.1:1514
3028+ log ring@myring local0 # To TCP log
3029+
3030+ log-forward syslog2local
3031+ bind 127.0.0.1:2514
3032+ log ${Slg1_addr}:${Slg1_port} local0 # To VTest syslog
3033+} -start
3034+
3035+client c1 -connect ${h1_fe_1_sock} {
3036+ txreq -url "/client_c1"
3037+ rxresp
3038+ expect resp.status == 200
3039+} -repeat 50 -start
3040+
3041+syslog Slg1 -wait
3042diff --git a/reg-tests/mailers/healthcheckmail.vtc b/reg-tests/mailers/healthcheckmail.vtc
3043index 43bf588..d36a0d3 100644
3044--- a/reg-tests/mailers/healthcheckmail.vtc
3045+++ b/reg-tests/mailers/healthcheckmail.vtc
3046@@ -5,7 +5,7 @@ feature ignore_unknown_macro
3047
3048 syslog S1 -level notice {
3049 recv
3050- expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.+reason: Socket error.+info: \".+\".+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
3051+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Health check for server be1/srv1 failed.+check duration: [[:digit:]]+ms.+status: 0/1 DOWN."
3052 recv info
3053 expect ~ "[^:\\[ ]\\[${h1_pid}\\]: Result=SUCCESS Bytes=[[:digit:]]+"
3054 } -start
3055diff --git a/reg-tests/ssl/log_forward_ssl.vtc b/reg-tests/ssl/log_forward_ssl.vtc
3056new file mode 100644
3057index 0000000..6b7515b
3058--- /dev/null
3059+++ b/reg-tests/ssl/log_forward_ssl.vtc
3060@@ -0,0 +1,60 @@
3061+varnishtest "Test the TCP+SSL load-forward"
3062+feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.3-dev1)'"
3063+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
3064+feature ignore_unknown_macro
3065+
3066+server s1 {
3067+ rxreq
3068+ txresp
3069+} -repeat 500 -start
3070+
3071+syslog Slg1 -level info {
3072+ recv
3073+ expect ~ "[^:\\[ ]\\[${h1_pid}\\]: .* \"GET /client_c1 HTTP/1.1\""
3074+} -repeat 50 -start
3075+
3076+haproxy h1 -conf {
3077+ global
3078+ insecure-fork-wanted
3079+ defaults
3080+ mode http
3081+ option httplog
3082+ timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
3083+ timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
3084+ timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
3085+
3086+ frontend fe1
3087+ bind "fd@${fe_1}"
3088+ log 127.0.0.1:1514 local0
3089+# log ${Slg1_addr}:${Slg1_port} local0
3090+ default_backend be
3091+
3092+ backend be
3093+ server app1 ${s1_addr}:${s1_port}
3094+
3095+ ring myring
3096+ description "My local buffer"
3097+ format rfc5424
3098+ maxlen 1200
3099+ size 32764
3100+ timeout connect 5s
3101+ timeout server 10s
3102+ # syslog tcp server
3103+ server mysyslogsrv 127.0.0.1:2514 ssl verify none
3104+
3105+ log-forward syslog2tcp
3106+ dgram-bind 127.0.0.1:1514
3107+ log ring@myring local0 # To TCP log
3108+
3109+ log-forward syslog2local
3110+ bind 127.0.0.1:2514 ssl crt ${testdir}/common.pem
3111+ log ${Slg1_addr}:${Slg1_port} local0 # To VTest syslog
3112+} -start
3113+
3114+client c1 -connect ${h1_fe_1_sock} {
3115+ txreq -url "/client_c1"
3116+ rxresp
3117+ expect resp.status == 200
3118+} -repeat 50 -start
3119+
3120+syslog Slg1 -wait
3121diff --git a/reg-tests/startup/automatic_maxconn.vtc b/reg-tests/startup/automatic_maxconn.vtc
3122new file mode 100644
3123index 0000000..686a5c5
3124--- /dev/null
3125+++ b/reg-tests/startup/automatic_maxconn.vtc
3126@@ -0,0 +1,102 @@
3127+#REGTEST_TYPE=broken
3128+#REQUIRE_VERSION=2.2
3129+#REQUIRE_OPTION=OPENSSL
3130+
3131+# Check the maxconn computation with the -m parameter
3132+# Broken because it can't work with ASAN.
3133+
3134+varnishtest "Automatic maxconn computation"
3135+
3136+
3137+feature ignore_unknown_macro
3138+
3139+server s1 {
3140+ rxreq
3141+ txresp
3142+} -start
3143+
3144+
3145+haproxy h1 -arg "-m 1024" -conf {
3146+} -start
3147+
3148+haproxy h1 -cli {
3149+ send "show info"
3150+ expect ~ ".*Maxconn: 29000\n.*"
3151+}
3152+
3153+haproxy h2 -arg "-m 384" -conf {
3154+} -start
3155+
3156+haproxy h2 -cli {
3157+ send "show info"
3158+ expect ~ ".*Maxconn: 10000\n.*"
3159+}
3160+
3161+haproxy h3 -arg "-m 256" -conf {
3162+} -start
3163+
3164+haproxy h3 -cli {
3165+ send "show info"
3166+ expect ~ ".*Maxconn: 7300\n.*"
3167+}
3168+
3169+# 1 SSL front but no back
3170+
3171+haproxy h4 -arg "-m 256" -conf {
3172+ defaults
3173+ mode http
3174+ timeout connect 1s
3175+ timeout client 1s
3176+ timeout server 1s
3177+
3178+ frontend fe1
3179+ bind "fd@${fe1}" ssl crt ${testdir}/common.pem
3180+
3181+} -start
3182+
3183+haproxy h4 -cli {
3184+ send "show info"
3185+ expect ~ ".*Maxconn: 1900\n.*"
3186+}
3187+
3188+# 1 SSL back but not front
3189+
3190+haproxy h5 -arg "-m 256" -conf {
3191+ defaults
3192+ mode http
3193+ timeout connect 1s
3194+ timeout client 1s
3195+ timeout server 1s
3196+
3197+ listen li2
3198+ bind "fd@${li2}"
3199+ server ssl "${s1_addr}:${s1_port}" ssl verify none
3200+
3201+} -start
3202+
3203+haproxy h5 -cli {
3204+ send "show info"
3205+ expect ~ ".*Maxconn: 1900\n.*"
3206+}
3207+
3208+
3209+# 1 SSL front and 1 back
3210+
3211+haproxy h6 -arg "-m 256" -conf {
3212+ defaults
3213+ mode http
3214+ timeout connect 1s
3215+ timeout client 1s
3216+ timeout server 1s
3217+
3218+ listen li3
3219+ bind "fd@${li3}" ssl crt ${testdir}/common.pem
3220+ server ssl "${s1_addr}:${s1_port}" ssl verify none
3221+
3222+} -start
3223+
3224+haproxy h6 -cli {
3225+ send "show info"
3226+ expect ~ ".*Maxconn: 1700\n.*"
3227+}
3228+
3229diff --git a/reg-tests/startup/common.pem b/reg-tests/startup/common.pem
3230new file mode 100644
3231index 0000000..206e417
3232--- /dev/null
3233+++ b/reg-tests/startup/common.pem
3234@@ -0,0 +1,117 @@
3235+-----BEGIN RSA PRIVATE KEY-----
3236+MIIEpAIBAAKCAQEAnb0BDF7FsqzslakNg7u/n/JQkq6nheuKwvyTqECfpc9y7uSB
3237+e/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97N1/LZa6vecjjgGSP0Aag/gS/ocnM
3238+RIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKttJP8xME7j3bTwIDElx/hNI0n7L+yS
3239+kAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6VkIzdOEtH6TcghXmuGcuqvLNH9Buo
3240+syngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+JHm0pkDzAZ2WluNsuXlrJToPirWyj
3241+6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd3wIDAQABAoIBABojc8UE/2W4WgwC
3242+04Z82ig7Ezb7Ui9S9M+S4zUCYHItijIkE4DkIfO3y7Hk4x6iJdyb191HK9UdC5p9
3243+32upS9XFPgM/izx3GZvxDhO+xXbSep7ovbyuQ3pPkHTx3TTavpm3GyvmcTKKoy4R
3244+jP4dWhzDXPdQW1ol3ZS4EDau4rlyClY6oi1mq9aBEX3MqVjB/nO7s2AbdgclAgP2
3245+OZMhTzWYR1k5tYySHCXh3ggGMCikyvHU0+SsGyrstYzP1VYi/n3f0VgqW/5ZjG8x
3246+6SHpe04unErPF3HuSun2ZMCFdBxaTFZ8FENb8evrSXe3nQOc9W21RQdRRrNNUbjl
3247+JYI4veECgYEA0ATYKMS1VCUYRZoQ49b5GTg7avUYqfW4bEo4fSfBue8NrnKR3Wu8
3248+PPBiCTuIYq1vSF+60B7Vu+hW0A8OuQ2UuMxLpYcQ7lKfNad/+yAfoWWafIqCqNU9
3249+at0QMdbW6A69d6jZt7OrXtleBsphCnN58jTz4ch4PIa2Oyq46NUXCvUCgYEAwh8t
3250+G6BOHOs3yRNI2s9Y9EEfwoil2uIKrZhqiL3AwdIpu5uNIMuPnbaEpXvRX6jv/qtL
3251+321i8vZLc31aM7zfxQ6B4ReQFJfYC80FJsWvcLwT9hB9mTJpLS4sIu5tzQc87O6w
3252+RtjFMom+5ns5hfPB4Eccy0EtbQWVY4nCzUeO6QMCgYBSvqqRRPXwG7VU8lznlHqP
3253+upuABzChYrnScY+Y0TixUlL54l79Wb6N6vzEOWceAWkzu8iewrU4QspNhr/PgoR3
3254+IeSxWlG0yy7Dc/ZnmTabx8O06I/iwrfkizzG5nOj6UEamRLJjPGNEB/jyZriQl7u
3255+pnugg1K4mMliLbNSAnlhBQKBgQCmYepbv260Qrex1KGhSg9Ia3k5V74weYYFfJnz
3256+UhChD+1NK+ourcsOtp3C6PlwMHBjq5aAjlU9QfUxq8NgjQaO8/xGXdfUjsFSfAtq
3257+TA4vZkUFpuTAJgEYBHc4CXx7OzTxLzRPxQRgaMgC7KNFOMR34vu/CsJQq3R7uFwL
3258+bsYC2QKBgQCtEmg1uDZVdByX9zyUMuRxz5Tq/vDcp+A5lJj2mha1+bUMaKX2+lxQ
3259+vPxY55Vaw/ukWkJirRrpGv6IytBn0dLAFSlKZworZGBaxsm8OGTFJ5Oe9+kZTjI9
3260+hvjpClOA1otbmj2F2uZAbuIjxQGDNUkLoifN5yDYCC8JPujHuHmULw==
3261+-----END RSA PRIVATE KEY-----
3262+-----BEGIN CERTIFICATE-----
3263+MIIGeTCCBGGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJGUjEW
3264+MBQGA1UECBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoT
3265+B296b24uaW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYP
3266+c3VwcG9ydEBvem9uLmlvMB4XDTE2MDExNzIzMDIzOFoXDTE4MDExNjIzMDIzOFow
3267+gb4xCzAJBgNVBAYTAkZSMRYwFAYDVQQIEw1JbGUtZGUtRnJhbmNlMRowGAYDVQQH
3268+ExFOZXVpbGx5LXN1ci1TZWluZTEYMBYGA1UEChMPVE9BRCBDb25zdWx0aW5nMRcw
3269+FQYDVQQLEw5lUGFyYXBoZXIgVGVhbTEWMBQGA1UEAxMNd3d3LnRlc3QxLmNvbTEw
3270+MC4GCSqGSIb3DQEJARYhYXJuYXVsdC5taWNoZWxAdG9hZC1jb25zdWx0aW5nLmZy
3271+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb0BDF7FsqzslakNg7u/
3272+n/JQkq6nheuKwvyTqECfpc9y7uSBe/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97
3273+N1/LZa6vecjjgGSP0Aag/gS/ocnMRIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKtt
3274+JP8xME7j3bTwIDElx/hNI0n7L+ySkAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6V
3275+kIzdOEtH6TcghXmuGcuqvLNH9BuosyngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+J
3276+Hm0pkDzAZ2WluNsuXlrJToPirWyj6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd
3277+3wIDAQABo4IBvzCCAbswCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMB
3278+MB0GA1UdDgQWBBTIihFNVNgOseQnsWEcAQxAbIKE4TCBsgYDVR0jBIGqMIGngBRv
3279+G9At9gzk2MW5Z7JVey1LtPIZ8KGBg6SBgDB+MQswCQYDVQQGEwJGUjEWMBQGA1UE
3280+CBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB296b24u
3281+aW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYPc3VwcG9y
3282+dEBvem9uLmlvggkA15FtIaGcrk8wDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg9j
3283+b21tb25OYW1lOmNvcHkwCQYDVR0SBAIwADBIBgNVHR8EQTA/MD2gO6A5hjdodHRw
3284+Oi8vb3BlbnNzbGNhLnRvYWQtY29uc3VsdGluZy5jb20vb3BlbnZwbi9MYXRlc3Qu
3285+Y3JsMBEGCWCGSAGG+EIBAQQEAwIGQDAxBglghkgBhvhCAQ0EJBYiVE9BRC1Db25z
3286+dWx0aW5nIHNlcnZlciBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAewDa
3287+9BukGNJMex8gsXmmdaczTr8yh9Uvw4NJcZS38I+26o//2g+d6i7wxcQg8hIm62Hj
3288+0TblGU3+RsJo4uzcWxxA5YUYlVszbHNBRpQengEE5pjwHvoXVMNES6Bt8xP04+Vj
3289+0qVnA8gUaDMk9lN5anK7tF/mbHOIJwHJZYCa2t3y95dIOVEXFwOIzzbSbaprjkLN
3290+w0BgR5paJz7NZWNqo4sZHUUz94uH2bPEd01SqHO0dJwEVxadgxuPnD05I9gqGpGX
3291+Zf3Rn7EQylvUtX9mpPaulQPXc3emefewLUSSAdnZrVikZK2J/B4lSi9FpUwl4iQH
3292+pZoE0QLQHtB1SBKacnOAddGSTLSdFvpzjErjjWSpMukF0vutmrP86GG3xtshWVhI
3293+u+yLfDJVm/pXfaeDtWMXpxIT/U1i0avpk5MZtFMRC0MTaxEWBTnnJm+/yiaAXQYg
3294+E1ZIP0mkZkiUojIawTR7JTjHGhIraP9UVPNceVy0DLfETHEou3vhwBn7PFOz7piJ
3295+wjp3A47DStJD4fapaX6B1fqM+n34CMD9ZAiJFgQEIQfObAWC9hyr4m+pqkp1Qfuw
3296+vsAP/ZoS1CBirJfm3i+Gshh+VeH+TAmO/NBBYCfzBdgkNz4tJCkOc7CUT/NQTR/L
3297+N2OskR/Fkge149RJi7hHvE3gk/mtGtNmHJPuQ+s=
3298+-----END CERTIFICATE-----
3299+-----BEGIN CERTIFICATE-----
3300+MIIJazCCBVOgAwIBAgIUWHoc5e2FUECgyCvyVf8wCtt8gTYwDQYJKoZIhvcNAQEL
3301+BQAwRTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
3302+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA4MDQxODU4MTZaFw0yMDA5
3303+MDMxODU4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
3304+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggQiMA0GCSqGSIb3DQEB
3305+AQUAA4IEDwAwggQKAoIEAQDARiuHkhrnf38Md1nxGDSneJfwv/QksdNNMNTJBdjg
3306+OVmaRCIAyz43oefTWDQ/TebbSwB+Lg9pud1zadGWhlZRhCgBPP8JDMhIKH4eXIRk
3307+5IIa8WD08EwvSlqJL0r4gsMtVsxy7BZHAkka/2Ket9pyGt4kG5n75RFdc6BI80/8
3308+RwJt/MDxPrcVBAT7LnCluxQpyya9mZCabj7l+9a2yU2hgWS6QqfZJ133krkP/MMh
3309+AEQkSoA4mmBwWk9yPqXmUqiOi7v6iLkIUEh5SgYVPRk9BtU/kDaUdSwuqRrpCZo4
3310+SsWZWFLxBmLHkSh+G+BWjCVYMQr2ye7e+VMT/20+5xAfq4fj9n5BsPcx3QcVuTof
3311+RAc/Oygnt4MYnIcUb7zRFvCAvgpUHL7BnEn6nhyXjHJGqGDchsg8m9t3v/Y3ohq+
3312+qmrSzdeuylE1n3W5aWJlbFmyXegNP45MJ0xicesVrXEWF7YD/ir9mGJ8bQYr4blf
3313+77PrbF02komC6AzVPKOJa0jR+eW1wErzYlkYgez6ylBWCiHJd1dhEHlK3h2rXdYa
3314+Gnb45ILCLpEDjNEUrHifLLNXwqJpgZQsJU6BgMgk7ZgBfAKrCfTeg0rkCqCAPeVb
3315+8eSLf7FBF7YBRJ5P6u8qXc4RtgEu607GaWV0gIMfyVBY52oV+OaNsEdFetrJnp3c
3316+friG8vJ+7jdq6zjUCGgnfUIHoViJPh3JuFfhA3jT0gQDKW5PeI7dxhrNvlqdYfHI
3317+fxX7Y1/J6cTQkqJ1cai2f0bwJIJiTAThNbG+zrtjJ7fZ3wJ4udyU/IKrwShqtmTb
3318+1Ofj0tJDdwOH8i84vIySLUvR9aAb7ClFlnsx6rzwOxG90W7C0LA2M0EHm4FezJm/
3319+FfujnZwEWr1T9Wki6qE0MHCbdN/TTDws//EKkkE44FC+amL96w0IQl70vpE37j2A
3320+zlDWvFFID95SIxfmpkwWDvXDKv6gr1GMLeysCl2fgpY05Xidw5cEo9/tEkuWn/dG
3321+x/D9hnLBGeroA0251ES12jemqDjI2U0tfaeHakjwSsoWElf94Qmuh2iPZ+1zIxQs
3322+7o6nAWN8X9hfsmrDTTHlww0TEfrjlbzG5Yh+0ZRxmejgiUyOCXck+eh/ZXMXvfWh
3323+y3CorIIuWgkRjm80PYkdaRDJdZuyP6R7tXfTXNVzAiSQf0Qx9ru2KB2Fs/XZPamH
3324+KjItAU5Q6msIVvaRMS0muQgV+b6hqSEBzqXqJfAlpVLHXr5FqK+U7EB9y02B6piB
3325+tAmxqXP8OOCoQql6/vgIcrDFUOo6KtGBW36ef74XE3KCUVaIzVJZSIt6i/Vi0bZj
3326+bAjsJUQ3qDlHdorv9TRVOhnC1GUz7SuYnpEOyiXmyx3LAgMBAAGjUzBRMB0GA1Ud
3327+DgQWBBQ62csZcH/meQcENHhNbqz9LMzwjjAfBgNVHSMEGDAWgBQ62csZcH/meQcE
3328+NHhNbqz9LMzwjjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQBA
3329+wLsGf3R1+/I2zQE+lsj7RasZtA/Cos92iEGDAPvFbx9e+roG8Gg8KBsEJu/HN0JH
3330+lMMiQ8dDRHSBMvRBENL5/57oOOhmqc+1u5sazLuANhzAYPZG17Klib7YpEwWoXar
3331+FDDiJYtCyLW0oNLpCswYopWK9GC0RJNucB0NFvOxehJ2sP2/fxGBQMB09L6mjKjd
3332+4KsOzyd3dNf0VYS6jB+/1pcKSHKQUo9HRHB5FK04PsYHoh4AtmEHvmYQKcWWidgU
3333+v26ftlH00ERzuW2juqBbz9mghlNRqXi0IyZ9b4tSj29dxW+WWFzo7j2zEPaD6z2W
3334+DEHq7zvON+g+q6qLgWeszqMgJzjvWjMj00E/t06PoHPiz/cAnDKEqp+ZzxCIFrxj
3335+/qneChpogDWyLbawhyyzbZvbirx5znOSbWjPZgydqaNEFViqbxwinBx4Xxabo6XN
3336+TU020FuMWmgfbIcvtgjKgyKqc97l7JMNNm7LQV9+9W0U5zdIqQKLZ9MMrd2w3xh4
3337+MAB8NKnwzHReK0TWwUU9HSgFAGdEX6HnyZ3bQ13ijg+sNBRMEi0gBHaqZKDdyoft
3338+B2u2uasSwioV48dbSIcHl+rTBKxiMh5XQ7ENnaGOJkjsIqTVzizqnPHU8eMBnSbb
3339+dsXlamROYII44+j3Ku6OGt51w86eGk4VxI3tmaECcJKqTkwUFD8AcNDrkjtmLuxK
3340+12yjnoM+u1cclfqQ5NOtRc6MJZ27jCobfBBhVdKVDp4X1WNyqGlbsU5adDAzknuI
3341+GT7MJO7lGjkZX2n54BNPSfrSknYMOVYcZqL0Dbcrhx5IyEmg+iOlOu1HO1tdnZop
3342+ej4vT+1V2w9Sa4Wo3UCo84jcm5v/4z7jCYh4BRQ60CFb7GLxZoqXIslcGSPool3n
3343+jl8JWoaLXrJUPfZGXo1iAlayJ5EiMyZl4eB/TBUf6TMm8vLvsPiUT+CEsjLppOdS
3344+eYppZAZ6H1JrJGs5kKBdOJHGn6Pkp5QsHIswOBd1HqHrBbYbZmDaDLRHduILWLrM
3345+e0/IfDdeXB/bKfmZoEpT8xRiauw15p0AHLumiK7KISAehfgBqUnxx+YmgGoZ7EWX
3346+KnMYAfCuC6oJ1DL0gp4Z9yMK1eu+GV1sLxPq9ZruEHW1R+H+4sGyiA5Gso2tgB6/
3347+XW//wxKclNp5LZR7hqfs/kGuh5asrJrnEbMwWn2+tr/LqfYtYh1D6nHfIXpT0o1d
3348+rNy/HrsKnRDMWxjm03r4hCViuNVD3Zb9anAF/NSPDVu8ATM5JbJNrCYX4eipz6ZE
3349+aQBkwIBkTPgtgP4r8v2G+uMYDw8nq7xh72FK107aeTTwc6MgU5jfeFNMr2XJisJd
3350+lSem1ngKYQSEzjVsTE4c
3351+-----END CERTIFICATE-----
3352diff --git a/scripts/announce-release b/scripts/announce-release
3353index 37e2ac4..c990821 100755
3354--- a/scripts/announce-release
3355+++ b/scripts/announce-release
3356@@ -210,20 +210,21 @@ else
3357 fi
3358
3359 (echo "Please find the usual URLs below :"
3360- echo " Site index : http://www.haproxy.org/"
3361- echo " Documentation : http://docs.haproxy.org/"
3362+ echo " Site index : https://www.haproxy.org/"
3363+ echo " Documentation : https://docs.haproxy.org/"
3364 echo " Wiki : https://github.com/haproxy/wiki/wiki"
3365- echo " Discourse : http://discourse.haproxy.org/"
3366+ echo " Discourse : https://discourse.haproxy.org/"
3367 echo " Slack channel : https://slack.haproxy.org/"
3368 echo " Issue tracker : https://github.com/haproxy/haproxy/issues"
3369- echo " Sources : http://www.haproxy.org/download/${BRANCH}/src/"
3370- echo " Git repository : http://git.haproxy.org/git/${gitdir}/"
3371- echo " Git Web browsing : http://git.haproxy.org/?p=${gitdir}"
3372- echo " Changelog : http://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
3373- echo " Pending bugs : http://www.haproxy.org/l/pending-bugs"
3374- echo " Reviewed bugs : http://www.haproxy.org/l/reviewed-bugs"
3375- echo " Code reports : http://www.haproxy.org/l/code-reports"
3376- echo " Latest builds : http://www.haproxy.org/l/dev-packages"
3377+ echo " Sources : https://www.haproxy.org/download/${BRANCH}/src/"
3378+ echo " Git repository : https://git.haproxy.org/git/${gitdir}/"
3379+ echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}"
3380+ echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG"
3381+ echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest"
3382+ echo " Pending bugs : https://www.haproxy.org/l/pending-bugs"
3383+ echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs"
3384+ echo " Code reports : https://www.haproxy.org/l/code-reports"
3385+ echo " Latest builds : https://www.haproxy.org/l/dev-packages"
3386 ) >> "$OUTPUT"
3387
3388 # sign
3389diff --git a/src/backend.c b/src/backend.c
3390index 6f2cc05..64780e4 100644
3391--- a/src/backend.c
3392+++ b/src/backend.c
3393@@ -2326,7 +2326,6 @@ void back_handle_st_cer(struct stream *s)
3394
3395 /* only wait when we're retrying on the same server */
3396 if ((si->state == SI_ST_ASS ||
3397- (s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_RR ||
3398 (s->be->srv_act <= 1)) && !reused) {
3399 si->state = SI_ST_TAR;
3400 si->exp = tick_add(now_ms, MS_TO_TICKS(delay));
3401diff --git a/src/cache.c b/src/cache.c
3402index ad4e715..ecf62fb 100644
3403--- a/src/cache.c
3404+++ b/src/cache.c
3405@@ -136,7 +136,7 @@ struct cache_st {
3406 struct cache_entry {
3407 unsigned int complete; /* An entry won't be valid until complete is not null. */
3408 unsigned int latest_validation; /* latest validation date */
3409- unsigned int expire; /* expiration date */
3410+ unsigned int expire; /* expiration date (wall clock time) */
3411 unsigned int age; /* Origin server "Age" header value */
3412
3413 struct eb32_node eb; /* ebtree node used to hold the cache object */
3414@@ -188,7 +188,7 @@ struct cache_entry *entry_exist(struct cache *cache, char *hash)
3415 if (memcmp(entry->hash, hash, sizeof(entry->hash)))
3416 return NULL;
3417
3418- if (entry->expire > now.tv_sec) {
3419+ if (entry->expire > date.tv_sec) {
3420 return entry;
3421 } else {
3422 delete_entry(entry);
3423@@ -249,7 +249,7 @@ struct cache_entry *secondary_entry_exist(struct cache *cache, struct cache_entr
3424 * when we find them. Calling delete_entry would be too costly
3425 * so we simply call eb32_delete. The secondary_entry count will
3426 * be updated when we try to insert a new entry to this list. */
3427- if (entry->expire <= now.tv_sec) {
3428+ if (entry->expire <= date.tv_sec) {
3429 eb32_delete(&entry->eb);
3430 entry->eb.key = 0;
3431 }
3432@@ -258,7 +258,7 @@ struct cache_entry *secondary_entry_exist(struct cache *cache, struct cache_entr
3433 }
3434
3435 /* Expired entry */
3436- if (entry && entry->expire <= now.tv_sec) {
3437+ if (entry && entry->expire <= date.tv_sec) {
3438 eb32_delete(&entry->eb);
3439 entry->eb.key = 0;
3440 entry = NULL;
3441@@ -283,7 +283,7 @@ static unsigned int clear_expired_duplicates(struct eb32_node **dup_tail)
3442 while (prev) {
3443 entry = container_of(prev, struct cache_entry, eb);
3444 prev = eb32_prev_dup(prev);
3445- if (entry->expire <= now.tv_sec) {
3446+ if (entry->expire <= date.tv_sec) {
3447 eb32_delete(&entry->eb);
3448 entry->eb.key = 0;
3449 }
3450@@ -315,7 +315,7 @@ static struct eb32_node *insert_entry(struct cache *cache, struct cache_entry *n
3451 struct eb32_node *prev = NULL;
3452 struct cache_entry *entry = NULL;
3453 unsigned int entry_count = 0;
3454- unsigned int last_clear_ts = now.tv_sec;
3455+ unsigned int last_clear_ts = date.tv_sec;
3456
3457 struct eb32_node *node = eb32_insert(&cache->entries, &new_entry->eb);
3458
3459@@ -338,7 +338,7 @@ static struct eb32_node *insert_entry(struct cache *cache, struct cache_entry *n
3460 * space. In order to avoid going over the same list too
3461 * often, we first check the timestamp of the last check
3462 * performed. */
3463- if (last_clear_ts == now.tv_sec) {
3464+ if (last_clear_ts == date.tv_sec) {
3465 /* Too many entries for this primary key, clear the
3466 * one that was inserted. */
3467 eb32_delete(node);
3468@@ -351,7 +351,7 @@ static struct eb32_node *insert_entry(struct cache *cache, struct cache_entry *n
3469 /* Still too many entries for this primary key, delete
3470 * the newly inserted one. */
3471 entry = container_of(prev, struct cache_entry, eb);
3472- entry->last_clear_ts = now.tv_sec;
3473+ entry->last_clear_ts = date.tv_sec;
3474 eb32_delete(node);
3475 node->key = 0;
3476 return NULL;
3477@@ -811,8 +811,8 @@ int http_calc_maxage(struct stream *s, struct cache *cache, int *true_maxage)
3478 /* A request having an expiring date earlier
3479 * than the current date should be considered as
3480 * stale. */
3481- expires = (expires_val >= now.tv_sec) ?
3482- (expires_val - now.tv_sec) : 0;
3483+ expires = (expires_val >= date.tv_sec) ?
3484+ (expires_val - date.tv_sec) : 0;
3485 }
3486 else {
3487 /* Following RFC 7234#5.3, an invalid date
3488@@ -886,7 +886,7 @@ static time_t get_last_modified_time(struct htx *htx)
3489 /* Fallback on the current time if no "Last-Modified" or "Date" header
3490 * was found. */
3491 if (!last_modified)
3492- last_modified = now.tv_sec;
3493+ last_modified = date.tv_sec;
3494
3495 return last_modified;
3496 }
3497@@ -1120,7 +1120,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
3498 * is set by the end of this function (in case of concurrent accesses to
3499 * the same resource). This way the second access will find an existing
3500 * but not yet usable entry in the tree and will avoid storing its data. */
3501- object->expire = now.tv_sec + 2;
3502+ object->expire = date.tv_sec + 2;
3503
3504 memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
3505 if (vary_signature)
3506@@ -1224,8 +1224,8 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
3507 if (cache_ctx) {
3508 cache_ctx->first_block = first;
3509 /* store latest value and expiration time */
3510- object->latest_validation = now.tv_sec;
3511- object->expire = now.tv_sec + effective_maxage;
3512+ object->latest_validation = date.tv_sec;
3513+ object->expire = date.tv_sec + effective_maxage;
3514 return ACT_RET_CONT;
3515 }
3516
3517@@ -1416,7 +1416,7 @@ static int htx_cache_add_age_hdr(struct appctx *appctx, struct htx *htx)
3518 char *end;
3519
3520 chunk_reset(&trash);
3521- age = MAX(0, (int)(now.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age;
3522+ age = MAX(0, (int)(date.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age;
3523 if (unlikely(age > CACHE_ENTRY_MAX_AGE))
3524 age = CACHE_ENTRY_MAX_AGE;
3525 end = ultoa_o(age, b_head(&trash), b_size(&trash));
3526@@ -2602,13 +2602,13 @@ static int cli_io_handler_show_cache(struct appctx *appctx)
3527 entry = container_of(node, struct cache_entry, eb);
3528 next_key = node->key + 1;
3529
3530- if (entry->expire > now.tv_sec) {
3531+ if (entry->expire > date.tv_sec) {
3532 chunk_printf(&trash, "%p hash:%u vary:0x", entry, read_u32(entry->hash));
3533 for (i = 0; i < HTTP_CACHE_SEC_KEY_LEN; ++i)
3534 chunk_appendf(&trash, "%02x", (unsigned char)entry->secondary_key[i]);
3535 chunk_appendf(&trash, " size:%u (%u blocks), refcount:%u, expire:%d\n",
3536 block_ptr(entry)->len, block_ptr(entry)->block_count,
3537- block_ptr(entry)->refcount, entry->expire - (int)now.tv_sec);
3538+ block_ptr(entry)->refcount, entry->expire - (int)date.tv_sec);
3539 } else {
3540 /* time to remove that one */
3541 delete_entry(entry);
3542diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
3543index 4603376..35bd498 100644
3544--- a/src/cfgparse-listen.c
3545+++ b/src/cfgparse-listen.c
3546@@ -292,6 +292,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
3547 curr_defproxy = last_defproxy;
3548
3549 if (strcmp(args[arg], "from") == 0) {
3550+ struct ebpt_node *next_by_name;
3551+
3552 curr_defproxy = proxy_find_by_name(args[arg+1], PR_CAP_DEF, 0);
3553
3554 if (!curr_defproxy) {
3555@@ -300,8 +302,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
3556 goto out;
3557 }
3558
3559- if (ebpt_next_dup(&curr_defproxy->conf.by_name)) {
3560- struct proxy *px2 = container_of(ebpt_next_dup(&curr_defproxy->conf.by_name), struct proxy, conf.by_name);
3561+ if ((next_by_name = ebpt_next_dup(&curr_defproxy->conf.by_name))) {
3562+ struct proxy *px2 = container_of(next_by_name, struct proxy, conf.by_name);
3563
3564 ha_alert("parsing [%s:%d] : ambiguous defaults section name '%s' referenced by %s '%s' exists at least at %s:%d and %s:%d.\n",
3565 file, linenum, args[arg+1], proxy_cap_str(rc), name,
3566diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c
3567index 654b020..fcd0416 100644
3568--- a/src/cfgparse-ssl.c
3569+++ b/src/cfgparse-ssl.c
3570@@ -758,7 +758,7 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str
3571 {
3572 int code;
3573 char *p = args[cur_arg + 1];
3574- unsigned long long *ignerr = &conf->crt_ignerr;
3575+ unsigned long long *ignerr = conf->crt_ignerr_bitfield;
3576
3577 if (!*p) {
3578 memprintf(err, "'%s' : missing error IDs list", args[cur_arg]);
3579@@ -766,21 +766,21 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str
3580 }
3581
3582 if (strcmp(args[cur_arg], "ca-ignore-err") == 0)
3583- ignerr = &conf->ca_ignerr;
3584+ ignerr = conf->ca_ignerr_bitfield;
3585
3586 if (strcmp(p, "all") == 0) {
3587- *ignerr = ~0ULL;
3588+ cert_ignerr_bitfield_set_all(ignerr);
3589 return 0;
3590 }
3591
3592 while (p) {
3593 code = atoi(p);
3594- if ((code <= 0) || (code > 63)) {
3595- memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'",
3596- args[cur_arg], code, args[cur_arg + 1]);
3597+ if ((code <= 0) || (code > SSL_MAX_VFY_ERROR_CODE)) {
3598+ memprintf(err, "'%s' : ID '%d' out of range (1..%d) in error IDs list '%s'",
3599+ args[cur_arg], code, SSL_MAX_VFY_ERROR_CODE, args[cur_arg + 1]);
3600 return ERR_ALERT | ERR_FATAL;
3601 }
3602- *ignerr |= 1ULL << code;
3603+ cert_ignerr_bitfield_set(ignerr, code);
3604 p = strchr(p, ',');
3605 if (p)
3606 p++;
3607diff --git a/src/cfgparse.c b/src/cfgparse.c
3608index 4b42ec0..27bab1d 100644
3609--- a/src/cfgparse.c
3610+++ b/src/cfgparse.c
3611@@ -10,10 +10,10 @@
3612 *
3613 */
3614
3615-#ifdef USE_LIBCRYPT
3616-/* This is to have crypt() defined on Linux */
3617+/* This is to have crypt() and sched_setaffinity() defined on Linux */
3618 #define _GNU_SOURCE
3619
3620+#ifdef USE_LIBCRYPT
3621 #ifdef USE_CRYPT_H
3622 /* some platforms such as Solaris need this */
3623 #include <crypt.h>
3624@@ -29,6 +29,9 @@
3625 #include <pwd.h>
3626 #include <grp.h>
3627 #include <errno.h>
3628+#ifdef USE_CPU_AFFINITY
3629+#include <sched.h>
3630+#endif
3631 #include <sys/types.h>
3632 #include <sys/stat.h>
3633 #include <fcntl.h>
3634@@ -62,6 +65,7 @@
3635 #include <haproxy/lb_map.h>
3636 #include <haproxy/listener.h>
3637 #include <haproxy/log.h>
3638+#include <haproxy/sink.h>
3639 #include <haproxy/mailers.h>
3640 #include <haproxy/namespace.h>
3641 #include <haproxy/obj_type-t.h>
3642@@ -2630,6 +2634,7 @@ int check_config_validity()
3643 {
3644 int cfgerr = 0;
3645 struct proxy *curproxy = NULL;
3646+ struct proxy *init_proxies_list = NULL;
3647 struct stktable *t;
3648 struct server *newsrv = NULL;
3649 int err_code = 0;
3650@@ -2707,7 +2712,11 @@ int check_config_validity()
3651 proxies_list = next;
3652 }
3653
3654- for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
3655+ /* starting to initialize the main proxies list */
3656+ init_proxies_list = proxies_list;
3657+
3658+init_proxies_list_stage1:
3659+ for (curproxy = init_proxies_list; curproxy; curproxy = curproxy->next) {
3660 struct switching_rule *rule;
3661 struct server_rule *srule;
3662 struct sticking_rule *mrule;
3663@@ -2837,11 +2846,16 @@ int check_config_validity()
3664 case PR_MODE_CLI:
3665 cfgerr += proxy_cfg_ensure_no_http(curproxy);
3666 break;
3667+
3668 case PR_MODE_SYSLOG:
3669+ /* this mode is initialized as the classic tcp proxy */
3670+ cfgerr += proxy_cfg_ensure_no_http(curproxy);
3671+ break;
3672+
3673 case PR_MODE_PEERS:
3674 case PR_MODES:
3675 /* should not happen, bug gcc warn missing switch statement */
3676- ha_alert("config : %s '%s' cannot use peers or syslog mode for this proxy. NOTE: PLEASE REPORT THIS TO DEVELOPERS AS YOU'RE NOT SUPPOSED TO BE ABLE TO CREATE A CONFIGURATION TRIGGERING THIS!\n",
3677+ ha_alert("config: %s '%s' cannot initialize this proxy mode (peers) in this way. NOTE: PLEASE REPORT THIS TO DEVELOPERS AS YOU'RE NOT SUPPOSED TO BE ABLE TO CREATE A CONFIGURATION TRIGGERING THIS!\n",
3678 proxy_type_str(curproxy), curproxy->id);
3679 cfgerr++;
3680 break;
3681@@ -3966,6 +3980,24 @@ out_uri_auth_compat:
3682 }
3683 }
3684
3685+ /*
3686+ * We have just initialized the main proxies list
3687+ * we must also configure the log-forward proxies list
3688+ */
3689+ if (init_proxies_list == proxies_list) {
3690+ init_proxies_list = cfg_log_forward;
3691+ /* check if list is not null to avoid infinite loop */
3692+ if (init_proxies_list)
3693+ goto init_proxies_list_stage1;
3694+ }
3695+
3696+ if (init_proxies_list == cfg_log_forward) {
3697+ init_proxies_list = sink_proxies_list;
3698+ /* check if list is not null to avoid infinite loop */
3699+ if (init_proxies_list)
3700+ goto init_proxies_list_stage1;
3701+ }
3702+
3703 /***********************************************************/
3704 /* At this point, target names have already been resolved. */
3705 /***********************************************************/
3706@@ -4087,7 +4119,11 @@ out_uri_auth_compat:
3707
3708 /* perform the final checks before creating tasks */
3709
3710- for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
3711+ /* starting to initialize the main proxies list */
3712+ init_proxies_list = proxies_list;
3713+
3714+init_proxies_list_stage2:
3715+ for (curproxy = init_proxies_list; curproxy; curproxy = curproxy->next) {
3716 struct listener *listener;
3717 unsigned int next_id;
3718
3719@@ -4209,6 +4245,17 @@ out_uri_auth_compat:
3720 }
3721
3722 /*
3723+ * We have just initialized the main proxies list
3724+ * we must also configure the log-forward proxies list
3725+ */
3726+ if (init_proxies_list == proxies_list) {
3727+ init_proxies_list = cfg_log_forward;
3728+ /* check if list is not null to avoid infinite loop */
3729+ if (init_proxies_list)
3730+ goto init_proxies_list_stage2;
3731+ }
3732+
3733+ /*
3734 * Recount currently required checks.
3735 */
3736
3737diff --git a/src/check.c b/src/check.c
3738index 1a40b6f..2205063 100644
3739--- a/src/check.c
3740+++ b/src/check.c
3741@@ -1715,6 +1715,13 @@ static int init_srv_agent_check(struct server *srv)
3742 LIST_INSERT(srv->agent.tcpcheck_rules->list, &chk->list);
3743 }
3744
3745+ /* <chk> is always defined here and it is a CONNECT action. If there is
3746+ * a preset variable, it means there is an agent string defined and data
3747+ * will be sent after the connect.
3748+ */
3749+ if (!LIST_ISEMPTY(&srv->agent.tcpcheck_rules->preset_vars))
3750+ chk->connect.options |= TCPCHK_OPT_HAS_DATA;
3751+
3752
3753 err = init_check(&srv->agent, PR_O2_TCPCHK_CHK);
3754 if (err) {
3755diff --git a/src/dns.c b/src/dns.c
3756index 1ef5e87..c4b2af0 100644
3757--- a/src/dns.c
3758+++ b/src/dns.c
3759@@ -1023,7 +1023,7 @@ struct dns_session *dns_session_new(struct dns_stream_server *dss)
3760 if (dss->maxconn && (dss->maxconn <= dss->cur_conns))
3761 return NULL;
3762
3763- ds = pool_alloc(dns_session_pool);
3764+ ds = pool_zalloc(dns_session_pool);
3765 if (!ds)
3766 return NULL;
3767
3768diff --git a/src/ev_epoll.c b/src/ev_epoll.c
3769index 330c38c..041d6d8 100644
3770--- a/src/ev_epoll.c
3771+++ b/src/ev_epoll.c
3772@@ -185,7 +185,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3773
3774 thread_harmless_now();
3775
3776- /* now let's wait for polled events */
3777+ /* Now let's wait for polled events. */
3778 wait_time = wake ? 0 : compute_poll_timeout(exp);
3779 tv_entering_poll();
3780 activity_count_runtime();
3781@@ -201,7 +201,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3782 }
3783 if (timeout || !wait_time)
3784 break;
3785- if (signal_queue_len || wake)
3786+ if (wake)
3787 break;
3788 if (tick_isset(exp) && tick_is_expired(exp, now_ms))
3789 break;
3790diff --git a/src/ev_evports.c b/src/ev_evports.c
3791index 109e59c..e012e00 100644
3792--- a/src/ev_evports.c
3793+++ b/src/ev_evports.c
3794@@ -153,9 +153,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3795
3796 thread_harmless_now();
3797
3798- /*
3799- * Determine how long to wait for events to materialise on the port.
3800- */
3801+ /* Now let's wait for polled events. */
3802 wait_time = wake ? 0 : compute_poll_timeout(exp);
3803 tv_entering_poll();
3804 activity_count_runtime();
3805@@ -195,7 +193,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3806 break;
3807 if (timeout || !wait_time)
3808 break;
3809- if (signal_queue_len || wake)
3810+ if (wake)
3811 break;
3812 if (tick_isset(exp) && tick_is_expired(exp, now_ms))
3813 break;
3814diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c
3815index d51a833..0d81d67 100644
3816--- a/src/ev_kqueue.c
3817+++ b/src/ev_kqueue.c
3818@@ -141,7 +141,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3819 }
3820 fd_nbupdt = 0;
3821
3822- /* now let's wait for events */
3823+ /* Now let's wait for polled events. */
3824 wait_time = wake ? 0 : compute_poll_timeout(exp);
3825 fd = global.tune.maxpollevents;
3826 tv_entering_poll();
3827@@ -167,7 +167,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3828 }
3829 if (timeout || !wait_time)
3830 break;
3831- if (signal_queue_len || wake)
3832+ if (wake)
3833 break;
3834 if (tick_isset(exp) && tick_is_expired(exp, now_ms))
3835 break;
3836diff --git a/src/ev_poll.c b/src/ev_poll.c
3837index c30aadb..4d136a0 100644
3838--- a/src/ev_poll.c
3839+++ b/src/ev_poll.c
3840@@ -21,6 +21,7 @@
3841 #include <haproxy/api.h>
3842 #include <haproxy/fd.h>
3843 #include <haproxy/global.h>
3844+#include <haproxy/signal.h>
3845 #include <haproxy/ticks.h>
3846 #include <haproxy/time.h>
3847
3848@@ -198,7 +199,7 @@ static void _do_poll(struct poller *p, int exp, int wake)
3849 }
3850 }
3851
3852- /* now let's wait for events */
3853+ /* Now let's wait for polled events. */
3854 wait_time = wake ? 0 : compute_poll_timeout(exp);
3855 tv_entering_poll();
3856 activity_count_runtime();
3857diff --git a/src/fcgi-app.c b/src/fcgi-app.c
3858index 29a3602..8fca1e9 100644
3859--- a/src/fcgi-app.c
3860+++ b/src/fcgi-app.c
3861@@ -589,7 +589,7 @@ static int proxy_parse_use_fcgi_app(char **args, int section, struct proxy *curp
3862 struct fcgi_flt_conf *fcgi_conf = NULL;
3863 int retval = 0;
3864
3865- if (!(curpx->cap & PR_CAP_BE)) {
3866+ if ((curpx->cap & PR_CAP_DEF) || !(curpx->cap & PR_CAP_BE)) {
3867 memprintf(err, "'%s' only available in backend or listen section", args[0]);
3868 retval = -1;
3869 goto end;
3870diff --git a/src/fcgi.c b/src/fcgi.c
3871index 1c2543d..778ce9e 100644
3872--- a/src/fcgi.c
3873+++ b/src/fcgi.c
3874@@ -47,7 +47,7 @@ int fcgi_encode_record_hdr(struct buffer *out, const struct fcgi_header *h)
3875 out->area[len++] = ((h->len >> 8) & 0xff);
3876 out->area[len++] = (h->len & 0xff);
3877 out->area[len++] = h->padding;
3878- len++; /* rsv */
3879+ out->area[len++] = 0; /* rsv */
3880
3881 out->data = len;
3882 return 1;
3883@@ -94,7 +94,11 @@ int fcgi_encode_begin_request(struct buffer *out, const struct fcgi_begin_reques
3884 out->area[len++] = ((r->role >> 8) & 0xff);
3885 out->area[len++] = (r->role & 0xff);
3886 out->area[len++] = r->flags;
3887- len += 5; /* rsv */
3888+ out->area[len++] = 0; /* rsv */
3889+ out->area[len++] = 0;
3890+ out->area[len++] = 0;
3891+ out->area[len++] = 0;
3892+ out->area[len++] = 0;
3893
3894 out->data = len;
3895 return 1;
3896diff --git a/src/fd.c b/src/fd.c
3897index b9c8ccc..3c9629f 100644
3898--- a/src/fd.c
3899+++ b/src/fd.c
3900@@ -206,7 +206,7 @@ lock_self:
3901 #ifdef HA_CAS_IS_8B
3902 unlikely(!_HA_ATOMIC_CAS(((uint64_t *)&_GET_NEXT(fd, off)), (uint64_t *)&cur_list.u64, next_list.u64))
3903 #else
3904- unlikely(!_HA_ATOMIC_DWCAS(((long *)&_GET_NEXT(fd, off)), (uint32_t *)&cur_list.u32, &next_list.u32))
3905+ unlikely(!_HA_ATOMIC_DWCAS(((long *)&_GET_NEXT(fd, off)), (uint32_t *)&cur_list.u32, (const uint32_t *)&next_list.u32))
3906 #endif
3907 );
3908 next = cur_list.ent.next;
3909@@ -666,9 +666,9 @@ static void deinit_pollers_per_thread()
3910 /* rd and wr are init at the same place, but only rd is init to -1, so
3911 we rely to rd to close. */
3912 if (poller_rd_pipe > -1) {
3913- close(poller_rd_pipe);
3914+ fd_delete(poller_rd_pipe);
3915 poller_rd_pipe = -1;
3916- close(poller_wr_pipe[tid]);
3917+ fd_delete(poller_wr_pipe[tid]);
3918 poller_wr_pipe[tid] = -1;
3919 }
3920 }
3921diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
3922index a9c49f5..66eb601 100644
3923--- a/src/flt_http_comp.c
3924+++ b/src/flt_http_comp.c
3925@@ -304,23 +304,18 @@ set_compression_response_header(struct comp_state *st, struct stream *s, struct
3926 struct htx_sl *sl;
3927 struct http_hdr_ctx ctx;
3928
3929- /*
3930- * Add Content-Encoding header when it's not identity encoding.
3931- * RFC 2616 : Identity encoding: This content-coding is used only in the
3932- * Accept-Encoding header, and SHOULD NOT be used in the Content-Encoding
3933- * header.
3934- */
3935- if (st->comp_algo->cfg_name_len != 8 || memcmp(st->comp_algo->cfg_name, "identity", 8) != 0) {
3936- struct ist v = ist2(st->comp_algo->ua_name, st->comp_algo->ua_name_len);
3937-
3938- if (!http_add_header(htx, ist("Content-Encoding"), v))
3939- goto error;
3940- }
3941-
3942 sl = http_get_stline(htx);
3943 if (!sl)
3944 goto error;
3945
3946+ /* add "Transfer-Encoding: chunked" header */
3947+ if (!(msg->flags & HTTP_MSGF_TE_CHNK)) {
3948+ if (!http_add_header(htx, ist("Transfer-Encoding"), ist("chunked")))
3949+ goto error;
3950+ msg->flags |= HTTP_MSGF_TE_CHNK;
3951+ sl->flags |= (HTX_SL_F_XFER_ENC|HTX_SL_F_CHNK);
3952+ }
3953+
3954 /* remove Content-Length header */
3955 if (msg->flags & HTTP_MSGF_CNT_LEN) {
3956 ctx.blk = NULL;
3957@@ -330,14 +325,6 @@ set_compression_response_header(struct comp_state *st, struct stream *s, struct
3958 sl->flags &= ~HTX_SL_F_CLEN;
3959 }
3960
3961- /* add "Transfer-Encoding: chunked" header */
3962- if (!(msg->flags & HTTP_MSGF_TE_CHNK)) {
3963- if (!http_add_header(htx, ist("Transfer-Encoding"), ist("chunked")))
3964- goto error;
3965- msg->flags |= HTTP_MSGF_TE_CHNK;
3966- sl->flags |= (HTX_SL_F_XFER_ENC|HTX_SL_F_CHNK);
3967- }
3968-
3969 /* convert "ETag" header to a weak ETag */
3970 ctx.blk = NULL;
3971 if (http_find_header(htx, ist("ETag"), &ctx, 1)) {
3972@@ -355,6 +342,19 @@ set_compression_response_header(struct comp_state *st, struct stream *s, struct
3973 if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding")))
3974 goto error;
3975
3976+ /*
3977+ * Add Content-Encoding header when it's not identity encoding.
3978+ * RFC 2616 : Identity encoding: This content-coding is used only in the
3979+ * Accept-Encoding header, and SHOULD NOT be used in the Content-Encoding
3980+ * header.
3981+ */
3982+ if (st->comp_algo->cfg_name_len != 8 || memcmp(st->comp_algo->cfg_name, "identity", 8) != 0) {
3983+ struct ist v = ist2(st->comp_algo->ua_name, st->comp_algo->ua_name_len);
3984+
3985+ if (!http_add_header(htx, ist("Content-Encoding"), v))
3986+ goto error;
3987+ }
3988+
3989 return 1;
3990
3991 error:
3992diff --git a/src/flt_spoe.c b/src/flt_spoe.c
3993index cb7eed4..4826aa0 100644
3994--- a/src/flt_spoe.c
3995+++ b/src/flt_spoe.c
3996@@ -1259,7 +1259,7 @@ spoe_release_appctx(struct appctx *appctx)
3997 /* Destroy the task attached to this applet */
3998 task_destroy(spoe_appctx->task);
3999
4000- /* Notify all waiting streams */
4001+ /* Report an error to all streams in the appctx waiting queue */
4002 list_for_each_entry_safe(ctx, back, &spoe_appctx->waiting_queue, list) {
4003 LIST_DELETE(&ctx->list);
4004 LIST_INIT(&ctx->list);
4005@@ -1271,8 +1271,8 @@ spoe_release_appctx(struct appctx *appctx)
4006 task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
4007 }
4008
4009- /* If the applet was processing a fragmented frame, notify the
4010- * corresponding stream. */
4011+ /* If the applet was processing a fragmented frame, report an error to
4012+ * the corresponding stream. */
4013 if (spoe_appctx->frag_ctx.ctx) {
4014 ctx = spoe_appctx->frag_ctx.ctx;
4015 ctx->spoe_appctx = NULL;
4016@@ -1281,7 +1281,11 @@ spoe_release_appctx(struct appctx *appctx)
4017 task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
4018 }
4019
4020- if (!LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) {
4021+ if (!LIST_ISEMPTY(&agent->rt[tid].applets)) {
4022+ /* If there are still some running applets, remove reference on
4023+ * the current one from streams in the async waiting queue. In
4024+ * async mode, the ACK may be received from another appctx.
4025+ */
4026 list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) {
4027 if (ctx->spoe_appctx == spoe_appctx)
4028 ctx->spoe_appctx = NULL;
4029@@ -1289,16 +1293,25 @@ spoe_release_appctx(struct appctx *appctx)
4030 goto end;
4031 }
4032 else {
4033- /* It is the last running applet and the sending and waiting
4034- * queues are not empty. Try to start a new one if HAproxy is
4035- * not stopping.
4036+ /* It is the last running applet and the sending and async
4037+ * waiting queues are not empty. So try to start a new applet if
4038+ * HAproxy is not stopping. On success, we remove reference on
4039+ * the current appctx from streams in the async waiting queue.
4040+ * In async mode, the ACK may be received from another appctx.
4041 */
4042 if (!stopping &&
4043 (!LIST_ISEMPTY(&agent->rt[tid].sending_queue) || !LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) &&
4044- spoe_create_appctx(agent->spoe_conf))
4045+ spoe_create_appctx(agent->spoe_conf)) {
4046+ list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) {
4047+ if (ctx->spoe_appctx == spoe_appctx)
4048+ ctx->spoe_appctx = NULL;
4049+ }
4050 goto end;
4051+ }
4052
4053- /* otherwise, notify all waiting streams */
4054+ /* Otherwise, report an error to all streams in the sending and
4055+ * async waiting queues.
4056+ */
4057 list_for_each_entry_safe(ctx, back, &agent->rt[tid].sending_queue, list) {
4058 LIST_DELETE(&ctx->list);
4059 LIST_INIT(&ctx->list);
4060diff --git a/src/h1.c b/src/h1.c
4061index 3a6c1c3..73de48b 100644
4062--- a/src/h1.c
4063+++ b/src/h1.c
4064@@ -130,6 +130,50 @@ void h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value)
4065 }
4066 }
4067
4068+/* Validate the authority and the host header value for CONNECT method. If there
4069+ * is hast header, its value is normalized. 0 is returned on success, -1 if the
4070+ * authority is invalid and -2 if the host is invalid.
4071+ */
4072+static int h1_validate_connect_authority(struct ist authority, struct ist *host_hdr)
4073+{
4074+ struct ist uri_host, uri_port, host, host_port;
4075+
4076+ if (!isttest(authority))
4077+ goto invalid_authority;
4078+ uri_host = authority;
4079+ uri_port = http_get_host_port(authority);
4080+ if (!isttest(uri_port))
4081+ goto invalid_authority;
4082+ uri_host.len -= (istlen(uri_port) + 1);
4083+
4084+ if (!host_hdr || !isttest(*host_hdr))
4085+ goto end;
4086+
4087+ /* Get the port of the host header value, if any */
4088+ host = *host_hdr;
4089+ host_port = http_get_host_port(*host_hdr);
4090+ if (isttest(host_port)) {
4091+ host.len -= (istlen(host_port) + 1);
4092+ if (!isteqi(host, uri_host) || !isteq(host_port, uri_port))
4093+ goto invalid_host;
4094+ if (http_is_default_port(IST_NULL, uri_port))
4095+ *host_hdr = host; /* normalize */
4096+ }
4097+ else {
4098+ if (!http_is_default_port(IST_NULL, uri_port) || !isteqi(host, uri_host))
4099+ goto invalid_host;
4100+ }
4101+
4102+ end:
4103+ return 0;
4104+
4105+ invalid_authority:
4106+ return -1;
4107+
4108+ invalid_host:
4109+ return -2;
4110+}
4111+
4112 /* Parse the Connection: header of an HTTP/1 request, looking for "close",
4113 * "keep-alive", and "upgrade" values, and updating h1m->flags according to
4114 * what was found there. Note that flags are only added, not removed, so the
4115@@ -706,6 +750,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
4116
4117 if (likely(*ptr == ':')) {
4118 col = ptr - start;
4119+ if (col <= sol) {
4120+ state = H1_MSG_HDR_NAME;
4121+ goto http_msg_invalid;
4122+ }
4123 EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP);
4124 }
4125
4126@@ -868,22 +916,9 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
4127 else if (isteqi(n, ist("upgrade"))) {
4128 h1_parse_upgrade_header(h1m, v);
4129 }
4130- else if (!(h1m->flags & (H1_MF_HDRS_ONLY|H1_MF_RESP)) && isteqi(n, ist("host"))) {
4131- if (host_idx == -1) {
4132- struct ist authority;
4133-
4134- authority = http_get_authority(sl.rq.u, 1);
4135- if (authority.len && !isteqi(v, authority)) {
4136- if (h1m->err_pos < -1) {
4137- state = H1_MSG_HDR_L2_LWS;
4138- ptr = v.ptr; /* Set ptr on the error */
4139- goto http_msg_invalid;
4140- }
4141- if (h1m->err_pos == -1) /* capture the error pointer */
4142- h1m->err_pos = v.ptr - start + skip; /* >= 0 now */
4143- }
4144+ else if (!(h1m->flags & H1_MF_RESP) && isteqi(n, ist("host"))) {
4145+ if (host_idx == -1)
4146 host_idx = hdr_count;
4147- }
4148 else {
4149 if (!isteqi(v, hdr[host_idx].v)) {
4150 state = H1_MSG_HDR_L2_LWS;
4151@@ -934,6 +969,48 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
4152 if (restarting)
4153 goto restart;
4154
4155+
4156+ if (!(h1m->flags & (H1_MF_HDRS_ONLY|H1_MF_RESP))) {
4157+ struct ist authority;
4158+
4159+ authority = http_get_authority(sl.rq.u, 1);
4160+ if (sl.rq.meth == HTTP_METH_CONNECT) {
4161+ struct ist *host = ((host_idx != -1) ? &hdr[host_idx].v : NULL);
4162+ int ret;
4163+
4164+ ret = h1_validate_connect_authority(authority, host);
4165+ if (ret < 0) {
4166+ if (h1m->err_pos < -1) {
4167+ state = H1_MSG_LAST_LF;
4168+ /* WT: gcc seems to see a path where sl.rq.u.ptr was used
4169+ * uninitialized, but it doesn't know that the function is
4170+ * called with initial states making this impossible.
4171+ */
4172+ ALREADY_CHECKED(sl.rq.u.ptr);
4173+ ptr = ((ret == -1) ? sl.rq.u.ptr : host->ptr); /* Set ptr on the error */
4174+ goto http_msg_invalid;
4175+ }
4176+ if (h1m->err_pos == -1) /* capture the error pointer */
4177+ h1m->err_pos = ((ret == -1) ? sl.rq.u.ptr : host->ptr) - start + skip; /* >= 0 now */
4178+ }
4179+ }
4180+ else if (host_idx != -1 && istlen(authority)) {
4181+ struct ist host = hdr[host_idx].v;
4182+
4183+ /* For non-CONNECT method, the authority must match the host header value */
4184+ if (!isteqi(authority, host)) {
4185+ if (h1m->err_pos < -1) {
4186+ state = H1_MSG_LAST_LF;
4187+ ptr = host.ptr; /* Set ptr on the error */
4188+ goto http_msg_invalid;
4189+ }
4190+ if (h1m->err_pos == -1) /* capture the error pointer */
4191+ h1m->err_pos = v.ptr - start + skip; /* >= 0 now */
4192+ }
4193+
4194+ }
4195+ }
4196+
4197 state = H1_MSG_DATA;
4198 if (h1m->flags & H1_MF_XFER_ENC) {
4199 if (h1m->flags & H1_MF_CLEN) {
4200diff --git a/src/h1_htx.c b/src/h1_htx.c
4201index b6a91f2..650acba 100644
4202--- a/src/h1_htx.c
4203+++ b/src/h1_htx.c
4204@@ -279,6 +279,9 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
4205 goto output_full;
4206 }
4207
4208+ if ((h1m->flags & (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) && code != 101)
4209+ h1m->flags &= ~(H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET);
4210+
4211 if (((h1m->flags & H1_MF_METH_CONNECT) && code >= 200 && code < 300) || code == 101) {
4212 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
4213 h1m->flags |= H1_MF_XFER_LEN;
4214diff --git a/src/haproxy.c b/src/haproxy.c
4215index b484195..2f85293 100644
4216--- a/src/haproxy.c
4217+++ b/src/haproxy.c
4218@@ -1,6 +1,6 @@
4219 /*
4220 * HAProxy : High Availability-enabled HTTP/TCP proxy
4221- * Copyright 2000-2022 Willy Tarreau <willy@haproxy.org>.
4222+ * Copyright 2000-2023 Willy Tarreau <willy@haproxy.org>.
4223 *
4224 * This program is free software; you can redistribute it and/or
4225 * modify it under the terms of the GNU General Public License
4226@@ -2080,6 +2080,10 @@ static void init(int argc, char **argv)
4227 exit(1);
4228 }
4229
4230+ /* set the default maxconn in the master, but let it be rewritable with -n */
4231+ if (global.mode & MODE_MWORKER_WAIT)
4232+ global.maxconn = DEFAULT_MAXCONN;
4233+
4234 if (cfg_maxconn > 0)
4235 global.maxconn = cfg_maxconn;
4236
4237@@ -2629,7 +2633,7 @@ void run_poll_loop()
4238 if (killed > 1)
4239 break;
4240
4241- /* expire immediately if events are pending */
4242+ /* expire immediately if events or signals are pending */
4243 wake = 1;
4244 if (thread_has_tasks())
4245 activity[tid].wake_tasks++;
4246@@ -2639,6 +2643,10 @@ void run_poll_loop()
4247 if (thread_has_tasks()) {
4248 activity[tid].wake_tasks++;
4249 _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit);
4250+ } else if (signal_queue_len) {
4251+ /* this check is required to avoid
4252+ * a race with wakeup on signals using wake_threads() */
4253+ _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit);
4254 } else
4255 wake = 0;
4256 }
4257diff --git a/src/hlua.c b/src/hlua.c
4258index 0af3eb0..aea338f 100644
4259--- a/src/hlua.c
4260+++ b/src/hlua.c
4261@@ -738,7 +738,11 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
4262 break;
4263
4264 case ARGT_TAB:
4265- argp[idx].data.prx = p;
4266+ if (!p->table) {
4267+ msg = "Mandatory argument expected";
4268+ goto error;
4269+ }
4270+ argp[idx].data.t = p->table;
4271 argp[idx].type = ARGT_TAB;
4272 argp[idx+1].type = ARGT_STOP;
4273 break;
4274@@ -979,6 +983,7 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
4275 return 0;
4276
4277 error:
4278+ argp[idx].type = ARGT_STOP;
4279 for (i = 0; i < idx; i++) {
4280 if (argp[i].type == ARGT_STR)
4281 chunk_destroy(&argp[i].data.str);
4282@@ -4421,7 +4426,7 @@ __LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_K
4283 /* The message was fully consumed and no more data are expected
4284 * (EOM flag set).
4285 */
4286- if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4287+ if (htx_is_empty(htx) && (req->flags & CF_EOI))
4288 stop = 1;
4289
4290 htx_to_buf(htx, &req->buf);
4291@@ -4513,7 +4518,7 @@ __LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KCon
4292 /* The message was fully consumed and no more data are expected
4293 * (EOM flag set).
4294 */
4295- if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4296+ if (htx_is_empty(htx) && (req->flags & CF_EOI))
4297 len = 0;
4298
4299 htx_to_buf(htx, &req->buf);
4300diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c
4301index 26aa509..010bd13 100644
4302--- a/src/hlua_fcn.c
4303+++ b/src/hlua_fcn.c
4304@@ -1305,6 +1305,7 @@ int hlua_proxy_pause(lua_State *L)
4305 struct proxy *px;
4306
4307 px = hlua_check_proxy(L, 1);
4308+ /* safe to call without PROXY_LOCK - pause_proxy takes it */
4309 pause_proxy(px);
4310 return 0;
4311 }
4312@@ -1314,6 +1315,7 @@ int hlua_proxy_resume(lua_State *L)
4313 struct proxy *px;
4314
4315 px = hlua_check_proxy(L, 1);
4316+ /* safe to call without PROXY_LOCK - resume_proxy takes it */
4317 resume_proxy(px);
4318 return 0;
4319 }
4320@@ -1323,6 +1325,7 @@ int hlua_proxy_stop(lua_State *L)
4321 struct proxy *px;
4322
4323 px = hlua_check_proxy(L, 1);
4324+ /* safe to call without PROXY_LOCK - stop_proxy takes it */
4325 stop_proxy(px);
4326 return 0;
4327 }
4328diff --git a/src/hpack-dec.c b/src/hpack-dec.c
4329index 4fa9bfd..ed39007 100644
4330--- a/src/hpack-dec.c
4331+++ b/src/hpack-dec.c
4332@@ -32,6 +32,7 @@
4333
4334 #include <import/ist.h>
4335 #include <haproxy/chunk.h>
4336+#include <haproxy/global.h>
4337 #include <haproxy/h2.h>
4338 #include <haproxy/hpack-dec.h>
4339 #include <haproxy/hpack-huff.h>
4340@@ -419,6 +420,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len,
4341 /* <name> and <value> are correctly filled here */
4342 }
4343
4344+ /* We must not accept empty header names (forbidden by the spec and used
4345+ * as a list termination).
4346+ */
4347+ if (!name.len) {
4348+ hpack_debug_printf("##ERR@%d##\n", __LINE__);
4349+ ret = -HPACK_ERR_INVALID_ARGUMENT;
4350+ goto leave;
4351+ }
4352+
4353 /* here's what we have here :
4354 * - name.len > 0
4355 * - value is filled with either const data or data allocated from tmp
4356diff --git a/src/http.c b/src/http.c
4357index 0b00e47..c10b433 100644
4358--- a/src/http.c
4359+++ b/src/http.c
4360@@ -468,6 +468,38 @@ const char *http_get_reason(unsigned int status)
4361 }
4362 }
4363
4364+/* Returns the ist string corresponding to port part (without ':') in the host
4365+ * <host> or IST_NULL if not found.
4366+*/
4367+struct ist http_get_host_port(const struct ist host)
4368+{
4369+ char *start, *end, *ptr;
4370+
4371+ start = istptr(host);
4372+ end = istend(host);
4373+ for (ptr = end; ptr > start && isdigit((unsigned char)*--ptr););
4374+
4375+ /* no port found */
4376+ if (likely(*ptr != ':' || ptr+1 == end || ptr == start))
4377+ return IST_NULL;
4378+
4379+ return istnext(ist2(ptr, end - ptr));
4380+}
4381+
4382+
4383+/* Return non-zero if the port <port> is a default port. If the scheme <schm> is
4384+ * set, it is used to detect default ports (HTTP => 80 and HTTPS => 443)
4385+ * port. Otherwise, both are considered as default ports.
4386+ */
4387+int http_is_default_port(const struct ist schm, const struct ist port)
4388+{
4389+ if (!isttest(schm))
4390+ return (isteq(port, ist("443")) || isteq(port, ist("80")));
4391+ else
4392+ return (isteq(port, ist("443")) && isteqi(schm, ist("https://"))) ||
4393+ (isteq(port, ist("80")) && isteqi(schm, ist("http://")));
4394+}
4395+
4396 /* Returns non-zero if the scheme <schm> is syntactically correct according to
4397 * RFC3986#3.1, otherwise zero. It expects only the scheme and nothing else
4398 * (particularly not the following "://").
4399diff --git a/src/http_act.c b/src/http_act.c
4400index f88c856..59e614f 100644
4401--- a/src/http_act.c
4402+++ b/src/http_act.c
4403@@ -1877,6 +1877,8 @@ static void release_http_redir(struct act_rule *rule)
4404 free(redir->cookie_str);
4405 list_for_each_entry_safe(lf, lfb, &redir->rdr_fmt, list) {
4406 LIST_DELETE(&lf->list);
4407+ release_sample_expr(lf->expr);
4408+ free(lf->arg);
4409 free(lf);
4410 }
4411 free(redir);
4412diff --git a/src/http_ana.c b/src/http_ana.c
4413index 4491ea1..2e2095b 100644
4414--- a/src/http_ana.c
4415+++ b/src/http_ana.c
4416@@ -938,9 +938,8 @@ int http_wait_for_request_body(struct stream *s, struct channel *req, int an_bit
4417 {
4418 struct session *sess = s->sess;
4419 struct http_txn *txn = s->txn;
4420- struct http_msg *msg = &s->txn->req;
4421
4422- DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn, msg);
4423+ DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn, &s->txn->req);
4424
4425
4426 switch (http_wait_for_msg_body(s, req, s->be->timeout.httpreq, 0)) {
4427@@ -998,7 +997,7 @@ int http_wait_for_request_body(struct stream *s, struct channel *req, int an_bit
4428 if (!(s->flags & SF_ERR_MASK))
4429 s->flags |= SF_ERR_PRXCOND;
4430 if (!(s->flags & SF_FINST_MASK))
4431- s->flags |= (msg->msg_state < HTTP_MSG_DATA ? SF_FINST_R : SF_FINST_D);
4432+ s->flags |= SF_FINST_R;
4433
4434 req->analysers &= AN_REQ_FLT_END;
4435 req->analyse_exp = TICK_ETERNITY;
4436@@ -2655,17 +2654,21 @@ static enum rule_result http_req_restrict_header_names(struct stream *s, struct
4437
4438 if (type == HTX_BLK_HDR) {
4439 struct ist n = htx_get_blk_name(htx, blk);
4440- int i;
4441+ int i, end = istlen(n);
4442
4443- for (i = 0; i < istlen(n); i++) {
4444+ for (i = 0; i < end; i++) {
4445 if (!isalnum((unsigned char)n.ptr[i]) && n.ptr[i] != '-') {
4446- /* Block the request or remove the header */
4447- if (px->options2 & PR_O2_RSTRICT_REQ_HDR_NAMES_BLK)
4448- goto block;
4449- blk = htx_remove_blk(htx, blk);
4450- continue;
4451+ break;
4452 }
4453 }
4454+
4455+ if (i < end) {
4456+ /* Disallowed character found - block the request or remove the header */
4457+ if (px->options2 & PR_O2_RSTRICT_REQ_HDR_NAMES_BLK)
4458+ goto block;
4459+ blk = htx_remove_blk(htx, blk);
4460+ continue;
4461+ }
4462 }
4463 if (type == HTX_BLK_EOH)
4464 break;
4465@@ -2778,6 +2781,7 @@ int http_res_set_status(unsigned int status, struct ist reason, struct stream *s
4466
4467 if (!http_replace_res_status(htx, ist2(trash.area, trash.data), reason))
4468 return -1;
4469+ s->txn->status = status;
4470 return 0;
4471 }
4472
4473@@ -4241,7 +4245,7 @@ enum rule_result http_wait_for_msg_body(struct stream *s, struct channel *chn,
4474 if (!(s->flags & SF_ERR_MASK))
4475 s->flags |= SF_ERR_CLITO;
4476 if (!(s->flags & SF_FINST_MASK))
4477- s->flags |= SF_FINST_D;
4478+ s->flags |= SF_FINST_R;
4479 _HA_ATOMIC_INC(&sess->fe->fe_counters.failed_req);
4480 if (sess->listener && sess->listener->counters)
4481 _HA_ATOMIC_INC(&sess->listener->counters->failed_req);
4482@@ -4254,7 +4258,7 @@ enum rule_result http_wait_for_msg_body(struct stream *s, struct channel *chn,
4483 if (!(s->flags & SF_ERR_MASK))
4484 s->flags |= SF_ERR_SRVTO;
4485 if (!(s->flags & SF_FINST_MASK))
4486- s->flags |= SF_FINST_D;
4487+ s->flags |= SF_FINST_R;
4488 stream_inc_http_fail_ctr(s);
4489 http_reply_and_close(s, txn->status, http_error_message(s));
4490 ret = HTTP_RULE_RES_ABRT;
4491@@ -5205,8 +5209,10 @@ struct http_txn *http_create_txn(struct stream *s)
4492
4493 txn->auth.method = HTTP_AUTH_UNKNOWN;
4494
4495- vars_init(&s->vars_txn, SCOPE_TXN);
4496- vars_init(&s->vars_reqres, SCOPE_REQ);
4497+ /* here we don't want to re-initialize s->vars_txn and s->vars_reqres
4498+ * variable lists, because they were already initialized upon stream
4499+ * creation in stream_new(), and thus may already contain some variables
4500+ */
4501
4502 return txn;
4503 }
4504diff --git a/src/http_fetch.c b/src/http_fetch.c
4505index 3950eea..6678c85 100644
4506--- a/src/http_fetch.c
4507+++ b/src/http_fetch.c
4508@@ -222,7 +222,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, struct che
4509 if (IS_HTX_STRM(s)) {
4510 htx = htxbuf(&chn->buf);
4511
4512- if (msg->msg_state == HTTP_MSG_ERROR || (htx->flags & HTX_FL_PARSING_ERROR))
4513+ if (htx->flags & HTX_FL_PARSING_ERROR)
4514 return NULL;
4515
4516 if (msg->msg_state < HTTP_MSG_BODY) {
4517@@ -307,7 +307,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, struct che
4518 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
4519 s->flags |= SF_REDIRECTABLE;
4520 }
4521- else
4522+ else if (txn->status == -1)
4523 txn->status = sl->info.res.status;
4524 if (sl->flags & HTX_SL_F_VER_11)
4525 msg->flags |= HTTP_MSGF_VER_11;
4526@@ -330,20 +330,21 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char
4527 {
4528 struct channel *chn = SMP_REQ_CHN(smp);
4529 struct http_txn *txn;
4530- struct htx *htx;
4531+ struct htx *htx = NULL;
4532 int meth;
4533
4534 txn = (smp->strm ? smp->strm->txn : NULL);
4535 if (!txn)
4536 return 0;
4537
4538- if (txn->meth == HTTP_METH_OTHER) {
4539+ meth = txn->meth;
4540+ if (meth == HTTP_METH_OTHER) {
4541 htx = smp_prefetch_htx(smp, chn, NULL, 1);
4542 if (!htx)
4543 return 0;
4544+ meth = txn->meth;
4545 }
4546
4547- meth = txn->meth;
4548 smp->data.type = SMP_T_METH;
4549 smp->data.u.meth.meth = meth;
4550 if (meth == HTTP_METH_OTHER) {
4551diff --git a/src/http_htx.c b/src/http_htx.c
4552index 6f5c1a1..60525bb 100644
4553--- a/src/http_htx.c
4554+++ b/src/http_htx.c
4555@@ -388,6 +388,9 @@ int http_replace_req_uri(struct htx *htx, const struct ist uri)
4556 goto fail;
4557
4558 sl = http_get_stline(htx);
4559+ ALREADY_CHECKED(sl); /* the stline exists because http_replace_stline() succeded */
4560+ sl->flags &= ~HTX_SL_F_NORMALIZED_URI;
4561+
4562 if (!http_update_host(htx, sl, uri))
4563 goto fail;
4564
4565@@ -918,7 +921,7 @@ int http_str_to_htx(struct buffer *buf, struct ist raw, char **errmsg)
4566 ret = h1_headers_to_hdr_list(raw.ptr, raw.ptr + raw.len,
4567 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &h1sl);
4568 if (ret <= 0) {
4569- memprintf(errmsg, "unabled to parse headers (error offset: %d)", h1m.err_pos);
4570+ memprintf(errmsg, "unable to parse headers (error offset: %d)", h1m.err_pos);
4571 goto error;
4572 }
4573
4574@@ -1565,6 +1568,7 @@ struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struc
4575 fd = -1;
4576 obj[objlen] = '\0';
4577 reply->type = HTTP_REPLY_LOGFMT;
4578+ LIST_INIT(&reply->body.fmt);
4579 cur_arg++;
4580 }
4581 else if (strcmp(args[cur_arg], "lf-string") == 0) {
4582@@ -1581,6 +1585,7 @@ struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struc
4583 obj = strdup(args[cur_arg]);
4584 objlen = strlen(args[cur_arg]);
4585 reply->type = HTTP_REPLY_LOGFMT;
4586+ LIST_INIT(&reply->body.fmt);
4587 cur_arg++;
4588 }
4589 else if (strcmp(args[cur_arg], "hdr") == 0) {
4590@@ -1721,12 +1726,6 @@ struct http_reply *http_parse_http_reply(const char **args, int *orig_arg, struc
4591 return NULL;
4592 }
4593
4594-static int uri_is_default_port(const struct ist scheme, const struct ist port)
4595-{
4596- return (isteq(port, ist("443")) && isteqi(scheme, ist("https://"))) ||
4597- (isteq(port, ist("80")) && isteqi(scheme, ist("http://")));
4598-}
4599-
4600 /* Apply schemed-based normalization as described on rfc3986 on section 6.3.2.
4601 * Returns 0 if no error has been found else non-zero.
4602 *
4603@@ -1741,7 +1740,6 @@ int http_scheme_based_normalize(struct htx *htx)
4604 struct http_hdr_ctx ctx;
4605 struct htx_sl *sl;
4606 struct ist uri, scheme, authority, host, port;
4607- char *start, *end, *ptr;
4608
4609 sl = http_get_stline(htx);
4610
4611@@ -1755,25 +1753,16 @@ int http_scheme_based_normalize(struct htx *htx)
4612 if (!isttest(scheme))
4613 return 0;
4614
4615- /* Extract the port if present in authority. To properly support ipv6
4616- * hostnames, do a reverse search on the last ':' separator as long as
4617- * digits are found.
4618- */
4619- authority = http_get_authority(uri, 0);
4620- start = istptr(authority);
4621- end = istend(authority);
4622- for (ptr = end; ptr > start && isdigit((unsigned char)*--ptr); )
4623- ;
4624-
4625- /* if no port found, no normalization to proceed */
4626- if (likely(*ptr != ':'))
4627+ /* Extract the port if present in authority */
4628+ authority = http_get_authority(uri, 1);
4629+ port = http_get_host_port(authority);
4630+ if (!isttest(port)) {
4631+ /* if no port found, no normalization to proceed */
4632 return 0;
4633+ }
4634+ host = isttrim(authority, istlen(authority) - istlen(port) - 1);
4635
4636- /* split host/port on the ':' separator found */
4637- host = ist2(start, ptr - start);
4638- port = istnext(ist2(ptr, end - ptr));
4639-
4640- if (istlen(port) && uri_is_default_port(scheme, port)) {
4641+ if (istlen(port) && http_is_default_port(scheme, port)) {
4642 /* reconstruct the uri with removal of the port */
4643 struct buffer *temp = get_trash_chunk();
4644 struct ist meth, vsn;
4645diff --git a/src/listener.c b/src/listener.c
4646index 0ffd0fe..67616f5 100644
4647--- a/src/listener.c
4648+++ b/src/listener.c
4649@@ -45,6 +45,7 @@ static struct bind_kw_list bind_keywords = {
4650 /* list of the temporarily limited listeners because of lack of resource */
4651 static struct mt_list global_listener_queue = MT_LIST_HEAD_INIT(global_listener_queue);
4652 static struct task *global_listener_queue_task;
4653+__decl_thread(static HA_RWLOCK_T global_listener_rwlock);
4654
4655 /* listener status for stats */
4656 const char* li_status_st[LI_STATE_COUNT] = {
4657@@ -297,13 +298,14 @@ void enable_listener(struct listener *listener)
4658
4659 /*
4660 * This function completely stops a listener. It will need to operate under the
4661- * proxy's lock, the protocol's lock, and the listener's lock. The caller is
4662- * responsible for indicating in lpx, lpr, lli whether the respective locks are
4663- * already held (non-zero) or not (zero) so that the function picks the missing
4664- * ones, in this order. The proxy's listeners count is updated and the proxy is
4665+ * It will need to operate under the proxy's lock and the protocol's lock.
4666+ * The caller is responsible for indicating in lpx, lpr whether the
4667+ * respective locks are already held (non-zero) or not (zero) so that the
4668+ * function picks the missing ones, in this order.
4669+ * The proxy's listeners count is updated and the proxy is
4670 * disabled and woken up after the last one is gone.
4671 */
4672-void stop_listener(struct listener *l, int lpx, int lpr, int lli)
4673+void stop_listener(struct listener *l, int lpx, int lpr)
4674 {
4675 struct proxy *px = l->bind_conf->frontend;
4676
4677@@ -320,8 +322,7 @@ void stop_listener(struct listener *l, int lpx, int lpr, int lli)
4678 if (!lpr)
4679 HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
4680
4681- if (!lli)
4682- HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
4683+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
4684
4685 if (l->state > LI_INIT) {
4686 do_unbind_listener(l);
4687@@ -332,8 +333,7 @@ void stop_listener(struct listener *l, int lpx, int lpr, int lli)
4688 proxy_cond_disable(px);
4689 }
4690
4691- if (!lli)
4692- HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &l->lock);
4693+ HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &l->lock);
4694
4695 if (!lpr)
4696 HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);
4697@@ -422,12 +422,18 @@ int default_resume_listener(struct listener *l)
4698 * closes upon SHUT_WR and refuses to rebind. So a common validation path
4699 * involves SHUT_WR && listen && SHUT_RD. In case of success, the FD's polling
4700 * is disabled. It normally returns non-zero, unless an error is reported.
4701+ * It will need to operate under the proxy's lock. The caller is
4702+ * responsible for indicating in lpx whether the proxy locks is
4703+ * already held (non-zero) or not (zero) so that the function picks it.
4704 */
4705-int pause_listener(struct listener *l)
4706+int pause_listener(struct listener *l, int lpx)
4707 {
4708 struct proxy *px = l->bind_conf->frontend;
4709 int ret = 1;
4710
4711+ if (!lpx)
4712+ HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4713+
4714 HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
4715
4716 if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) &&
4717@@ -450,6 +456,10 @@ int pause_listener(struct listener *l)
4718 }
4719 end:
4720 HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &l->lock);
4721+
4722+ if (!lpx)
4723+ HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4724+
4725 return ret;
4726 }
4727
4728@@ -462,13 +472,19 @@ int pause_listener(struct listener *l)
4729 * state, it's totally rebound. This can happen if a pause() has completely
4730 * stopped it. If the resume fails, 0 is returned and an error might be
4731 * displayed.
4732+ * It will need to operate under the proxy's lock. The caller is
4733+ * responsible for indicating in lpx whether the proxy locks is
4734+ * already held (non-zero) or not (zero) so that the function picks it.
4735 */
4736-int resume_listener(struct listener *l)
4737+int resume_listener(struct listener *l, int lpx)
4738 {
4739 struct proxy *px = l->bind_conf->frontend;
4740 int was_paused = px && px->li_paused;
4741 int ret = 1;
4742
4743+ if (!lpx)
4744+ HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4745+
4746 HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock);
4747
4748 /* check that another thread didn't to the job in parallel (e.g. at the
4749@@ -484,6 +500,10 @@ int resume_listener(struct listener *l)
4750 if (l->state == LI_READY)
4751 goto end;
4752
4753+ /* the listener might have been stopped in parallel */
4754+ if (l->state < LI_PAUSED)
4755+ goto end;
4756+
4757 if (l->rx.proto->resume)
4758 ret = l->rx.proto->resume(l);
4759
4760@@ -503,6 +523,10 @@ int resume_listener(struct listener *l)
4761 }
4762 end:
4763 HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &l->lock);
4764+
4765+ if (!lpx)
4766+ HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4767+
4768 return ret;
4769 }
4770
4771@@ -545,7 +569,7 @@ void dequeue_all_listeners()
4772 /* This cannot fail because the listeners are by definition in
4773 * the LI_LIMITED state.
4774 */
4775- resume_listener(listener);
4776+ resume_listener(listener, 0);
4777 }
4778 }
4779
4780@@ -558,7 +582,7 @@ void dequeue_proxy_listeners(struct proxy *px)
4781 /* This cannot fail because the listeners are by definition in
4782 * the LI_LIMITED state.
4783 */
4784- resume_listener(listener);
4785+ resume_listener(listener, 0);
4786 }
4787 }
4788
4789@@ -1084,7 +1108,7 @@ void listener_accept(struct listener *l)
4790 (!tick_isset(global_listener_queue_task->expire) ||
4791 tick_is_expired(global_listener_queue_task->expire, now_ms))))) {
4792 /* at least one thread has to this when quitting */
4793- resume_listener(l);
4794+ resume_listener(l, 0);
4795
4796 /* Dequeues all of the listeners waiting for a resource */
4797 dequeue_all_listeners();
4798@@ -1103,7 +1127,7 @@ void listener_accept(struct listener *l)
4799 * Let's put it to pause in this case.
4800 */
4801 if (l->rx.proto && l->rx.proto->rx_listening(&l->rx) == 0) {
4802- pause_listener(l);
4803+ pause_listener(l, 0);
4804 goto end;
4805 }
4806
4807@@ -1112,7 +1136,9 @@ void listener_accept(struct listener *l)
4808 * later than <expire> ahead. The listener turns to LI_LIMITED.
4809 */
4810 limit_listener(l, &global_listener_queue);
4811+ HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock);
4812 task_schedule(global_listener_queue_task, expire);
4813+ HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock);
4814 goto end;
4815
4816 limit_proxy:
4817@@ -1141,7 +1167,7 @@ void listener_release(struct listener *l)
4818 _HA_ATOMIC_DEC(&l->thr_conn[tid]);
4819
4820 if (l->state == LI_FULL || l->state == LI_LIMITED)
4821- resume_listener(l);
4822+ resume_listener(l, 0);
4823
4824 /* Dequeues all of the listeners waiting for a resource */
4825 dequeue_all_listeners();
4826@@ -1162,6 +1188,7 @@ static int listener_queue_init()
4827 /* very simple initialization, users will queue the task if needed */
4828 global_listener_queue_task->context = NULL; /* not even a context! */
4829 global_listener_queue_task->process = manage_global_listener_queue;
4830+ HA_RWLOCK_INIT(&global_listener_rwlock);
4831
4832 return 0;
4833 }
4834@@ -1199,7 +1226,9 @@ struct task *manage_global_listener_queue(struct task *t, void *context, unsigne
4835 dequeue_all_listeners();
4836
4837 out:
4838+ HA_RWLOCK_WRLOCK(LISTENER_LOCK, &global_listener_rwlock);
4839 t->expire = TICK_ETERNITY;
4840+ HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &global_listener_rwlock);
4841 task_queue(t);
4842 return t;
4843 }
4844diff --git a/src/log.c b/src/log.c
4845index c431937..fbc8a2f 100644
4846--- a/src/log.c
4847+++ b/src/log.c
4848@@ -1381,17 +1381,21 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str
4849 }
4850
4851 if (src && len) {
4852- if (++len > size)
4853- len = size;
4854+ /* escape_string and strlcpy2 will both try to add terminating NULL-byte
4855+ * to dst, so we need to make sure that extra byte will fit into dst
4856+ * before calling them
4857+ */
4858 if (node->options & LOG_OPT_ESC) {
4859 char *ret;
4860
4861- ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
4862+ ret = escape_string(dst, (dst + size - 1), '\\', rfc5424_escape_map, src, src + len);
4863 if (ret == NULL || *ret != '\0')
4864 return NULL;
4865 len = ret - dst;
4866 }
4867 else {
4868+ if (++len > size)
4869+ len = size;
4870 len = strlcpy2(dst, src, len);
4871 }
4872
4873@@ -1402,6 +1406,7 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str
4874 if (size < 2)
4875 return NULL;
4876 *(dst++) = '-';
4877+ size -= 1;
4878 }
4879
4880 if (node->options & LOG_OPT_QUOTE) {
4881@@ -1877,7 +1882,7 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, int level,
4882 if (msg.len > logsrv->maxlen)
4883 msg.len = logsrv->maxlen;
4884
4885- sent = sink_write(logsrv->sink, &msg, 1, level, logsrv->facility, metadata);
4886+ sent = sink_write(logsrv->sink, &msg, 1, level, facility, metadata);
4887 }
4888 else if (logsrv->addr.ss_family == AF_CUST_EXISTING_FD) {
4889 struct ist msg;
4890@@ -3418,6 +3423,7 @@ void parse_log_message(char *buf, size_t buflen, int *level, int *facility,
4891 */
4892
4893 p += 2;
4894+ *size -= 2;
4895 /* timestamp is NILVALUE '-' */
4896 if (*size > 2 && (p[0] == '-') && p[1] == ' ') {
4897 metadata[LOG_META_TIME] = ist2(p, 1);
4898@@ -3811,7 +3817,7 @@ static void syslog_io_handler(struct appctx *appctx)
4899 if (buf->area[to_skip - 1] != ' ')
4900 goto parse_error;
4901
4902- msglen = strtol(trash.area, &p, 10);
4903+ msglen = strtol(buf->area, &p, 10);
4904 if (!msglen || p != &buf->area[to_skip - 1])
4905 goto parse_error;
4906
4907diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c
4908index d916496..7334b56 100644
4909--- a/src/mux_fcgi.c
4910+++ b/src/mux_fcgi.c
4911@@ -1399,7 +1399,7 @@ static int fcgi_set_default_param(struct fcgi_conn *fconn, struct fcgi_strm *fst
4912 * captured
4913 */
4914 params->scriptname = ist2(path.ptr + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so);
4915- if (!(params->mask & FCGI_SP_PATH_INFO) && (pmatch[2].rm_so == -1 || pmatch[2].rm_eo == -1))
4916+ if (!(params->mask & FCGI_SP_PATH_INFO) && !(pmatch[2].rm_so == -1 || pmatch[2].rm_eo == -1))
4917 params->pathinfo = ist2(path.ptr + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
4918
4919 check_index:
4920@@ -2188,9 +2188,10 @@ static size_t fcgi_strm_send_stdin(struct fcgi_conn *fconn, struct fcgi_strm *fs
4921 size = htx_get_blksz(blk);
4922 if (unlikely(size == count && htx_nbblks(htx) == 1 && type == HTX_BLK_DATA)) {
4923 void *old_area = mbuf->area;
4924+ int eom = (htx->flags & HTX_FL_EOM);
4925
4926 /* Last block of the message: Reserve the size for the empty stdin record */
4927- if (htx->flags & HTX_FL_EOM)
4928+ if (eom)
4929 extra_bytes = FCGI_RECORD_HEADER_SZ;
4930
4931 if (b_data(mbuf)) {
4932@@ -2226,6 +2227,8 @@ static size_t fcgi_strm_send_stdin(struct fcgi_conn *fconn, struct fcgi_strm *fs
4933
4934 htx = (struct htx *)buf->area;
4935 htx_reset(htx);
4936+ if (eom)
4937+ goto empty_stdin;
4938 goto end;
4939 }
4940
4941@@ -2275,7 +2278,9 @@ static size_t fcgi_strm_send_stdin(struct fcgi_conn *fconn, struct fcgi_strm *fs
4942 b_data(&outbuf) + v.len + extra_bytes <= b_room(mbuf) &&
4943 b_data(mbuf) <= MAX_DATA_REALIGN)
4944 goto realign_again;
4945- v.len = b_room(&outbuf) - FCGI_RECORD_HEADER_SZ - extra_bytes;
4946+ v.len = (FCGI_RECORD_HEADER_SZ + extra_bytes > b_room(&outbuf)
4947+ ? 0
4948+ : b_room(&outbuf) - FCGI_RECORD_HEADER_SZ - extra_bytes);
4949 }
4950 if (!v.len || !chunk_memcat(&outbuf, v.ptr, v.len)) {
4951 if (outbuf.data == FCGI_RECORD_HEADER_SZ)
4952@@ -2306,6 +2311,7 @@ static size_t fcgi_strm_send_stdin(struct fcgi_conn *fconn, struct fcgi_strm *fs
4953
4954 /* Send the empty stding here to finish the message */
4955 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM)) {
4956+ empty_stdin:
4957 TRACE_PROTO("sending FCGI STDIN record", FCGI_EV_TX_RECORD|FCGI_EV_TX_STDIN, fconn->conn, fstrm, htx);
4958 if (!fcgi_strm_send_empty_stdin(fconn, fstrm)) {
4959 /* bytes already reserved for this record. It should not fail */
4960@@ -4184,14 +4190,14 @@ static int fcgi_show_fd(struct buffer *msg, struct connection *conn)
4961 if (fstrm->cs)
4962 chunk_appendf(msg, " .cs.flg=0x%08x .cs.data=%p",
4963 fstrm->cs->flags, fstrm->cs->data);
4964- chunk_appendf(&trash, " .subs=%p", fstrm->subs);
4965+ chunk_appendf(msg, " .subs=%p", fstrm->subs);
4966 if (fstrm->subs) {
4967- chunk_appendf(&trash, "(ev=%d tl=%p", fstrm->subs->events, fstrm->subs->tasklet);
4968- chunk_appendf(&trash, " tl.calls=%d tl.ctx=%p tl.fct=",
4969+ chunk_appendf(msg, "(ev=%d tl=%p", fstrm->subs->events, fstrm->subs->tasklet);
4970+ chunk_appendf(msg, " tl.calls=%d tl.ctx=%p tl.fct=",
4971 fstrm->subs->tasklet->calls,
4972 fstrm->subs->tasklet->context);
4973- resolve_sym_name(&trash, NULL, fstrm->subs->tasklet->process);
4974- chunk_appendf(&trash, ")");
4975+ resolve_sym_name(msg, NULL, fstrm->subs->tasklet->process);
4976+ chunk_appendf(msg, ")");
4977 }
4978 }
4979 return 0;
4980diff --git a/src/mux_h1.c b/src/mux_h1.c
4981index 8d5de5e..c29c4ed 100644
4982--- a/src/mux_h1.c
4983+++ b/src/mux_h1.c
4984@@ -2133,7 +2133,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
4985 /* EOM flag is set or empty payload (C-L to 0) and it is the last block */
4986 if (htx_is_unique_blk(chn_htx, blk) &&
4987 ((chn_htx->flags & HTX_FL_EOM) || ((h1m->flags & H1_MF_CLEN) && !h1m->curr_len))) {
4988- if (h1m->flags & H1_MF_CHNK) {
4989+ if ((h1m->flags & H1_MF_CHNK) && !(h1s->flags & H1S_F_BODYLESS_RESP)) {
4990 if (!chunk_memcat(&tmp, "\r\n0\r\n\r\n", 7))
4991 goto full;
4992 }
4993@@ -2556,9 +2556,10 @@ static int h1_handle_req_tout(struct h1c *h1c)
4994 _HA_ATOMIC_INC(&sess->listener->counters->failed_req);
4995
4996 h1c->errcode = 408;
4997+ ret = h1_send_error(h1c);
4998 if (b_data(&h1c->ibuf) || !(sess->fe->options & PR_O_NULLNOLOG))
4999- ret = h1_send_error(h1c);
5000- sess_log(sess);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches