Bug#928461: unblock: haproxy/1.8.20-1 (pre-approval)
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Hey!
HAProxy 1.8.20 was released last week. This is a bugfix only release.
Upstream has stated his dislike of cherry-picking only some of the
fixes and would prefer us to ship a pristine 1.8.19 instead of a
patched version if we do not want to ship 1.8.20 as is. See the full
rationale here:
<https://www.mail-archive.com/haproxy@formilux.org/msg33550.html>
Here is upstream changelog:
- BUG/MAJOR: listener: Make sure the listener exist before using it.
- BUG/MINOR: listener: keep accept rate counters accurate under saturation
- BUG/MEDIUM: logs: Only attempt to free startup_logs once.
- BUG/MEDIUM: 51d: fix possible segfault on deinit_51degrees()
- BUG/MINOR: ssl: fix warning about ssl-min/max-ver support
- MEDIUM: threads: Use __ATOMIC_SEQ_CST when using the newer atomic API.
- BUG/MEDIUM: threads/fd: do not forget to take into account epoll_fd/pipes
- BUG/MAJOR: spoe: Fix initialization of thread-dependent fields
- BUG/MAJOR: stats: Fix how huge POST data are read from the channel
- BUG/MINOR: http/counters: fix missing increment of fe->srv_aborts
- BUG/MEDIUM: ssl: ability to set TLS 1.3 ciphers using ssl-default-server-ciphersuites
- DOC: The option httplog is no longer valid in a backend.
- BUG/MAJOR: checks: segfault during tcpcheck_main
- BUILD: makefile: work around an old bug in GNU make-3.80
- MINOR: tools: make memvprintf() never pass a NULL target to vsnprintf()
- BUILD: makefile: fix build of IPv6 header on aix51
- BUILD: makefile: add _LINUX_SOURCE_COMPAT to build on AIX-51
- BUILD: Makefile: disable shared cache on AIX 5.1
- BUG/MINOR: cli: correctly handle abns in 'show cli sockets'
- MINOR: cli: start addresses by a prefix in 'show cli sockets'
- BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
- BUILD: use inttypes.h instead of stdint.h
- BUILD: connection: fix naming of ip_v field
- BUG/MEDIUM: pattern: assign pattern IDs after checking the config validity
- BUG/MEDIUM: spoe: Queue message only if no SPOE applet is attached to the stream
- BUG/MEDIUM: spoe: Return an error if nothing is encoded for fragmented messages
- BUG/MINOR: threads: fix the process range of thread masks
- MINOR: lists: Implement locked variations.
- BUG/MEDIUM: lists: Properly handle the case we're removing the first elt.
- BUG/MEDIUM: list: fix the rollback on addq in the locked liss
- BUG/MEDIUM: list: fix LIST_POP_LOCKED's removal of the last pointer
- BUG/MEDIUM: list: add missing store barriers when updating elements and head
- MINOR: list: make the delete and pop operations idempotent
- BUG/MEDIUM: list: correct fix for LIST_POP_LOCKED's removal of last element
- BUG/MEDIUM: list: fix again LIST_ADDQ_LOCKED
- BUG/MEDIUM: list: fix incorrect pointer unlocking in LIST_DEL_LOCKED()
- MAJOR: listener: do not hold the listener lock in listener_accept()
- BUG/MEDIUM: listener: use a self-locked list for the dequeue lists
- BUG/MEDIUM: listener: make sure the listener never accepts too many conns
- BUILD/MINOR: listener: Silent a few signedness warnings.
- MINOR: skip get_gmtime where tm is unused
- BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
- BUG/MEDIUM: maps: only try to parse the default value when it's present
- BUG/MINOR: acl: properly detect pattern type SMP_T_ADDR
- BUG/MEDIUM: thread/http: Add missing locks in set-map and add-acl HTTP rules
- BUG/MINOR: 51d: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
- BUG/MINOR: da: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
- BUG/MINOR: spoe: Don't systematically wakeup SPOE stream in the applet handler
Here is a diffstat:
CHANGELOG | 50 +++
Makefile | 6
README | 2
VERDATE | 2
VERSION | 2
contrib/hpack/gen-rht.c | 2
contrib/plug_qdisc/plug_qdisc.c | 2
contrib/spoa_example/include/spop_functions.h | 2
contrib/wireshark-dissectors/peers/packet-happp.c | 2
debian/changelog | 11
debian/tests/control | 4
debian/tests/proxy-localhost | 48 +++
doc/configuration.txt | 4
examples/haproxy.spec | 5
include/common/hathreads.h | 18 -
include/common/hpack-dec.h | 2
include/common/hpack-enc.h | 2
include/common/hpack-huff.h | 2
include/common/hpack-tbl.h | 2
include/common/http-hdr.h | 2
include/common/mini-clist.h | 156 ++++++++++
include/proto/proto_http.h | 10
include/proto/shctx.h | 2
src/51d.c | 5
src/acl.c | 1
src/checks.c | 2
src/cli.c | 10
src/connection.c | 8
src/da.c | 2
src/flt_spoe.c | 33 +-
src/h2.c | 2
src/haproxy.c | 7
src/hlua.c | 2
src/hpack-dec.c | 2
src/hpack-enc.c | 2
src/hpack-huff.c | 2
src/hpack-tbl.c | 2
src/listener.c | 247 +++++++++-------
src/log.c | 7
src/map.c | 6
src/peers.c | 77 +++-
src/proto_http.c | 339 +++++++++++-----------
src/session.c | 5
src/sha1.c | 2
src/ssl_sock.c | 4
src/standard.c | 4
src/stats.c | 25 +
src/xxhash.c | 2
48 files changed, 756 insertions(+), 380 deletions(-)
The two main contributors to these changes are:
BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
<http://git.haproxy.org/?p=haproxy-1.8.git;a=commitdiff;h=b05ee4aa74a95be49c78198ca601000b47c93da2>
BUG/MEDIUM: listener: make sure the listener never accepts too many conns
<http://git.haproxy.org/?p=haproxy-1.8.git;a=commitdiff;h=c98cdf7cc755c579a8b9cceee4809089267615ce>
I am attaching the full debdiff.
Is it OK to push this version in unstable?
unblock haproxy/1.8.20-1
- -- System Information:
Debian Release: 10.0
APT prefers unstable-debug
APT policy: (500, 'unstable-debug'), (500, 'unstable'), (101, 'experimental-debug'), (101, 'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 4.19.0-4-amd64 (SMP w/4 CPU cores)
Kernel taint flags: TAINT_USER, TAINT_WARN, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=fr_FR.utf8, LC_CTYPE=fr_FR.utf8 (charmap=UTF-8), LANGUAGE=en_US:en (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
-----BEGIN PGP SIGNATURE-----
iQJGBAEBCAAwFiEErvI0h2bzccaJpzYAlaQv6DU1JfkFAlzOlbgSHGJlcm5hdEBk
ZWJpYW4ub3JnAAoJEJWkL+g1NSX5Wv4P/jhvcbjoUhLUZrXzMb6SvOUn6DN7RNiW
LDDkidjSi699+VbBlqwOcsG18E7YoB2AYzhhpeizx2o+yQSM2zweAjddRJ+RnEvl
Fcnv5FXw5dXK5Km6Mw3rTZkENt4zlHFN8GbbiVr8egmujmj/xNjSAUU7YAjNrycP
FjIZUaGGKnR57DgQUc6wjhC10LAD6+Hwa+M1dPz51u+kqpxXQ6o0TLoAqY3Icwu3
lkt6kG5c+yppHlKaEouquRM8Hkf+heDyL6xPDMbd4WeG1YxAG2rcxRgmTUYhH4Qt
MQo5yQMtzQtU3u8ingvpG5P7dwqwPnKfQurDYnslD2YDPyPFk708tqtoCkSjFB7f
35ZCuUvphm/2gAE38n7ZBxb/+Emyy0IHsMfLiq9I6R4b0/8DSbgPFUTZc2i/WXt5
lHoTLKITNhSdZ9154xQIn7QvbHSH3Weh8ax3eC35iDdoKJBs01FmSpSgCWPtYjvj
DHUsDJ2QcpXSN8cvxDgUs8Bhjk/nZAU4ly2EYZkAzUgl97izfODv9zHuRpCoZJ/9
96xG6YS2ooRkMPQLMnKVp1lRfKl9kr93uDvlci8Y94kG8jWZYJPBSLb6CJ4aUDWZ
4c/+v3KHqclxP3TxzRI6Ag1yvQOm10hkXn5qTXTx5Vls3cCx1e9Y6xHACM0QYc7C
2NDyVc0MDKpb
=Y7yl
-----END PGP SIGNATURE-----
diff -Nru haproxy-1.8.19/CHANGELOG haproxy-1.8.20/CHANGELOG
--- haproxy-1.8.19/CHANGELOG 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/CHANGELOG 2019-04-25 23:59:27.000000000 +0200
@@ -1,6 +1,56 @@
ChangeLog :
===========
+2019/04/25 : 1.8.20
+ - BUG/MAJOR: listener: Make sure the listener exist before using it.
+ - BUG/MINOR: listener: keep accept rate counters accurate under saturation
+ - BUG/MEDIUM: logs: Only attempt to free startup_logs once.
+ - BUG/MEDIUM: 51d: fix possible segfault on deinit_51degrees()
+ - BUG/MINOR: ssl: fix warning about ssl-min/max-ver support
+ - MEDIUM: threads: Use __ATOMIC_SEQ_CST when using the newer atomic API.
+ - BUG/MEDIUM: threads/fd: do not forget to take into account epoll_fd/pipes
+ - BUG/MAJOR: spoe: Fix initialization of thread-dependent fields
+ - BUG/MAJOR: stats: Fix how huge POST data are read from the channel
+ - BUG/MINOR: http/counters: fix missing increment of fe->srv_aborts
+ - BUG/MEDIUM: ssl: ability to set TLS 1.3 ciphers using ssl-default-server-ciphersuites
+ - DOC: The option httplog is no longer valid in a backend.
+ - BUG/MAJOR: checks: segfault during tcpcheck_main
+ - BUILD: makefile: work around an old bug in GNU make-3.80
+ - MINOR: tools: make memvprintf() never pass a NULL target to vsnprintf()
+ - BUILD: makefile: fix build of IPv6 header on aix51
+ - BUILD: makefile: add _LINUX_SOURCE_COMPAT to build on AIX-51
+ - BUILD: Makefile: disable shared cache on AIX 5.1
+ - BUG/MINOR: cli: correctly handle abns in 'show cli sockets'
+ - MINOR: cli: start addresses by a prefix in 'show cli sockets'
+ - BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
+ - BUILD: use inttypes.h instead of stdint.h
+ - BUILD: connection: fix naming of ip_v field
+ - BUG/MEDIUM: pattern: assign pattern IDs after checking the config validity
+ - BUG/MEDIUM: spoe: Queue message only if no SPOE applet is attached to the stream
+ - BUG/MEDIUM: spoe: Return an error if nothing is encoded for fragmented messages
+ - BUG/MINOR: threads: fix the process range of thread masks
+ - MINOR: lists: Implement locked variations.
+ - BUG/MEDIUM: lists: Properly handle the case we're removing the first elt.
+ - BUG/MEDIUM: list: fix the rollback on addq in the locked liss
+ - BUG/MEDIUM: list: fix LIST_POP_LOCKED's removal of the last pointer
+ - BUG/MEDIUM: list: add missing store barriers when updating elements and head
+ - MINOR: list: make the delete and pop operations idempotent
+ - BUG/MEDIUM: list: correct fix for LIST_POP_LOCKED's removal of last element
+ - BUG/MEDIUM: list: fix again LIST_ADDQ_LOCKED
+ - BUG/MEDIUM: list: fix incorrect pointer unlocking in LIST_DEL_LOCKED()
+ - MAJOR: listener: do not hold the listener lock in listener_accept()
+ - BUG/MEDIUM: listener: use a self-locked list for the dequeue lists
+ - BUG/MEDIUM: listener: make sure the listener never accepts too many conns
+ - BUILD/MINOR: listener: Silent a few signedness warnings.
+ - MINOR: skip get_gmtime where tm is unused
+ - BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
+ - BUG/MEDIUM: maps: only try to parse the default value when it's present
+ - BUG/MINOR: acl: properly detect pattern type SMP_T_ADDR
+ - BUG/MEDIUM: thread/http: Add missing locks in set-map and add-acl HTTP rules
+ - BUG/MINOR: 51d: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
+ - BUG/MINOR: da: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
+ - BUG/MINOR: spoe: Don't systematically wakeup SPOE stream in the applet handler
+
2019/02/11 : 1.8.19
- DOC: ssl: Clarify when pre TLSv1.3 cipher can be used
- DOC: ssl: Stop documenting ciphers example to use
diff -Nru haproxy-1.8.19/contrib/hpack/gen-rht.c haproxy-1.8.20/contrib/hpack/gen-rht.c
--- haproxy-1.8.19/contrib/hpack/gen-rht.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/contrib/hpack/gen-rht.c 2019-04-25 23:59:27.000000000 +0200
@@ -9,7 +9,7 @@
* 00 => 0x0a, 01 => 0x0d, 10 => 0x16, 11 => EOS
*/
-#include <stdint.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff -Nru haproxy-1.8.19/contrib/plug_qdisc/plug_qdisc.c haproxy-1.8.20/contrib/plug_qdisc/plug_qdisc.c
--- haproxy-1.8.19/contrib/plug_qdisc/plug_qdisc.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/contrib/plug_qdisc/plug_qdisc.c 2019-04-25 23:59:27.000000000 +0200
@@ -1,4 +1,4 @@
-#include <stdint.h>
+#include <inttypes.h>
#include <netlink/cache.h>
#include <netlink/cli/utils.h>
#include <netlink/cli/tc.h>
diff -Nru haproxy-1.8.19/contrib/spoa_example/include/spop_functions.h haproxy-1.8.20/contrib/spoa_example/include/spop_functions.h
--- haproxy-1.8.19/contrib/spoa_example/include/spop_functions.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/contrib/spoa_example/include/spop_functions.h 2019-04-25 23:59:27.000000000 +0200
@@ -1,7 +1,7 @@
#ifndef _SPOP_FUNCTIONS_H
#define _SPOP_FUNCTIONS_H
-#include <stdint.h>
+#include <inttypes.h>
#include <string.h>
#include <spoe_types.h>
diff -Nru haproxy-1.8.19/contrib/wireshark-dissectors/peers/packet-happp.c haproxy-1.8.20/contrib/wireshark-dissectors/peers/packet-happp.c
--- haproxy-1.8.19/contrib/wireshark-dissectors/peers/packet-happp.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/contrib/wireshark-dissectors/peers/packet-happp.c 2019-04-25 23:59:27.000000000 +0200
@@ -22,7 +22,7 @@
*/
#include <stdio.h>
-#include <stdint.h>
+#include <inttypes.h>
#include <inttypes.h>
#include <arpa/inet.h>
diff -Nru haproxy-1.8.19/debian/changelog haproxy-1.8.20/debian/changelog
--- haproxy-1.8.19/debian/changelog 2019-02-12 09:30:54.000000000 +0100
+++ haproxy-1.8.20/debian/changelog 2019-05-05 09:34:08.000000000 +0200
@@ -1,3 +1,14 @@
+haproxy (1.8.20-1) unstable; urgency=medium
+
+ * New upstream version 1.8.20
+ - BUG/MAJOR: checks: segfault during tcpcheck_main
+ - BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
+ - BUG/MAJOR: listener: Make sure the listener exist before using it.
+ - BUG/MAJOR: spoe: Fix initialization of thread-dependent fields
+ - BUG/MAJOR: stats: Fix how huge POST data are read from the channel
+
+ -- Vincent Bernat <bernat@debian.org> Sun, 05 May 2019 09:34:08 +0200
+
haproxy (1.8.19-1) unstable; urgency=medium
* New upstream version 1.8.19
diff -Nru haproxy-1.8.19/debian/tests/control haproxy-1.8.20/debian/tests/control
--- haproxy-1.8.19/debian/tests/control 2018-12-14 12:05:34.000000000 +0100
+++ haproxy-1.8.20/debian/tests/control 2019-05-05 09:34:08.000000000 +0200
@@ -1,3 +1,7 @@
Tests: cli
Depends: haproxy, socat
Restrictions: needs-root
+
+Tests: proxy-localhost
+Depends: haproxy, wget, apache2
+Restrictions: needs-root, allow-stderr, isolation-container
diff -Nru haproxy-1.8.19/debian/tests/proxy-localhost haproxy-1.8.20/debian/tests/proxy-localhost
--- haproxy-1.8.19/debian/tests/proxy-localhost 1970-01-01 01:00:00.000000000 +0100
+++ haproxy-1.8.20/debian/tests/proxy-localhost 2019-05-05 09:34:08.000000000 +0200
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+set -eux
+
+cat > /etc/haproxy/haproxy.cfg <<EOF
+global
+ chroot /var/lib/haproxy
+ user haproxy
+ group haproxy
+ daemon
+ maxconn 4096
+
+defaults
+ log global
+ option dontlognull
+ option redispatch
+ retries 3
+ timeout client 50s
+ timeout connect 10s
+ timeout http-request 5s
+ timeout server 50s
+ maxconn 4096
+
+frontend test-front
+ bind *:8080
+ mode http
+ default_backend test-back
+
+backend test-back
+ mode http
+ stick store-request src
+ stick-table type ip size 256k expire 30m
+ server test-1 localhost:80
+EOF
+
+service haproxy restart
+
+# index.html is shipped with apache2
+# Download it via haproxy and compare
+if wget -t1 http://localhost:8080 -O- | cmp /var/www/html/index.html -; then
+ echo "OK: index.html downloaded via haproxy matches the source file."
+else
+ echo "FAIL: downloaded index.html via haproxy is different from the"
+ echo " file delivered by apache."
+ exit 1
+fi
+
+exit 0
diff -Nru haproxy-1.8.19/doc/configuration.txt haproxy-1.8.20/doc/configuration.txt
--- haproxy-1.8.19/doc/configuration.txt 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/doc/configuration.txt 2019-04-25 23:59:27.000000000 +0200
@@ -4,7 +4,7 @@
----------------------
version 1.8
willy tarreau
- 2019/02/11
+ 2019/04/25
This document covers the configuration language as implemented in the version
@@ -2118,7 +2118,7 @@
option http-use-proxy-header (*) X X X -
option httpchk X - X X
option httpclose (*) X X X X
-option httplog X X X X
+option httplog X X X -
option http_proxy (*) X X X X
option independent-streams (*) X X X X
option ldap-check X - X X
diff -Nru haproxy-1.8.19/examples/haproxy.spec haproxy-1.8.20/examples/haproxy.spec
--- haproxy-1.8.19/examples/haproxy.spec 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/examples/haproxy.spec 2019-04-25 23:59:27.000000000 +0200
@@ -1,6 +1,6 @@
Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments
Name: haproxy
-Version: 1.8.19
+Version: 1.8.20
Release: 1
License: GPL
Group: System Environment/Daemons
@@ -74,6 +74,9 @@
%attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
%changelog
+* jeu. avril 25 2019 Christopher Faulet <cfaulet@haproxy.com>
+- updated to 1.8.20
+
* Mon Feb 11 2019 Willy Tarreau <w@1wt.eu>
- updated to 1.8.19
diff -Nru haproxy-1.8.19/include/common/hathreads.h haproxy-1.8.20/include/common/hathreads.h
--- haproxy-1.8.19/include/common/hathreads.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/hathreads.h 2019-04-25 23:59:27.000000000 +0200
@@ -213,14 +213,14 @@
})
#else
/* gcc >= 4.7 */
-#define HA_ATOMIC_CAS(val, old, new) __atomic_compare_exchange_n(val, old, new, 0, 0, 0)
-#define HA_ATOMIC_ADD(val, i) __atomic_add_fetch(val, i, 0)
-#define HA_ATOMIC_XADD(val, i) __atomic_fetch_add(val, i, 0)
-#define HA_ATOMIC_SUB(val, i) __atomic_sub_fetch(val, i, 0)
-#define HA_ATOMIC_AND(val, flags) __atomic_and_fetch(val, flags, 0)
-#define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, 0)
-#define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, 0)
-#define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, 0)
+#define HA_ATOMIC_CAS(val, old, new) __atomic_compare_exchange_n(val, old, new, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_ADD(val, i) __atomic_add_fetch(val, i, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_XADD(val, i) __atomic_fetch_add(val, i, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_SUB(val, i) __atomic_sub_fetch(val, i, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_AND(val, flags) __atomic_and_fetch(val, flags, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, __ATOMIC_SEQ_CST)
+#define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, __ATOMIC_SEQ_CST)
#endif
#define HA_ATOMIC_UPDATE_MAX(val, new) \
@@ -344,7 +344,6 @@
TASK_WQ_LOCK,
POOL_LOCK,
LISTENER_LOCK,
- LISTENER_QUEUE_LOCK,
PROXY_LOCK,
SERVER_LOCK,
UPDATED_SERVERS_LOCK,
@@ -467,7 +466,6 @@
case TASK_WQ_LOCK: return "TASK_WQ";
case POOL_LOCK: return "POOL";
case LISTENER_LOCK: return "LISTENER";
- case LISTENER_QUEUE_LOCK: return "LISTENER_QUEUE";
case PROXY_LOCK: return "PROXY";
case SERVER_LOCK: return "SERVER";
case UPDATED_SERVERS_LOCK: return "UPDATED_SERVERS";
diff -Nru haproxy-1.8.19/include/common/hpack-dec.h haproxy-1.8.20/include/common/hpack-dec.h
--- haproxy-1.8.19/include/common/hpack-dec.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/hpack-dec.h 2019-04-25 23:59:27.000000000 +0200
@@ -28,7 +28,7 @@
#ifndef _COMMON_HPACK_DEC_H
#define _COMMON_HPACK_DEC_H
-#include <stdint.h>
+#include <inttypes.h>
#include <common/chunk.h>
#include <common/config.h>
#include <common/hpack-tbl.h>
diff -Nru haproxy-1.8.19/include/common/hpack-enc.h haproxy-1.8.20/include/common/hpack-enc.h
--- haproxy-1.8.19/include/common/hpack-enc.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/hpack-enc.h 2019-04-25 23:59:27.000000000 +0200
@@ -28,7 +28,7 @@
#ifndef _COMMON_HPACK_ENC_H
#define _COMMON_HPACK_ENC_H
-#include <stdint.h>
+#include <inttypes.h>
#include <common/chunk.h>
#include <common/config.h>
#include <common/ist.h>
diff -Nru haproxy-1.8.19/include/common/hpack-huff.h haproxy-1.8.20/include/common/hpack-huff.h
--- haproxy-1.8.19/include/common/hpack-huff.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/hpack-huff.h 2019-04-25 23:59:27.000000000 +0200
@@ -27,7 +27,7 @@
#ifndef _PROTO_HPACK_HUFF_H
#define _PROTO_HPACK_HUFF_H
-#include <stdint.h>
+#include <inttypes.h>
int huff_enc(const char *s, char *out);
int huff_dec(const uint8_t *huff, int hlen, char *out, int olen);
diff -Nru haproxy-1.8.19/include/common/hpack-tbl.h haproxy-1.8.20/include/common/hpack-tbl.h
--- haproxy-1.8.19/include/common/hpack-tbl.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/hpack-tbl.h 2019-04-25 23:59:27.000000000 +0200
@@ -27,7 +27,7 @@
#ifndef _COMMON_HPACK_TBL_H
#define _COMMON_HPACK_TBL_H
-#include <stdint.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <common/config.h>
#include <common/http-hdr.h>
diff -Nru haproxy-1.8.19/include/common/http-hdr.h haproxy-1.8.20/include/common/http-hdr.h
--- haproxy-1.8.19/include/common/http-hdr.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/http-hdr.h 2019-04-25 23:59:27.000000000 +0200
@@ -27,7 +27,7 @@
#ifndef _COMMON_HTTP_HDR_H
#define _COMMON_HTTP_HDR_H
-#include <stdint.h>
+#include <inttypes.h>
#include <common/ist.h>
/* a header field made of a name and a value. Such structure stores 4 longs so
diff -Nru haproxy-1.8.19/include/common/mini-clist.h haproxy-1.8.20/include/common/mini-clist.h
--- haproxy-1.8.19/include/common/mini-clist.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/common/mini-clist.h 2019-04-25 23:59:27.000000000 +0200
@@ -163,5 +163,161 @@
&item->member != (list_head); \
item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
+#include <common/hathreads.h>
+#define LLIST_BUSY ((struct list *)1)
+
+/*
+ * Locked version of list manipulation macros.
+ * It is OK to use those concurrently from multiple threads, as long as the
+ * list is only used with the locked variants. The only "unlocked" macro you
+ * can use with a locked list is LIST_INIT.
+ */
+#define LIST_ADD_LOCKED(lh, el) \
+ do { \
+ while (1) { \
+ struct list *n; \
+ struct list *p; \
+ n = HA_ATOMIC_XCHG(&(lh)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ __ha_barrier_store(); \
+ p = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (el)->n = n; \
+ (el)->p = p; \
+ __ha_barrier_store(); \
+ n->p = (el); \
+ __ha_barrier_store(); \
+ p->n = (el); \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+#define LIST_ADDQ_LOCKED(lh, el) \
+ do { \
+ while (1) { \
+ struct list *n; \
+ struct list *p; \
+ p = HA_ATOMIC_XCHG(&(lh)->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) \
+ continue; \
+ __ha_barrier_store(); \
+ n = HA_ATOMIC_XCHG(&p->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) { \
+ (lh)->p = p; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (el)->n = n; \
+ (el)->p = p; \
+ __ha_barrier_store(); \
+ p->n = (el); \
+ __ha_barrier_store(); \
+ n->p = (el); \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+#define LIST_DEL_LOCKED(el) \
+ do { \
+ while (1) { \
+ struct list *n, *n2; \
+ struct list *p, *p2 = NULL; \
+ n = HA_ATOMIC_XCHG(&(el)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ p = HA_ATOMIC_XCHG(&(el)->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ if (p != (el)) { \
+ p2 = HA_ATOMIC_XCHG(&p->n, LLIST_BUSY); \
+ if (p2 == LLIST_BUSY) { \
+ (el)->p = p; \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ } \
+ if (n != (el)) { \
+ n2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (n2 == LLIST_BUSY) { \
+ if (p2 != NULL) \
+ p->n = p2; \
+ (el)->p = p; \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ } \
+ n->p = p; \
+ p->n = n; \
+ __ha_barrier_store(); \
+ (el)->p = (el); \
+ (el)->n = (el); \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+
+/* Remove the first element from the list, and return it */
+#define LIST_POP_LOCKED(lh, pt, el) \
+ ({ \
+ void *_ret; \
+ while (1) { \
+ struct list *n, *n2; \
+ struct list *p, *p2; \
+ n = HA_ATOMIC_XCHG(&(lh)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ if (n == (lh)) { \
+ (lh)->n = lh; \
+ __ha_barrier_store(); \
+ _ret = NULL; \
+ break; \
+ } \
+ p = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ n2 = HA_ATOMIC_XCHG(&n->n, LLIST_BUSY); \
+ if (n2 == LLIST_BUSY) { \
+ n->p = p; \
+ __ha_barrier_store(); \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ p2 = HA_ATOMIC_XCHG(&n2->p, LLIST_BUSY); \
+ if (p2 == LLIST_BUSY) { \
+ n->n = n2; \
+ n->p = p; \
+ __ha_barrier_store(); \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (lh)->n = n2; \
+ (n2)->p = (lh); \
+ __ha_barrier_store(); \
+ (n)->p = (n); \
+ (n)->n = (n); \
+ __ha_barrier_store(); \
+ _ret = LIST_ELEM(n, pt, el); \
+ break; \
+ } \
+ (_ret); \
+ })
#endif /* _COMMON_MINI_CLIST_H */
diff -Nru haproxy-1.8.19/include/proto/proto_http.h haproxy-1.8.20/include/proto/proto_http.h
--- haproxy-1.8.19/include/proto/proto_http.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/proto/proto_http.h 2019-04-25 23:59:27.000000000 +0200
@@ -132,7 +132,7 @@
int val_hdr(struct arg *arg, char **err_msg);
int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
- const struct arg *args, struct sample *smp, int req_vol);
+ const struct channel *chn, struct sample *smp, int req_vol);
enum act_return http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
struct session *sess, struct stream *s, int flags);
@@ -144,11 +144,11 @@
/* Note: these functions *do* modify the sample. Even in case of success, at
* least the type and uint value are modified.
*/
-#define CHECK_HTTP_MESSAGE_FIRST() \
- do { int r = smp_prefetch_http(smp->px, smp->strm, smp->opt, args, smp, 1); if (r <= 0) return r; } while (0)
+#define CHECK_HTTP_MESSAGE_FIRST(chn) \
+ do { int r = smp_prefetch_http(smp->px, smp->strm, smp->opt, (chn), smp, 1); if (r <= 0) return r; } while (0)
-#define CHECK_HTTP_MESSAGE_FIRST_PERM() \
- do { int r = smp_prefetch_http(smp->px, smp->strm, smp->opt, args, smp, 0); if (r <= 0) return r; } while (0)
+#define CHECK_HTTP_MESSAGE_FIRST_PERM(chn) \
+ do { int r = smp_prefetch_http(smp->px, smp->strm, smp->opt, (chn), smp, 0); if (r <= 0) return r; } while (0)
static inline void http_req_keywords_register(struct action_kw_list *kw_list)
{
diff -Nru haproxy-1.8.19/include/proto/shctx.h haproxy-1.8.20/include/proto/shctx.h
--- haproxy-1.8.19/include/proto/shctx.h 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/include/proto/shctx.h 2019-04-25 23:59:27.000000000 +0200
@@ -17,7 +17,7 @@
#include <common/mini-clist.h>
#include <types/shctx.h>
-#include <stdint.h>
+#include <inttypes.h>
#ifndef USE_PRIVATE_CACHE
#ifdef USE_PTHREAD_PSHARED
diff -Nru haproxy-1.8.19/Makefile haproxy-1.8.20/Makefile
--- haproxy-1.8.19/Makefile 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/Makefile 2019-04-25 23:59:27.000000000 +0200
@@ -358,7 +358,8 @@
# This is for AIX 5.1
USE_POLL = implicit
USE_LIBCRYPT = implicit
- TARGET_CFLAGS = -Dss_family=__ss_family
+ USE_PRIVATE_CACHE = implicit
+ TARGET_CFLAGS = -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API -D_LINUX_SOURCE_COMPAT -Dunsetenv=my_unsetenv
DEBUG_CFLAGS =
else
ifeq ($(TARGET),aix52)
@@ -905,7 +906,8 @@
DEP = $(INCLUDES) .build_opts
# Used only to force a rebuild if some build options change
-.build_opts: $(shell rm -f .build_opts.new; echo \'$(TARGET) $(BUILD_OPTIONS) $(VERBOSE_CFLAGS)\' > .build_opts.new; if cmp -s .build_opts .build_opts.new; then rm -f .build_opts.new; else mv -f .build_opts.new .build_opts; fi)
+build_opts = $(shell rm -f .build_opts.new; echo \'$(TARGET) $(BUILD_OPTIONS) $(VERBOSE_CFLAGS)\' > .build_opts.new; if cmp -s .build_opts .build_opts.new; then rm -f .build_opts.new; else mv -f .build_opts.new .build_opts; fi)
+.build_opts: $(build_opts)
haproxy: $(OPTIONS_OBJS) $(EBTREE_OBJS) $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^ $(LDOPTS)
diff -Nru haproxy-1.8.19/README haproxy-1.8.20/README
--- haproxy-1.8.19/README 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/README 2019-04-25 23:59:27.000000000 +0200
@@ -3,7 +3,7 @@
----------------------
version 1.8
willy tarreau
- 2019/02/11
+ 2019/04/25
1) How to build it
diff -Nru haproxy-1.8.19/src/51d.c haproxy-1.8.20/src/51d.c
--- haproxy-1.8.19/src/51d.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/51d.c 2019-04-25 23:59:27.000000000 +0200
@@ -384,7 +384,7 @@
* Data type has to be reset to ensure the string output is processed
* correctly.
*/
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST((smp->strm ? &smp->strm->req : NULL));
smp->data.type = SMP_T_STR;
/* Flags the sample to show it uses constant memory*/
@@ -639,7 +639,8 @@
free(global_51degrees.header_names);
#ifdef FIFTYONEDEGREES_H_PATTERN_INCLUDED
- fiftyoneDegreesWorksetPoolFree(global_51degrees.pool);
+ if (global_51degrees.pool)
+ fiftyoneDegreesWorksetPoolFree(global_51degrees.pool);
#endif
#ifdef FIFTYONEDEGREES_H_TRIE_INCLUDED
free(global_51degrees.device_offsets.firstOffset);
diff -Nru haproxy-1.8.19/src/acl.c haproxy-1.8.20/src/acl.c
--- haproxy-1.8.19/src/acl.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/acl.c 2019-04-25 23:59:27.000000000 +0200
@@ -400,6 +400,7 @@
expr->pat.prune = pat_prune_fcts[PAT_MATCH_INT];
expr->pat.expect_type = pat_match_types[PAT_MATCH_INT];
break;
+ case SMP_T_ADDR:
case SMP_T_IPV4:
case SMP_T_IPV6:
expr->pat.parse = pat_parse_fcts[PAT_MATCH_IP];
diff -Nru haproxy-1.8.19/src/checks.c haproxy-1.8.20/src/checks.c
--- haproxy-1.8.19/src/checks.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/checks.c 2019-04-25 23:59:27.000000000 +0200
@@ -2771,7 +2771,7 @@
conn_install_mux(conn, &mux_pt_ops, cs);
ret = SF_ERR_INTERNAL;
- if (proto->connect)
+ if (proto && proto->connect)
ret = proto->connect(conn,
1 /* I/O polling is always needed */,
(next && next->action == TCPCHK_ACT_EXPECT) ? 0 : 2);
diff -Nru haproxy-1.8.19/src/cli.c haproxy-1.8.20/src/cli.c
--- haproxy-1.8.19/src/cli.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/cli.c 2019-04-25 23:59:27.000000000 +0200
@@ -972,15 +972,19 @@
const struct sockaddr_un *un;
un = (struct sockaddr_un *)&l->addr;
- chunk_appendf(&trash, "%s ", un->sun_path);
+ if (un->sun_path[0] == '\0') {
+ chunk_appendf(&trash, "abns@%s ", un->sun_path+1);
+ } else {
+ chunk_appendf(&trash, "unix@%s ", un->sun_path);
+ }
} else if (l->addr.ss_family == AF_INET) {
addr_to_str(&l->addr, addr, sizeof(addr));
port_to_str(&l->addr, port, sizeof(port));
- chunk_appendf(&trash, "%s:%s ", addr, port);
+ chunk_appendf(&trash, "ipv4@%s:%s ", addr, port);
} else if (l->addr.ss_family == AF_INET6) {
addr_to_str(&l->addr, addr, sizeof(addr));
port_to_str(&l->addr, port, sizeof(port));
- chunk_appendf(&trash, "[%s]:%s ", addr, port);
+ chunk_appendf(&trash, "ipv6@[%s]:%s ", addr, port);
} else
continue;
diff -Nru haproxy-1.8.19/src/connection.c haproxy-1.8.20/src/connection.c
--- haproxy-1.8.19/src/connection.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/connection.c 2019-04-25 23:59:27.000000000 +0200
@@ -699,7 +699,7 @@
{
char *line;
uint32_t hdr_len;
- uint8_t ip_v;
+ uint8_t ip_ver;
/* we might have been called just after an asynchronous shutr */
if (conn->flags & CO_FL_SOCK_RD_SH)
@@ -765,9 +765,9 @@
goto missing;
/* Get IP version from the first four bits */
- ip_v = (*line & 0xf0) >> 4;
+ ip_ver = (*line & 0xf0) >> 4;
- if (ip_v == 4) {
+ if (ip_ver == 4) {
struct ip *hdr_ip4;
struct my_tcphdr *hdr_tcp;
@@ -797,7 +797,7 @@
conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
}
- else if (ip_v == 6) {
+ else if (ip_ver == 6) {
struct ip6_hdr *hdr_ip6;
struct my_tcphdr *hdr_tcp;
diff -Nru haproxy-1.8.19/src/da.c haproxy-1.8.20/src/da.c
--- haproxy-1.8.19/src/da.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/da.c 2019-04-25 23:59:27.000000000 +0200
@@ -293,7 +293,7 @@
return 1;
}
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST((smp->strm ? &smp->strm->req : NULL));
smp->data.type = SMP_T_STR;
/**
diff -Nru haproxy-1.8.19/src/flt_spoe.c haproxy-1.8.20/src/flt_spoe.c
--- haproxy-1.8.19/src/flt_spoe.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/flt_spoe.c 2019-04-25 23:59:27.000000000 +0200
@@ -1929,8 +1929,6 @@
if (SPOE_APPCTX(appctx)->task->expire != TICK_ETERNITY)
task_queue(SPOE_APPCTX(appctx)->task);
- si_oc(si)->flags |= CF_READ_DONTWAIT;
- task_wakeup(si_strm(si)->task, TASK_WOKEN_IO);
}
struct applet spoe_applet = {
@@ -2086,11 +2084,14 @@
return -1;
}
- /* Add the SPOE context in the sending queue and update all running
- * info */
- LIST_ADDQ(&agent->rt[tid].sending_queue, &ctx->list);
+ /* Add the SPOE context in the sending queue if the stream has no applet
+ * already assigned and wakeup all idle applets. Otherwise, don't queue
+ * it. */
if (agent->rt[tid].sending_rate)
agent->rt[tid].sending_rate--;
+ if (ctx->frag_ctx.spoe_appctx)
+ return 1;
+ LIST_ADDQ(&agent->rt[tid].sending_queue, &ctx->list);
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
" - Add stream in sending queue"
@@ -2273,7 +2274,9 @@
return 1;
too_big:
- if (!(agent->flags & SPOE_FL_SND_FRAGMENTATION)) {
+ /* Return an error if fragmentation is unsupported or if nothing has
+ * been encoded because its too big and not splittable. */
+ if (!(agent->flags & SPOE_FL_SND_FRAGMENTATION) || p == ctx->buffer->p) {
ctx->status_code = SPOE_CTX_ERR_TOO_BIG;
return -1;
}
@@ -2937,20 +2940,20 @@
if (global.nbthread == 1)
conf->agent->flags |= SPOE_FL_ASYNC;
- if ((curagent->rt = calloc(global.nbthread, sizeof(*curagent->rt))) == NULL) {
+ if ((conf->agent->rt = calloc(global.nbthread, sizeof(*conf->agent->rt))) == NULL) {
ha_alert("Proxy %s : out of memory initializing SPOE agent '%s' declared at %s:%d.\n",
px->id, conf->agent->id, conf->agent->conf.file, conf->agent->conf.line);
return 1;
}
for (i = 0; i < global.nbthread; ++i) {
- curagent->rt[i].frame_size = curagent->max_frame_size;
- curagent->rt[i].applets_act = 0;
- curagent->rt[i].applets_idle = 0;
- curagent->rt[i].sending_rate = 0;
- LIST_INIT(&curagent->rt[i].applets);
- LIST_INIT(&curagent->rt[i].sending_queue);
- LIST_INIT(&curagent->rt[i].waiting_queue);
- HA_SPIN_INIT(&curagent->rt[i].lock);
+ conf->agent->rt[i].frame_size = conf->agent->max_frame_size;
+ conf->agent->rt[i].applets_act = 0;
+ conf->agent->rt[i].applets_idle = 0;
+ conf->agent->rt[i].sending_rate = 0;
+ LIST_INIT(&conf->agent->rt[i].applets);
+ LIST_INIT(&conf->agent->rt[i].sending_queue);
+ LIST_INIT(&conf->agent->rt[i].waiting_queue);
+ HA_SPIN_INIT(&conf->agent->rt[i].lock);
}
free(conf->agent->b.name);
diff -Nru haproxy-1.8.19/src/h2.c haproxy-1.8.20/src/h2.c
--- haproxy-1.8.19/src/h2.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/h2.c 2019-04-25 23:59:27.000000000 +0200
@@ -25,7 +25,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdint.h>
+#include <inttypes.h>
#include <common/config.h>
#include <common/h2.h>
#include <common/http-hdr.h>
diff -Nru haproxy-1.8.19/src/haproxy.c haproxy-1.8.20/src/haproxy.c
--- haproxy-1.8.19/src/haproxy.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/haproxy.c 2019-04-25 23:59:27.000000000 +0200
@@ -1570,14 +1570,14 @@
exit(1);
}
- pattern_finalize_config();
-
err_code |= check_config_validity();
if (err_code & (ERR_ABORT|ERR_FATAL)) {
ha_alert("Fatal errors found in configuration.\n");
exit(1);
}
+ pattern_finalize_config();
+
/* recompute the amount of per-process memory depending on nbproc and
* the shared SSL cache size (allowed to exist in all processes).
*/
@@ -1828,6 +1828,9 @@
global.hardmaxconn = global.maxconn; /* keep this max value */
global.maxsock += global.maxconn * 2; /* each connection needs two sockets */
global.maxsock += global.maxpipes * 2; /* each pipe needs two FDs */
+ global.maxsock += global.nbthread; /* one epoll_fd/kqueue_fd per thread */
+ global.maxsock += 2 * global.nbthread; /* one wake-up pipe (2 fd) per thread */
+
/* compute fd used by async engines */
if (global.ssl_used_async_engines) {
int sides = !!global.ssl_used_frontend + !!global.ssl_used_backend;
diff -Nru haproxy-1.8.19/src/hlua.c haproxy-1.8.20/src/hlua.c
--- haproxy-1.8.19/src/hlua.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/hlua.c 2019-04-25 23:59:27.000000000 +0200
@@ -6458,7 +6458,7 @@
const char *error;
/* Wait for a full HTTP request. */
- if (!smp_prefetch_http(px, strm, 0, NULL, &smp, 0)) {
+ if (!smp_prefetch_http(px, strm, 0, req, &smp, 0)) {
if (smp.flags & SMP_F_MAY_CHANGE)
return -1;
return 0;
diff -Nru haproxy-1.8.19/src/hpack-dec.c haproxy-1.8.20/src/hpack-dec.c
--- haproxy-1.8.19/src/hpack-dec.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/hpack-dec.c 2019-04-25 23:59:27.000000000 +0200
@@ -25,7 +25,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdint.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff -Nru haproxy-1.8.19/src/hpack-enc.c haproxy-1.8.20/src/hpack-enc.c
--- haproxy-1.8.19/src/hpack-enc.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/hpack-enc.c 2019-04-25 23:59:27.000000000 +0200
@@ -25,7 +25,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdint.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff -Nru haproxy-1.8.19/src/hpack-huff.c haproxy-1.8.20/src/hpack-huff.c
--- haproxy-1.8.19/src/hpack-huff.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/hpack-huff.c 2019-04-25 23:59:27.000000000 +0200
@@ -26,7 +26,7 @@
*/
#include <stdio.h>
-#include <stdint.h>
+#include <inttypes.h>
#include <string.h>
#include <common/config.h>
diff -Nru haproxy-1.8.19/src/hpack-tbl.c haproxy-1.8.20/src/hpack-tbl.c
--- haproxy-1.8.19/src/hpack-tbl.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/hpack-tbl.c 2019-04-25 23:59:27.000000000 +0200
@@ -25,7 +25,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdint.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff -Nru haproxy-1.8.19/src/listener.c haproxy-1.8.20/src/listener.c
--- haproxy-1.8.19/src/listener.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/listener.c 2019-04-25 23:59:27.000000000 +0200
@@ -39,9 +39,6 @@
#include <proto/stream.h>
#include <proto/task.h>
- /* listner_queue lock (same for global and per proxy queues) */
-__decl_hathreads(static HA_SPINLOCK_T lq_lock);
-
/* List head of all known bind keywords */
static struct bind_kw_list bind_keywords = {
.list = LIST_HEAD_INIT(bind_keywords.list)
@@ -94,11 +91,7 @@
goto end;
if (listener->state == LI_READY)
fd_stop_recv(listener->fd);
- if (listener->state == LI_LIMITED) {
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- LIST_DEL(&listener->wait_queue);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- }
+ LIST_DEL_LOCKED(&listener->wait_queue);
listener->state = LI_LISTEN;
end:
HA_SPIN_UNLOCK(LISTENER_LOCK, &listener->lock);
@@ -134,11 +127,7 @@
goto end;
}
- if (l->state == LI_LIMITED) {
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- LIST_DEL(&l->wait_queue);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- }
+ LIST_DEL_LOCKED(&l->wait_queue);
fd_stop_recv(l->fd);
l->state = LI_PAUSED;
@@ -157,7 +146,7 @@
* stopped it. If the resume fails, 0 is returned and an error might be
* displayed.
*/
-static int __resume_listener(struct listener *l)
+int resume_listener(struct listener *l)
{
int ret = 1;
@@ -199,8 +188,7 @@
if (l->state == LI_READY)
goto end;
- if (l->state == LI_LIMITED)
- LIST_DEL(&l->wait_queue);
+ LIST_DEL_LOCKED(&l->wait_queue);
if (l->nbconn >= l->maxconn) {
l->state = LI_FULL;
@@ -214,51 +202,34 @@
return ret;
}
-int resume_listener(struct listener *l)
-{
- int ret;
-
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- ret = __resume_listener(l);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- return ret;
-}
-
/* Marks a ready listener as full so that the stream code tries to re-enable
* it upon next close() using resume_listener().
- *
- * Note: this function is only called from listener_accept so <l> is already
- * locked.
*/
static void listener_full(struct listener *l)
{
+ HA_SPIN_LOCK(LISTENER_LOCK, &l->lock);
if (l->state >= LI_READY) {
- if (l->state == LI_LIMITED) {
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- LIST_DEL(&l->wait_queue);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
+ LIST_DEL_LOCKED(&l->wait_queue);
+ if (l->state != LI_FULL) {
+ fd_stop_recv(l->fd);
+ l->state = LI_FULL;
}
-
- fd_stop_recv(l->fd);
- l->state = LI_FULL;
}
+ HA_SPIN_UNLOCK(LISTENER_LOCK, &l->lock);
}
/* Marks a ready listener as limited so that we only try to re-enable it when
* resources are free again. It will be queued into the specified queue.
- *
- * Note: this function is only called from listener_accept so <l> is already
- * locked.
*/
static void limit_listener(struct listener *l, struct list *list)
{
+ HA_SPIN_LOCK(LISTENER_LOCK, &l->lock);
if (l->state == LI_READY) {
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- LIST_ADDQ(list, &l->wait_queue);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
+ LIST_ADDQ_LOCKED(list, &l->wait_queue);
fd_stop_recv(l->fd);
l->state = LI_LIMITED;
}
+ HA_SPIN_UNLOCK(LISTENER_LOCK, &l->lock);
}
/* This function adds all of the protocol's listener's file descriptors to the
@@ -293,17 +264,14 @@
/* Dequeues all of the listeners waiting for a resource in wait queue <queue>. */
void dequeue_all_listeners(struct list *list)
{
- struct listener *listener, *l_back;
+ struct listener *listener;
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- list_for_each_entry_safe(listener, l_back, list, wait_queue) {
+ while ((listener = LIST_POP_LOCKED(list, struct listener *, wait_queue))) {
/* This cannot fail because the listeners are by definition in
- * the LI_LIMITED state. The function also removes the entry
- * from the queue.
+ * the LI_LIMITED state.
*/
- __resume_listener(listener);
+ resume_listener(listener);
}
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
}
/* Must be called with the lock held. Depending on <do_close> value, it does
@@ -314,11 +282,7 @@
if (listener->state == LI_READY)
fd_stop_recv(listener->fd);
- if (listener->state == LI_LIMITED) {
- HA_SPIN_LOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- LIST_DEL(&listener->wait_queue);
- HA_SPIN_UNLOCK(LISTENER_QUEUE_LOCK, &lq_lock);
- }
+ LIST_DEL_LOCKED(&listener->wait_queue);
if (listener->state >= LI_PAUSED) {
if (do_close) {
@@ -400,6 +364,7 @@
l->fd = fd;
memcpy(&l->addr, ss, sizeof(*ss));
+ LIST_INIT(&l->wait_queue);
l->state = LI_INIT;
proto->add(l, port);
@@ -422,15 +387,14 @@
*/
void delete_listener(struct listener *listener)
{
- if (listener->state != LI_ASSIGNED)
- return;
-
HA_SPIN_LOCK(LISTENER_LOCK, &listener->lock);
- listener->state = LI_INIT;
- LIST_DEL(&listener->proto_list);
- listener->proto->nb_listeners--;
- HA_ATOMIC_SUB(&jobs, 1);
- HA_ATOMIC_SUB(&listeners, 1);
+ if (listener->state == LI_ASSIGNED) {
+ listener->state = LI_INIT;
+ LIST_DEL(&listener->proto_list);
+ listener->proto->nb_listeners--;
+ HA_ATOMIC_SUB(&jobs, 1);
+ HA_ATOMIC_SUB(&listeners, 1);
+ }
HA_SPIN_UNLOCK(LISTENER_LOCK, &listener->lock);
}
@@ -441,8 +405,11 @@
void listener_accept(int fd)
{
struct listener *l = fdtab[fd].owner;
- struct proxy *p = l->bind_conf->frontend;
- int max_accept = l->maxaccept ? l->maxaccept : 1;
+ struct proxy *p;
+ int max_accept;
+ int next_conn = 0;
+ int next_feconn = 0;
+ int next_actconn = 0;
int expire;
int cfd;
int ret;
@@ -450,13 +417,10 @@
static int accept4_broken;
#endif
- if (HA_SPIN_TRYLOCK(LISTENER_LOCK, &l->lock))
+ if (!l)
return;
-
- if (unlikely(l->nbconn >= l->maxconn)) {
- listener_full(l);
- goto end;
- }
+ p = l->bind_conf->frontend;
+ max_accept = l->maxaccept ? l->maxaccept : 1;
if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
int max = freq_ctr_remain(&global.sess_per_sec, global.sps_lim, 0);
@@ -516,20 +480,68 @@
* worst case. If we fail due to system limits or temporary resource
* shortage, we try again 100ms later in the worst case.
*/
- while (max_accept--) {
+ for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) {
struct sockaddr_storage addr;
socklen_t laddr = sizeof(addr);
unsigned int count;
- if (unlikely(actconn >= global.maxconn) && !(l->options & LI_O_UNLIMITED)) {
- limit_listener(l, &global_listener_queue);
- task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
- goto end;
+ /* pre-increase the number of connections without going too far.
+ * We process the listener, then the proxy, then the process.
+ * We know which ones to unroll based on the next_xxx value.
+ */
+ do {
+ count = l->nbconn;
+ if (count >= l->maxconn) {
+ /* the listener was marked full or another
+ * thread is going to do it.
+ */
+ next_conn = 0;
+ goto end;
+ }
+ next_conn = count + 1;
+ } while (!HA_ATOMIC_CAS(&l->nbconn, (int *)&count, next_conn));
+
+ if (next_conn == l->maxconn) {
+ /* we filled it, mark it full */
+ listener_full(l);
}
- if (unlikely(p && p->feconn >= p->maxconn)) {
- limit_listener(l, &p->listener_queue);
- goto end;
+ if (p) {
+ do {
+ count = p->feconn;
+ if (count >= p->maxconn) {
+ /* the frontend was marked full or another
+ * thread is going to do it.
+ */
+ next_feconn = 0;
+ goto end;
+ }
+ next_feconn = count + 1;
+ } while (!HA_ATOMIC_CAS(&p->feconn, &count, next_feconn));
+
+ if (unlikely(next_feconn == p->maxconn)) {
+ /* we just filled it */
+ limit_listener(l, &p->listener_queue);
+ }
+ }
+
+ if (!(l->options & LI_O_UNLIMITED)) {
+ do {
+ count = actconn;
+ if (count >= global.maxconn) {
+ /* the process was marked full or another
+ * thread is going to do it.
+ */
+ next_actconn = 0;
+ goto end;
+ }
+ next_actconn = count + 1;
+ } while (!HA_ATOMIC_CAS(&actconn, (int *)&count, next_actconn));
+
+ if (unlikely(next_actconn == global.maxconn)) {
+ limit_listener(l, &global_listener_queue);
+ task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
+ }
}
#ifdef USE_ACCEPT4
@@ -563,6 +575,11 @@
goto transient_error;
case EINTR:
case ECONNABORTED:
+ HA_ATOMIC_SUB(&l->nbconn, 1);
+ if (p)
+ HA_ATOMIC_SUB(&p->feconn, 1);
+ if (!(l->options & LI_O_UNLIMITED))
+ HA_ATOMIC_SUB(&actconn, 1);
continue;
case ENFILE:
if (p)
@@ -589,6 +606,20 @@
}
}
+ /* The connection was accepted, it must be counted as such */
+ if (l->counters)
+ HA_ATOMIC_UPDATE_MAX(&l->counters->conn_max, next_conn);
+
+ if (p)
+ HA_ATOMIC_UPDATE_MAX(&p->fe_counters.conn_max, next_feconn);
+
+ proxy_inc_fe_conn_ctr(l, p);
+
+ if (!(l->options & LI_O_UNLIMITED)) {
+ count = update_freq_ctr(&global.conn_per_sec, 1);
+ HA_ATOMIC_UPDATE_MAX(&global.cps_max, count);
+ }
+
if (unlikely(cfd >= global.maxsock)) {
send_log(p, LOG_EMERG,
"Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
@@ -599,16 +630,14 @@
goto end;
}
- /* increase the per-process number of cumulated connections */
- if (!(l->options & LI_O_UNLIMITED)) {
- count = update_freq_ctr(&global.conn_per_sec, 1);
- HA_ATOMIC_UPDATE_MAX(&global.cps_max, count);
- HA_ATOMIC_ADD(&actconn, 1);
- }
-
- count = HA_ATOMIC_ADD(&l->nbconn, 1);
- if (l->counters)
- HA_ATOMIC_UPDATE_MAX(&l->counters->conn_max, count);
+ /* past this point, l->accept() will automatically decrement
+ * l->nbconn, feconn and actconn once done. Setting next_*conn=0
+ * allows the error path not to rollback on nbconn. It's more
+ * convenient than duplicating all exit labels.
+ */
+ next_conn = 0;
+ next_feconn = 0;
+ next_actconn = 0;
ret = l->accept(l, cfd, &addr);
if (unlikely(ret <= 0)) {
@@ -623,12 +652,9 @@
goto transient_error;
}
- if (l->nbconn >= l->maxconn) {
- listener_full(l);
- goto end;
- }
-
- /* increase the per-process number of cumulated connections */
+ /* increase the per-process number of cumulated sessions, this
+ * may only be done once l->accept() has accepted the connection.
+ */
if (!(l->options & LI_O_UNLIMITED)) {
count = update_freq_ctr(&global.sess_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&global.sps_max, count);
@@ -640,7 +666,7 @@
}
#endif
- } /* end of while (max_accept--) */
+ } /* end of for (max_accept--) */
/* we've exhausted max_accept, so there is no need to poll again */
stop:
@@ -655,7 +681,28 @@
limit_listener(l, &global_listener_queue);
task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire));
end:
- HA_SPIN_UNLOCK(LISTENER_LOCK, &l->lock);
+ if (next_conn)
+ HA_ATOMIC_SUB(&l->nbconn, 1);
+
+ if (p && next_feconn)
+ HA_ATOMIC_SUB(&p->feconn, 1);
+
+ if (next_actconn)
+ HA_ATOMIC_SUB(&actconn, 1);
+
+ if ((l->state == LI_FULL && l->nbconn < l->maxconn) ||
+ (l->state == LI_LIMITED && ((!p || p->feconn < p->maxconn) && (actconn < global.maxconn)))) {
+ /* at least one thread has to this when quitting */
+ resume_listener(l);
+
+ /* Dequeues all of the listeners waiting for a resource */
+ if (!LIST_ISEMPTY(&global_listener_queue))
+ dequeue_all_listeners(&global_listener_queue);
+
+ if (!LIST_ISEMPTY(&p->listener_queue) &&
+ (!p->fe_sps_lim || freq_ctr_remain(&p->fe_sess_per_sec, p->fe_sps_lim, 0) > 0))
+ dequeue_all_listeners(&p->listener_queue);
+ }
}
/* Notify the listener that a connection initiated from it was released. This
@@ -668,8 +715,11 @@
if (!(l->options & LI_O_UNLIMITED))
HA_ATOMIC_SUB(&actconn, 1);
+ if (fe)
+ HA_ATOMIC_SUB(&fe->feconn, 1);
HA_ATOMIC_SUB(&l->nbconn, 1);
- if (l->state == LI_FULL)
+
+ if (l->state == LI_FULL || l->state == LI_LIMITED)
resume_listener(l);
/* Dequeues all of the listeners waiting for a resource */
@@ -957,7 +1007,7 @@
conf->bind_proc |= proc;
if (thread) {
- for (i = 0; i < MAX_THREADS; i++)
+ for (i = 0; i < LONGBITS; i++)
if (!proc || (proc & (1UL << i)))
conf->bind_thread[i] |= thread;
}
@@ -1005,7 +1055,6 @@
sample_register_fetches(&smp_kws);
acl_register_keywords(&acl_kws);
bind_register_keywords(&bind_kws);
- HA_SPIN_INIT(&lq_lock);
}
/*
diff -Nru haproxy-1.8.19/src/log.c haproxy-1.8.20/src/log.c
--- haproxy-1.8.19/src/log.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/log.c 2019-04-25 23:59:27.000000000 +0200
@@ -1380,11 +1380,15 @@
/* Deinitialize log buffers used for syslog messages */
void deinit_log_buffers()
{
+ void *tmp_startup_logs;
+
free(logheader);
free(logheader_rfc5424);
free(logline);
free(logline_rfc5424);
- free(startup_logs);
+ tmp_startup_logs = HA_ATOMIC_XCHG(&startup_logs, NULL);
+ free(tmp_startup_logs);
+
logheader = NULL;
logheader_rfc5424 = NULL;
logline = NULL;
@@ -1647,7 +1651,6 @@
break;
case LOG_FMT_TS: // %Ts
- get_gmtime(s->logs.accept_date.tv_sec, &tm);
if (tmp->options & LOG_OPT_HEXA) {
iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)s->logs.accept_date.tv_sec);
if (iret < 0 || iret > dst + maxsize - tmplog)
diff -Nru haproxy-1.8.19/src/map.c haproxy-1.8.20/src/map.c
--- haproxy-1.8.19/src/map.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/map.c 2019-04-25 23:59:27.000000000 +0200
@@ -142,10 +142,10 @@
1, err, file, line))
return 0;
- /* the maps of type IP have a string as defaultvalue. This
- * string canbe anipv4 or an ipv6, we must convert it.
+ /* the maps of type IP support a string as default value. This
+ * string can be an ipv4 or an ipv6, we must convert it.
*/
- if (desc->conv->out_type == SMP_T_ADDR) {
+ if (arg[1].type != ARGT_STOP && desc->conv->out_type == SMP_T_ADDR) {
struct sample_data data;
if (!map_parse_ip(arg[1].data.str.str, &data)) {
memprintf(err, "map: cannot parse default ip <%s>.", arg[1].data.str.str);
diff -Nru haproxy-1.8.19/src/peers.c haproxy-1.8.20/src/peers.c
--- haproxy-1.8.19/src/peers.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/peers.c 2019-04-25 23:59:27.000000000 +0200
@@ -172,7 +172,7 @@
#define PEER_DWNGRD_MINOR_VER 0
struct peers *cfg_peers = NULL;
-static void peer_session_forceshutdown(struct appctx *appctx);
+static void peer_session_forceshutdown(struct peer *peer);
/* This function encode an uint64 to 'dynamic' length format.
The encoded value is written at address *str, and the
@@ -493,14 +493,52 @@
}
/*
+ * Function to deinit connected peer
+ */
+void __peer_session_deinit(struct peer *peer)
+{
+ struct stream_interface *si;
+ struct stream *s;
+ struct peers *peers;
+
+ if (!peer->appctx)
+ return;
+
+ si = peer->appctx->owner;
+ if (!si)
+ return;
+
+ s = si_strm(si);
+ if (!s)
+ return;
+
+ peers = strm_fe(s)->parent;
+ if (!peers)
+ return;
+
+ /* Re-init current table pointers to force announcement on re-connect */
+ peer->remote_table = peer->last_local_table = NULL;
+ peer->appctx = NULL;
+ if (peer->flags & PEER_F_LEARN_ASSIGN) {
+ /* unassign current peer for learning */
+ peer->flags &= ~(PEER_F_LEARN_ASSIGN);
+ peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
+
+ /* reschedule a resync */
+ peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
+ }
+ /* reset teaching and learning flags to 0 */
+ peer->flags &= PEER_TEACH_RESET;
+ peer->flags &= PEER_LEARN_RESET;
+ task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
+}
+
+/*
* Callback to release a session with a peer
*/
static void peer_session_release(struct appctx *appctx)
{
- struct stream_interface *si = appctx->owner;
- struct stream *s = si_strm(si);
struct peer *peer = appctx->ctx.peers.ptr;
- struct peers *peers = strm_fe(s)->parent;
/* appctx->ctx.peers.ptr is not a peer session */
if (appctx->st0 < PEER_SESS_ST_SENDSUCCESS)
@@ -509,24 +547,9 @@
/* peer session identified */
if (peer) {
HA_SPIN_LOCK(PEER_LOCK, &peer->lock);
- if (peer->appctx == appctx) {
- /* Re-init current table pointers to force announcement on re-connect */
- peer->remote_table = peer->last_local_table = NULL;
- peer->appctx = NULL;
- if (peer->flags & PEER_F_LEARN_ASSIGN) {
- /* unassign current peer for learning */
- peer->flags &= ~(PEER_F_LEARN_ASSIGN);
- peers->flags &= ~(PEERS_F_RESYNC_ASSIGN|PEERS_F_RESYNC_PROCESS);
-
- /* reschedule a resync */
- peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(5000));
- }
- /* reset teaching and learning flags to 0 */
- peer->flags &= PEER_TEACH_RESET;
- peer->flags &= PEER_LEARN_RESET;
- }
+ if (peer->appctx == appctx)
+ __peer_session_deinit(peer);
HA_SPIN_UNLOCK(PEER_LOCK, &peer->lock);
- task_wakeup(peers->sync_task, TASK_WOKEN_MSG);
}
}
@@ -704,7 +727,7 @@
* for a while.
*/
curpeer->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
- peer_session_forceshutdown(curpeer->appctx);
+ peer_session_forceshutdown(curpeer);
}
if (maj_ver != (unsigned int)-1 && min_ver != (unsigned int)-1) {
if (min_ver == PEER_DWNGRD_MINOR_VER) {
@@ -1832,11 +1855,14 @@
.release = peer_session_release,
};
+
/*
* Use this function to force a close of a peer session
*/
-static void peer_session_forceshutdown(struct appctx *appctx)
+static void peer_session_forceshutdown(struct peer *peer)
{
+ struct appctx *appctx = peer->appctx;
+
/* Note that the peer sessions which have just been created
* (->st0 == PEER_SESS_ST_CONNECT) must not
* be shutdown, if not, the TCP session will never be closed
@@ -1849,6 +1875,8 @@
if (appctx->applet != &peer_applet)
return;
+ __peer_session_deinit(peer);
+
appctx->st0 = PEER_SESS_ST_END;
appctx_wakeup(appctx);
}
@@ -2094,8 +2122,7 @@
*/
ps->reconnect = tick_add(now_ms, MS_TO_TICKS(50 + random() % 2000));
if (ps->appctx) {
- peer_session_forceshutdown(ps->appctx);
- ps->appctx = NULL;
+ peer_session_forceshutdown(ps);
}
}
}
diff -Nru haproxy-1.8.19/src/proto_http.c haproxy-1.8.20/src/proto_http.c
--- haproxy-1.8.19/src/proto_http.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/proto_http.c 2019-04-25 23:59:27.000000000 +0200
@@ -2717,12 +2717,14 @@
value->str[value->len] = '\0';
/* perform update */
+ HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
if (pat_ref_find_elt(ref, key->str) != NULL)
/* update entry if it exists */
pat_ref_set(ref, key->str, value->str, NULL);
else
/* insert a new entry */
pat_ref_add(ref, key->str, value->str, NULL);
+ HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
free_trash_chunk(key);
free_trash_chunk(value);
@@ -2978,8 +2980,10 @@
/* perform update */
/* check if the entry already exists */
+ HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
if (pat_ref_find_elt(ref, key->str) == NULL)
pat_ref_add(ref, key->str, NULL, NULL);
+ HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
free_trash_chunk(key);
break;
@@ -6150,6 +6154,7 @@
if (!buffer_pending(res->buf)) {
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_SRVCL;
+ HA_ATOMIC_ADD(&sess->fe->fe_counters.srv_aborts, 1);
HA_ATOMIC_ADD(&s->be->be_counters.srv_aborts, 1);
if (objt_server(s->target))
HA_ATOMIC_ADD(&objt_server(s->target)->counters.srv_aborts, 1);
@@ -9446,6 +9451,8 @@
/************************************************************************/
/* The code below is dedicated to ACL parsing and matching */
/************************************************************************/
+#define SMP_REQ_CHN(smp) (smp->strm ? &smp->strm->req : NULL)
+#define SMP_RES_CHN(smp) (smp->strm ? &smp->strm->res : NULL)
/* This function ensures that the prerequisites for an L7 fetch are ready,
@@ -9462,7 +9469,7 @@
* 1 if an HTTP message is ready
*/
int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
- const struct arg *args, struct sample *smp, int req_vol)
+ const struct channel *chn, struct sample *smp, int req_vol)
{
struct http_txn *txn;
struct http_msg *msg;
@@ -9471,7 +9478,7 @@
* initialization (eg: tcp-request connection), so this function is the
* one responsible for guarding against this case for all HTTP users.
*/
- if (!s)
+ if (!s || !chn)
return 0;
if (!s->txn) {
@@ -9480,78 +9487,78 @@
http_init_txn(s);
}
txn = s->txn;
- msg = &txn->req;
- /* Check for a dependency on a request */
smp->data.type = SMP_T_BOOL;
- if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
- /* If the buffer does not leave enough free space at the end,
- * we must first realign it.
- */
- if (s->req.buf->p > s->req.buf->data &&
- s->req.buf->i + s->req.buf->p > s->req.buf->data + s->req.buf->size - global.tune.maxrewrite)
- buffer_slow_realign(s->req.buf);
+ if (chn->flags & CF_ISRESP) {
+ /* Check for a dependency on a response */
+ if (txn->rsp.msg_state < HTTP_MSG_BODY) {
+ smp->flags |= SMP_F_MAY_CHANGE;
+ return 0;
+ }
+ goto end;
+ }
- if (unlikely(txn->req.msg_state < HTTP_MSG_BODY)) {
- if (msg->msg_state == HTTP_MSG_ERROR)
- return 0;
+ /* Check for a dependency on a request */
+ msg = &txn->req;
- /* Try to decode HTTP request */
- if (likely(msg->next < s->req.buf->i))
- http_msg_analyzer(msg, &txn->hdr_idx);
-
- /* Still no valid request ? */
- if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
- if ((msg->msg_state == HTTP_MSG_ERROR) ||
- buffer_full(s->req.buf, global.tune.maxrewrite)) {
- return 0;
- }
- /* wait for final state */
- smp->flags |= SMP_F_MAY_CHANGE;
- return 0;
- }
+ if (req_vol && (smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) {
+ return 0; /* data might have moved and indexes changed */
+ }
- /* OK we just got a valid HTTP request. We have some minor
- * preparation to perform so that further checks can rely
- * on HTTP tests.
- */
+ /* If the buffer does not leave enough free space at the end, we must
+ * first realign it.
+ */
+ if (chn->buf->p > chn->buf->data &&
+ chn->buf->i + chn->buf->p > chn->buf->data + chn->buf->size - global.tune.maxrewrite)
+ buffer_slow_realign(chn->buf);
- /* If the request was parsed but was too large, we must absolutely
- * return an error so that it is not processed. At the moment this
- * cannot happen, but if the parsers are to change in the future,
- * we want this check to be maintained.
- */
- if (unlikely(s->req.buf->i + s->req.buf->p >
- s->req.buf->data + s->req.buf->size - global.tune.maxrewrite)) {
- msg->err_state = msg->msg_state;
- msg->msg_state = HTTP_MSG_ERROR;
- smp->data.u.sint = 1;
- return 1;
- }
+ if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
+ if (msg->msg_state == HTTP_MSG_ERROR)
+ return 0;
- txn->meth = find_http_meth(msg->chn->buf->p, msg->sl.rq.m_l);
- if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
- s->flags |= SF_REDIRECTABLE;
+ /* Try to decode HTTP request */
+ if (likely(msg->next < chn->buf->i))
+ http_msg_analyzer(msg, &txn->hdr_idx);
- if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
+ /* Still no valid request ? */
+ if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
+ if ((msg->msg_state == HTTP_MSG_ERROR) ||
+ buffer_full(chn->buf, global.tune.maxrewrite)) {
return 0;
+ }
+ /* wait for final state */
+ smp->flags |= SMP_F_MAY_CHANGE;
+ return 0;
}
- if (req_vol && txn->rsp.msg_state != HTTP_MSG_RPBEFORE) {
- return 0; /* data might have moved and indexes changed */
+ /* OK we just got a valid HTTP message. We have some minor
+ * preparation to perform so that further checks can rely
+ * on HTTP tests.
+ */
+
+ /* If the message was parsed but was too large, we must absolutely
+ * return an error so that it is not processed. At the moment this
+ * cannot happen, but if the parsers are to change in the future,
+ * we want this check to be maintained.
+ */
+ if (unlikely(chn->buf->i + chn->buf->p >
+ chn->buf->data + chn->buf->size - global.tune.maxrewrite)) {
+ msg->err_state = msg->msg_state;
+ msg->msg_state = HTTP_MSG_ERROR;
+ smp->data.u.sint = 1;
+ return 1;
}
- /* otherwise everything's ready for the request */
- }
- else {
- /* Check for a dependency on a response */
- if (txn->rsp.msg_state < HTTP_MSG_BODY) {
- smp->flags |= SMP_F_MAY_CHANGE;
+ txn->meth = find_http_meth(chn->buf->p, msg->sl.rq.m_l);
+ if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
+ s->flags |= SF_REDIRECTABLE;
+
+ if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
return 0;
- }
}
+ end:
/* everything's OK */
smp->data.u.sint = 1;
return 1;
@@ -9591,19 +9598,21 @@
static int
smp_fetch_meth(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
int meth;
struct http_txn *txn;
- CHECK_HTTP_MESSAGE_FIRST_PERM();
+ CHECK_HTTP_MESSAGE_FIRST_PERM(chn);
txn = smp->strm->txn;
meth = txn->meth;
smp->data.type = SMP_T_METH;
smp->data.u.meth.meth = meth;
if (meth == HTTP_METH_OTHER) {
- if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
+ if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) {
/* ensure the indexes are not affected */
return 0;
+ }
smp->flags |= SMP_F_CONST;
smp->data.u.meth.str.len = txn->req.sl.rq.m_l;
smp->data.u.meth.str.str = txn->req.chn->buf->p;
@@ -9645,15 +9654,16 @@
static int
smp_fetch_rqver(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
char *ptr;
int len;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
len = txn->req.sl.rq.v_l;
- ptr = txn->req.chn->buf->p + txn->req.sl.rq.v;
+ ptr = chn->buf->p + txn->req.sl.rq.v;
while ((len-- > 0) && (*ptr++ != '/'));
if (len <= 0)
@@ -9670,18 +9680,17 @@
static int
smp_fetch_stver(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_RES_CHN(smp);
struct http_txn *txn;
char *ptr;
int len;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
- if (txn->rsp.msg_state < HTTP_MSG_BODY)
- return 0;
len = txn->rsp.sl.st.v_l;
- ptr = txn->rsp.chn->buf->p;
+ ptr = chn->buf->p;
while ((len-- > 0) && (*ptr++ != '/'));
if (len <= 0)
@@ -9699,18 +9708,19 @@
static int
smp_fetch_stcode(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_RES_CHN(smp);
struct http_txn *txn;
char *ptr;
int len;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
if (txn->rsp.msg_state < HTTP_MSG_BODY)
return 0;
len = txn->rsp.sl.st.c_l;
- ptr = txn->rsp.chn->buf->p + txn->rsp.sl.st.c;
+ ptr = chn->buf->p + txn->rsp.sl.st.c;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = __strl2ui(ptr, len);
@@ -9745,20 +9755,21 @@
static int
smp_fetch_hdrs(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
struct hdr_idx *idx;
struct http_txn *txn;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
idx = &txn->hdr_idx;
msg = &txn->req;
smp->data.type = SMP_T_STR;
- smp->data.u.str.str = msg->chn->buf->p + hdr_idx_first_pos(idx);
+ smp->data.u.str.str = chn->buf->p + hdr_idx_first_pos(idx);
smp->data.u.str.len = msg->eoh - hdr_idx_first_pos(idx) + 1 +
- (msg->chn->buf->p[msg->eoh] == '\r');
+ (chn->buf->p[msg->eoh] == '\r');
return 1;
}
@@ -9779,7 +9790,7 @@
static int
smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- struct http_msg *msg;
+ struct channel *chn = SMP_REQ_CHN(smp);
struct chunk *temp;
struct hdr_idx *idx;
const char *cur_ptr, *cur_next, *p;
@@ -9792,7 +9803,7 @@
char *buf;
char *end;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
temp = get_trash_chunk();
buf = temp->str;
@@ -9800,11 +9811,10 @@
txn = smp->strm->txn;
idx = &txn->hdr_idx;
- msg = &txn->req;
/* Build array of headers. */
old_idx = 0;
- cur_next = msg->chn->buf->p + hdr_idx_first_pos(idx);
+ cur_next = chn->buf->p + hdr_idx_first_pos(idx);
while (1) {
cur_idx = idx->v[old_idx].next;
if (!cur_idx)
@@ -9879,25 +9889,23 @@
static int
smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
unsigned long len;
unsigned long block1;
char *body;
struct chunk *temp;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
- msg = &smp->strm->txn->req;
- else
- msg = &smp->strm->txn->rsp;
+ msg = &smp->strm->txn->req;
len = http_body_bytes(msg);
- body = b_ptr(msg->chn->buf, -http_data_rewind(msg));
+ body = b_ptr(chn->buf, -http_data_rewind(msg));
block1 = len;
- if (block1 > msg->chn->buf->data + msg->chn->buf->size - body)
- block1 = msg->chn->buf->data + msg->chn->buf->size - body;
+ if (block1 > chn->buf->data + chn->buf->size - body)
+ block1 = chn->buf->data + chn->buf->size - body;
if (block1 == len) {
/* buffer is not wrapped (or empty) */
@@ -9910,7 +9918,7 @@
/* buffer is wrapped, we need to defragment it */
temp = get_trash_chunk();
memcpy(temp->str, body, block1);
- memcpy(temp->str + block1, msg->chn->buf->data, len - block1);
+ memcpy(temp->str + block1, chn->buf->data, len - block1);
smp->data.type = SMP_T_BIN;
smp->data.u.str.str = temp->str;
smp->data.u.str.len = len;
@@ -9926,15 +9934,12 @@
static int
smp_fetch_body_len(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
- CHECK_HTTP_MESSAGE_FIRST();
-
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
- msg = &smp->strm->txn->req;
- else
- msg = &smp->strm->txn->rsp;
+ CHECK_HTTP_MESSAGE_FIRST(chn);
+ msg = &smp->strm->txn->req;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = http_body_bytes(msg);
@@ -9950,15 +9955,12 @@
static int
smp_fetch_body_size(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
- CHECK_HTTP_MESSAGE_FIRST();
-
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
- msg = &smp->strm->txn->req;
- else
- msg = &smp->strm->txn->rsp;
+ CHECK_HTTP_MESSAGE_FIRST(chn);
+ msg = &smp->strm->txn->req;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = msg->body_len;
@@ -9971,14 +9973,15 @@
static int
smp_fetch_url(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
smp->data.type = SMP_T_STR;
smp->data.u.str.len = txn->req.sl.rq.u_l;
- smp->data.u.str.str = txn->req.chn->buf->p + txn->req.sl.rq.u;
+ smp->data.u.str.str = chn->buf->p + txn->req.sl.rq.u;
smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
return 1;
}
@@ -9986,13 +9989,14 @@
static int
smp_fetch_url_ip(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
struct sockaddr_storage addr;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
- url2sa(txn->req.chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
+ url2sa(chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
return 0;
@@ -10005,13 +10009,14 @@
static int
smp_fetch_url_port(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
struct sockaddr_storage addr;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
- url2sa(txn->req.chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
+ url2sa(chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
return 0;
@@ -10031,6 +10036,8 @@
static int
smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ /* possible keywords: req.fhdr, res.fhdr */
+ struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx *ctx = smp->ctx.a[0];
const struct http_msg *msg;
@@ -10055,10 +10062,9 @@
occ = args[1].data.sint;
}
- CHECK_HTTP_MESSAGE_FIRST();
-
+ CHECK_HTTP_MESSAGE_FIRST(chn);
idx = &smp->strm->txn->hdr_idx;
- msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
+ msg = (!(chn->flags & CF_ISRESP) ? &smp->strm->txn->req : &smp->strm->txn->rsp);
if (ctx && !(smp->flags & SMP_F_NOT_LAST))
/* search for header from the beginning */
@@ -10088,9 +10094,10 @@
static int
smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ /* possible keywords: req.fhdr_cnt, res.fhdr_cnt */
+ struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx ctx;
- const struct http_msg *msg;
int cnt;
const char *name = NULL;
int len = 0;
@@ -10100,14 +10107,12 @@
len = args->data.str.len;
}
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
idx = &smp->strm->txn->hdr_idx;
- msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
-
ctx.idx = 0;
cnt = 0;
- while (http_find_full_header2(name, len, msg->chn->buf->p, idx, &ctx))
+ while (http_find_full_header2(name, len, chn->buf->p, idx, &ctx))
cnt++;
smp->data.type = SMP_T_SINT;
@@ -10119,24 +10124,24 @@
static int
smp_fetch_hdr_names(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ /* possible keywords: req.hdr_names, res.hdr_names */
+ struct channel *chn = ((kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx ctx;
- const struct http_msg *msg;
struct chunk *temp;
char del = ',';
if (args && args->type == ARGT_STR)
del = *args[0].data.str.str;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
idx = &smp->strm->txn->hdr_idx;
- msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
temp = get_trash_chunk();
ctx.idx = 0;
- while (http_find_next_header(msg->chn->buf->p, idx, &ctx)) {
+ while (http_find_next_header(chn->buf->p, idx, &ctx)) {
if (temp->len)
temp->str[temp->len++] = del;
memcpy(temp->str + temp->len, ctx.line, ctx.del);
@@ -10159,6 +10164,8 @@
static int
smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ /* possible keywords: req.hdr / hdr, res.hdr / shdr */
+ struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx *ctx = smp->ctx.a[0];
const struct http_msg *msg;
@@ -10183,10 +10190,10 @@
occ = args[1].data.sint;
}
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
idx = &smp->strm->txn->hdr_idx;
- msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
+ msg = (!(chn->flags & CF_ISRESP) ? &smp->strm->txn->req : &smp->strm->txn->rsp);
if (ctx && !(smp->flags & SMP_F_NOT_LAST))
/* search for header from the beginning */
@@ -10215,9 +10222,10 @@
static int
smp_fetch_hdr_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ /* possible keywords: req.hdr_cnt / hdr_cnt, res.hdr_cnt / shdr_cnt */
+ struct channel *chn = ((kw[0] == 'h' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx ctx;
- const struct http_msg *msg;
int cnt;
const char *name = NULL;
int len = 0;
@@ -10227,14 +10235,13 @@
len = args->data.str.len;
}
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
idx = &smp->strm->txn->hdr_idx;
- msg = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &smp->strm->txn->req : &smp->strm->txn->rsp;
ctx.idx = 0;
cnt = 0;
- while (http_find_header2(name, len, msg->chn->buf->p, idx, &ctx))
+ while (http_find_header2(name, len, chn->buf->p, idx, &ctx))
cnt++;
smp->data.type = SMP_T_SINT;
@@ -10299,13 +10306,14 @@
static int
smp_fetch_path(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
char *ptr, *end;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
- end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
+ end = chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
ptr = http_get_path(txn);
if (!ptr)
return 0;
@@ -10332,16 +10340,17 @@
static int
smp_fetch_base(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
char *ptr, *end, *beg;
struct hdr_ctx ctx;
struct chunk *temp;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
ctx.idx = 0;
- if (!http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx) || !ctx.vlen)
+ if (!http_find_header2("Host", 4, chn->buf->p, &txn->hdr_idx, &ctx) || !ctx.vlen)
return smp_fetch_path(args, smp, kw, private);
/* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
@@ -10352,7 +10361,7 @@
smp->data.u.str.len = ctx.vlen;
/* now retrieve the path */
- end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
+ end = chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
beg = http_get_path(txn);
if (!beg)
beg = end;
@@ -10379,17 +10388,18 @@
int
smp_fetch_base32(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
struct hdr_ctx ctx;
unsigned int hash = 0;
char *ptr, *beg, *end;
int len;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
ctx.idx = 0;
- if (http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
+ if (http_find_header2("Host", 4, chn->buf->p, &txn->hdr_idx, &ctx)) {
/* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
ptr = ctx.line + ctx.val;
len = ctx.vlen;
@@ -10398,7 +10408,7 @@
}
/* now retrieve the path */
- end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
+ end = chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
beg = http_get_path(txn);
if (!beg)
beg = end;
@@ -10465,13 +10475,14 @@
static int
smp_fetch_query(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
char *ptr, *end;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
- ptr = txn->req.chn->buf->p + txn->req.sl.rq.u;
+ ptr = chn->buf->p + txn->req.sl.rq.u;
end = ptr + txn->req.sl.rq.u_l;
/* look up the '?' */
@@ -10490,11 +10501,13 @@
static int
smp_fetch_proto_http(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
+
/* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged
* as a layer7 ACL, which involves automatic allocation of hdr_idx.
*/
- CHECK_HTTP_MESSAGE_FIRST_PERM();
+ CHECK_HTTP_MESSAGE_FIRST_PERM(chn);
smp->data.type = SMP_T_BOOL;
smp->data.u.sint = 1;
@@ -10514,11 +10527,12 @@
static int
smp_fetch_http_auth(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
if (!args || args->type != ARGT_USR)
return 0;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
if (!get_http_auth(smp->strm))
return 0;
@@ -10533,10 +10547,12 @@
static int
smp_fetch_http_auth_grp(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
+
if (!args || args->type != ARGT_USR)
return 0;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
if (!get_http_auth(smp->strm))
return 0;
@@ -10827,10 +10843,10 @@
*/
int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- struct http_txn *txn;
+ /* possible keywords: req.cookie / cookie / cook, res.cookie / scook / set-cookie */
+ struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx *ctx = smp->ctx.a[2];
- const struct http_msg *msg;
const char *hdr_name;
int hdr_name_len;
char *sol;
@@ -10847,17 +10863,14 @@
smp->ctx.a[2] = ctx;
}
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
- txn = smp->strm->txn;
idx = &smp->strm->txn->hdr_idx;
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
- msg = &txn->req;
+ if (!(chn->flags & CF_ISRESP)) {
hdr_name = "Cookie";
hdr_name_len = 6;
} else {
- msg = &txn->rsp;
hdr_name = "Set-Cookie";
hdr_name_len = 10;
}
@@ -10871,7 +10884,7 @@
* next one.
*/
- sol = msg->chn->buf->p;
+ sol = chn->buf->p;
if (!(smp->flags & SMP_F_NOT_LAST)) {
/* search for the header from the beginning, we must first initialize
* the search parameters.
@@ -10928,10 +10941,10 @@
static int
smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
- struct http_txn *txn;
+ /* possible keywords: req.cook_cnt / cook_cnt, res.cook_cnt / scook_cnt */
+ struct channel *chn = ((kw[0] == 'c' || kw[2] == 'q') ? SMP_REQ_CHN(smp) : SMP_RES_CHN(smp));
struct hdr_idx *idx;
struct hdr_ctx ctx;
- const struct http_msg *msg;
const char *hdr_name;
int hdr_name_len;
int cnt;
@@ -10941,22 +10954,19 @@
if (!args || args->type != ARGT_STR)
return 0;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
- txn = smp->strm->txn;
idx = &smp->strm->txn->hdr_idx;
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
- msg = &txn->req;
+ if (!(chn->flags & CF_ISRESP)) {
hdr_name = "Cookie";
hdr_name_len = 6;
} else {
- msg = &txn->rsp;
hdr_name = "Set-Cookie";
hdr_name_len = 10;
}
- sol = msg->chn->buf->p;
+ sol = chn->buf->p;
val_end = val_beg = NULL;
ctx.idx = 0;
cnt = 0;
@@ -11286,6 +11296,7 @@
static int
smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
char delim = '?';
const char *name;
@@ -11307,16 +11318,16 @@
delim = *args[1].data.str.str;
if (!smp->ctx.a[0]) { // first call, find the query string
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
msg = &smp->strm->txn->req;
- smp->ctx.a[0] = find_param_list(msg->chn->buf->p + msg->sl.rq.u,
+ smp->ctx.a[0] = find_param_list(chn->buf->p + msg->sl.rq.u,
msg->sl.rq.u_l, delim);
if (!smp->ctx.a[0])
return 0;
- smp->ctx.a[1] = msg->chn->buf->p + msg->sl.rq.u + msg->sl.rq.u_l;
+ smp->ctx.a[1] = chn->buf->p + msg->sl.rq.u + msg->sl.rq.u_l;
/* Assume that the context is filled with NULL pointer
* before the first call.
@@ -11338,6 +11349,7 @@
static int
smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_msg *msg;
unsigned long len;
unsigned long block1;
@@ -11356,19 +11368,15 @@
}
if (!smp->ctx.a[0]) { // first call, find the query string
- CHECK_HTTP_MESSAGE_FIRST();
-
- if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ)
- msg = &smp->strm->txn->req;
- else
- msg = &smp->strm->txn->rsp;
+ CHECK_HTTP_MESSAGE_FIRST(chn);
+ msg = &smp->strm->txn->req;
len = http_body_bytes(msg);
- body = b_ptr(msg->chn->buf, -http_data_rewind(msg));
+ body = b_ptr(chn->buf, -http_data_rewind(msg));
block1 = len;
- if (block1 > msg->chn->buf->data + msg->chn->buf->size - body)
- block1 = msg->chn->buf->data + msg->chn->buf->size - body;
+ if (block1 > chn->buf->data + chn->buf->size - body)
+ block1 = chn->buf->data + chn->buf->size - body;
if (block1 == len) {
/* buffer is not wrapped (or empty) */
@@ -11385,8 +11393,8 @@
/* buffer is wrapped, we need to defragment it */
smp->ctx.a[0] = body;
smp->ctx.a[1] = body + block1;
- smp->ctx.a[2] = msg->chn->buf->data;
- smp->ctx.a[3] = msg->chn->buf->data + ( len - block1 );
+ smp->ctx.a[2] = chn->buf->data;
+ smp->ctx.a[3] = chn->buf->data + ( len - block1 );
}
}
return smp_fetch_param('&', name, name_len, args, smp, kw, private);
@@ -11421,17 +11429,18 @@
static int
smp_fetch_url32(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
+ struct channel *chn = SMP_REQ_CHN(smp);
struct http_txn *txn;
struct hdr_ctx ctx;
unsigned int hash = 0;
char *ptr, *beg, *end;
int len;
- CHECK_HTTP_MESSAGE_FIRST();
+ CHECK_HTTP_MESSAGE_FIRST(chn);
txn = smp->strm->txn;
ctx.idx = 0;
- if (http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
+ if (http_find_header2("Host", 4, chn->buf->p, &txn->hdr_idx, &ctx)) {
/* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
ptr = ctx.line + ctx.val;
len = ctx.vlen;
@@ -11440,7 +11449,7 @@
}
/* now retrieve the path */
- end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
+ end = chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
beg = http_get_path(txn);
if (!beg)
beg = end;
diff -Nru haproxy-1.8.19/src/session.c haproxy-1.8.20/src/session.c
--- haproxy-1.8.19/src/session.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/session.c 2019-04-25 23:59:27.000000000 +0200
@@ -53,10 +53,6 @@
vars_init(&sess->vars, SCOPE_SESS);
sess->task = NULL;
sess->t_handshake = -1; /* handshake not done yet */
- HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.conn_max,
- HA_ATOMIC_ADD(&fe->feconn, 1));
- if (li)
- proxy_inc_fe_conn_ctr(li, fe);
HA_ATOMIC_ADD(&totalconn, 1);
HA_ATOMIC_ADD(&jobs, 1);
}
@@ -65,7 +61,6 @@
void session_free(struct session *sess)
{
- HA_ATOMIC_SUB(&sess->fe->feconn, 1);
if (sess->listener)
listener_release(sess->listener);
session_store_counters(sess);
diff -Nru haproxy-1.8.19/src/sha1.c haproxy-1.8.20/src/sha1.c
--- haproxy-1.8.19/src/sha1.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/sha1.c 2019-04-25 23:59:27.000000000 +0200
@@ -26,7 +26,7 @@
/* this is only to get definitions for memcpy(), ntohl() and htonl() */
#include <string.h>
-#include <stdint.h>
+#include <inttypes.h>
#include <arpa/inet.h>
#include <import/sha1.h>
diff -Nru haproxy-1.8.19/src/ssl_sock.c haproxy-1.8.20/src/ssl_sock.c
--- haproxy-1.8.19/src/ssl_sock.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/ssl_sock.c 2019-04-25 23:59:27.000000000 +0200
@@ -4696,7 +4696,7 @@
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if (srv->ssl_ctx.ciphersuites &&
- !SSL_CTX_set_cipher_list(srv->ssl_ctx.ctx, srv->ssl_ctx.ciphersuites)) {
+ !SSL_CTX_set_ciphersuites(srv->ssl_ctx.ctx, srv->ssl_ctx.ciphersuites)) {
ha_alert("Proxy '%s', server '%s' [%s:%d] : unable to set TLS 1.3 cipher suites to '%s'.\n",
curproxy->id, srv->id,
srv->conf.file, srv->conf.line, srv->ssl_ctx.ciphersuites);
@@ -7418,7 +7418,7 @@
static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{
-#if (OPENSSL_VERSION_NUMBER < 0x10101000L) || !defined(OPENSSL_IS_BORINGSSL)
+#if (OPENSSL_VERSION_NUMBER < 0x10101000L) && !defined(OPENSSL_IS_BORINGSSL)
ha_warning("crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped).\n");
#endif
return parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods, err);
diff -Nru haproxy-1.8.19/src/standard.c haproxy-1.8.20/src/standard.c
--- haproxy-1.8.19/src/standard.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/standard.c 2019-04-25 23:59:27.000000000 +0200
@@ -3402,12 +3402,14 @@
return NULL;
do {
+ char buf1;
+
/* vsnprintf() will return the required length even when the
* target buffer is NULL. We do this in a loop just in case
* intermediate evaluations get wrong.
*/
va_copy(args, orig_args);
- needed = vsnprintf(ret, allocated, format, args);
+ needed = vsnprintf(ret ? ret : &buf1, allocated, format, args);
va_end(args);
if (needed < allocated) {
/* Note: on Solaris 8, the first iteration always
diff -Nru haproxy-1.8.19/src/stats.c haproxy-1.8.20/src/stats.c
--- haproxy-1.8.19/src/stats.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/stats.c 2019-04-25 23:59:27.000000000 +0200
@@ -2441,6 +2441,7 @@
"Action not processed because of invalid parameters."
"<ul>"
"<li>The action is maybe unknown.</li>"
+ "<li>Invalid key parameter (empty or too long).</li>"
"<li>The backend name is probably unknown or ambiguous (duplicated names).</li>"
"<li>Some server names are probably unknown or ambiguous (duplicated names in the backend).</li>"
"</ul>"
@@ -2634,17 +2635,20 @@
int reql;
temp = get_trash_chunk();
- if (temp->size < s->txn->req.body_len) {
- /* too large request */
- appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
- goto out;
- }
+ /* we need more data */
+ if (s->txn->req.msg_state < HTTP_MSG_DONE) {
+ /* check if we can receive more */
+ if (buffer_total_space(s->req.buf) <= global.tune.maxrewrite) {
+ appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
+ goto out;
+ }
+ goto wait;
+ }
reql = co_getblk(si_oc(si), temp->str, s->txn->req.body_len, s->txn->req.eoh + 2);
if (reql <= 0) {
- /* we need more data */
- appctx->ctx.stats.st_code = STAT_STATUS_NONE;
- return 0;
+ appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
+ goto out;
}
first_param = temp->str;
@@ -2673,7 +2677,7 @@
strncpy(key, cur_param + poffset, plen);
key[plen - 1] = '\0';
} else {
- appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
+ appctx->ctx.stats.st_code = STAT_STATUS_ERRP;
goto out;
}
@@ -2929,6 +2933,9 @@
}
out:
return 1;
+ wait:
+ appctx->ctx.stats.st_code = STAT_STATUS_NONE;
+ return 0;
}
diff -Nru haproxy-1.8.19/src/xxhash.c haproxy-1.8.20/src/xxhash.c
--- haproxy-1.8.19/src/xxhash.c 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/src/xxhash.c 2019-04-25 23:59:27.000000000 +0200
@@ -98,7 +98,7 @@
// Basic Types
//**************************************
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99
-# include <stdint.h>
+# include <inttypes.h>
typedef uint8_t BYTE;
typedef uint16_t U16;
typedef uint32_t U32;
diff -Nru haproxy-1.8.19/VERDATE haproxy-1.8.20/VERDATE
--- haproxy-1.8.19/VERDATE 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/VERDATE 2019-04-25 23:59:27.000000000 +0200
@@ -1,2 +1,2 @@
$Format:%ci$
-2019/02/11
+2019/04/25
diff -Nru haproxy-1.8.19/VERSION haproxy-1.8.20/VERSION
--- haproxy-1.8.19/VERSION 2019-02-11 14:16:19.000000000 +0100
+++ haproxy-1.8.20/VERSION 2019-04-25 23:59:27.000000000 +0200
@@ -1 +1 @@
-1.8.19
+1.8.20
Reply to: