Merge ~lucaskanashiro/ubuntu/+source/haproxy:focal-mre into ubuntu/+source/haproxy:ubuntu/focal-devel
- Git
- lp:~lucaskanashiro/ubuntu/+source/haproxy
- focal-mre
- Merge into ubuntu/focal-devel
Status: | Merged |
---|---|
Approved by: | git-ubuntu bot |
Approved revision: | not available |
Merge reported by: | Lucas Kanashiro |
Merged at revision: | e6f5d977ade8c6ac8ba443f1d0a703818f69915f |
Proposed branch: | ~lucaskanashiro/ubuntu/+source/haproxy:focal-mre |
Merge into: | ubuntu/+source/haproxy:ubuntu/focal-devel |
Diff against target: |
3076 lines (+954/-440) 68 files modified
.github/matrix.py (+6/-3) .github/workflows/cross-zoo.yml (+110/-0) .github/workflows/vtest.yml (+5/-2) .github/workflows/windows.yml (+2/-1) CHANGELOG (+100/-0) Makefile (+5/-1) SUBVERS (+1/-1) VERDATE (+2/-2) VERSION (+1/-1) contrib/prometheus-exporter/service-prometheus.c (+1/-0) contrib/wurfl/wurfl/wurfl.h (+10/-5) debian/changelog (+18/-0) debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch (+0/-2) debian/patches/haproxy.service-add-documentation.patch (+4/-4) debian/patches/series (+0/-2) dev/null (+0/-175) doc/configuration.txt (+99/-41) doc/management.txt (+4/-0) doc/proxy-protocol.txt (+1/-1) include/common/buf.h (+1/-1) include/common/compiler.h (+3/-1) include/common/memory.h (+2/-2) include/common/standard.h (+3/-2) include/proto/server.h (+1/-0) include/proto/ssl_sock.h (+25/-0) include/types/global.h (+1/-0) include/types/listener.h (+11/-2) reg-tests/http-messaging/http_abortonclose.vtc (+27/-5) reg-tests/http-messaging/http_request_buffer.vtc (+29/-4) scripts/announce-release (+12/-11) scripts/make-releases-json (+103/-0) scripts/publish-release (+6/-0) src/backend.c (+0/-5) src/cache.c (+7/-7) src/cfgparse-listen.c (+2/-1) src/cfgparse.c (+40/-12) src/dns.c (+18/-6) 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/flt_spoe.c (+22/-9) src/h1.c (+4/-0) src/haproxy.c (+10/-2) src/hlua.c (+3/-1) src/hlua_fcn.c (+3/-0) src/hpack-dec.c (+9/-0) src/http_fetch.c (+9/-6) src/http_msg.c (+7/-1) src/listener.c (+6/-0) src/log.c (+8/-3) src/memory.c (+6/-6) src/mux_h1.c (+1/-1) src/mux_h2.c (+9/-2) src/mworker.c (+4/-2) src/peers.c (+40/-23) src/proto_http.c (+8/-2) src/proto_htx.c (+1/-0) src/proto_sockpair.c (+1/-1) src/proxy.c (+24/-10) src/sample.c (+2/-1) src/server.c (+4/-5) src/signal.c (+3/-0) src/ssl_sock.c (+50/-27) src/standard.c (+4/-3) src/stick_table.c (+29/-17) src/stream.c (+18/-8) src/stream_interface.c (+1/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
git-ubuntu bot | Approve | ||
Sergio Durigan Junior (community) | Approve | ||
Canonical Server | Pending | ||
Canonical Server Reporter | Pending | ||
Review via email: mp+429079@code.launchpad.net |
This proposal supersedes a proposal from 2022-08-29.
Commit message
Description of the change
Update with upstream version 2.0.29. MRE bug: LP #1987914
A couple of patches needed a refresh because there is a change in the systemd service unit file where network.target was replaced by network-
https:/
Moreover, most of the patches were applied in this version, therefore removed from the package.
PPA with the proposed package:
https:/
Sergio Durigan Junior (sergiodj) wrote : | # |
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Thanks for the review Sergio. I did update the changelog with major and critical bug fixes as I did in the Jammy MP.
Regarding the upstream tarball, I did get it using uscan and used uupdate to update the source package, after that I committed all the changes. Not sure why it diverge it TBH.
Sergio Durigan Junior (sergiodj) wrote : | # |
Thanks, Lucas.
Maybe there's something that uupdate does to get rid of these files... Anyway, as I said above, it's not really important and shouldn't block this upload.
Therefore, LGTM, +1.
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Thanks Sergio! Package uploaded:
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
git-ubuntu bot (git-ubuntu-bot) wrote : | # |
Approvers: lucaskanashiro, sergiodj
Uploaders: lucaskanashiro, sergiodj
MP auto-approved
- cbc0ff8... by Lucas Kanashiro
-
Import upstream version 2.0.31 (LP: #2012557)
- 2f28b07... by Lucas Kanashiro
-
Remove patches applied by upstream
- e6f5d97... by Lucas Kanashiro
-
changelog
- 95521a4... by Lucas Kanashiro
-
Refresh existing patches
Preview Diff
1 | diff --git a/.github/matrix.py b/.github/matrix.py |
2 | index 2ea3053..3d704ae 100644 |
3 | --- a/.github/matrix.py |
4 | +++ b/.github/matrix.py |
5 | @@ -8,6 +8,7 @@ |
6 | |
7 | import json |
8 | import sys |
9 | +from os import environ |
10 | |
11 | if len(sys.argv) == 2: |
12 | build_type = sys.argv[1] |
13 | @@ -50,7 +51,7 @@ matrix = [] |
14 | |
15 | # Ubuntu |
16 | |
17 | -os = "ubuntu-latest" |
18 | +os = "ubuntu-20.04" |
19 | TARGET = "linux-glibc" |
20 | for CC in ["gcc", "clang"]: |
21 | matrix.append( |
22 | @@ -125,7 +126,7 @@ for CC in ["gcc", "clang"]: |
23 | |
24 | # ASAN |
25 | |
26 | -os = "ubuntu-latest" |
27 | +os = "ubuntu-20.04" |
28 | CC = "clang" |
29 | TARGET = "linux-glibc" |
30 | matrix.append( |
31 | @@ -173,4 +174,6 @@ for CC in ["clang"]: |
32 | |
33 | print(json.dumps(matrix, indent=4, sort_keys=True)) |
34 | |
35 | -print("::set-output name=matrix::{}".format(json.dumps({"include": matrix}))) |
36 | +if environ.get('GITHUB_OUTPUT') is not None: |
37 | + with open(environ.get('GITHUB_OUTPUT'), 'a') as f: |
38 | + print("matrix={}".format(json.dumps({"include": matrix})), file=f) |
39 | diff --git a/.github/workflows/cross-zoo.yml b/.github/workflows/cross-zoo.yml |
40 | new file mode 100644 |
41 | index 0000000..e2a5816 |
42 | --- /dev/null |
43 | +++ b/.github/workflows/cross-zoo.yml |
44 | @@ -0,0 +1,110 @@ |
45 | +# |
46 | +# this is naamed "zoo" after OpenSSL "cross zoo pipeline" |
47 | +# |
48 | +name: Cross Compile |
49 | + |
50 | +on: |
51 | + schedule: |
52 | + - cron: "0 0 21 * *" |
53 | + |
54 | +permissions: |
55 | + contents: read |
56 | + |
57 | +jobs: |
58 | + cross-compilation: |
59 | + strategy: |
60 | + matrix: |
61 | + platform: [ |
62 | + { |
63 | + arch: aarch64-linux-gnu, |
64 | + libs: libc6-dev-arm64-cross, |
65 | + target: linux-aarch64 |
66 | + }, { |
67 | + arch: alpha-linux-gnu, |
68 | + libs: libc6.1-dev-alpha-cross, |
69 | + target: linux-alpha-gcc |
70 | + }, { |
71 | + arch: arm-linux-gnueabi, |
72 | + libs: libc6-dev-armel-cross, |
73 | + target: linux-armv4 |
74 | + }, { |
75 | + arch: arm-linux-gnueabihf, |
76 | + libs: libc6-dev-armhf-cross, |
77 | + target: linux-armv4 |
78 | + }, { |
79 | + arch: hppa-linux-gnu, |
80 | + libs: libc6-dev-hppa-cross, |
81 | + target: -static linux-generic32 |
82 | + }, { |
83 | + arch: m68k-linux-gnu, |
84 | + libs: libc6-dev-m68k-cross, |
85 | + target: -static -m68040 linux-latomic |
86 | + }, { |
87 | + arch: mips-linux-gnu, |
88 | + libs: libc6-dev-mips-cross, |
89 | + target: -static linux-mips32 |
90 | + }, { |
91 | + arch: mips64-linux-gnuabi64, |
92 | + libs: libc6-dev-mips64-cross, |
93 | + target: -static linux64-mips64 |
94 | + }, { |
95 | + arch: mipsel-linux-gnu, |
96 | + libs: libc6-dev-mipsel-cross, |
97 | + target: linux-mips32 |
98 | + }, { |
99 | + arch: powerpc64le-linux-gnu, |
100 | + libs: libc6-dev-ppc64el-cross, |
101 | + target: linux-ppc64le |
102 | + }, { |
103 | + arch: riscv64-linux-gnu, |
104 | + libs: libc6-dev-riscv64-cross, |
105 | + target: linux64-riscv64 |
106 | + }, { |
107 | + arch: s390x-linux-gnu, |
108 | + libs: libc6-dev-s390x-cross, |
109 | + target: linux64-s390x |
110 | + }, { |
111 | + arch: sh4-linux-gnu, |
112 | + libs: libc6-dev-sh4-cross, |
113 | + target: no-async linux-latomic |
114 | + }, { |
115 | + arch: hppa-linux-gnu, |
116 | + libs: libc6-dev-hppa-cross, |
117 | + target: linux-generic32, |
118 | + }, { |
119 | + arch: m68k-linux-gnu, |
120 | + libs: libc6-dev-m68k-cross, |
121 | + target: -mcfv4e linux-latomic |
122 | + }, { |
123 | + arch: mips-linux-gnu, |
124 | + libs: libc6-dev-mips-cross, |
125 | + target: linux-mips32 |
126 | + }, { |
127 | + arch: mips64-linux-gnuabi64, |
128 | + libs: libc6-dev-mips64-cross, |
129 | + target: linux64-mips64 |
130 | + }, { |
131 | + arch: sparc64-linux-gnu, |
132 | + libs: libc6-dev-sparc64-cross, |
133 | + target: linux64-sparcv9 |
134 | + } |
135 | + ] |
136 | + runs-on: ubuntu-latest |
137 | + steps: |
138 | + - name: install packages |
139 | + run: | |
140 | + sudo apt-get update |
141 | + sudo apt-get -yq --force-yes install \ |
142 | + gcc-${{ matrix.platform.arch }} \ |
143 | + ${{ matrix.platform.libs }} |
144 | + - uses: actions/checkout@v2 |
145 | + |
146 | + |
147 | + - name: install quictls |
148 | + run: | |
149 | + QUICTLS_EXTRA_ARGS="--cross-compile-prefix=${{ matrix.platform.arch }}- ${{ matrix.platform.target }}" QUICTLS=yes scripts/build-ssl.sh |
150 | + |
151 | + - name: Build |
152 | + run: | |
153 | + 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" |
154 | + |
155 | diff --git a/.github/workflows/vtest.yml b/.github/workflows/vtest.yml |
156 | index 8c838cc..b919418 100644 |
157 | --- a/.github/workflows/vtest.yml |
158 | +++ b/.github/workflows/vtest.yml |
159 | @@ -49,7 +49,7 @@ jobs: |
160 | - name: Generate cache key |
161 | id: generate-cache-key |
162 | run: | |
163 | - echo "::set-output name=key::$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')" |
164 | + echo "key=$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')" >> $GITHUB_OUTPUT |
165 | |
166 | - name: Cache SSL libs |
167 | if: ${{ matrix.ssl && matrix.ssl != 'stock' && matrix.ssl != 'BORINGSSL=yes' && matrix.ssl != 'QUICTLS=yes' }} |
168 | @@ -96,6 +96,9 @@ jobs: |
169 | run: make -C contrib/wurfl |
170 | - name: Compile HAProxy with ${{ matrix.CC }} |
171 | run: | |
172 | + echo "::group::Show compiler's version" |
173 | + echo | ${{ matrix.CC }} -v |
174 | + echo "::endgroup::" |
175 | echo "::group::Show platform specific defines" |
176 | echo | ${{ matrix.CC }} -dM -xc -E - |
177 | echo "::endgroup::" |
178 | @@ -119,7 +122,7 @@ jobs: |
179 | fi |
180 | echo "::endgroup::" |
181 | haproxy -vv |
182 | - echo "::set-output name=version::$(haproxy -v |awk 'NR==1{print $3}')" |
183 | + echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT |
184 | - name: Install problem matcher for VTest |
185 | # This allows one to more easily see which tests fail. |
186 | run: echo "::add-matcher::.github/vtest.json" |
187 | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml |
188 | index ceac981..0292e09 100644 |
189 | --- a/.github/workflows/windows.yml |
190 | +++ b/.github/workflows/windows.yml |
191 | @@ -55,9 +55,10 @@ jobs: |
192 | ERR=1 \ |
193 | TARGET=${{ matrix.TARGET }} \ |
194 | CC=${{ matrix.CC }} \ |
195 | + DEBUG_CFLAGS="-g -Wno-deprecated-declarations" \ |
196 | ${{ join(matrix.FLAGS, ' ') }} |
197 | - name: Show HAProxy version |
198 | id: show-version |
199 | run: | |
200 | ./haproxy -vv |
201 | - echo "::set-output name=version::$(./haproxy -v |awk 'NR==1{print $3}')" |
202 | + echo "version=$(./haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT |
203 | diff --git a/CHANGELOG b/CHANGELOG |
204 | index 6ae4bed..4b5713f 100644 |
205 | --- a/CHANGELOG |
206 | +++ b/CHANGELOG |
207 | @@ -1,6 +1,106 @@ |
208 | ChangeLog : |
209 | =========== |
210 | |
211 | +2023/02/14 : 2.0.31 |
212 | + - SCRIPTS: announce-release: add a link to the data plane API |
213 | + - CI: github: change "ubuntu-latest" to "ubuntu-20.04" |
214 | + - BUG/MEDIUM: ssl: Verify error codes can exceed 63 |
215 | + - BUG/MINOR: ssl: Fix potential overflow |
216 | + - BUG/MEDIUM: mworker: fix segv in early failure of mworker mode with peers |
217 | + - BUG/MEDIUM: resolvers: Use tick_first() to update the resolvers task timeout |
218 | + - LICENSE: wurfl: clarify the dummy library license. |
219 | + - BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream flag set |
220 | + - BUG/MINOR: pool/stats: Use ullong to report total pool usage in bytes in stats |
221 | + - BUILD: makefile: build the features list dynamically |
222 | + - BUILD: makefile: sort the features list |
223 | + - BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is realigned |
224 | + - BUG/MINOR: resolvers: Wait the resolution execution for a do_resolv action |
225 | + - BUG/MINOR: promex: Don't forget to consume the request on error |
226 | + - BUG/MINOR: http-fetch: Don't block HTTP sample fetch eval in HTTP_MSG_ERROR state |
227 | + - BUG/MINOR: http-ana: make set-status also update txn->status |
228 | + - BUG/MEDIUM: ssl: wrong eviction from the session cache tree |
229 | + - BUG/MEDIUM: stick-table: do not leave entries in end of window during purge |
230 | + - BUG/MEDIUM: cache: use the correct time reference when comparing dates |
231 | + - DOC: config: fix option spop-check proxy compatibility |
232 | + - DOC: config: 'http-send-name-header' option may be used in default section |
233 | + - DOC: proxy-protocol: fix wrong byte in provided example |
234 | + - CI: github: don't warn on deprecated openssl functions on windows |
235 | + - BUG/CRITICAL: http: properly reject empty http header field names |
236 | + |
237 | +2022/12/09 : 2.0.30 |
238 | + - CI: determine actual LibreSSL version dynamically |
239 | + - BUILD: fix build warning on solaris based systems with __maybe_unused. |
240 | + - REGTESTS: abortonclose: Fix some race conditions |
241 | + - BUG/MINOR: peers: fix error reporting of "bind" lines |
242 | + - BUG/MEDIUM: http: Properly reject non-HTTP/1.x protocols |
243 | + - BUG/MEDIUM: peers: fix segfault using multiple bind on peers sections |
244 | + - BUG/MEDIUM: peers: prevent unitialized multiple listeners on peers section |
245 | + - BUG/MEDIUM: sample: Fix adjusting size in word converter |
246 | + - SCRIPTS: add make-releases-json to recreate a releases.json file in download dirs |
247 | + - SCRIPTS: make publish-release try to launch make-releases-json |
248 | + - DOC: peers: indicate that some server settings are not usable |
249 | + - DOC: peers: clarify when entry expiration date is renewed. |
250 | + - DOC: peers: fix port number and addresses on new peers section format |
251 | + - BUG/MINOR: conn_stream: do not confirm a connection from the frontend path |
252 | + - REGTESTS: abortonclose: Add a barrier to not mix up log messages |
253 | + - REGTESTS: http_request_buffer: Increase client timeout to wait "slow" clients |
254 | + - BUILD: compiler: implement unreachable for older compilers too |
255 | + - BUG/MINOR: server: do not enable DNS resolution on disabled proxies |
256 | + - BUG/MINOR: http-ana: Set method to HTTP_METH_OTHER when an HTTP txn is created |
257 | + - BUG/MINOR: http-fetch: Use integer value when possible in "method" sample fetch |
258 | + - BUG/MINOR: peers/config: always fill the bind_conf's argument |
259 | + - BUG/MINOR: peers: fix possible NULL dereferences at config parsing |
260 | + - BUG/MINOR: backend: Fallback on RR algo if balance on source is impossible |
261 | + - BUG/MINOR: sockpair: wrong return value for fd_send_uxst() |
262 | + - BUG/MINOR: ssl: free the fields in srv->ssl_ctx |
263 | + - MINOR: peers: Use a dedicated reconnect timeout when stopping the local peer |
264 | + - BUG/MEDIUM: peers: limit reconnect attempts of the old process on reload |
265 | + - BUG/MINOR: peers: Use right channel flag to consider the peer as connected |
266 | + - MINOR: server: Constify source server to copy its settings |
267 | + - REORG: server: Export srv_settings_cpy() function |
268 | + - BUG/MEDIUM: proxy: Perform a custom copy for default server settings |
269 | + - BUILD: http: silence an uninitialized warning affecting gcc-5 |
270 | + - BUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle |
271 | + - BUG/MINOR: resolvers: return the correct value in resolvers_finalize_config() |
272 | + - DOC: configuration: do-resolve doesn't work with a port in the string |
273 | + - BUG/MEDIUM: spoe: Properly update streams waiting for a ACK in async mode |
274 | + - BUG/MEDIUM: peers: Add connect and server timeut to peers proxy |
275 | + - BUG/MEDIUM: peers: Don't use resync timer when local resync is in progress |
276 | + - BUG/MEDIUM: peers: Don't start resync on reload if local peer is not up-to-date |
277 | + - REGTESTS: http_request_buffer: Add a barrier to not mix up log messages |
278 | + - BUG/MINOR: h1: Support headers case adjustment for TCP proxies |
279 | + - BUG/MINOR: signals/poller: set the poller timeout to 0 when there are signals |
280 | + - BUG/MINOR: signals/poller: ensure wakeup from signals |
281 | + - BUG/MEDIUM: proxy: ensure pause_proxy() and resume_proxy() own PROXY_LOCK |
282 | + - BUG/MEDIUM: captures: free() an error capture out of the proxy lock |
283 | + - SCRIPTS: announce-release: update some URLs to https |
284 | + - BUG/MINOR: log: improper behavior when escaping log data |
285 | + - BUILD: fix compilation for OpenSSL-3.0.0-alpha17 |
286 | + - BUILD: cfgparse: Fix GCC warning about a variable used after realloc |
287 | + - BUG/MEDIUM: lua: handle stick table implicit arguments right. |
288 | + - BUG/MINOR: http-fetch: Update method after a prefetch in smp_fetch_meth() |
289 | + - BUILD: http_fetch: silence an uninitiialized warning with gcc-4/5/6 at -Os |
290 | + - DOC: configuration: missing 'if' in tcp-request content example |
291 | + - BUG/MAJOR: stick-tables: do not try to index a server name for applets |
292 | + - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in matrix.py |
293 | + - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in workflow definition |
294 | + - DOC: management: add forgotten "show startup-logs" |
295 | + - BUG/MAJOR: stick-table: don't process store-response rules for applets |
296 | + - BUG/MEDIUM: stick-table: fix a race condition when updating the expiration task |
297 | + - CI: add monthly gcc cross compile jobs |
298 | + - CI: emit the compiler's version in the build reports |
299 | + - BUG/MEDIUM: listener: Fix race condition when updating the global mngmt task |
300 | + - BUG/MINOR: http_ana/txn: don't re-initialize txn and req var lists |
301 | + - BUG/MEDIUM: peers: messages about unkown tables not correctly ignored |
302 | + - BUILD: peers: Remove unused variables |
303 | + - BUILD: listener: fix build warning on global_listener_rwlock without threads |
304 | + - DOC: config: provide some configuration hints for "http-reuse" |
305 | + - DOC: config: clarify the fact that SNI should not be used in HTTP scenarios |
306 | + - DOC: config: explain how default matching method for ACL works |
307 | + - DOC: config: clarify the fact that "retries" is not just for connections |
308 | + - DOC: config: clarify the -m dir and -m dom pattern matching methods |
309 | + - Revert "CI: determine actual LibreSSL version dynamically" |
310 | + |
311 | 2022/05/13 : 2.0.29 |
312 | - BUG/MINOR: tools: fix url2sa return value with IPv4 |
313 | - Revert "BUG/MAJOR: mux-pt: Always destroy the backend connection on detach" |
314 | diff --git a/Makefile b/Makefile |
315 | index 7eddac0..bd1042b 100644 |
316 | --- a/Makefile |
317 | +++ b/Makefile |
318 | @@ -449,7 +449,11 @@ ignore_implicit = $(if $(subst environment,,$(origin $(1))), \ |
319 | # is used to report a list of all flags which were used to build this version. |
320 | # Do not assign anything to it. |
321 | BUILD_OPTIONS := $(foreach opt,$(use_opts),$(call ignore_implicit,$(opt))) |
322 | -BUILD_FEATURES := $(foreach opt,$(patsubst USE_%,%,$(use_opts)),$(if $(USE_$(opt)),+$(opt),-$(opt))) |
323 | + |
324 | +# Make a list of all known features with +/- prepended depending on their |
325 | +# activation status. Must be a macro so that dynamically enabled ones are |
326 | +# evaluated with their current status. |
327 | +BUILD_FEATURES = $(foreach opt,$(patsubst USE_%,%,$(sort $(use_opts))),$(if $(USE_$(opt)),+$(opt),-$(opt))) |
328 | |
329 | # All USE_* options have their equivalent macro defined in the code (some might |
330 | # possibly be unused though) |
331 | diff --git a/SUBVERS b/SUBVERS |
332 | index 50af805..e1824da 100644 |
333 | --- a/SUBVERS |
334 | +++ b/SUBVERS |
335 | @@ -1,2 +1,2 @@ |
336 | --5e15b0f |
337 | +-c8b1c15 |
338 | |
339 | diff --git a/VERDATE b/VERDATE |
340 | index cba5e36..2f36592 100644 |
341 | --- a/VERDATE |
342 | +++ b/VERDATE |
343 | @@ -1,2 +1,2 @@ |
344 | -2022-05-13 17:43:21 +0200 |
345 | -2022/05/13 |
346 | +2023-02-14 16:58:28 +0100 |
347 | +2023/02/14 |
348 | diff --git a/VERSION b/VERSION |
349 | index 3df5a46..e235558 100644 |
350 | --- a/VERSION |
351 | +++ b/VERSION |
352 | @@ -1 +1 @@ |
353 | -2.0.29 |
354 | +2.0.31 |
355 | diff --git a/contrib/prometheus-exporter/service-prometheus.c b/contrib/prometheus-exporter/service-prometheus.c |
356 | index d420cbc..3cc502c 100644 |
357 | --- a/contrib/prometheus-exporter/service-prometheus.c |
358 | +++ b/contrib/prometheus-exporter/service-prometheus.c |
359 | @@ -2465,6 +2465,7 @@ static void promex_appctx_handle_io(struct appctx *appctx) |
360 | res->flags |= CF_READ_NULL; |
361 | si_shutr(si); |
362 | si_shutw(si); |
363 | + goto out; |
364 | } |
365 | |
366 | struct applet promex_applet = { |
367 | diff --git a/contrib/wurfl/wurfl/wurfl.h b/contrib/wurfl/wurfl/wurfl.h |
368 | index ca512da..4e089c2 100644 |
369 | --- a/contrib/wurfl/wurfl/wurfl.h |
370 | +++ b/contrib/wurfl/wurfl/wurfl.h |
371 | @@ -4,11 +4,16 @@ |
372 | * Copyright (c) ScientiaMobile, Inc. |
373 | * http://www.scientiamobile.com |
374 | * |
375 | - * This software package is the property of ScientiaMobile Inc. and is licensed |
376 | - * commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor). |
377 | - * If you represent the Licensee, please refer to the licensing agreement which has been signed |
378 | - * between the two parties. If you do not represent the Licensee, you are not authorized to use |
379 | - * this software in any way. |
380 | + * This software package is the property of ScientiaMobile Inc. and is distributed under |
381 | + * a dual licensing scheme: |
382 | + * |
383 | + * 1) commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor). |
384 | + * If you represent the Licensee, please refer to the licensing agreement which has been signed |
385 | + * between the two parties. If you do not represent the Licensee, you are not authorized to use |
386 | + * this software in any way. |
387 | + * |
388 | + * 2) LGPL when used in the context of the HAProxy project with the purpose of testing compatibility |
389 | + * of HAProxy with ScientiaMobile software. |
390 | * |
391 | */ |
392 | |
393 | diff --git a/debian/changelog b/debian/changelog |
394 | index 2e61d7f..5e79222 100644 |
395 | --- a/debian/changelog |
396 | +++ b/debian/changelog |
397 | @@ -1,3 +1,21 @@ |
398 | +haproxy (2.0.31-0ubuntu0.1) focal; urgency=medium |
399 | + |
400 | + * New upstream release (LP: #2012557). |
401 | + - Major and critical bug fixes according to the upstream changelog: |
402 | + + BUG/MAJOR: stick-tables: do not try to index a server name for applets |
403 | + + BUG/MAJOR: stick-table: don't process store-response rules for applets |
404 | + + BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is |
405 | + realigned |
406 | + + BUG/CRITICAL: http: properly reject empty http header field names |
407 | + - Remove patches applied by upstream in debian/patches: |
408 | + + CVE-2023-0056.patch |
409 | + + CVE-2023-25725.patch |
410 | + - Refresh existing patches in debian/patches: |
411 | + + 0002-Use-dpkg-buildflags-to-build-halog.patch |
412 | + + haproxy.service-add-documentation.patch |
413 | + |
414 | + -- Lucas Kanashiro <kanashiro@ubuntu.com> Wed, 22 Mar 2023 17:39:46 -0300 |
415 | + |
416 | haproxy (2.0.29-0ubuntu1.3) focal-security; urgency=medium |
417 | |
418 | * SECURITY UPDATE: incorrect handling of empty http header field names |
419 | diff --git a/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch b/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
420 | index a039316..94e1fb1 100644 |
421 | --- a/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
422 | +++ b/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
423 | @@ -8,8 +8,6 @@ Last-Update: 2013-07-02 |
424 | contrib/halog/Makefile | 16 +++++----------- |
425 | 1 file changed, 5 insertions(+), 11 deletions(-) |
426 | |
427 | -diff --git a/contrib/halog/Makefile b/contrib/halog/Makefile |
428 | -index 5e687c0..ab34027 100644 |
429 | --- a/contrib/halog/Makefile |
430 | +++ b/contrib/halog/Makefile |
431 | @@ -1,22 +1,16 @@ |
432 | diff --git a/debian/patches/CVE-2023-0056.patch b/debian/patches/CVE-2023-0056.patch |
433 | deleted file mode 100644 |
434 | index a10f21b..0000000 |
435 | --- a/debian/patches/CVE-2023-0056.patch |
436 | +++ /dev/null |
437 | @@ -1,39 +0,0 @@ |
438 | -Backport of: |
439 | - |
440 | -From 827a6299e6995c5c3ba620d8b7cbacdaef67f2c4 Mon Sep 17 00:00:00 2001 |
441 | -From: Christopher Faulet <cfaulet@haproxy.com> |
442 | -Date: Thu, 22 Dec 2022 09:47:01 +0100 |
443 | -Subject: [PATCH] BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream |
444 | - flag set |
445 | - |
446 | -As state in RFC9113#8.1, HEADERS frame with the ES flag set that carries an |
447 | -informational status code is malformed. However, there is no test on this |
448 | -condition. |
449 | - |
450 | -On 2.4 and higher, it is hard to predict consequences of this bug because |
451 | -end of the message is only reported with a flag. But on 2.2 and lower, it |
452 | -leads to a crash because there is an unexpected extra EOM block at the end |
453 | -of an interim response. |
454 | - |
455 | -Now, when a ES flag is detected on a HEADERS frame for an interim message, a |
456 | -stream error is sent (RST_STREAM/PROTOCOL_ERROR). |
457 | - |
458 | -This patch should solve the issue #1972. It should be backported as far as |
459 | -2.0. |
460 | ---- |
461 | - src/mux_h2.c | 5 +++++ |
462 | - 1 file changed, 5 insertions(+) |
463 | - |
464 | ---- a/src/mux_h2.c |
465 | -+++ b/src/mux_h2.c |
466 | -@@ -3935,6 +3935,10 @@ next_frame: |
467 | - *flags |= H2_SF_HEADERS_RCVD; |
468 | - |
469 | - if ((h2c->dff & H2_F_HEADERS_END_STREAM)) { |
470 | -+ if (msgf & H2_MSGF_RSP_1XX) { |
471 | -+ /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */ |
472 | -+ goto fail; |
473 | -+ } |
474 | - /* Mark the end of message, either using EOM in HTX or with the |
475 | - * trailing CRLF after the end of trailers. Note that DATA_CHNK |
476 | - * is not set during headers with END_STREAM. For HTX trailers, |
477 | diff --git a/debian/patches/CVE-2023-25725.patch b/debian/patches/CVE-2023-25725.patch |
478 | deleted file mode 100644 |
479 | index e57d84b..0000000 |
480 | --- a/debian/patches/CVE-2023-25725.patch |
481 | +++ /dev/null |
482 | @@ -1,175 +0,0 @@ |
483 | -From 7382253d6a3636fa85510063bdcc9f2e8f8f696d Mon Sep 17 00:00:00 2001 |
484 | -From: Willy Tarreau <w@1wt.eu> |
485 | -Date: Thu, 9 Feb 2023 21:36:54 +0100 |
486 | -Subject: BUG/CRITICAL: http: properly reject empty http header field names |
487 | - |
488 | -The HTTP header parsers surprizingly accepts empty header field names, |
489 | -and this is a leftover from the original code that was agnostic to this. |
490 | - |
491 | -When muxes were introduced, for H2 first, the HPACK decompressor needed |
492 | -to feed headers lists, and since empty header names were strictly |
493 | -forbidden by the protocol, the lists of headers were purposely designed |
494 | -to be terminated by an empty header field name (a principle that is |
495 | -similar to H1's empty line termination). This principle was preserved |
496 | -and generalized to other protocols migrated to muxes (H1/FCGI/H3 etc) |
497 | -without anyone ever noticing that the H1 parser was still able to deliver |
498 | -empty header field names to this list. In addition to this it turns out |
499 | -that the HPACK decompressor, despite a comment in the code, may |
500 | -successfully decompress an empty header field name, and this mistake |
501 | -was propagated to the QPACK decompressor as well. |
502 | - |
503 | -The impact is that an empty header field name may be used to truncate |
504 | -the list of headers and thus make some headers disappear. While for |
505 | -H2/H3 the impact is limited as haproxy sees a request with missing |
506 | -headers, and headers are not used to delimit messages, in the case of |
507 | -HTTP/1, the impact is significant because the presence (and sometimes |
508 | -contents) of certain sensitive headers is detected during the parsing. |
509 | -Thus, some of these headers may be seen, marked as present, their value |
510 | -extracted, but never delivered to upper layers and obviously not |
511 | -forwarded to the other side either. This can have for consequence that |
512 | -certain important header fields such as Connection, Upgrade, Host, |
513 | -Content-length, Transfer-Encoding etc are possibly seen as different |
514 | -between what haproxy uses to parse/forward/route and what is observed |
515 | -in http-request rules and of course, forwarded. One direct consequence |
516 | -is that it is possible to exploit this property in HTTP/1 to make |
517 | -affected versions of haproxy forward more data than is advertised on |
518 | -the other side, and bypass some access controls or routing rules by |
519 | -crafting extraneous requests. Note, however, that responses to such |
520 | -requests will normally not be passed back to the client, but this can |
521 | -still cause some harm. |
522 | - |
523 | -This specific risk can be mostly worked around in configuration using |
524 | -the following rule that will rely on the bug's impact to precisely |
525 | -detect the inconsistency between the known body size and the one |
526 | -expected to be advertised to the server (the rule works from 2.0 to |
527 | -2.8-dev): |
528 | - |
529 | - 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 } |
530 | - |
531 | -This will exclusively block such carefully crafted requests delivered |
532 | -over HTTP/1. HTTP/2 and HTTP/3 do not need content-length, and a body |
533 | -that arrives without being announced with a content-length will be |
534 | -forwarded using transfer-encoding, hence will not cause discrepancies. |
535 | -In HAProxy 2.0 in legacy mode ("no option http-use-htx"), this rule will |
536 | -simply have no effect but will not cause trouble either. |
537 | - |
538 | -A clean solution would consist in modifying the loops iterating over |
539 | -these headers lists to check the header name's pointer instead of its |
540 | -length (since both are zero at the end of the list), but this requires |
541 | -to touch tens of places and it's very easy to miss one. Functions such |
542 | -as htx_add_header(), htx_add_trailer(), htx_add_all_headers() would be |
543 | -good starting points for such a possible future change. |
544 | - |
545 | -Instead the current fix focuses on blocking empty headers where they |
546 | -are first inserted, hence in the H1/HPACK/QPACK decoders. One benefit |
547 | -of the current solution (for H1) is that it allows "show errors" to |
548 | -report a precise diagnostic when facing such invalid HTTP/1 requests, |
549 | -with the exact location of the problem and the originating address: |
550 | - |
551 | - $ printf "GET / HTTP/1.1\r\nHost: localhost\r\n:empty header\r\n\r\n" | nc 0 8001 |
552 | - HTTP/1.1 400 Bad request |
553 | - Content-length: 90 |
554 | - Cache-Control: no-cache |
555 | - Connection: close |
556 | - Content-Type: text/html |
557 | - |
558 | - <html><body><h1>400 Bad request</h1> |
559 | - Your browser sent an invalid request. |
560 | - </body></html> |
561 | - |
562 | - $ socat /var/run/haproxy.stat <<< "show errors" |
563 | - Total events captured on [10/Feb/2023:16:29:37.530] : 1 |
564 | - |
565 | - [10/Feb/2023:16:29:34.155] frontend decrypt (#2): invalid request |
566 | - backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:31092 |
567 | - buffer starts at 0 (including 0 out), 16334 free, |
568 | - len 50, wraps at 16336, error at position 33 |
569 | - H1 connection flags 0x00000000, H1 stream flags 0x00000810 |
570 | - H1 msg state MSG_HDR_NAME(17), H1 msg flags 0x00001410 |
571 | - H1 chunk len 0 bytes, H1 body len 0 bytes : |
572 | - |
573 | - 00000 GET / HTTP/1.1\r\n |
574 | - 00016 Host: localhost\r\n |
575 | - 00033 :empty header\r\n |
576 | - 00048 \r\n |
577 | - |
578 | -I want to address sincere and warm thanks for their great work to the |
579 | -team composed of the following security researchers who found the issue |
580 | -together and reported it: Bahruz Jabiyev, Anthony Gavazzi, and Engin |
581 | -Kirda from Northeastern University, Kaan Onarlioglu from Akamai |
582 | -Technologies, Adi Peleg and Harvey Tuch from Google. And kudos to Amaury |
583 | -Denoyelle from HAProxy Technologies for spotting that the HPACK and |
584 | -QPACK decoders would let this pass despite the comment explicitly |
585 | -saying otherwise. |
586 | - |
587 | -This fix must be backported as far as 2.0. The QPACK changes can be |
588 | -dropped before 2.6. In 2.0 there is also the equivalent code for legacy |
589 | -mode, which doesn't suffer from the list truncation, but it would better |
590 | -be fixed regardless. |
591 | - |
592 | -CVE-2023-25725 was assigned to this issue. |
593 | - |
594 | ---- |
595 | - src/h1.c | 4 ++++ |
596 | - src/hpack-dec.c | 9 +++++++++ |
597 | - src/http_msg.c | 8 +++++++- |
598 | - 3 files changed, 20 insertions(+), 1 deletion(-) |
599 | - |
600 | -diff --git a/src/h1.c b/src/h1.c |
601 | -index 3839fbe97..69a7cedcb 100644 |
602 | ---- a/src/h1.c |
603 | -+++ b/src/h1.c |
604 | -@@ -672,6 +672,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop, |
605 | - |
606 | - if (likely(*ptr == ':')) { |
607 | - col = ptr - start; |
608 | -+ if (col <= sol) { |
609 | -+ state = H1_MSG_HDR_NAME; |
610 | -+ goto http_msg_invalid; |
611 | -+ } |
612 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP); |
613 | - } |
614 | - |
615 | -diff --git a/src/hpack-dec.c b/src/hpack-dec.c |
616 | -index 7f3e7624b..0fc71ebeb 100644 |
617 | ---- a/src/hpack-dec.c |
618 | -+++ b/src/hpack-dec.c |
619 | -@@ -425,6 +425,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len, |
620 | - /* <name> and <value> are correctly filled here */ |
621 | - } |
622 | - |
623 | -+ /* We must not accept empty header names (forbidden by the spec and used |
624 | -+ * as a list termination). |
625 | -+ */ |
626 | -+ if (!name.len) { |
627 | -+ hpack_debug_printf("##ERR@%d##\n", __LINE__); |
628 | -+ ret = -HPACK_ERR_INVALID_ARGUMENT; |
629 | -+ goto leave; |
630 | -+ } |
631 | -+ |
632 | - /* here's what we have here : |
633 | - * - name.len > 0 |
634 | - * - value is filled with either const data or data allocated from tmp |
635 | -diff --git a/src/http_msg.c b/src/http_msg.c |
636 | -index 067a7f863..e07c81c67 100644 |
637 | ---- a/src/http_msg.c |
638 | -+++ b/src/http_msg.c |
639 | -@@ -1006,8 +1006,14 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) |
640 | - if (likely(HTTP_IS_TOKEN(*ptr))) |
641 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME); |
642 | - |
643 | -- if (likely(*ptr == ':')) |
644 | -+ if (likely(*ptr == ':')) { |
645 | -+ if (ptr == input + msg->sol) { |
646 | -+ /* empty header names are not permitted */ |
647 | -+ state = HTTP_MSG_HDR_NAME; |
648 | -+ goto http_msg_invalid; |
649 | -+ } |
650 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP); |
651 | -+ } |
652 | - |
653 | - if (likely(msg->err_pos < -1) || *ptr == '\n') { |
654 | - state = HTTP_MSG_HDR_NAME; |
655 | --- |
656 | -2.35.3 |
657 | - |
658 | diff --git a/debian/patches/haproxy.service-add-documentation.patch b/debian/patches/haproxy.service-add-documentation.patch |
659 | index 1ebd2f1..023cb17 100644 |
660 | --- a/debian/patches/haproxy.service-add-documentation.patch |
661 | +++ b/debian/patches/haproxy.service-add-documentation.patch |
662 | @@ -11,11 +11,11 @@ Last-Update: 2022-08-26 |
663 | |
664 | --- a/contrib/systemd/haproxy.service.in |
665 | +++ b/contrib/systemd/haproxy.service.in |
666 | -@@ -1,5 +1,7 @@ |
667 | +@@ -1,6 +1,6 @@ |
668 | [Unit] |
669 | Description=HAProxy Load Balancer |
670 | -+Documentation=man:haproxy(1) |
671 | -+Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz |
672 | - After=network-online.target rsyslog.service |
673 | +-After=network-online.target rsyslog.service |
674 | ++After=network-online.target |
675 | Wants=network-online.target |
676 | |
677 | + [Service] |
678 | diff --git a/debian/patches/series b/debian/patches/series |
679 | index f7b2e27..0945bb0 100644 |
680 | --- a/debian/patches/series |
681 | +++ b/debian/patches/series |
682 | @@ -1,5 +1,3 @@ |
683 | 0002-Use-dpkg-buildflags-to-build-halog.patch |
684 | haproxy.service-start-after-syslog.patch |
685 | haproxy.service-add-documentation.patch |
686 | -CVE-2023-0056.patch |
687 | -CVE-2023-25725.patch |
688 | diff --git a/doc/configuration.txt b/doc/configuration.txt |
689 | index 4394d07..4c7c59e 100644 |
690 | --- a/doc/configuration.txt |
691 | +++ b/doc/configuration.txt |
692 | @@ -3,7 +3,7 @@ |
693 | Configuration Manual |
694 | ---------------------- |
695 | version 2.0 |
696 | - 2022/05/13 |
697 | + 2023/02/14 |
698 | |
699 | |
700 | This document covers the configuration language as implemented in the version |
701 | @@ -2106,9 +2106,10 @@ default-server [param*] |
702 | Arguments: |
703 | <param*> is a list of parameters for this server. The "default-server" |
704 | keyword accepts an important number of options and has a complete |
705 | - section dedicated to it. Please refer to section 5 for more |
706 | - details. |
707 | - |
708 | + section dedicated to it. In a peers section, the transport |
709 | + parameters of a "default-server" line are supported. Please refer |
710 | + to section 5 for more details, and the "server" keyword below in |
711 | + this section for some of the restrictions. |
712 | |
713 | See also: "server" and section 5 about server options |
714 | |
715 | @@ -2140,12 +2141,16 @@ peer <peername> <ip>:<port> [param*] |
716 | |
717 | server <peername> [<ip>:<port>] [param*] |
718 | As previously mentioned, "peer" keyword may be replaced by "server" keyword |
719 | - with a support for all "server" parameters found in 5.2 paragraph. |
720 | - If the underlying peer is local, <ip>:<port> parameters must not be present. |
721 | - These parameters must be provided on a "bind" line (see "bind" keyword |
722 | - of this "peers" section). |
723 | - Some of these parameters are irrelevant for "peers" sections. |
724 | + with a support for all "server" parameters found in 5.2 paragraph that are |
725 | + related to transport settings. If the underlying peer is local, <ip>:<port> |
726 | + parameters must not be present; these parameters must be provided on a "bind" |
727 | + line (see "bind" keyword of this "peers" section). |
728 | |
729 | + A number of "server" parameters are irrelevant for "peers" sections. Peers by |
730 | + nature do not support dynamic host name resolution nor health checks, hence |
731 | + parameters like "init_addr", "resolvers", "check", "agent-check", or "track" |
732 | + are not supported. Similarly, there is no load balancing nor stickiness, thus |
733 | + parameters such as "weight" or "cookie" have no effect. |
734 | |
735 | Example: |
736 | # The old way. |
737 | @@ -2165,10 +2170,11 @@ server <peername> [<ip>:<port>] [param*] |
738 | |
739 | Example: |
740 | peers mypeers |
741 | - bind 127.0.0.11:10001 ssl crt mycerts/pem |
742 | - default-server ssl verify none |
743 | - server hostA 127.0.0.10:10000 |
744 | - server hostB #local peer |
745 | + bind 192.168.0.1:1024 ssl crt mycerts/pem |
746 | + default-server ssl verify none |
747 | + server haproxy1 #local peer |
748 | + server haproxy2 192.168.0.2:1024 |
749 | + server haproxy3 10.2.0.1:1024 |
750 | |
751 | |
752 | table <tablename> type {ip | integer | string [len <length>] | binary [len <length>]} |
753 | @@ -2433,7 +2439,7 @@ http-check send-state X - X X |
754 | http-request - X X X |
755 | http-response - X X X |
756 | http-reuse X - X X |
757 | -http-send-name-header - - X X |
758 | +http-send-name-header X - X X |
759 | id - X X X |
760 | ignore-persist - - X X |
761 | load-server-state-from-file X - X X |
762 | @@ -2493,7 +2499,7 @@ option socket-stats (*) X X X - |
763 | option splice-auto (*) X X X X |
764 | option splice-request (*) X X X X |
765 | option splice-response (*) X X X X |
766 | -option spop-check - - - X |
767 | +option spop-check X - X X |
768 | option srvtcpka (*) X - X X |
769 | option ssl-hello-chk X - X X |
770 | -- keyword -------------------------- defaults - frontend - listen -- backend - |
771 | @@ -4466,7 +4472,8 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> : |
772 | based on information found in the request (IE a Host header). |
773 | If this action is used to find the server's IP address (using the |
774 | "set-dst" action), then the server IP address in the backend must be set |
775 | - to 0.0.0.0. |
776 | + to 0.0.0.0. The do-resolve action takes an host-only parameter, any port must |
777 | + be removed from the string. |
778 | |
779 | Example: |
780 | resolvers mydns |
781 | @@ -4481,7 +4488,7 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> : |
782 | |
783 | frontend fe |
784 | bind 10.42.0.1:80 |
785 | - http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower |
786 | + http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower,regsub(:[0-9]*$,) |
787 | http-request capture var(txn.myip) len 40 |
788 | |
789 | # return 503 when the variable is not set, |
790 | @@ -5420,7 +5427,26 @@ http-reuse { never | safe | aggressive | always } |
791 | because almost no new connection will be established while idle connections |
792 | remain available. This is particularly true with the "always" strategy. |
793 | |
794 | - See also : "option http-keep-alive", "server maxconn" |
795 | + The rules to decide to keep an idle connection opened or to close it after |
796 | + processing are also governed by the "tune.pool-low-fd-ratio" (default: 20%) |
797 | + and "tune.pool-high-fd-ratio" (default: 25%). These correspond to the |
798 | + percentage of total file descriptors spent in idle connections above which |
799 | + haproxy will respectively refrain from keeping a connection opened after a |
800 | + response, and actively kill idle connections. Some setups using a very high |
801 | + ratio of idle connections, either because of too low a global "maxconn", or |
802 | + due to a lot of HTTP/2 or HTTP/3 traffic on the frontend (few connections) |
803 | + but HTTP/1 connections on the backend, may observe a lower reuse rate because |
804 | + too few connections are kept open. It may be desirable in this case to adjust |
805 | + such thresholds or simply to increase the global "maxconn" value. |
806 | + |
807 | + Similarly, when thread groups are explicitly enabled, it is important to |
808 | + understand that idle connections are only usable between threads from a same |
809 | + group. As such it may happen that unfair load between groups leads to more |
810 | + idle connections being needed, causing a lower reuse rate. The same solution |
811 | + may then be applied (increase global "maxconn" or increase pool ratios). |
812 | + |
813 | + See also : "option http-keep-alive", "server maxconn", "thread-groups", |
814 | + "tune.pool-high-fd-ratio", "tune.pool-low-fd-ratio" |
815 | |
816 | |
817 | http-send-name-header [<header>] |
818 | @@ -7490,7 +7516,7 @@ no option splice-response |
819 | option spop-check |
820 | Use SPOP health checks for server testing |
821 | May be used in sections : defaults | frontend | listen | backend |
822 | - no | no | no | yes |
823 | + yes | no | yes | yes |
824 | Arguments : none |
825 | |
826 | It is possible to test that the server correctly talks SPOP protocol instead |
827 | @@ -8333,24 +8359,26 @@ reqitarpit <search> [{if | unless} <cond>] (ignore case) (deprecated) |
828 | |
829 | |
830 | retries <value> |
831 | - Set the number of retries to perform on a server after a connection failure |
832 | + Set the number of retries to perform on a server after a failure |
833 | May be used in sections: defaults | frontend | listen | backend |
834 | yes | no | yes | yes |
835 | Arguments : |
836 | - <value> is the number of times a connection attempt should be retried on |
837 | - a server when a connection either is refused or times out. The |
838 | - default value is 3. |
839 | + <value> is the number of times a request or connection attempt should be |
840 | + retried on a server after a failure. |
841 | |
842 | - It is important to understand that this value applies to the number of |
843 | - connection attempts, not full requests. When a connection has effectively |
844 | - been established to a server, there will be no more retry. |
845 | + By default, retries apply only to new connection attempts. However, when |
846 | + the "retry-on" directive is used, other conditions might trigger a retry |
847 | + (e.g. empty response, undesired status code), and each of them will count |
848 | + one attempt, and when the total number attempts reaches the value here, an |
849 | + error will be returned. |
850 | |
851 | In order to avoid immediate reconnections to a server which is restarting, |
852 | a turn-around timer of min("timeout connect", one second) is applied before |
853 | - a retry occurs. |
854 | + a retry occurs on the same server. |
855 | |
856 | - When "option redispatch" is set, the last retry may be performed on another |
857 | - server even if a cookie references a different server. |
858 | + When "option redispatch" is set, some retries may be performed on another |
859 | + server even if a cookie references a different server. By default this will |
860 | + only be the last retry unless an argument is passed to "option redispatch". |
861 | |
862 | See also : "option redispatch" |
863 | |
864 | @@ -9607,13 +9635,16 @@ stick-table type {ip | integer | string [len <length>] | binary [len <length>]} |
865 | belonging to the same unique process. |
866 | |
867 | <expire> defines the maximum duration of an entry in the table since it |
868 | - was last created, refreshed or matched. The expiration delay is |
869 | + was last created, refreshed using 'track-sc' or matched using |
870 | + 'stick match' or 'stick on' rule. The expiration delay is |
871 | defined using the standard time format, similarly as the various |
872 | timeouts. The maximum duration is slightly above 24 days. See |
873 | section 2.4 for more information. If this delay is not specified, |
874 | the session won't automatically expire, but older entries will |
875 | be removed once full. Be sure not to use the "nopurge" parameter |
876 | if not expiration delay is specified. |
877 | + Note: 'table_*' converters performs lookups but won't update touch |
878 | + expire since they don't require 'track-sc'. |
879 | |
880 | <data_type> is used to store additional information in the stick-table. This |
881 | may be used by ACLs in order to control various criteria related |
882 | @@ -10448,7 +10479,7 @@ tcp-request content <action> [{if | unless} <condition>] |
883 | evaluated. |
884 | |
885 | Example: |
886 | - tcp-request content use-service lua.deny { src -f /etc/haproxy/blacklist.lst } |
887 | + tcp-request content use-service lua.deny if { src -f /etc/haproxy/blacklist.lst } |
888 | |
889 | Example: |
890 | |
891 | @@ -12880,8 +12911,10 @@ sni <expression> |
892 | The "sni" parameter evaluates the sample fetch expression, converts it to a |
893 | string and uses the result as the host name sent in the SNI TLS extension to |
894 | the server. A typical use case is to send the SNI received from the client in |
895 | - a bridged HTTPS scenario, using the "ssl_fc_sni" sample fetch for the |
896 | - expression, though alternatives such as req.hdr(host) can also make sense. If |
897 | + a bridged TCP/SSL scenario, using the "ssl_fc_sni" sample fetch for the |
898 | + expression. THIS MUST NOT BE USED FOR HTTPS, where req.hdr(host) should be |
899 | + used instead, since SNI in HTTPS must always match the Host field and clients |
900 | + are allowed to use different host names over the same connection). If |
901 | "verify required" is set (which is the recommended setting), the resulting |
902 | name will also be matched against the server certificate's names. See the |
903 | "verify" directive for more details. If you want to set a SNI for health |
904 | @@ -13520,7 +13553,11 @@ possible to convert the sample to lowercase before matching, like this : |
905 | All ACL-specific criteria imply a default matching method. Most often, these |
906 | criteria are composed by concatenating the name of the original sample fetch |
907 | method and the matching method. For example, "hdr_beg" applies the "beg" match |
908 | -to samples retrieved using the "hdr" fetch method. Since all ACL-specific |
909 | +to samples retrieved using the "hdr" fetch method. This matching method is only |
910 | +usable when the keyword is used alone, without any converter. In case any such |
911 | +converter were to be applied after such an ACL keyword, the default matching |
912 | +method from the ACL keyword is simply ignored since what will matter for the |
913 | +matching is the output type of the last converter. Since all ACL-specific |
914 | criteria rely on a sample fetch method, it is always possible instead to use |
915 | the original sample fetch method and the explicit matching method using "-m". |
916 | |
917 | @@ -13646,13 +13683,24 @@ different forms : |
918 | - suffix match (-m end) : the patterns are compared with the end of the |
919 | extracted string, and the ACL matches if any of them matches. |
920 | |
921 | - - subdir match (-m dir) : the patterns are looked up inside the extracted |
922 | - string, delimited with slashes ("/"), and the ACL matches if any of them |
923 | - matches. |
924 | - |
925 | - - domain match (-m dom) : the patterns are looked up inside the extracted |
926 | - string, delimited with dots ("."), and the ACL matches if any of them |
927 | - matches. |
928 | + - subdir match (-m dir) : the patterns are looked up anywhere inside the |
929 | + extracted string, delimited with slashes ("/"), the beginning or the end |
930 | + of the string. The ACL matches if any of them matches. As such, the string |
931 | + "/images/png/logo/32x32.png", would match "/images", "/images/png", |
932 | + "images/png", "/png/logo", "logo/32x32.png" or "32x32.png" but not "png" |
933 | + nor "32x32". |
934 | + |
935 | + - domain match (-m dom) : the patterns are looked up anywhere inside the |
936 | + extracted string, delimited with dots ("."), colons (":"), slashes ("/"), |
937 | + question marks ("?"), the beginning or the end of the string. This is made |
938 | + to be used with URLs. Leading and trailing delimiters in the pattern are |
939 | + ignored. The ACL matches if any of them matches. As such, in the example |
940 | + string "http://www1.dc-eu.example.com:80/blah", the patterns "http", |
941 | + "www1", ".www1", "dc-eu", "example", "com", "80", "dc-eu.example", |
942 | + "blah", ":www1:", "dc-eu.example:80" would match, but not "eu" nor "dc". |
943 | + Using it to match domain suffixes for filtering or routing is generally |
944 | + not a good idea, as the routing could easily be fooled by prepending the |
945 | + matching prefix in front of another domain for example. |
946 | |
947 | String matching applies to verbatim strings as they are passed, with the |
948 | exception of the backslash ("\") which makes it possible to escape some |
949 | @@ -16168,6 +16216,16 @@ ssl_fc_sni : string |
950 | requires that the SSL library is built with support for TLS extensions |
951 | enabled (check haproxy -vv). |
952 | |
953 | + CAUTION! Except under very specific conditions, it is normally not correct to |
954 | + use this field as a substitute for the HTTP "Host" header field. For example, |
955 | + when forwarding an HTTPS connection to a server, the SNI field must be set |
956 | + from the HTTP Host header field using "req.hdr(host)" and not from the front |
957 | + SNI value. The reason is that SNI is solely used to select the certificate |
958 | + the server side will present, and that clients are then allowed to send |
959 | + requests with different Host values as long as they match the names in the |
960 | + certificate. As such, "ssl_fc_sni" should normally not be used as an argument |
961 | + to the "sni" server keyword, unless the backend works in TCP mode. |
962 | + |
963 | ACL derivatives : |
964 | ssl_fc_sni_end : suffix match |
965 | ssl_fc_sni_reg : regex match |
966 | diff --git a/doc/management.txt b/doc/management.txt |
967 | index 337cc14..f90110b 100644 |
968 | --- a/doc/management.txt |
969 | +++ b/doc/management.txt |
970 | @@ -2458,6 +2458,10 @@ show stat [{<iid>|<proxy>} <type> <sid>] [typed|json] |
971 | $ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ |
972 | python -m json.tool |
973 | |
974 | +show startup-logs |
975 | + Dump all messages emitted during the startup of the current haproxy process, |
976 | + each startup-logs buffer is unique to its haproxy worker. |
977 | + |
978 | show table |
979 | Dump general information on all known stick-tables. Their name is returned |
980 | (the name of the proxy which holds them), their type (currently zero, always |
981 | diff --git a/doc/proxy-protocol.txt b/doc/proxy-protocol.txt |
982 | index ff64c8b..45bafe3 100644 |
983 | --- a/doc/proxy-protocol.txt |
984 | +++ b/doc/proxy-protocol.txt |
985 | @@ -500,7 +500,7 @@ protocol. Identifying the protocol version is easy : |
986 | - if the incoming byte count is 16 or above and the 13 first bytes match |
987 | the protocol signature block followed by the protocol version 2 : |
988 | |
989 | - \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02 |
990 | + \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x20 |
991 | |
992 | - otherwise, if the incoming byte count is 8 or above, and the 5 first |
993 | characters match the US-ASCII representation of "PROXY" then the protocol |
994 | diff --git a/include/common/buf.h b/include/common/buf.h |
995 | index 1ee6420..3770b9a 100644 |
996 | --- a/include/common/buf.h |
997 | +++ b/include/common/buf.h |
998 | @@ -469,7 +469,7 @@ static inline void b_slow_realign(struct buffer *b, char *swap, size_t output) |
999 | |
1000 | /* process output data in two steps to cover wrapping */ |
1001 | if (block1 > b_size(b) - b_head_ofs(b)) { |
1002 | - block2 = b_size(b) - b_head_ofs(b); |
1003 | + block2 = b_peek_ofs(b, block1); |
1004 | block1 -= block2; |
1005 | } |
1006 | memcpy(swap + b_size(b) - output, b_head(b), block1); |
1007 | diff --git a/include/common/compiler.h b/include/common/compiler.h |
1008 | index c023c9d..4b76cec 100644 |
1009 | --- a/include/common/compiler.h |
1010 | +++ b/include/common/compiler.h |
1011 | @@ -77,10 +77,12 @@ |
1012 | #endif |
1013 | #endif |
1014 | |
1015 | +#ifndef __maybe_unused |
1016 | /* silence the "unused" warnings without having to place painful #ifdefs. |
1017 | * For use with variables or functions. |
1018 | */ |
1019 | #define __maybe_unused __attribute__((unused)) |
1020 | +#endif |
1021 | |
1022 | /* This allows gcc to know that some locations are never reached, for example |
1023 | * after a longjmp() in the Lua code, hence that some errors caught by such |
1024 | @@ -91,7 +93,7 @@ |
1025 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) |
1026 | #define my_unreachable() __builtin_unreachable() |
1027 | #else |
1028 | -#define my_unreachable() |
1029 | +#define my_unreachable() do { } while (1) |
1030 | #endif |
1031 | |
1032 | /* This macro may be used to block constant propagation that lets the compiler |
1033 | diff --git a/include/common/memory.h b/include/common/memory.h |
1034 | index 6c0b137..ee3b7f0 100644 |
1035 | --- a/include/common/memory.h |
1036 | +++ b/include/common/memory.h |
1037 | @@ -131,8 +131,8 @@ void create_pool_callback(struct pool_head **ptr, char *name, unsigned int size) |
1038 | void dump_pools_to_trash(); |
1039 | void dump_pools(void); |
1040 | int pool_total_failures(); |
1041 | -unsigned long pool_total_allocated(); |
1042 | -unsigned long pool_total_used(); |
1043 | +unsigned long long pool_total_allocated(); |
1044 | +unsigned long long pool_total_used(); |
1045 | |
1046 | /* |
1047 | * This function frees whatever can be freed in pool <pool>. |
1048 | diff --git a/include/common/standard.h b/include/common/standard.h |
1049 | index 38e2bb7..49b72c8 100644 |
1050 | --- a/include/common/standard.h |
1051 | +++ b/include/common/standard.h |
1052 | @@ -498,7 +498,8 @@ char *encode_chunk(char *start, char *stop, |
1053 | |
1054 | /* |
1055 | * Tries to prefix characters tagged in the <map> with the <escape> |
1056 | - * character. The input <string> must be zero-terminated. The result will |
1057 | + * character. The input <string> is processed until string_stop |
1058 | + * is reached or NULL-byte is encountered. The result will |
1059 | * be stored between <start> (included) and <stop> (excluded). This |
1060 | * function will always try to terminate the resulting string with a '\0' |
1061 | * before <stop>, and will return its position if the conversion |
1062 | @@ -506,7 +507,7 @@ char *encode_chunk(char *start, char *stop, |
1063 | */ |
1064 | char *escape_string(char *start, char *stop, |
1065 | const char escape, const long *map, |
1066 | - const char *string); |
1067 | + const char *string, const char *string_stop); |
1068 | |
1069 | /* |
1070 | * Tries to prefix characters tagged in the <map> with the <escape> |
1071 | diff --git a/include/proto/server.h b/include/proto/server.h |
1072 | index 8934075..7f8c725 100644 |
1073 | --- a/include/proto/server.h |
1074 | +++ b/include/proto/server.h |
1075 | @@ -46,6 +46,7 @@ extern struct list toremove_connections[MAX_THREADS]; |
1076 | int srv_downtime(const struct server *s); |
1077 | int srv_lastsession(const struct server *s); |
1078 | int srv_getinter(const struct check *check); |
1079 | +void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl); |
1080 | int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve); |
1081 | int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater); |
1082 | const char *update_server_addr_port(struct server *s, const char *addr, const char *port, char *updater); |
1083 | diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h |
1084 | index d6d01a7..f23cbdc 100644 |
1085 | --- a/include/proto/ssl_sock.h |
1086 | +++ b/include/proto/ssl_sock.h |
1087 | @@ -102,6 +102,31 @@ void ssl_async_fd_free(int fd); |
1088 | |
1089 | #define sh_ssl_sess_tree_lookup(k) (struct sh_ssl_sess_hdr *)ebmb_lookup(sh_ssl_sess_tree, \ |
1090 | (k), SSL_MAX_SSL_SESSION_ID_LENGTH); |
1091 | + |
1092 | +static inline int cert_ignerr_bitfield_get(const unsigned long long *bitfield, int bit_index) |
1093 | +{ |
1094 | + int byte_index = bit_index >> 6; |
1095 | + int val = 0; |
1096 | + |
1097 | + if (byte_index < IGNERR_BF_SIZE) |
1098 | + val = bitfield[byte_index] & (1ULL << (bit_index & 0x3F)); |
1099 | + |
1100 | + return val != 0; |
1101 | +} |
1102 | + |
1103 | +static inline void cert_ignerr_bitfield_set(unsigned long long *bitfield, int bit_index) |
1104 | +{ |
1105 | + int byte_index = bit_index >> 6; |
1106 | + |
1107 | + if (byte_index < IGNERR_BF_SIZE) |
1108 | + bitfield[byte_index] |= (1ULL << (bit_index & 0x3F)); |
1109 | +} |
1110 | + |
1111 | +static inline void cert_ignerr_bitfield_set_all(unsigned long long *bitfield) |
1112 | +{ |
1113 | + memset(bitfield, -1, IGNERR_BF_SIZE*sizeof(*bitfield)); |
1114 | +} |
1115 | + |
1116 | #endif /* USE_OPENSSL */ |
1117 | #endif /* _PROTO_SSL_SOCK_H */ |
1118 | |
1119 | diff --git a/include/types/global.h b/include/types/global.h |
1120 | index eab3345..a505009 100644 |
1121 | --- a/include/types/global.h |
1122 | +++ b/include/types/global.h |
1123 | @@ -240,6 +240,7 @@ extern char hostname[MAX_HOSTNAME_LEN]; |
1124 | extern char localpeer[MAX_HOSTNAME_LEN]; |
1125 | extern struct list global_listener_queue; /* list of the temporarily limited listeners */ |
1126 | extern struct task *global_listener_queue_task; |
1127 | +__decl_hathreads(extern HA_RWLOCK_T global_listener_rwlock); |
1128 | extern unsigned int warned; /* bitfield of a few warnings to emit just once */ |
1129 | extern volatile unsigned long sleeping_thread_mask; |
1130 | extern struct list proc_list; /* list of process in mworker mode */ |
1131 | diff --git a/include/types/listener.h b/include/types/listener.h |
1132 | index def48b0..10464fa 100644 |
1133 | --- a/include/types/listener.h |
1134 | +++ b/include/types/listener.h |
1135 | @@ -139,12 +139,21 @@ struct ssl_bind_conf { |
1136 | #endif |
1137 | }; |
1138 | |
1139 | +/* |
1140 | + * In OpenSSL 3.0.0, the biggest verify error code's value is 94 and on the |
1141 | + * latest 1.1.1 it already reaches 79 so we need to size the ca/crt-ignore-err |
1142 | + * arrays accordingly. If the max error code increases, the arrays might need to |
1143 | + * be resized. |
1144 | + */ |
1145 | +#define SSL_MAX_VFY_ERROR_CODE 94 |
1146 | +#define IGNERR_BF_SIZE ((SSL_MAX_VFY_ERROR_CODE >> 6) + 1) |
1147 | + |
1148 | /* "bind" line settings */ |
1149 | struct bind_conf { |
1150 | #ifdef USE_OPENSSL |
1151 | struct ssl_bind_conf ssl_conf; /* ssl conf for ctx setting */ |
1152 | - unsigned long long ca_ignerr; /* ignored verify errors in handshake if depth > 0 */ |
1153 | - unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */ |
1154 | + unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */ |
1155 | + unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */ |
1156 | SSL_CTX *initial_ctx; /* SSL context for initial negotiation */ |
1157 | SSL_CTX *default_ctx; /* SSL context of first/default certificate */ |
1158 | struct ssl_bind_conf *default_ssl_conf; /* custom SSL conf of default_ctx */ |
1159 | diff --git a/reg-tests/http-messaging/http_abortonclose.vtc b/reg-tests/http-messaging/http_abortonclose.vtc |
1160 | index 733242b..b6066ba 100644 |
1161 | --- a/reg-tests/http-messaging/http_abortonclose.vtc |
1162 | +++ b/reg-tests/http-messaging/http_abortonclose.vtc |
1163 | @@ -7,10 +7,12 @@ feature ignore_unknown_macro |
1164 | #REQUIRE_VERSION=2.0 |
1165 | #REGTEST_TYPE=slow |
1166 | |
1167 | +# b0 : Wait s1 was detected as DOWN to be sure it is stopped |
1168 | # b1 : Don't send /c4 before /c3 was received by s2 server |
1169 | # b2 : Don't finish c2 before c1 and c3 before c4 (from syslog POV) |
1170 | # b3 : finish c3 before s2 |
1171 | |
1172 | +barrier b0 cond 2 -cyclic |
1173 | barrier b1 cond 2 -cyclic |
1174 | barrier b2 cond 2 -cyclic |
1175 | barrier b3 cond 2 -cyclic |
1176 | @@ -32,12 +34,16 @@ server s2 { |
1177 | } -start |
1178 | |
1179 | syslog S -level info { |
1180 | + recv alert |
1181 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: Server check/srv1 is DOWN.*" |
1182 | + barrier b0 sync |
1183 | + |
1184 | recv |
1185 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c1 HTTP/1\\.1\"" |
1186 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c1 HTTP/1\\.1\"" |
1187 | barrier b2 sync |
1188 | recv |
1189 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CC-- .* .* \"GET /c2 HTTP/1\\.1\"" |
1190 | - |
1191 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_2/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CC-- .* .* \"GET /c2 HTTP/1\\.1\"" |
1192 | + barrier b2 sync |
1193 | recv |
1194 | expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be2/<NOSRV> [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CQ-- .* .* \"GET /c4 HTTP/1\\.1\"" |
1195 | barrier b2 sync |
1196 | @@ -60,7 +66,8 @@ haproxy h1 -conf { |
1197 | option httplog |
1198 | log ${S_addr}:${S_port} local0 debug err |
1199 | bind "fd@${fe1}" |
1200 | - use_backend be1 |
1201 | + use_backend be1_1 if { path /c1 } |
1202 | + use_backend be1_2 if { path /c2 } |
1203 | |
1204 | frontend fe2 |
1205 | option httplog |
1206 | @@ -68,13 +75,25 @@ haproxy h1 -conf { |
1207 | bind "fd@${fe2}" |
1208 | use_backend be2 |
1209 | |
1210 | - backend be1 |
1211 | + backend be1_1 |
1212 | + server srv1 ${s1_addr}:${s1_port} |
1213 | + |
1214 | + backend be1_2 |
1215 | + timeout connect 1s |
1216 | + retries 10 |
1217 | server srv1 ${s1_addr}:${s1_port} |
1218 | |
1219 | backend be2 |
1220 | server srv1 ${s2_addr}:${s2_port} maxconn 1 |
1221 | + |
1222 | + backend check |
1223 | + server srv1 ${s1_addr}:${s1_port} check |
1224 | + log ${S_addr}:${S_port} local0 debug alert |
1225 | } -start |
1226 | |
1227 | +# Wait s1 was detected as DOWN |
1228 | +barrier b0 sync |
1229 | + |
1230 | # No server, wait all connection retries : SC-- |
1231 | client c1 -connect ${h1_fe1_sock} { |
1232 | txreq -url /c1 |
1233 | @@ -90,6 +109,9 @@ client c2 -connect ${h1_fe1_sock} { |
1234 | txreq -url /c2 |
1235 | } -run |
1236 | |
1237 | +# Wait c2 log entry |
1238 | +barrier b2 sync |
1239 | + |
1240 | # server with maxconn=1, abort waiting the server reply : CH-- |
1241 | client c3 -connect ${h1_fe2_sock} { |
1242 | txreq -url /c3 |
1243 | diff --git a/reg-tests/http-messaging/http_request_buffer.vtc b/reg-tests/http-messaging/http_request_buffer.vtc |
1244 | index 4fd7bb2..3c47599 100644 |
1245 | --- a/reg-tests/http-messaging/http_request_buffer.vtc |
1246 | +++ b/reg-tests/http-messaging/http_request_buffer.vtc |
1247 | @@ -9,6 +9,8 @@ feature ignore_unknown_macro |
1248 | # thanks to "http-buffer-request". If this was the case, c2 client |
1249 | # could not connect to s1 server and this would lead to make this test fail. |
1250 | |
1251 | +barrier b1 cond 2 -cyclic |
1252 | + |
1253 | server s1 { |
1254 | rxreq |
1255 | expect req.bodylen == 257 |
1256 | @@ -24,12 +26,18 @@ server s1 { |
1257 | syslog S -level info { |
1258 | recv |
1259 | 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\"" |
1260 | + barrier b1 sync |
1261 | + |
1262 | recv |
1263 | expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\"" |
1264 | + barrier b1 sync |
1265 | + |
1266 | recv |
1267 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\"" |
1268 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\"" |
1269 | + barrier b1 sync |
1270 | + |
1271 | recv |
1272 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* -1 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\"" |
1273 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* -1 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\"" |
1274 | } -start |
1275 | |
1276 | haproxy h1 -conf { |
1277 | @@ -49,6 +57,14 @@ haproxy h1 -conf { |
1278 | log ${S_addr}:${S_port} local0 debug err |
1279 | bind "fd@${fe1}" |
1280 | use_backend be1 |
1281 | + |
1282 | + frontend fe2 |
1283 | + timeout client 10s |
1284 | + option httplog |
1285 | + option http-buffer-request |
1286 | + log ${S_addr}:${S_port} local0 debug err |
1287 | + bind "fd@${fe2}" |
1288 | + use_backend be1 |
1289 | } -start |
1290 | |
1291 | # 1 byte of the payload is missing. |
1292 | @@ -80,6 +96,9 @@ client c1 -connect ${h1_fe1_sock} { |
1293 | expect resp.status == 408 |
1294 | } -run |
1295 | |
1296 | +# Wait matching on log message |
1297 | +barrier b1 sync |
1298 | + |
1299 | # Payload is fully sent |
1300 | # ==> Request must be sent to the server. A 200 must be received |
1301 | client c2 -connect ${h1_fe1_sock} { |
1302 | @@ -88,10 +107,13 @@ client c2 -connect ${h1_fe1_sock} { |
1303 | expect resp.status == 200 |
1304 | } -run |
1305 | |
1306 | +# Wait matching on log message |
1307 | +barrier b1 sync |
1308 | + |
1309 | # Payload is fully sent in 2 steps (with a small delay, smaller than the client |
1310 | # timeout) and splitted on a chunk size. |
1311 | # ==> Request must be sent to the server. A 200 must be received |
1312 | -client c3 -connect ${h1_fe1_sock} { |
1313 | +client c3 -connect ${h1_fe2_sock} { |
1314 | send "POST /1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1" |
1315 | delay 0.01 |
1316 | send "\r\n1\r\n0\r\n\r\n" |
1317 | @@ -99,11 +121,14 @@ client c3 -connect ${h1_fe1_sock} { |
1318 | expect resp.status == 200 |
1319 | } -run |
1320 | |
1321 | +# Wait matching on log message |
1322 | +barrier b1 sync |
1323 | + |
1324 | # Last CRLF of the request payload is missing but payload is sent in 2 steps |
1325 | # (with a small delay, smaller than the client timeout) and splitted on a chunk |
1326 | # size. The client aborts before sending the last CRLF. |
1327 | # ==> Request must be handled as an error with 'CR--' termination state. |
1328 | -client c4 -connect ${h1_fe1_sock} { |
1329 | +client c4 -connect ${h1_fe2_sock} { |
1330 | send "POST /2 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1" |
1331 | delay 0.01 |
1332 | send "\r\n1\r\n0\r\n" |
1333 | diff --git a/scripts/announce-release b/scripts/announce-release |
1334 | index a229301..4c75a3b 100755 |
1335 | --- a/scripts/announce-release |
1336 | +++ b/scripts/announce-release |
1337 | @@ -210,20 +210,21 @@ else |
1338 | fi |
1339 | |
1340 | (echo "Please find the usual URLs below :" |
1341 | - echo " Site index : http://www.haproxy.org/" |
1342 | - echo " Documentation : http://docs.haproxy.org/" |
1343 | + echo " Site index : https://www.haproxy.org/" |
1344 | + echo " Documentation : https://docs.haproxy.org/" |
1345 | echo " Wiki : https://github.com/haproxy/wiki/wiki" |
1346 | - echo " Discourse : http://discourse.haproxy.org/" |
1347 | + echo " Discourse : https://discourse.haproxy.org/" |
1348 | echo " Slack channel : https://slack.haproxy.org/" |
1349 | echo " Issue tracker : https://github.com/haproxy/haproxy/issues" |
1350 | - echo " Sources : http://www.haproxy.org/download/${BRANCH}/src/" |
1351 | - echo " Git repository : http://git.haproxy.org/git/${gitdir}/" |
1352 | - echo " Git Web browsing : http://git.haproxy.org/?p=${gitdir}" |
1353 | - echo " Changelog : http://www.haproxy.org/download/${BRANCH}/src/CHANGELOG" |
1354 | - echo " Pending bugs : http://www.haproxy.org/l/pending-bugs" |
1355 | - echo " Reviewed bugs : http://www.haproxy.org/l/reviewed-bugs" |
1356 | - echo " Code reports : http://www.haproxy.org/l/code-reports" |
1357 | - echo " Latest builds : http://www.haproxy.org/l/dev-packages" |
1358 | + echo " Sources : https://www.haproxy.org/download/${BRANCH}/src/" |
1359 | + echo " Git repository : https://git.haproxy.org/git/${gitdir}/" |
1360 | + echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}" |
1361 | + echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG" |
1362 | + echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest" |
1363 | + echo " Pending bugs : https://www.haproxy.org/l/pending-bugs" |
1364 | + echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs" |
1365 | + echo " Code reports : https://www.haproxy.org/l/code-reports" |
1366 | + echo " Latest builds : https://www.haproxy.org/l/dev-packages" |
1367 | ) >> "$OUTPUT" |
1368 | |
1369 | # sign |
1370 | diff --git a/scripts/make-releases-json b/scripts/make-releases-json |
1371 | new file mode 100755 |
1372 | index 0000000..38bb2b6 |
1373 | --- /dev/null |
1374 | +++ b/scripts/make-releases-json |
1375 | @@ -0,0 +1,103 @@ |
1376 | +#!/usr/bin/env bash |
1377 | +# |
1378 | +# Scan a branch directory for source tarballs and rebuild the releases.json |
1379 | +# file for that branch. md5 and sha256 are added if present. The highest |
1380 | +# numberred version is referenced as the latest release. |
1381 | +# |
1382 | +# Usage: $0 [-b branch] [-o outfile] /path/to/download/branch |
1383 | +# |
1384 | + |
1385 | +USAGE="Usage: ${0##*/} [-b branch] [-o outfile] DIR" |
1386 | +OUTPUT= |
1387 | +BRANCH= |
1388 | +DIR= |
1389 | + |
1390 | +die() { |
1391 | + [ "$#" -eq 0 ] || echo "$*" >&2 |
1392 | + exit 1 |
1393 | +} |
1394 | + |
1395 | +err() { |
1396 | + echo "$*" >&2 |
1397 | +} |
1398 | + |
1399 | +quit() { |
1400 | + [ "$#" -eq 0 -o -n "$QUIET" ] || echo "$*" |
1401 | + exit 0 |
1402 | +} |
1403 | + |
1404 | +emit_json() { |
1405 | + printf '{\n "branch": "%s",\n' ${BRANCH} |
1406 | + latest="" |
1407 | + for file in $(find "$DIR/src" -name 'haproxy-[0-9]*.gz' -printf "%P\n" |grep -v '[0-9]-patches*' | sort -rV ); do |
1408 | + rel="${file##*haproxy-}" |
1409 | + rel="${rel%%.tar.*}" |
1410 | + if [ -z "$latest" ]; then |
1411 | + latest="$rel"; |
1412 | + printf ' "latest_release": "%s",\n' ${latest} |
1413 | + printf ' "releases": {\n' |
1414 | + else |
1415 | + printf ",\n" |
1416 | + fi |
1417 | + printf ' "%s": {\n' ${rel} |
1418 | + printf ' "file": "%s"' ${file} |
1419 | + if [ -s "$DIR/src/$file.md5" ]; then |
1420 | + printf ',\n "md5": "%s"' $(awk '{print $1}' "$DIR/src/$file.md5") |
1421 | + fi |
1422 | + if [ -s "$DIR/src/$file.sha256" ]; then |
1423 | + printf ',\n "sha256": "%s"' $(awk '{print $1}' "$DIR/src/$file.sha256") |
1424 | + fi |
1425 | + printf '\n }' |
1426 | + done |
1427 | + |
1428 | + if [ -n "$latest" ]; then |
1429 | + printf "\n }" ## "releases" |
1430 | + fi |
1431 | + |
1432 | + printf '\n}\n' |
1433 | +} |
1434 | + |
1435 | + |
1436 | +### main |
1437 | + |
1438 | +while [ -n "$1" -a -z "${1##-*}" ]; do |
1439 | + case "$1" in |
1440 | + -b) BRANCH="$2" ; shift 2 ;; |
1441 | + -o) OUTPUT="$2" ; shift 2 ;; |
1442 | + -h|--help) quit "$USAGE" ;; |
1443 | + *) die "$USAGE" ;; |
1444 | + esac |
1445 | +done |
1446 | + |
1447 | +if [ $# -ne 1 ]; then |
1448 | + die "$USAGE" |
1449 | +fi |
1450 | + |
1451 | +DIR="$1" ; shift |
1452 | +if [ -z "$DIR" ]; then |
1453 | + die "Missing download directory name." |
1454 | +fi |
1455 | + |
1456 | +if [ ! -d "$DIR/." ]; then |
1457 | + die "Download directory doesn't exist : $DIR" |
1458 | +fi |
1459 | + |
1460 | +if [ ! -d "$DIR/src" ]; then |
1461 | + die "Download directory must contain 'src' : $DIR" |
1462 | +fi |
1463 | + |
1464 | +if [ -z "$BRANCH" ]; then |
1465 | + BRANCH=${DIR##*/} |
1466 | + if [ -n "${BRANCH//[0-9.]}" ]; then |
1467 | + die "Couldn't determine branch number from dir name: $BRANCH" |
1468 | + fi |
1469 | +fi |
1470 | + |
1471 | +# echo "debug: DIR=$DIR BRANCH=$BRANCH" |
1472 | +if [ -n "$OUTPUT" ]; then |
1473 | + emit_json > "$OUTPUT.tmp" |
1474 | + mv -f "$OUTPUT.tmp" "$OUTPUT" |
1475 | + rm -f "$OUTPUT.tmp" |
1476 | +else |
1477 | + emit_json |
1478 | +fi |
1479 | diff --git a/scripts/publish-release b/scripts/publish-release |
1480 | index abde56f..d785244 100755 |
1481 | --- a/scripts/publish-release |
1482 | +++ b/scripts/publish-release |
1483 | @@ -17,6 +17,7 @@ BRANCH= |
1484 | DEVEL= |
1485 | QUIET= |
1486 | AUTO= |
1487 | +ARG0="$0" |
1488 | NEW= |
1489 | DIR= |
1490 | DOC=( ) |
1491 | @@ -178,6 +179,11 @@ for i in "${DOC[@]}"; do |
1492 | $CMD_GZIP < "$TARGET_DIR/doc/${i#doc/}" > "$TARGET_DIR/doc/${i#doc/}.gz" |
1493 | done |
1494 | |
1495 | +if [ -x "${ARG0%/*}/make-releases-json" ]; then |
1496 | + # regenerate versions |
1497 | + "${ARG0%/*}/make-releases-json" -o "$TARGET_DIR/src/releases.json" "$TARGET_DIR" |
1498 | +fi |
1499 | + |
1500 | echo "Done : ls -l ${TARGET_DIR}" |
1501 | ( cd "$TARGET_DIR" ; |
1502 | ls -l src/CHANGELOG "src${DEVEL}/haproxy-${NEW}".tar.gz{,.md5,.sha256} $(for i in "${DOC[@]}"; do echo "doc/${i#doc/}"{,.gz}; done) |
1503 | diff --git a/src/backend.c b/src/backend.c |
1504 | index 056e53a..3fe9fdc 100644 |
1505 | --- a/src/backend.c |
1506 | +++ b/src/backend.c |
1507 | @@ -728,11 +728,6 @@ int assign_server(struct stream *s) |
1508 | (void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr, |
1509 | 16, prev_srv); |
1510 | } |
1511 | - else { |
1512 | - /* unknown IP family */ |
1513 | - err = SRV_STATUS_INTERNAL; |
1514 | - goto out; |
1515 | - } |
1516 | break; |
1517 | |
1518 | case BE_LB_HASH_URI: |
1519 | diff --git a/src/cache.c b/src/cache.c |
1520 | index 07c406c..d94a76e 100644 |
1521 | --- a/src/cache.c |
1522 | +++ b/src/cache.c |
1523 | @@ -81,7 +81,7 @@ struct cache_st { |
1524 | |
1525 | struct cache_entry { |
1526 | unsigned int latest_validation; /* latest validation date */ |
1527 | - unsigned int expire; /* expiration date */ |
1528 | + unsigned int expire; /* expiration date (wall clock time) */ |
1529 | unsigned int age; /* Origin server "Age" header value */ |
1530 | unsigned int eoh; /* Origin server end of headers offset. */ // field used in legacy mode only |
1531 | |
1532 | @@ -114,7 +114,7 @@ struct cache_entry *entry_exist(struct cache *cache, char *hash) |
1533 | if (memcmp(entry->hash, hash, sizeof(entry->hash))) |
1534 | return NULL; |
1535 | |
1536 | - if (entry->expire > now.tv_sec) { |
1537 | + if (entry->expire > date.tv_sec) { |
1538 | return entry; |
1539 | } else { |
1540 | eb32_delete(node); |
1541 | @@ -864,8 +864,8 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px, |
1542 | shctx_unlock(shctx); |
1543 | |
1544 | /* store latest value and expiration time */ |
1545 | - object->latest_validation = now.tv_sec; |
1546 | - object->expire = now.tv_sec + http_calc_maxage(s, cconf->c.cache); |
1547 | + object->latest_validation = date.tv_sec; |
1548 | + object->expire = date.tv_sec + http_calc_maxage(s, cconf->c.cache); |
1549 | return ACT_RET_CONT; |
1550 | } |
1551 | |
1552 | @@ -1059,7 +1059,7 @@ static int htx_cache_add_age_hdr(struct appctx *appctx, struct htx *htx) |
1553 | char *end; |
1554 | |
1555 | chunk_reset(&trash); |
1556 | - age = MAX(0, (int)(now.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age; |
1557 | + age = MAX(0, (int)(date.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age; |
1558 | if (unlikely(age > CACHE_ENTRY_MAX_AGE)) |
1559 | age = CACHE_ENTRY_MAX_AGE; |
1560 | end = ultoa_o(age, b_head(&trash), b_size(&trash)); |
1561 | @@ -1877,11 +1877,11 @@ static int cli_io_handler_show_cache(struct appctx *appctx) |
1562 | entry = container_of(node, struct cache_entry, eb); |
1563 | next_key = node->key + 1; |
1564 | |
1565 | - if (entry->expire > now.tv_sec) { |
1566 | + if (entry->expire > date.tv_sec) { |
1567 | chunk_printf(&trash, "%p hash:%u size:%u (%u blocks), refcount:%u, expire:%d\n", |
1568 | entry, (*(unsigned int *)entry->hash), |
1569 | block_ptr(entry)->len, block_ptr(entry)->block_count, |
1570 | - block_ptr(entry)->refcount, entry->expire - (int)now.tv_sec); |
1571 | + block_ptr(entry)->refcount, entry->expire - (int)date.tv_sec); |
1572 | } else { |
1573 | /* time to remove that one */ |
1574 | eb32_delete(&entry->eb); |
1575 | diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c |
1576 | index 8bb85c6..7520620 100644 |
1577 | --- a/src/cfgparse-listen.c |
1578 | +++ b/src/cfgparse-listen.c |
1579 | @@ -381,7 +381,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) |
1580 | } |
1581 | |
1582 | /* set default values */ |
1583 | - memcpy(&curproxy->defsrv, &defproxy.defsrv, sizeof(curproxy->defsrv)); |
1584 | + srv_settings_cpy(&curproxy->defsrv, &defproxy.defsrv, 0); |
1585 | + |
1586 | curproxy->defsrv.id = "default-server"; |
1587 | |
1588 | curproxy->state = defproxy.state; |
1589 | diff --git a/src/cfgparse.c b/src/cfgparse.c |
1590 | index 36cb18d..e4a93dd 100644 |
1591 | --- a/src/cfgparse.c |
1592 | +++ b/src/cfgparse.c |
1593 | @@ -540,9 +540,10 @@ static struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, |
1594 | |
1595 | if (!LIST_ISEMPTY(&p->conf.bind)) { |
1596 | bind_conf = LIST_ELEM((&p->conf.bind)->n, typeof(bind_conf), by_fe); |
1597 | - free(bind_conf->file); |
1598 | - bind_conf->file = strdup(file); |
1599 | - bind_conf->line = line; |
1600 | + /* |
1601 | + * We keep bind_conf->file and bind_conf->line unchanged |
1602 | + * to make them available for error messages |
1603 | + */ |
1604 | if (arg) { |
1605 | free(bind_conf->arg); |
1606 | bind_conf->arg = strdup(arg); |
1607 | @@ -627,7 +628,12 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1608 | } |
1609 | |
1610 | bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, |
1611 | - NULL, xprt_get(XPRT_RAW)); |
1612 | + args[1], xprt_get(XPRT_RAW)); |
1613 | + if (!bind_conf) { |
1614 | + ha_alert("parsing [%s:%d] : '%s %s' : cannot allocate memory.\n", file, linenum, args[0], args[1]); |
1615 | + err_code |= ERR_FATAL; |
1616 | + goto out; |
1617 | + } |
1618 | if (*args[0] == 'b') { |
1619 | struct listener *l; |
1620 | |
1621 | @@ -637,6 +643,11 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1622 | goto out; |
1623 | } |
1624 | |
1625 | + if (!LIST_ISEMPTY(&bind_conf->listeners)) { |
1626 | + ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); |
1627 | + err_code |= ERR_FATAL; |
1628 | + } |
1629 | + |
1630 | if (!str2listener(args[1], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { |
1631 | if (errmsg && *errmsg) { |
1632 | indent_msg(&errmsg, 2); |
1633 | @@ -644,11 +655,14 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1634 | } |
1635 | else |
1636 | ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", |
1637 | - file, linenum, args[0], args[1], args[2]); |
1638 | + file, linenum, args[0], args[1], args[1]); |
1639 | err_code |= ERR_FATAL; |
1640 | goto out; |
1641 | } |
1642 | - l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); |
1643 | + /* |
1644 | + * Newly allocated listener is at the end of the list |
1645 | + */ |
1646 | + l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); |
1647 | l->maxaccept = 1; |
1648 | l->accept = session_accept_fd; |
1649 | l->analysers |= curpeers->peers_fe->fe_req_ana; |
1650 | @@ -848,6 +862,16 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1651 | goto out; |
1652 | |
1653 | bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); |
1654 | + if (!bind_conf) { |
1655 | + ha_alert("parsing [%s:%d] : '%s %s' : Cannot allocate memory.\n", file, linenum, args[0], args[1]); |
1656 | + err_code |= ERR_FATAL; |
1657 | + goto out; |
1658 | + } |
1659 | + |
1660 | + if (!LIST_ISEMPTY(&bind_conf->listeners)) { |
1661 | + ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); |
1662 | + err_code |= ERR_FATAL; |
1663 | + } |
1664 | |
1665 | if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { |
1666 | if (errmsg && *errmsg) { |
1667 | @@ -861,7 +885,10 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1668 | goto out; |
1669 | } |
1670 | |
1671 | - l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); |
1672 | + /* |
1673 | + * Newly allocated listener is at the end of the list |
1674 | + */ |
1675 | + l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); |
1676 | l->maxaccept = 1; |
1677 | l->accept = session_accept_fd; |
1678 | l->analysers |= curpeers->peers_fe->fe_req_ana; |
1679 | @@ -2078,6 +2105,7 @@ next_line: |
1680 | |
1681 | /* if not enough space in thisline */ |
1682 | if (newlinesize > linesize) { |
1683 | + uintptr_t thisline_addr = (uintptr_t)thisline; /* Save thisline address to make GCC happy ! */ |
1684 | char *newline; |
1685 | |
1686 | newline = realloc(thisline, newlinesize * sizeof(*thisline)); |
1687 | @@ -2087,20 +2115,20 @@ next_line: |
1688 | goto next_line; /* slip current line */ |
1689 | } |
1690 | /* recompute pointers if realloc returns a new pointer */ |
1691 | - if (newline != thisline) { |
1692 | + if (newline != (char *)thisline_addr) { |
1693 | int i; |
1694 | int diff; |
1695 | |
1696 | for (i = 0; i <= arg; i++) { |
1697 | - diff = args[i] - thisline; |
1698 | + diff = args[i] - (char *)thisline_addr; |
1699 | args[i] = newline + diff; |
1700 | } |
1701 | |
1702 | - diff = var_end - thisline; |
1703 | + diff = var_end - (char *)thisline_addr; |
1704 | var_end = newline + diff; |
1705 | - diff = end - thisline; |
1706 | + diff = end - (char *)thisline_addr; |
1707 | end = newline + diff; |
1708 | - diff = line - thisline; |
1709 | + diff = line - (char *)thisline_addr; |
1710 | line = newline + diff; |
1711 | thisline = newline; |
1712 | } |
1713 | diff --git a/src/dns.c b/src/dns.c |
1714 | index 694f840..de9892b 100644 |
1715 | --- a/src/dns.c |
1716 | +++ b/src/dns.c |
1717 | @@ -175,11 +175,11 @@ static void dns_update_resolvers_timeout(struct dns_resolvers *resolvers) |
1718 | next = tick_add(now_ms, resolvers->timeout.resolve); |
1719 | if (!LIST_ISEMPTY(&resolvers->resolutions.curr)) { |
1720 | res = LIST_NEXT(&resolvers->resolutions.curr, struct dns_resolution *, list); |
1721 | - next = MIN(next, tick_add(res->last_query, resolvers->timeout.retry)); |
1722 | + next = tick_first(next, tick_add(res->last_query, resolvers->timeout.retry)); |
1723 | } |
1724 | |
1725 | list_for_each_entry(res, &resolvers->resolutions.wait, list) |
1726 | - next = MIN(next, tick_add(res->last_resolution, dns_resolution_timeout(res))); |
1727 | + next = tick_first(next, tick_add(res->last_resolution, dns_resolution_timeout(res))); |
1728 | |
1729 | resolvers->t->expire = next; |
1730 | task_queue(resolvers->t); |
1731 | @@ -1990,7 +1990,7 @@ static void dns_deinit(void) |
1732 | |
1733 | /* Finalizes the DNS configuration by allocating required resources and checking |
1734 | * live parameters. |
1735 | - * Returns 0 on success, ERR_* flags otherwise. |
1736 | + * Returns 0 on success, 1 on error. |
1737 | */ |
1738 | static int dns_finalize_config(void) |
1739 | { |
1740 | @@ -2058,6 +2058,13 @@ static int dns_finalize_config(void) |
1741 | for (px = proxies_list; px; px = px->next) { |
1742 | struct server *srv; |
1743 | |
1744 | + if (px->state == PR_STSTOPPED) { |
1745 | + /* must not run and will not work anyway since |
1746 | + * nothing in the proxy is initialized. |
1747 | + */ |
1748 | + continue; |
1749 | + } |
1750 | + |
1751 | for (srv = px->srv; srv; srv = srv->next) { |
1752 | struct dns_resolvers *resolvers; |
1753 | |
1754 | @@ -2093,10 +2100,10 @@ static int dns_finalize_config(void) |
1755 | if (err_code & (ERR_ALERT|ERR_ABORT)) |
1756 | goto err; |
1757 | |
1758 | - return err_code; |
1759 | + return 0; |
1760 | err: |
1761 | dns_deinit(); |
1762 | - return err_code; |
1763 | + return 1; |
1764 | |
1765 | } |
1766 | |
1767 | @@ -2262,7 +2269,12 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px, |
1768 | if (resolution->step == RSLV_STEP_RUNNING) |
1769 | goto yield; |
1770 | if (resolution->step == RSLV_STEP_NONE) { |
1771 | - /* We update the variable only if we have a valid response. */ |
1772 | + /* We update the variable only if we have a valid |
1773 | + * response. If the response was not received yet, we |
1774 | + * must yield. |
1775 | + */ |
1776 | + if (resolution->status == RSLV_STATUS_NONE) |
1777 | + goto yield; |
1778 | if (resolution->status == RSLV_STATUS_VALID) { |
1779 | struct sample smp; |
1780 | short ip_sin_family = 0; |
1781 | diff --git a/src/ev_epoll.c b/src/ev_epoll.c |
1782 | index 6c09c04..d836306 100644 |
1783 | --- a/src/ev_epoll.c |
1784 | +++ b/src/ev_epoll.c |
1785 | @@ -146,7 +146,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1786 | |
1787 | thread_harmless_now(); |
1788 | |
1789 | - /* now let's wait for polled events */ |
1790 | + /* Now let's wait for polled events. */ |
1791 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
1792 | tv_entering_poll(); |
1793 | activity_count_runtime(); |
1794 | @@ -160,7 +160,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1795 | break; |
1796 | if (timeout || !wait_time) |
1797 | break; |
1798 | - if (signal_queue_len || wake) |
1799 | + if (wake) |
1800 | break; |
1801 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
1802 | break; |
1803 | diff --git a/src/ev_evports.c b/src/ev_evports.c |
1804 | index eae72d0..2442579 100644 |
1805 | --- a/src/ev_evports.c |
1806 | +++ b/src/ev_evports.c |
1807 | @@ -141,9 +141,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1808 | |
1809 | thread_harmless_now(); |
1810 | |
1811 | - /* |
1812 | - * Determine how long to wait for events to materialise on the port. |
1813 | - */ |
1814 | + /* Now let's wait for polled events. */ |
1815 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
1816 | tv_entering_poll(); |
1817 | activity_count_runtime(); |
1818 | @@ -183,7 +181,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1819 | break; |
1820 | if (timeout || !wait_time) |
1821 | break; |
1822 | - if (signal_queue_len || wake) |
1823 | + if (wake) |
1824 | break; |
1825 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
1826 | break; |
1827 | diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c |
1828 | index 56e7147..47f4647 100644 |
1829 | --- a/src/ev_kqueue.c |
1830 | +++ b/src/ev_kqueue.c |
1831 | @@ -131,7 +131,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1832 | } |
1833 | fd_nbupdt = 0; |
1834 | |
1835 | - /* now let's wait for events */ |
1836 | + /* Now let's wait for polled events. */ |
1837 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
1838 | fd = global.tune.maxpollevents; |
1839 | tv_entering_poll(); |
1840 | @@ -155,7 +155,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1841 | break; |
1842 | if (timeout || !wait_time) |
1843 | break; |
1844 | - if (signal_queue_len || wake) |
1845 | + if (wake) |
1846 | break; |
1847 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
1848 | break; |
1849 | diff --git a/src/ev_poll.c b/src/ev_poll.c |
1850 | index 86bf8e8..39e5fd9 100644 |
1851 | --- a/src/ev_poll.c |
1852 | +++ b/src/ev_poll.c |
1853 | @@ -24,6 +24,7 @@ |
1854 | #include <common/time.h> |
1855 | |
1856 | #include <types/global.h> |
1857 | +#include <types/signal.h> |
1858 | |
1859 | #include <proto/activity.h> |
1860 | #include <proto/fd.h> |
1861 | @@ -193,7 +194,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1862 | } |
1863 | } |
1864 | |
1865 | - /* now let's wait for events */ |
1866 | + /* Now let's wait for polled events. */ |
1867 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
1868 | tv_entering_poll(); |
1869 | activity_count_runtime(); |
1870 | diff --git a/src/flt_spoe.c b/src/flt_spoe.c |
1871 | index 16b5d6f..128461b 100644 |
1872 | --- a/src/flt_spoe.c |
1873 | +++ b/src/flt_spoe.c |
1874 | @@ -1290,7 +1290,7 @@ spoe_release_appctx(struct appctx *appctx) |
1875 | /* Destroy the task attached to this applet */ |
1876 | task_destroy(spoe_appctx->task); |
1877 | |
1878 | - /* Notify all waiting streams */ |
1879 | + /* Report an error to all streams in the appctx waiting queue */ |
1880 | list_for_each_entry_safe(ctx, back, &spoe_appctx->waiting_queue, list) { |
1881 | LIST_DEL(&ctx->list); |
1882 | LIST_INIT(&ctx->list); |
1883 | @@ -1302,8 +1302,8 @@ spoe_release_appctx(struct appctx *appctx) |
1884 | task_wakeup(ctx->strm->task, TASK_WOKEN_MSG); |
1885 | } |
1886 | |
1887 | - /* If the applet was processing a fragmented frame, notify the |
1888 | - * corresponding stream. */ |
1889 | + /* If the applet was processing a fragmented frame, report an error to |
1890 | + * the corresponding stream. */ |
1891 | if (spoe_appctx->frag_ctx.ctx) { |
1892 | ctx = spoe_appctx->frag_ctx.ctx; |
1893 | ctx->spoe_appctx = NULL; |
1894 | @@ -1312,7 +1312,11 @@ spoe_release_appctx(struct appctx *appctx) |
1895 | task_wakeup(ctx->strm->task, TASK_WOKEN_MSG); |
1896 | } |
1897 | |
1898 | - if (!LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) { |
1899 | + if (!LIST_ISEMPTY(&agent->rt[tid].applets)) { |
1900 | + /* If there are still some running applets, remove reference on |
1901 | + * the current one from streams in the async waiting queue. In |
1902 | + * async mode, the ACK may be received from another appctx. |
1903 | + */ |
1904 | list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) { |
1905 | if (ctx->spoe_appctx == spoe_appctx) |
1906 | ctx->spoe_appctx = NULL; |
1907 | @@ -1320,16 +1324,25 @@ spoe_release_appctx(struct appctx *appctx) |
1908 | goto end; |
1909 | } |
1910 | else { |
1911 | - /* It is the last running applet and the sending and waiting |
1912 | - * queues are not empty. Try to start a new one if HAproxy is |
1913 | - * not stopping. |
1914 | + /* It is the last running applet and the sending and async |
1915 | + * waiting queues are not empty. So try to start a new applet if |
1916 | + * HAproxy is not stopping. On success, we remove reference on |
1917 | + * the current appctx from streams in the async waiting queue. |
1918 | + * In async mode, the ACK may be received from another appctx. |
1919 | */ |
1920 | if (!stopping && |
1921 | (!LIST_ISEMPTY(&agent->rt[tid].sending_queue) || !LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) && |
1922 | - spoe_create_appctx(agent->spoe_conf)) |
1923 | + spoe_create_appctx(agent->spoe_conf)) { |
1924 | + list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) { |
1925 | + if (ctx->spoe_appctx == spoe_appctx) |
1926 | + ctx->spoe_appctx = NULL; |
1927 | + } |
1928 | goto end; |
1929 | + } |
1930 | |
1931 | - /* otherwise, notify all waiting streams */ |
1932 | + /* Otherwise, report an error to all streams in the sending and |
1933 | + * async waiting queues. |
1934 | + */ |
1935 | list_for_each_entry_safe(ctx, back, &agent->rt[tid].sending_queue, list) { |
1936 | LIST_DEL(&ctx->list); |
1937 | LIST_INIT(&ctx->list); |
1938 | diff --git a/src/h1.c b/src/h1.c |
1939 | index 3839fbe..69a7ced 100644 |
1940 | --- a/src/h1.c |
1941 | +++ b/src/h1.c |
1942 | @@ -672,6 +672,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop, |
1943 | |
1944 | if (likely(*ptr == ':')) { |
1945 | col = ptr - start; |
1946 | + if (col <= sol) { |
1947 | + state = H1_MSG_HDR_NAME; |
1948 | + goto http_msg_invalid; |
1949 | + } |
1950 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP); |
1951 | } |
1952 | |
1953 | diff --git a/src/haproxy.c b/src/haproxy.c |
1954 | index aa37504..f6166d4 100644 |
1955 | --- a/src/haproxy.c |
1956 | +++ b/src/haproxy.c |
1957 | @@ -1,6 +1,6 @@ |
1958 | /* |
1959 | * HA-Proxy : High Availability-enabled HTTP/TCP proxy |
1960 | - * Copyright 2000-2022 Willy Tarreau <willy@haproxy.org>. |
1961 | + * Copyright 2000-2023 Willy Tarreau <willy@haproxy.org>. |
1962 | * |
1963 | * This program is free software; you can redistribute it and/or |
1964 | * modify it under the terms of the GNU General Public License |
1965 | @@ -242,6 +242,7 @@ struct mworker_proc *proc_self = NULL; |
1966 | /* list of the temporarily limited listeners because of lack of resource */ |
1967 | struct list global_listener_queue = LIST_HEAD_INIT(global_listener_queue); |
1968 | struct task *global_listener_queue_task; |
1969 | +__decl_hathreads(HA_RWLOCK_T global_listener_rwlock); |
1970 | static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state); |
1971 | |
1972 | static void *run_thread_poll_loop(void *data); |
1973 | @@ -2071,6 +2072,7 @@ static void init(int argc, char **argv) |
1974 | /* very simple initialization, users will queue the task if needed */ |
1975 | global_listener_queue_task->context = NULL; /* not even a context! */ |
1976 | global_listener_queue_task->process = manage_global_listener_queue; |
1977 | + HA_RWLOCK_INIT(&global_listener_rwlock); |
1978 | |
1979 | /* now we know the buffer size, we can initialize the channels and buffers */ |
1980 | init_buffer(); |
1981 | @@ -2778,7 +2780,7 @@ static void run_poll_loop() |
1982 | if (killed > 1) |
1983 | break; |
1984 | |
1985 | - /* expire immediately if events are pending */ |
1986 | + /* expire immediately if events or signals are pending */ |
1987 | wake = 1; |
1988 | if (fd_cache_mask & tid_bit) |
1989 | activity[tid].wake_cache++; |
1990 | @@ -2792,6 +2794,10 @@ static void run_poll_loop() |
1991 | if (global_tasks_mask & tid_bit) { |
1992 | activity[tid].wake_tasks++; |
1993 | _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit); |
1994 | + } else if (signal_queue_len) { |
1995 | + /* this check is required to avoid |
1996 | + * a race with wakeup on signals using wake_threads() */ |
1997 | + _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit); |
1998 | } else |
1999 | wake = 0; |
2000 | } |
2001 | @@ -2946,7 +2952,9 @@ static struct task *manage_global_listener_queue(struct task *t, void *context, |
2002 | dequeue_all_listeners(&global_listener_queue); |
2003 | |
2004 | out: |
2005 | + HA_RWLOCK_WRLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2006 | t->expire = next; |
2007 | + HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2008 | task_queue(t); |
2009 | return t; |
2010 | } |
2011 | diff --git a/src/hlua.c b/src/hlua.c |
2012 | index 888890f..bd8a679 100644 |
2013 | --- a/src/hlua.c |
2014 | +++ b/src/hlua.c |
2015 | @@ -649,7 +649,9 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, |
2016 | break; |
2017 | |
2018 | case ARGT_TAB: |
2019 | - argp[idx].data.prx = p; |
2020 | + if (!p->table) |
2021 | + WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected")); |
2022 | + argp[idx].data.t = p->table; |
2023 | argp[idx].type = ARGT_TAB; |
2024 | argp[idx+1].type = ARGT_STOP; |
2025 | break; |
2026 | diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c |
2027 | index 955a1ce..c42a60a 100644 |
2028 | --- a/src/hlua_fcn.c |
2029 | +++ b/src/hlua_fcn.c |
2030 | @@ -1298,6 +1298,7 @@ int hlua_proxy_pause(lua_State *L) |
2031 | struct proxy *px; |
2032 | |
2033 | px = hlua_check_proxy(L, 1); |
2034 | + /* safe to call without PROXY_LOCK - pause_proxy takes it */ |
2035 | pause_proxy(px); |
2036 | return 0; |
2037 | } |
2038 | @@ -1307,6 +1308,7 @@ int hlua_proxy_resume(lua_State *L) |
2039 | struct proxy *px; |
2040 | |
2041 | px = hlua_check_proxy(L, 1); |
2042 | + /* safe to call without PROXY_LOCK - resume_proxy takes it */ |
2043 | resume_proxy(px); |
2044 | return 0; |
2045 | } |
2046 | @@ -1316,6 +1318,7 @@ int hlua_proxy_stop(lua_State *L) |
2047 | struct proxy *px; |
2048 | |
2049 | px = hlua_check_proxy(L, 1); |
2050 | + /* safe to call without PROXY_LOCK - stop_proxy takes it */ |
2051 | stop_proxy(px); |
2052 | return 0; |
2053 | } |
2054 | diff --git a/src/hpack-dec.c b/src/hpack-dec.c |
2055 | index 7f3e762..0fc71eb 100644 |
2056 | --- a/src/hpack-dec.c |
2057 | +++ b/src/hpack-dec.c |
2058 | @@ -425,6 +425,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len, |
2059 | /* <name> and <value> are correctly filled here */ |
2060 | } |
2061 | |
2062 | + /* We must not accept empty header names (forbidden by the spec and used |
2063 | + * as a list termination). |
2064 | + */ |
2065 | + if (!name.len) { |
2066 | + hpack_debug_printf("##ERR@%d##\n", __LINE__); |
2067 | + ret = -HPACK_ERR_INVALID_ARGUMENT; |
2068 | + goto leave; |
2069 | + } |
2070 | + |
2071 | /* here's what we have here : |
2072 | * - name.len > 0 |
2073 | * - value is filled with either const data or data allocated from tmp |
2074 | diff --git a/src/http_fetch.c b/src/http_fetch.c |
2075 | index d40bc1d..ea87a52 100644 |
2076 | --- a/src/http_fetch.c |
2077 | +++ b/src/http_fetch.c |
2078 | @@ -244,7 +244,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, int vol) |
2079 | if (IS_HTX_STRM(s)) { |
2080 | htx = htxbuf(&chn->buf); |
2081 | |
2082 | - if (msg->msg_state == HTTP_MSG_ERROR || (htx->flags & HTX_FL_PARSING_ERROR)) |
2083 | + if (htx->flags & HTX_FL_PARSING_ERROR) |
2084 | return NULL; |
2085 | |
2086 | if (msg->msg_state < HTTP_MSG_BODY) { |
2087 | @@ -460,6 +460,7 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char |
2088 | struct channel *chn = SMP_REQ_CHN(smp); |
2089 | int meth; |
2090 | struct http_txn *txn; |
2091 | + struct htx *htx = NULL; |
2092 | |
2093 | if (smp->px->options2 & PR_O2_USE_HTX) { |
2094 | /* HTX version */ |
2095 | @@ -468,15 +469,17 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char |
2096 | return 0; |
2097 | |
2098 | meth = txn->meth; |
2099 | - smp->data.type = SMP_T_METH; |
2100 | - smp->data.u.meth.meth = meth; |
2101 | if (meth == HTTP_METH_OTHER) { |
2102 | - struct htx *htx; |
2103 | - struct htx_sl *sl; |
2104 | - |
2105 | htx = smp_prefetch_htx(smp, chn, 1); |
2106 | if (!htx) |
2107 | return 0; |
2108 | + meth = txn->meth; |
2109 | + } |
2110 | + |
2111 | + smp->data.type = SMP_T_METH; |
2112 | + smp->data.u.meth.meth = meth; |
2113 | + if (meth == HTTP_METH_OTHER) { |
2114 | + struct htx_sl *sl; |
2115 | |
2116 | if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) { |
2117 | /* ensure the indexes are not affected */ |
2118 | diff --git a/src/http_msg.c b/src/http_msg.c |
2119 | index 067a7f8..e07c81c 100644 |
2120 | --- a/src/http_msg.c |
2121 | +++ b/src/http_msg.c |
2122 | @@ -1006,8 +1006,14 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) |
2123 | if (likely(HTTP_IS_TOKEN(*ptr))) |
2124 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME); |
2125 | |
2126 | - if (likely(*ptr == ':')) |
2127 | + if (likely(*ptr == ':')) { |
2128 | + if (ptr == input + msg->sol) { |
2129 | + /* empty header names are not permitted */ |
2130 | + state = HTTP_MSG_HDR_NAME; |
2131 | + goto http_msg_invalid; |
2132 | + } |
2133 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP); |
2134 | + } |
2135 | |
2136 | if (likely(msg->err_pos < -1) || *ptr == '\n') { |
2137 | state = HTTP_MSG_HDR_NAME; |
2138 | diff --git a/src/listener.c b/src/listener.c |
2139 | index 2141017..0ba2ee1 100644 |
2140 | --- a/src/listener.c |
2141 | +++ b/src/listener.c |
2142 | @@ -766,7 +766,9 @@ void listener_accept(int fd) |
2143 | */ |
2144 | next_actconn = 0; |
2145 | limit_listener(l, &global_listener_queue); |
2146 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2147 | task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */ |
2148 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2149 | goto end; |
2150 | } |
2151 | next_actconn = count + 1; |
2152 | @@ -870,7 +872,9 @@ void listener_accept(int fd) |
2153 | p->id); |
2154 | close(cfd); |
2155 | limit_listener(l, &global_listener_queue); |
2156 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2157 | task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */ |
2158 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2159 | goto end; |
2160 | } |
2161 | |
2162 | @@ -1038,7 +1042,9 @@ void listener_accept(int fd) |
2163 | wait_expire: |
2164 | /* switch the listener to LI_LIMITED and wait until up to <expire> in the global queue */ |
2165 | limit_listener(l, &global_listener_queue); |
2166 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2167 | task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire)); |
2168 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2169 | end: |
2170 | if (next_conn) |
2171 | _HA_ATOMIC_SUB(&l->nbconn, 1); |
2172 | diff --git a/src/log.c b/src/log.c |
2173 | index e1c47ff..a63ba61 100644 |
2174 | --- a/src/log.c |
2175 | +++ b/src/log.c |
2176 | @@ -1262,17 +1262,21 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str |
2177 | } |
2178 | |
2179 | if (src && len) { |
2180 | - if (++len > size) |
2181 | - len = size; |
2182 | + /* escape_string and strlcpy2 will both try to add terminating NULL-byte |
2183 | + * to dst, so we need to make sure that extra byte will fit into dst |
2184 | + * before calling them |
2185 | + */ |
2186 | if (node->options & LOG_OPT_ESC) { |
2187 | char *ret; |
2188 | |
2189 | - ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src); |
2190 | + ret = escape_string(dst, (dst + size - 1), '\\', rfc5424_escape_map, src, src + len); |
2191 | if (ret == NULL || *ret != '\0') |
2192 | return NULL; |
2193 | len = ret - dst; |
2194 | } |
2195 | else { |
2196 | + if (++len > size) |
2197 | + len = size; |
2198 | len = strlcpy2(dst, src, len); |
2199 | } |
2200 | |
2201 | @@ -1283,6 +1287,7 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str |
2202 | if (size < 2) |
2203 | return NULL; |
2204 | *(dst++) = '-'; |
2205 | + size -= 1; |
2206 | } |
2207 | |
2208 | if (node->options & LOG_OPT_QUOTE) { |
2209 | diff --git a/src/memory.c b/src/memory.c |
2210 | index 242264c..bf19df3 100644 |
2211 | --- a/src/memory.c |
2212 | +++ b/src/memory.c |
2213 | @@ -531,24 +531,24 @@ int pool_total_failures() |
2214 | } |
2215 | |
2216 | /* This function returns the total amount of memory allocated in pools (in bytes) */ |
2217 | -unsigned long pool_total_allocated() |
2218 | +unsigned long long pool_total_allocated() |
2219 | { |
2220 | struct pool_head *entry; |
2221 | - unsigned long allocated = 0; |
2222 | + unsigned long long allocated = 0; |
2223 | |
2224 | list_for_each_entry(entry, &pools, list) |
2225 | - allocated += entry->allocated * entry->size; |
2226 | + allocated += entry->allocated * (unsigned long long)entry->size; |
2227 | return allocated; |
2228 | } |
2229 | |
2230 | /* This function returns the total amount of memory used in pools (in bytes) */ |
2231 | -unsigned long pool_total_used() |
2232 | +unsigned long long pool_total_used() |
2233 | { |
2234 | struct pool_head *entry; |
2235 | - unsigned long used = 0; |
2236 | + unsigned long long used = 0; |
2237 | |
2238 | list_for_each_entry(entry, &pools, list) |
2239 | - used += entry->used * entry->size; |
2240 | + used += entry->used * (unsigned long long)entry->size; |
2241 | return used; |
2242 | } |
2243 | |
2244 | diff --git a/src/mux_h1.c b/src/mux_h1.c |
2245 | index 560632a..4c91672 100644 |
2246 | --- a/src/mux_h1.c |
2247 | +++ b/src/mux_h1.c |
2248 | @@ -623,7 +623,7 @@ static int h1_process_req_vsn(struct h1s *h1s, struct h1m *h1m, union h1_sl sl) |
2249 | if (sl.rq.v.len != 8) |
2250 | return 0; |
2251 | |
2252 | - if (*(sl.rq.v.ptr + 4) != '/' || |
2253 | + if (!istnmatch(sl.rq.v, ist("HTTP/"), 5) || |
2254 | !isdigit((unsigned char)*(sl.rq.v.ptr + 5)) || |
2255 | *(sl.rq.v.ptr + 6) != '.' || |
2256 | !isdigit((unsigned char)*(sl.rq.v.ptr + 7))) |
2257 | diff --git a/src/mux_h2.c b/src/mux_h2.c |
2258 | index 09f8fa5..3141b36 100644 |
2259 | --- a/src/mux_h2.c |
2260 | +++ b/src/mux_h2.c |
2261 | @@ -60,6 +60,7 @@ static const struct h2s *h2_idle_stream; |
2262 | // (SHORT_READ is also excluded) |
2263 | |
2264 | #define H2_CF_DEM_SHORT_READ 0x00000200 // demux blocked on incomplete frame |
2265 | +#define H2_CF_DEM_IN_PROGRESS 0x00000400 // demux in progress (dsi,dfl,dft are valid) |
2266 | |
2267 | /* other flags */ |
2268 | #define H2_CF_GOAWAY_SENT 0x00001000 // a GOAWAY frame was successfully sent |
2269 | @@ -310,7 +311,6 @@ static struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned short s |
2270 | static struct h2s *h2c_bck_stream_new(struct h2c *h2c, struct conn_stream *cs, struct session *sess); |
2271 | static void h2s_alert(struct h2s *h2s); |
2272 | |
2273 | - |
2274 | /* Detect a pending read0 for a H2 connection. It happens if a read0 was |
2275 | * already reported on a previous xprt->rcvbuf() AND a frame parser failed |
2276 | * to parse pending data, confirming no more progress is possible because |
2277 | @@ -2546,6 +2546,7 @@ static void h2_process_demux(struct h2c *h2c) |
2278 | h2c->dft = hdr.ft; |
2279 | h2c->dff = hdr.ff; |
2280 | h2c->dpl = padlen; |
2281 | + h2c->flags |= H2_CF_DEM_IN_PROGRESS; |
2282 | h2c->st0 = H2_CS_FRAME_P; |
2283 | |
2284 | /* check for minimum basic frame format validity */ |
2285 | @@ -2821,8 +2822,10 @@ static void h2_process_demux(struct h2c *h2c) |
2286 | ret = MIN(b_data(&h2c->dbuf), h2c->dfl); |
2287 | b_del(&h2c->dbuf, ret); |
2288 | h2c->dfl -= ret; |
2289 | - if (!h2c->dfl) |
2290 | + if (!h2c->dfl) { |
2291 | + h2c->flags &= ~H2_CF_DEM_IN_PROGRESS; |
2292 | h2c->st0 = H2_CS_FRAME_H; |
2293 | + } |
2294 | } |
2295 | } |
2296 | |
2297 | @@ -3935,6 +3938,10 @@ next_frame: |
2298 | *flags |= H2_SF_HEADERS_RCVD; |
2299 | |
2300 | if ((h2c->dff & H2_F_HEADERS_END_STREAM)) { |
2301 | + if (msgf & H2_MSGF_RSP_1XX) { |
2302 | + /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */ |
2303 | + goto fail; |
2304 | + } |
2305 | /* Mark the end of message, either using EOM in HTX or with the |
2306 | * trailing CRLF after the end of trailers. Note that DATA_CHNK |
2307 | * is not set during headers with END_STREAM. For HTX trailers, |
2308 | diff --git a/src/mworker.c b/src/mworker.c |
2309 | index 5ff1ef9..487d071 100644 |
2310 | --- a/src/mworker.c |
2311 | +++ b/src/mworker.c |
2312 | @@ -417,8 +417,10 @@ void mworker_cleanlisteners() |
2313 | |
2314 | stop_proxy(curpeers->peers_fe); |
2315 | /* disable this peer section so that it kills itself */ |
2316 | - signal_unregister_handler(curpeers->sighandler); |
2317 | - task_destroy(curpeers->sync_task); |
2318 | + if (curpeers->sighandler) |
2319 | + signal_unregister_handler(curpeers->sighandler); |
2320 | + if (curpeers->sync_task) |
2321 | + task_destroy(curpeers->sync_task); |
2322 | curpeers->sync_task = NULL; |
2323 | task_destroy(curpeers->peers_fe->task); |
2324 | curpeers->peers_fe->task = NULL; |
2325 | diff --git a/src/peers.c b/src/peers.c |
2326 | index ec8de36..a206d9f 100644 |
2327 | --- a/src/peers.c |
2328 | +++ b/src/peers.c |
2329 | @@ -105,6 +105,7 @@ |
2330 | |
2331 | #define PEER_RESYNC_TIMEOUT 5000 /* 5 seconds */ |
2332 | #define PEER_RECONNECT_TIMEOUT 5000 /* 5 seconds */ |
2333 | +#define PEER_LOCAL_RECONNECT_TIMEOUT 500 /* 500ms */ |
2334 | #define PEER_HEARTBEAT_TIMEOUT 3000 /* 3 seconds */ |
2335 | |
2336 | /*****************************/ |
2337 | @@ -1369,7 +1370,6 @@ static inline int peer_send_teach_stage2_msgs(struct appctx *appctx, struct peer |
2338 | static int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int exp, |
2339 | char **msg_cur, char *msg_end, int msg_len, int totl) |
2340 | { |
2341 | - struct stream_interface *si = appctx->owner; |
2342 | struct shared_table *st = p->remote_table; |
2343 | struct stksess *ts, *newts; |
2344 | uint32_t update; |
2345 | @@ -1565,12 +1565,9 @@ static int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, |
2346 | |
2347 | HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
2348 | stktable_touch_remote(st->table, ts, 1); |
2349 | - return 1; |
2350 | |
2351 | ignore_msg: |
2352 | - /* skip consumed message */ |
2353 | - co_skip(si_oc(si), totl); |
2354 | - return 0; |
2355 | + return 1; |
2356 | |
2357 | malformed_unlock: |
2358 | /* malformed message */ |
2359 | @@ -1671,7 +1668,6 @@ static inline int peer_treat_switchmsg(struct appctx *appctx, struct peer *p, |
2360 | static inline int peer_treat_definemsg(struct appctx *appctx, struct peer *p, |
2361 | char **msg_cur, char *msg_end, int totl) |
2362 | { |
2363 | - struct stream_interface *si = appctx->owner; |
2364 | int table_id_len; |
2365 | struct shared_table *st; |
2366 | int table_type; |
2367 | @@ -1728,11 +1724,9 @@ static inline int peer_treat_definemsg(struct appctx *appctx, struct peer *p, |
2368 | |
2369 | p->remote_table->remote_data = table_data; |
2370 | p->remote_table->remote_id = table_id; |
2371 | - return 1; |
2372 | |
2373 | ignore_msg: |
2374 | - co_skip(si_oc(si), totl); |
2375 | - return 0; |
2376 | + return 1; |
2377 | |
2378 | malformed_exit: |
2379 | /* malformed message */ |
2380 | @@ -2413,7 +2407,7 @@ switchstate: |
2381 | } |
2382 | } |
2383 | |
2384 | - if (si_ic(si)->flags & CF_WRITE_PARTIAL) |
2385 | + if (si_ic(si)->flags & CF_WROTE_DATA) |
2386 | curpeer->statuscode = PEER_SESS_SC_CONNECTEDCODE; |
2387 | |
2388 | reql = peer_getline(appctx); |
2389 | @@ -2593,7 +2587,9 @@ void peers_setup_frontend(struct proxy *fe) |
2390 | fe->cap = PR_CAP_FE | PR_CAP_BE; |
2391 | fe->maxconn = 0; |
2392 | fe->conn_retries = CONN_RETRIES; |
2393 | + fe->timeout.connect = MS_TO_TICKS(1000); |
2394 | fe->timeout.client = MS_TO_TICKS(5000); |
2395 | + fe->timeout.server = MS_TO_TICKS(5000); |
2396 | fe->accept = frontend_accept; |
2397 | fe->default_target = &peer_applet.obj_type; |
2398 | fe->options2 |= PR_O2_INDEPSTR | PR_O2_SMARTCON | PR_O2_SMARTACC; |
2399 | @@ -2613,7 +2609,7 @@ static struct appctx *peer_session_create(struct peers *peers, struct peer *peer |
2400 | struct conn_stream *cs; |
2401 | |
2402 | peer->new_conn++; |
2403 | - peer->reconnect = tick_add(now_ms, MS_TO_TICKS(PEER_RECONNECT_TIMEOUT)); |
2404 | + peer->reconnect = tick_add(now_ms, (stopping ? MS_TO_TICKS(PEER_LOCAL_RECONNECT_TIMEOUT) : MS_TO_TICKS(PEER_RECONNECT_TIMEOUT))); |
2405 | peer->heartbeat = TICK_ETERNITY; |
2406 | peer->statuscode = PEER_SESS_SC_CONNECTCODE; |
2407 | s = NULL; |
2408 | @@ -2888,6 +2884,10 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2409 | peer_session_forceshutdown(ps); |
2410 | } |
2411 | } |
2412 | + |
2413 | + /* Set resync timeout for the local peer and request a immediate reconnect */ |
2414 | + peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(PEER_RESYNC_TIMEOUT)); |
2415 | + peers->local->reconnect = now_ms; |
2416 | } |
2417 | } |
2418 | |
2419 | @@ -2902,19 +2902,33 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2420 | } |
2421 | } |
2422 | else if (!ps->appctx) { |
2423 | + /* Re-arm resync timeout if necessary */ |
2424 | + if (!tick_isset(peers->resync_timeout)) |
2425 | + peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(PEER_RESYNC_TIMEOUT)); |
2426 | + |
2427 | /* If there's no active peer connection */ |
2428 | - if (ps->statuscode == 0 || |
2429 | - ps->statuscode == PEER_SESS_SC_SUCCESSCODE || |
2430 | - ps->statuscode == PEER_SESS_SC_CONNECTEDCODE || |
2431 | - ps->statuscode == PEER_SESS_SC_TRYAGAIN) { |
2432 | - /* connection never tried |
2433 | - * or previous peer connection was successfully established |
2434 | - * or previous tcp connect succeeded but init state incomplete |
2435 | - * or during previous connect, peer replies a try again statuscode */ |
2436 | - |
2437 | - /* connect to the local peer if we must push a local sync */ |
2438 | - if (peers->flags & PEERS_F_DONOTSTOP) { |
2439 | - peer_session_create(peers, ps); |
2440 | + if ((peers->flags & PEERS_RESYNC_STATEMASK) == PEERS_RESYNC_FINISHED && |
2441 | + !tick_is_expired(peers->resync_timeout, now_ms) && |
2442 | + (ps->statuscode == 0 || |
2443 | + ps->statuscode == PEER_SESS_SC_SUCCESSCODE || |
2444 | + ps->statuscode == PEER_SESS_SC_CONNECTEDCODE || |
2445 | + ps->statuscode == PEER_SESS_SC_TRYAGAIN)) { |
2446 | + /* The resync is finished for the local peer and |
2447 | + * the resync timeout is not expired and |
2448 | + * connection never tried |
2449 | + * or previous peer connection was successfully established |
2450 | + * or previous tcp connect succeeded but init state incomplete |
2451 | + * or during previous connect, peer replies a try again statuscode */ |
2452 | + |
2453 | + if (!tick_is_expired(ps->reconnect, now_ms)) { |
2454 | + /* reconnection timer is not expired. reschedule task for reconnect */ |
2455 | + task->expire = tick_first(task->expire, ps->reconnect); |
2456 | + } |
2457 | + else { |
2458 | + /* connect to the local peer if we must push a local sync */ |
2459 | + if (peers->flags & PEERS_F_DONOTSTOP) { |
2460 | + peer_session_create(peers, ps); |
2461 | + } |
2462 | } |
2463 | } |
2464 | else { |
2465 | @@ -2929,6 +2943,9 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2466 | } |
2467 | } |
2468 | else if (ps->statuscode == PEER_SESS_SC_SUCCESSCODE ) { |
2469 | + /* Reset resync timeout during a resync */ |
2470 | + peers->resync_timeout = TICK_ETERNITY; |
2471 | + |
2472 | /* current peer connection is active and established |
2473 | * wake up all peer handlers to push remaining local updates */ |
2474 | for (st = ps->tables; st ; st = st->next) { |
2475 | diff --git a/src/proto_http.c b/src/proto_http.c |
2476 | index bdc97de..8fb2294 100644 |
2477 | --- a/src/proto_http.c |
2478 | +++ b/src/proto_http.c |
2479 | @@ -7240,6 +7240,7 @@ void http_init_txn(struct stream *s) |
2480 | struct proxy *fe = strm_fe(s); |
2481 | struct conn_stream *cs = objt_cs(s->si[0].end); |
2482 | |
2483 | + txn->meth = HTTP_METH_OTHER; |
2484 | txn->flags = ((cs && cs->flags & CS_FL_NOT_FIRST) |
2485 | ? (TX_NOT_FIRST|TX_WAIT_NEXT_RQ) |
2486 | : 0); |
2487 | @@ -7268,8 +7269,10 @@ void http_init_txn(struct stream *s) |
2488 | if (txn->hdr_idx.v) |
2489 | hdr_idx_init(&txn->hdr_idx); |
2490 | |
2491 | - vars_init(&s->vars_txn, SCOPE_TXN); |
2492 | - vars_init(&s->vars_reqres, SCOPE_REQ); |
2493 | + /* here we don't want to re-initialize s->vars_txn and s->vars_reqres |
2494 | + * variable lists, because they were already initialized upon stream |
2495 | + * creation in stream_new(), and thus may already contain some variables |
2496 | + */ |
2497 | } |
2498 | |
2499 | /* to be used at the end of a transaction */ |
2500 | @@ -7300,6 +7303,9 @@ void http_reset_txn(struct stream *s) |
2501 | http_end_txn(s); |
2502 | http_init_txn(s); |
2503 | |
2504 | + vars_init(&s->vars_txn, SCOPE_TXN); |
2505 | + vars_init(&s->vars_reqres, SCOPE_REQ); |
2506 | + |
2507 | /* reinitialise the current rule list pointer to NULL. We are sure that |
2508 | * any rulelist match the NULL pointer. |
2509 | */ |
2510 | diff --git a/src/proto_htx.c b/src/proto_htx.c |
2511 | index f79d495..51fdd47 100644 |
2512 | --- a/src/proto_htx.c |
2513 | +++ b/src/proto_htx.c |
2514 | @@ -2808,6 +2808,7 @@ void htx_res_set_status(unsigned int status, const char *reason, struct stream * |
2515 | |
2516 | if (http_replace_res_status(htx, ist2(trash.area, trash.data))) |
2517 | http_replace_res_reason(htx, ist2(reason, strlen(reason))); |
2518 | + s->txn->status = status; |
2519 | } |
2520 | |
2521 | /* Executes the http-request rules <rules> for stream <s>, proxy <px> and |
2522 | diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c |
2523 | index 602cb6c..d3aeb4e 100644 |
2524 | --- a/src/proto_sockpair.c |
2525 | +++ b/src/proto_sockpair.c |
2526 | @@ -209,7 +209,7 @@ int send_fd_uxst(int fd, int send_fd) |
2527 | |
2528 | if (sendmsg(fd, &msghdr, 0) != sizeof(iobuf)) { |
2529 | ha_warning("Failed to transfer socket\n"); |
2530 | - return 1; |
2531 | + return -1; |
2532 | } |
2533 | |
2534 | return 0; |
2535 | diff --git a/src/proxy.c b/src/proxy.c |
2536 | index 92db68f..cb5f8e1 100644 |
2537 | --- a/src/proxy.c |
2538 | +++ b/src/proxy.c |
2539 | @@ -112,8 +112,8 @@ const struct cfg_opt cfg_opts2[] = |
2540 | { "http-pretend-keepalive", PR_O2_FAKE_KA, PR_CAP_BE, 0, PR_MODE_HTTP }, |
2541 | { "http-no-delay", PR_O2_NODELAY, PR_CAP_FE|PR_CAP_BE, 0, PR_MODE_HTTP }, |
2542 | { "http-use-htx", PR_O2_USE_HTX, PR_CAP_FE|PR_CAP_BE, 0, 0 }, |
2543 | - {"h1-case-adjust-bogus-client", PR_O2_H1_ADJ_BUGCLI, PR_CAP_FE, 0, PR_MODE_HTTP }, |
2544 | - {"h1-case-adjust-bogus-server", PR_O2_H1_ADJ_BUGSRV, PR_CAP_BE, 0, PR_MODE_HTTP }, |
2545 | + {"h1-case-adjust-bogus-client", PR_O2_H1_ADJ_BUGCLI, PR_CAP_FE, 0, 0 }, |
2546 | + {"h1-case-adjust-bogus-server", PR_O2_H1_ADJ_BUGSRV, PR_CAP_BE, 0, 0 }, |
2547 | {"disable-h2-upgrade", PR_O2_NO_H2_UPGRADE, PR_CAP_FE, 0, PR_MODE_HTTP }, |
2548 | { NULL, 0, 0, 0 } |
2549 | }; |
2550 | @@ -1209,14 +1209,18 @@ void soft_stop(void) |
2551 | * listener returns an error, then the proxy state is set to PR_STERROR |
2552 | * because we don't know how to resume from this. The function returns 0 |
2553 | * if it fails, or non-zero on success. |
2554 | + * The function takes the proxy's lock so it's safe to |
2555 | + * call from multiple places. |
2556 | */ |
2557 | int pause_proxy(struct proxy *p) |
2558 | { |
2559 | struct listener *l; |
2560 | |
2561 | + HA_SPIN_LOCK(PROXY_LOCK, &p->lock); |
2562 | + |
2563 | if (!(p->cap & PR_CAP_FE) || p->state == PR_STERROR || |
2564 | p->state == PR_STSTOPPED || p->state == PR_STPAUSED) |
2565 | - return 1; |
2566 | + goto end; |
2567 | |
2568 | ha_warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); |
2569 | send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); |
2570 | @@ -1229,10 +1233,13 @@ int pause_proxy(struct proxy *p) |
2571 | if (p->state == PR_STERROR) { |
2572 | ha_warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); |
2573 | send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); |
2574 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2575 | return 0; |
2576 | } |
2577 | |
2578 | p->state = PR_STPAUSED; |
2579 | +end: |
2580 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2581 | return 1; |
2582 | } |
2583 | |
2584 | @@ -1279,7 +1286,8 @@ void zombify_proxy(struct proxy *p) |
2585 | * to be called when going down in order to release the ports so that another |
2586 | * process may bind to them. It must also be called on disabled proxies at the |
2587 | * end of start-up. If all listeners are closed, the proxy is set to the |
2588 | - * PR_STSTOPPED state. The function takes the proxy's lock so it's safe to |
2589 | + * PR_STSTOPPED state. |
2590 | + * The function takes the proxy's lock so it's safe to |
2591 | * call from multiple places. |
2592 | */ |
2593 | void stop_proxy(struct proxy *p) |
2594 | @@ -1314,14 +1322,18 @@ void stop_proxy(struct proxy *p) |
2595 | * listeners and tries to enable them all. If any of them fails, the proxy is |
2596 | * put back to the paused state. It returns 1 upon success, or zero if an error |
2597 | * is encountered. |
2598 | + * The function takes the proxy's lock so it's safe to |
2599 | + * call from multiple places. |
2600 | */ |
2601 | int resume_proxy(struct proxy *p) |
2602 | { |
2603 | struct listener *l; |
2604 | int fail; |
2605 | |
2606 | + HA_SPIN_LOCK(PROXY_LOCK, &p->lock); |
2607 | + |
2608 | if (p->state != PR_STPAUSED) |
2609 | - return 1; |
2610 | + goto end; |
2611 | |
2612 | ha_warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); |
2613 | send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); |
2614 | @@ -1353,9 +1365,13 @@ int resume_proxy(struct proxy *p) |
2615 | |
2616 | p->state = PR_STREADY; |
2617 | if (fail) { |
2618 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2619 | + /* pause_proxy will take PROXY_LOCK */ |
2620 | pause_proxy(p); |
2621 | return 0; |
2622 | } |
2623 | +end: |
2624 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2625 | return 1; |
2626 | } |
2627 | |
2628 | @@ -1648,8 +1664,8 @@ void proxy_capture_error(struct proxy *proxy, int is_back, |
2629 | } else { |
2630 | es = HA_ATOMIC_XCHG(&proxy->invalid_req, es); |
2631 | } |
2632 | - free(es); |
2633 | HA_SPIN_UNLOCK(PROXY_LOCK, &proxy->lock); |
2634 | + free(es); |
2635 | } |
2636 | |
2637 | /* Configure all proxies which lack a maxconn setting to use the global one by |
2638 | @@ -2199,9 +2215,8 @@ static int cli_parse_disable_frontend(char **args, char *payload, struct appctx |
2639 | return 1; |
2640 | } |
2641 | |
2642 | - HA_SPIN_LOCK(PROXY_LOCK, &px->lock); |
2643 | + /* pause_proxy will take PROXY_LOCK */ |
2644 | ret = pause_proxy(px); |
2645 | - HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock); |
2646 | |
2647 | if (!ret) { |
2648 | appctx->ctx.cli.severity = LOG_ERR; |
2649 | @@ -2242,9 +2257,8 @@ static int cli_parse_enable_frontend(char **args, char *payload, struct appctx * |
2650 | return 1; |
2651 | } |
2652 | |
2653 | - HA_SPIN_LOCK(PROXY_LOCK, &px->lock); |
2654 | + /* resume_proxy will take PROXY_LOCK */ |
2655 | ret = resume_proxy(px); |
2656 | - HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock); |
2657 | |
2658 | if (!ret) { |
2659 | appctx->ctx.cli.severity = LOG_ERR; |
2660 | diff --git a/src/sample.c b/src/sample.c |
2661 | index 61e7097..e713f29 100644 |
2662 | --- a/src/sample.c |
2663 | +++ b/src/sample.c |
2664 | @@ -2196,13 +2196,14 @@ found: |
2665 | if (!smp->data.u.str.data) |
2666 | return 1; |
2667 | |
2668 | - smp->data.u.str.area = start; |
2669 | |
2670 | /* Compute remaining size if needed |
2671 | Note: smp->data.u.str.size cannot be set to 0 */ |
2672 | if (smp->data.u.str.size) |
2673 | smp->data.u.str.size -= start - smp->data.u.str.area; |
2674 | |
2675 | + smp->data.u.str.area = start; |
2676 | + |
2677 | return 1; |
2678 | } |
2679 | |
2680 | diff --git a/src/server.c b/src/server.c |
2681 | index 81639b7..bef825d 100644 |
2682 | --- a/src/server.c |
2683 | +++ b/src/server.c |
2684 | @@ -1582,8 +1582,7 @@ static void display_parser_err(const char *file, int linenum, char **args, int c |
2685 | file, linenum, args[0], args[1], args[cur_arg]); |
2686 | } |
2687 | |
2688 | -static void srv_conn_src_sport_range_cpy(struct server *srv, |
2689 | - struct server *src) |
2690 | +static void srv_conn_src_sport_range_cpy(struct server *srv, const struct server *src) |
2691 | { |
2692 | int range_sz; |
2693 | |
2694 | @@ -1604,7 +1603,7 @@ static void srv_conn_src_sport_range_cpy(struct server *srv, |
2695 | /* |
2696 | * Copy <src> server connection source settings to <srv> server everything needed. |
2697 | */ |
2698 | -static void srv_conn_src_cpy(struct server *srv, struct server *src) |
2699 | +static void srv_conn_src_cpy(struct server *srv, const struct server *src) |
2700 | { |
2701 | srv->conn_src.opts = src->conn_src.opts; |
2702 | srv->conn_src.source_addr = src->conn_src.source_addr; |
2703 | @@ -1630,7 +1629,7 @@ static void srv_conn_src_cpy(struct server *srv, struct server *src) |
2704 | * everything needed. |
2705 | */ |
2706 | #if defined(USE_OPENSSL) |
2707 | -static void srv_ssl_settings_cpy(struct server *srv, struct server *src) |
2708 | +static void srv_ssl_settings_cpy(struct server *srv, const struct server *src) |
2709 | { |
2710 | if (src->ssl_ctx.ca_file != NULL) |
2711 | srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file); |
2712 | @@ -1732,7 +1731,7 @@ static int srv_prepare_for_resolution(struct server *srv, const char *hostname) |
2713 | * <srv_tmpl> distinguishes these two cases (must be 1 if <srv> is a template, |
2714 | * 0 if not). |
2715 | */ |
2716 | -static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmpl) |
2717 | +void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl) |
2718 | { |
2719 | /* Connection source settings copy */ |
2720 | srv_conn_src_cpy(srv, src); |
2721 | diff --git a/src/signal.c b/src/signal.c |
2722 | index 288ef00..58c1710 100644 |
2723 | --- a/src/signal.c |
2724 | +++ b/src/signal.c |
2725 | @@ -58,6 +58,9 @@ void signal_handler(int sig) |
2726 | signal_state[sig].count++; |
2727 | if (sig) |
2728 | signal(sig, signal_handler); /* re-arm signal */ |
2729 | + |
2730 | + /* If the thread is TH_FL_SLEEPING we need to wake it */ |
2731 | + wake_thread(tid); |
2732 | } |
2733 | |
2734 | /* Call handlers of all pending signals and clear counts and queue length. The |
2735 | diff --git a/src/ssl_sock.c b/src/ssl_sock.c |
2736 | index 7ffcefc..b33580f 100644 |
2737 | --- a/src/ssl_sock.c |
2738 | +++ b/src/ssl_sock.c |
2739 | @@ -105,16 +105,20 @@ |
2740 | #define SSL_SOCK_SEND_UNLIMITED 0x00000004 |
2741 | #define SSL_SOCK_RECV_HEARTBEAT 0x00000008 |
2742 | |
2743 | -/* bits 0xFFFF0000 are reserved to store verify errors */ |
2744 | +/* bits 0xFFFFFF00 are reserved to store verify errors. |
2745 | + * The CA en CRT error codes will be stored on 7 bits each |
2746 | + * (since the max verify error code does not exceed 127) |
2747 | + * and the CA error depth will be stored on 4 bits. |
2748 | + */ |
2749 | |
2750 | /* Verify errors macros */ |
2751 | -#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 63) ? 63 : e) << (16)) |
2752 | -#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (6+16)) |
2753 | -#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 63) ? 63 : e) << (4+6+16)) |
2754 | +#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 127) ? 127 : e) << (8)) |
2755 | +#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (7+8)) |
2756 | +#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 127) ? 127 : e) << (4+7+8)) |
2757 | |
2758 | -#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (16)) & 63) |
2759 | -#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15) |
2760 | -#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63) |
2761 | +#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (8)) & 127) |
2762 | +#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (7+8)) & 15) |
2763 | +#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+7+8)) & 127) |
2764 | |
2765 | /* ssl_methods flags for ssl options */ |
2766 | #define MC_SSL_O_ALL 0x0000 |
2767 | @@ -1606,7 +1610,8 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store) |
2768 | ctx->xprt_st |= SSL_SOCK_CAEDEPTH_TO_ST(depth); |
2769 | } |
2770 | |
2771 | - if (err < 64 && __objt_listener(conn->target)->bind_conf->ca_ignerr & (1ULL << err)) { |
2772 | + if (err <= SSL_MAX_VFY_ERROR_CODE && |
2773 | + cert_ignerr_bitfield_get(__objt_listener(conn->target)->bind_conf->ca_ignerr_bitfield, err)) { |
2774 | ssl_sock_dump_errors(conn); |
2775 | ERR_clear_error(); |
2776 | return 1; |
2777 | @@ -1620,7 +1625,8 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store) |
2778 | ctx->xprt_st |= SSL_SOCK_CRTERROR_TO_ST(err); |
2779 | |
2780 | /* check if certificate error needs to be ignored */ |
2781 | - if (err < 64 && __objt_listener(conn->target)->bind_conf->crt_ignerr & (1ULL << err)) { |
2782 | + if (err <= SSL_MAX_VFY_ERROR_CODE && |
2783 | + cert_ignerr_bitfield_get(__objt_listener(conn->target)->bind_conf->crt_ignerr_bitfield, err)) { |
2784 | ssl_sock_dump_errors(conn); |
2785 | ERR_clear_error(); |
2786 | return 1; |
2787 | @@ -2175,13 +2181,13 @@ static void ssl_set_TLSv12_func(SSL *ssl, set_context_func c) { |
2788 | : SSL_set_min_proto_version(ssl, TLS1_2_VERSION); |
2789 | } |
2790 | static void ctx_set_TLSv13_func(SSL_CTX *ctx, set_context_func c) { |
2791 | -#if SSL_OP_NO_TLSv1_3 |
2792 | +#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) |
2793 | c == SET_MAX ? SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION) |
2794 | : SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); |
2795 | #endif |
2796 | } |
2797 | static void ssl_set_TLSv13_func(SSL *ssl, set_context_func c) { |
2798 | -#if SSL_OP_NO_TLSv1_3 |
2799 | +#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) |
2800 | c == SET_MAX ? SSL_set_max_proto_version(ssl, TLS1_3_VERSION) |
2801 | : SSL_set_min_proto_version(ssl, TLS1_3_VERSION); |
2802 | #endif |
2803 | @@ -4113,6 +4119,7 @@ static int sh_ssl_sess_store(unsigned char *s_id, unsigned char *data, int data_ |
2804 | if (oldsh_ssl_sess != sh_ssl_sess) { |
2805 | /* NOTE: Row couldn't be in use because we lock read & write function */ |
2806 | /* release the reserved row */ |
2807 | + first->len = 0; /* the len must be liberated in order not to call the release callback on it */ |
2808 | shctx_row_dec_hot(ssl_shctx, first); |
2809 | /* replace the previous session already in the tree */ |
2810 | sh_ssl_sess = oldsh_ssl_sess; |
2811 | @@ -5069,20 +5076,17 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf) |
2812 | return -err; |
2813 | } |
2814 | |
2815 | -/* release ssl context allocated for servers. */ |
2816 | +/* release ssl context allocated for servers. Most of the field free here |
2817 | + * must also be allocated in srv_ssl_settings_cpy() */ |
2818 | void ssl_sock_free_srv_ctx(struct server *srv) |
2819 | { |
2820 | #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation |
2821 | - if (srv->ssl_ctx.alpn_str) { |
2822 | - free(srv->ssl_ctx.alpn_str); |
2823 | - srv->ssl_ctx.alpn_str = NULL; |
2824 | - } |
2825 | + free(srv->ssl_ctx.alpn_str); |
2826 | + srv->ssl_ctx.alpn_str = NULL; |
2827 | #endif |
2828 | #ifdef OPENSSL_NPN_NEGOTIATED |
2829 | - if (srv->ssl_ctx.npn_str) { |
2830 | - free(srv->ssl_ctx.npn_str); |
2831 | - srv->ssl_ctx.npn_str = NULL; |
2832 | - } |
2833 | + free(srv->ssl_ctx.npn_str); |
2834 | + srv->ssl_ctx.npn_str = NULL; |
2835 | #endif |
2836 | if (srv->ssl_ctx.reused_sess) { |
2837 | int i; |
2838 | @@ -5101,6 +5105,25 @@ void ssl_sock_free_srv_ctx(struct server *srv) |
2839 | SSL_CTX_free(srv->ssl_ctx.ctx); |
2840 | srv->ssl_ctx.ctx = NULL; |
2841 | } |
2842 | + |
2843 | + free(srv->ssl_ctx.ca_file); |
2844 | + srv->ssl_ctx.ca_file = NULL; |
2845 | + free(srv->ssl_ctx.crl_file); |
2846 | + srv->ssl_ctx.crl_file = NULL; |
2847 | + free(srv->ssl_ctx.client_crt); |
2848 | + srv->ssl_ctx.client_crt = NULL; |
2849 | + free(srv->ssl_ctx.verify_host); |
2850 | + srv->ssl_ctx.verify_host = NULL; |
2851 | +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
2852 | + free(srv->sni_expr); |
2853 | + srv->sni_expr = NULL; |
2854 | +#endif |
2855 | + free(srv->ssl_ctx.ciphers); |
2856 | + srv->ssl_ctx.ciphers = NULL; |
2857 | +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES |
2858 | + free(srv->ssl_ctx.ciphersuites); |
2859 | + srv->ssl_ctx.ciphersuites = NULL; |
2860 | +#endif |
2861 | } |
2862 | |
2863 | /* Walks down the two trees in bind_conf and frees all the certs. The pointer may |
2864 | @@ -8083,7 +8106,7 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str |
2865 | { |
2866 | int code; |
2867 | char *p = args[cur_arg + 1]; |
2868 | - unsigned long long *ignerr = &conf->crt_ignerr; |
2869 | + unsigned long long *ignerr = conf->crt_ignerr_bitfield; |
2870 | |
2871 | if (!*p) { |
2872 | if (err) |
2873 | @@ -8092,22 +8115,22 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str |
2874 | } |
2875 | |
2876 | if (strcmp(args[cur_arg], "ca-ignore-err") == 0) |
2877 | - ignerr = &conf->ca_ignerr; |
2878 | + ignerr = conf->ca_ignerr_bitfield; |
2879 | |
2880 | if (strcmp(p, "all") == 0) { |
2881 | - *ignerr = ~0ULL; |
2882 | + cert_ignerr_bitfield_set_all(ignerr); |
2883 | return 0; |
2884 | } |
2885 | |
2886 | while (p) { |
2887 | code = atoi(p); |
2888 | - if ((code <= 0) || (code > 63)) { |
2889 | + if ((code <= 0) || (code > SSL_MAX_VFY_ERROR_CODE)) { |
2890 | if (err) |
2891 | - memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'", |
2892 | - args[cur_arg], code, args[cur_arg + 1]); |
2893 | + memprintf(err, "'%s' : ID '%d' out of range (1..%d) in error IDs list '%s'", |
2894 | + args[cur_arg], code, SSL_MAX_VFY_ERROR_CODE, args[cur_arg + 1]); |
2895 | return ERR_ALERT | ERR_FATAL; |
2896 | } |
2897 | - *ignerr |= 1ULL << code; |
2898 | + cert_ignerr_bitfield_set(ignerr, code); |
2899 | p = strchr(p, ','); |
2900 | if (p) |
2901 | p++; |
2902 | diff --git a/src/standard.c b/src/standard.c |
2903 | index 3dd3d6d..e941627 100644 |
2904 | --- a/src/standard.c |
2905 | +++ b/src/standard.c |
2906 | @@ -1613,7 +1613,8 @@ char *encode_chunk(char *start, char *stop, |
2907 | |
2908 | /* |
2909 | * Tries to prefix characters tagged in the <map> with the <escape> |
2910 | - * character. The input <string> must be zero-terminated. The result will |
2911 | + * character. The input <string> is processed until string_stop |
2912 | + * is reached or NULL-byte is encountered. The result will |
2913 | * be stored between <start> (included) and <stop> (excluded). This |
2914 | * function will always try to terminate the resulting string with a '\0' |
2915 | * before <stop>, and will return its position if the conversion |
2916 | @@ -1621,11 +1622,11 @@ char *encode_chunk(char *start, char *stop, |
2917 | */ |
2918 | char *escape_string(char *start, char *stop, |
2919 | const char escape, const long *map, |
2920 | - const char *string) |
2921 | + const char *string, const char *string_stop) |
2922 | { |
2923 | if (start < stop) { |
2924 | stop--; /* reserve one byte for the final '\0' */ |
2925 | - while (start < stop && *string != '\0') { |
2926 | + while (start < stop && string < string_stop && *string != '\0') { |
2927 | if (!ha_bit_test((unsigned char)(*string), map)) |
2928 | *start++ = *string; |
2929 | else { |
2930 | diff --git a/src/stick_table.c b/src/stick_table.c |
2931 | index 015463b..a3d63f3 100644 |
2932 | --- a/src/stick_table.c |
2933 | +++ b/src/stick_table.c |
2934 | @@ -215,7 +215,18 @@ int __stktable_trash_oldest(struct stktable *t, int to_batch) |
2935 | ts->exp.key = ts->expire; |
2936 | eb32_insert(&t->exps, &ts->exp); |
2937 | |
2938 | - if (!eb || eb->key > ts->exp.key) |
2939 | + /* the update might have jumped beyond the next element, |
2940 | + * possibly causing a wrapping. We need to check whether |
2941 | + * the next element should be used instead. If the next |
2942 | + * element doesn't exist it means we're on the right |
2943 | + * side and have to check the first one then. If it |
2944 | + * exists and is closer, we must use it, otherwise we |
2945 | + * use the current one. |
2946 | + */ |
2947 | + if (!eb) |
2948 | + eb = eb32_first(&t->exps); |
2949 | + |
2950 | + if (!eb || tick_is_lt(ts->exp.key, eb->key)) |
2951 | eb = &ts->exp; |
2952 | |
2953 | continue; |
2954 | @@ -547,11 +558,12 @@ struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts) |
2955 | return ts; |
2956 | } |
2957 | /* |
2958 | - * Trash expired sticky sessions from table <t>. The next expiration date is |
2959 | - * returned. |
2960 | + * Task processing function to trash expired sticky sessions. A pointer to the |
2961 | + * task itself is returned since it never dies. |
2962 | */ |
2963 | -static int stktable_trash_expired(struct stktable *t) |
2964 | +struct task *process_table_expire(struct task *task, void *context, unsigned short state) |
2965 | { |
2966 | + struct stktable *t = context; |
2967 | struct stksess *ts; |
2968 | struct eb32_node *eb; |
2969 | int looped = 0; |
2970 | @@ -597,7 +609,18 @@ static int stktable_trash_expired(struct stktable *t) |
2971 | ts->exp.key = ts->expire; |
2972 | eb32_insert(&t->exps, &ts->exp); |
2973 | |
2974 | - if (!eb || eb->key > ts->exp.key) |
2975 | + /* the update might have jumped beyond the next element, |
2976 | + * possibly causing a wrapping. We need to check whether |
2977 | + * the next element should be used instead. If the next |
2978 | + * element doesn't exist it means we're on the right |
2979 | + * side and have to check the first one then. If it |
2980 | + * exists and is closer, we must use it, otherwise we |
2981 | + * use the current one. |
2982 | + */ |
2983 | + if (!eb) |
2984 | + eb = eb32_first(&t->exps); |
2985 | + |
2986 | + if (!eb || tick_is_lt(ts->exp.key, eb->key)) |
2987 | eb = &ts->exp; |
2988 | continue; |
2989 | } |
2990 | @@ -611,19 +634,8 @@ static int stktable_trash_expired(struct stktable *t) |
2991 | /* We have found no task to expire in any tree */ |
2992 | t->exp_next = TICK_ETERNITY; |
2993 | out_unlock: |
2994 | + task->expire = t->exp_next; |
2995 | HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock); |
2996 | - return t->exp_next; |
2997 | -} |
2998 | - |
2999 | -/* |
3000 | - * Task processing function to trash expired sticky sessions. A pointer to the |
3001 | - * task itself is returned since it never dies. |
3002 | - */ |
3003 | -static struct task *process_table_expire(struct task *task, void *context, unsigned short state) |
3004 | -{ |
3005 | - struct stktable *t = context; |
3006 | - |
3007 | - task->expire = stktable_trash_expired(t); |
3008 | return task; |
3009 | } |
3010 | |
3011 | diff --git a/src/stream.c b/src/stream.c |
3012 | index 96bdce7..01f5ed5 100644 |
3013 | --- a/src/stream.c |
3014 | +++ b/src/stream.c |
3015 | @@ -228,8 +228,17 @@ struct stream *stream_new(struct session *sess, enum obj_type *origin) |
3016 | s->req_cap = NULL; |
3017 | s->res_cap = NULL; |
3018 | |
3019 | - /* Initialise all the variables contexts even if not used. |
3020 | + /* Initialize all the variables contexts even if not used. |
3021 | * This permits to prune these contexts without errors. |
3022 | + * |
3023 | + * We need to make sure that those lists are not re-initialized |
3024 | + * by stream-dependant underlying code because we could lose |
3025 | + * track of already defined variables, leading to data inconsistency |
3026 | + * and memory leaks... |
3027 | + * |
3028 | + * For reference: we had a very old bug caused by vars_txn and |
3029 | + * vars_reqres being accidentally re-initialized in http_create_txn() |
3030 | + * (https://github.com/haproxy/haproxy/issues/1935) |
3031 | */ |
3032 | vars_init(&s->vars_txn, SCOPE_TXN); |
3033 | vars_init(&s->vars_reqres, SCOPE_REQ); |
3034 | @@ -1708,7 +1717,7 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit |
3035 | void *ptr; |
3036 | struct dict_entry *de; |
3037 | |
3038 | - if (objt_server(s->target) && objt_server(s->target)->flags & SRV_F_NON_STICK) { |
3039 | + if (!objt_server(s->target) || (__objt_server(s->target)->flags & SRV_F_NON_STICK)) { |
3040 | stksess_free(s->store[i].table, s->store[i].ts); |
3041 | s->store[i].ts = NULL; |
3042 | continue; |
3043 | @@ -1724,14 +1733,15 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit |
3044 | HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); |
3045 | ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_ID); |
3046 | stktable_data_cast(ptr, server_id) = __objt_server(s->target)->puid; |
3047 | - HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
3048 | |
3049 | - HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); |
3050 | - de = dict_insert(&server_name_dict, __objt_server(s->target)->id); |
3051 | - if (de) { |
3052 | - ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_NAME); |
3053 | - stktable_data_cast(ptr, server_name) = de; |
3054 | + if (__objt_server(s->target)->id) { |
3055 | + de = dict_insert(&server_name_dict, __objt_server(s->target)->id); |
3056 | + if (de) { |
3057 | + ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_NAME); |
3058 | + stktable_data_cast(ptr, server_name) = de; |
3059 | + } |
3060 | } |
3061 | + |
3062 | HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
3063 | |
3064 | stktable_touch_local(s->store[i].table, ts, 1); |
3065 | diff --git a/src/stream_interface.c b/src/stream_interface.c |
3066 | index ab5c574..1adecf3 100644 |
3067 | --- a/src/stream_interface.c |
3068 | +++ b/src/stream_interface.c |
3069 | @@ -1149,7 +1149,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si) |
3070 | struct channel *oc = si_oc(si); |
3071 | struct conn_stream *cs = __objt_cs(si->end); |
3072 | |
3073 | - if (unlikely(!si_state_in(si->state, SI_SB_CON|SI_SB_RDY|SI_SB_EST) || |
3074 | + if (unlikely(!si_state_in(si->state, SI_SB_RDY|SI_SB_EST) || |
3075 | (oc->flags & CF_SHUTW))) |
3076 | return; |
3077 |
Thanks for the MP, Lucas.
I'd like to see an updated the d/changelog entry here to list the major bug fixes, just like you did for Jammy. I also took the liberty to trigger autopkgtest runs for every supported architecture against your PPA.
The first thing I did was to try to reproduce the upstream tarball import commit. I use a local, temporary gbp repository where I perform the import, and then I compare the commit generated by gbp against the commit in the MRE branch I'm reviewing.
For this specific MP, the two commits showed some differences. They are only related to files that seem to be auto-generated by github, and they're not really important for the build process per se, but I'm wondering why they're showing up. I grabbed the upstream tarball from this page:
https:/ /www.haproxy. org/?_gl= 1*xzll7y* _ga*MTQ0OTA0NDU xLjE2NTQ1OTYzNT E.*_ga_ VKZPMRNGK5* MTY1NjMzMzA5Ni4 1Ny4xLjE2NTYzMz Q4MjcuMA. .*_ga_MGHPDQ7WF P*MTY1NjMzMzA5N i41Ni4xLjE2NTYz MzQ4MjcuMA. .#down
Did you grab it from somewhere else?
The dropped patches are OK. The updated patches are also OK.
... and the autopkgtest run has finished, and everything looks OK.