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

Proposed by Lucas Kanashiro
Status: Merged
Approved by: git-ubuntu bot
Approved revision: not available
Merge reported by: Lucas Kanashiro
Merged at revision: 72681649158930cfa0da398b0215df767debd077
Proposed branch: ~lucaskanashiro/ubuntu/+source/haproxy:jammy-mre
Merge into: ubuntu/+source/haproxy:ubuntu/jammy-devel
Diff against target: 7019 lines (+2604/-830)
120 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 (+24/-0)
debian/patches/haproxy.service-start-after-syslog.patch (+0/-2)
debian/patches/reproducible.patch (+1/-3)
debian/patches/series (+0/-3)
debian/tests/control (+8/-0)
debian/tests/proxy-localhost (+4/-9)
debian/tests/proxy-ssl-pass-through (+59/-0)
debian/tests/proxy-ssl-termination (+48/-0)
debian/tests/utils (+58/-0)
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+439426@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:37:20]: @@@@@@@@@@@@@@@@@@@@ summary
cli PASS
proxy-localhost 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-0ubuntu1.3

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

Fixed. Up for review again.

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

One inline question about the version, and another question here: have you thought about pulling in the new kinetic DEP8 tests? After all, both jammy and kinetic are receiving the same haproxy upstream version after this. Considering these are MREs, I think it would be nice to have those tests here too, unless it's too involved.

review: Needs Information
6944eb2... by Lucas Kanashiro

Backport DEP-8 tests from lunar

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

I fixed the version string as we discussed in the other MP and backported the DEP-8 tests as you suggested, all tests passed:

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

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

haha, gotta love version strings :)

And thanks for bringing in the DEP8 tests

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

Subscribers

People subscribed via source and target branches