diff --git a/net/haproxy/Makefile b/net/haproxy/Makefile
index e01785a97..c99c9eabf 100644
--- a/net/haproxy/Makefile
+++ b/net/haproxy/Makefile
@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=haproxy
 PKG_VERSION:=1.8.19
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://www.haproxy.org/download/1.8/src/
diff --git a/net/haproxy/patches/008-BUG-MAJOR-stats-Fix-how-huge-POST-data-are-read-from-the-channel.patch b/net/haproxy/patches/008-BUG-MAJOR-stats-Fix-how-huge-POST-data-are-read-from-the-channel.patch
new file mode 100644
index 000000000..2b293e477
--- /dev/null
+++ b/net/haproxy/patches/008-BUG-MAJOR-stats-Fix-how-huge-POST-data-are-read-from-the-channel.patch
@@ -0,0 +1,92 @@
+commit 3c6ad99924236bf8b7741030bd163aacb820d451
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Wed Feb 27 15:30:57 2019 +0100
+
+    BUG/MAJOR: stats: Fix how huge POST data are read from the channel
+    
+    When the body length is greater than a chunk size (so if length of POST data
+    exceeds the buffer size), the requests is rejected with the status code
+    STAT_STATUS_EXCD. Otherwise the stats applet will wait to have all the data to
+    copy and parse them. But there is a problem when the total request size
+    (including the headers) is just lower than the buffer size but greater the
+    buffer size less the reserve. In such case, the body length is considered as
+    enough small to be processed but not entierly received. So the stats applet
+    waits for more data. But because outgoing data are still there, the channel's
+    buffer is considered as full and nothing more can be read, leading to a freeze
+    of the session.
+    
+    Note this bug is pretty easy to reproduce with the legacy HTTP. It is harder
+    with the HTX but still possible. To fix the bug, in the stats applet, when the
+    request is not fully received, we check if at least the reserve remains
+    available the channel's buffer.
+    
+    This patch must be backported as far as 1.5. But because the HTX does not exist
+    in 1.8 and lower, it will have to be adapted for these versions.
+    
+    (cherry picked from commit 2f9a41d52b28b88d44aab063bb2b88025a388981)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 18a5b1eece7e12047c1dc371c42f72d9d129ce0a)
+    [cf: HTX code removed and calls to the new buffer API replaced to use the old
+    one]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/stats.c b/src/stats.c
+index 4973bb8a..0a6c15f6 100644
+--- a/src/stats.c
++++ b/src/stats.c
+@@ -2441,6 +2441,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
+ 			              "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 @@ static int stats_process_http_post(struct stream_interface *si)
+ 	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 @@ static int stats_process_http_post(struct stream_interface *si)
+ 				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 @@ static int stats_process_http_post(struct stream_interface *si)
+ 	}
+  out:
+ 	return 1;
++ wait:
++	appctx->ctx.stats.st_code = STAT_STATUS_NONE;
++	return 0;
+ }
+ 
+ 
diff --git a/net/haproxy/patches/009-BUG-MINOR-http-counters-fix-missing-increment-of-fe--srv_aborts.patch b/net/haproxy/patches/009-BUG-MINOR-http-counters-fix-missing-increment-of-fe--srv_aborts.patch
new file mode 100644
index 000000000..ae1a0e553
--- /dev/null
+++ b/net/haproxy/patches/009-BUG-MINOR-http-counters-fix-missing-increment-of-fe--srv_aborts.patch
@@ -0,0 +1,30 @@
+commit f5ed1f24a9f7bb3b58f6f29b403963e0155e44a9
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Mon Mar 18 11:02:57 2019 +0100
+
+    BUG/MINOR: http/counters: fix missing increment of fe->srv_aborts
+    
+    When a server aborts a transfer, we used to increment the backend's
+    counter but not the frontend's during the forwarding phase. This fixes
+    it. It might be backported to all supported versions (possibly removing
+    the htx part) though it is of very low importance.
+    
+    (cherry picked from commit d1fd6f5f64e4d05d4993f2d43c1ee8c79a16fec1)
+    [wt: s/_HA_ATOMIC/HA_ATOMIC/]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 8aa5c6f660ecc9ed79e759a70112e1dbfd59831d)
+    [cf: HTX code removed]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index efd318e7..8b087c5b 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -6150,6 +6150,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
+ 		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);
diff --git a/net/haproxy/patches/010-BUG-MEDIUM-ssl-ability-to-set-TLS-1-3-ciphers-using-ssl-default-server-ciphersuites.patch b/net/haproxy/patches/010-BUG-MEDIUM-ssl-ability-to-set-TLS-1-3-ciphers-using-ssl-default-server-ciphersuites.patch
new file mode 100644
index 000000000..0fb3c0a91
--- /dev/null
+++ b/net/haproxy/patches/010-BUG-MEDIUM-ssl-ability-to-set-TLS-1-3-ciphers-using-ssl-default-server-ciphersuites.patch
@@ -0,0 +1,36 @@
+commit a2919cab08fff3fad434c574506b5ae23b4db131
+Author: Pierre Cheynier <p.cheynier@criteo.com>
+Date:   Thu Mar 21 16:15:47 2019 +0000
+
+    BUG/MEDIUM: ssl: ability to set TLS 1.3 ciphers using ssl-default-server-ciphersuites
+    
+    Any attempt to put TLS 1.3 ciphers on servers failed with output 'unable
+    to set TLS 1.3 cipher suites'.
+    
+    This was due to usage of SSL_CTX_set_cipher_list instead of
+    SSL_CTX_set_ciphersuites in the TLS 1.3 block (protected by
+    OPENSSL_VERSION_NUMBER >= 0x10101000L & so).
+    
+    This should be backported to 1.9 and 1.8.
+    
+    Signed-off-by: Pierre Cheynier <p.cheynier@criteo.com>
+    Reported-by: Damien Claisse <d.claisse@criteo.com>
+    Cc: Emeric Brun <ebrun@haproxy.com>
+    (cherry picked from commit bc34cd1de2ee80de63b5c4d319a501fc0d4ea2f5)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 4a8b9e3d5f4e76295c571900771fd1728bec474f)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/ssl_sock.c b/src/ssl_sock.c
+index afdb1fce..fbb7cf2b 100644
+--- a/src/ssl_sock.c
++++ b/src/ssl_sock.c
+@@ -4696,7 +4696,7 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
+ 
+ #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);
diff --git a/net/haproxy/patches/011-DOC-The-option-httplog-is-no-longer-valid-in-a-backend.patch b/net/haproxy/patches/011-DOC-The-option-httplog-is-no-longer-valid-in-a-backend.patch
new file mode 100644
index 000000000..9d913dda1
--- /dev/null
+++ b/net/haproxy/patches/011-DOC-The-option-httplog-is-no-longer-valid-in-a-backend.patch
@@ -0,0 +1,26 @@
+commit 6e9787fcc677b15cb9fc0baea8de545127b4fb85
+Author: Freddy Spierenburg <freddy@snarl.nl>
+Date:   Mon Mar 25 14:35:17 2019 +0100
+
+    DOC: The option httplog is no longer valid in a backend.
+    
+    This can be backported to 1.9 and 1.8.
+    
+    (cherry picked from commit e88b77351b3fe34a83d5208773a63f78fb140722)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 79b70b0f8f86315230323e7f826796dffba4b85b)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 8d75d568..3608a897 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -2118,7 +2118,7 @@ option http-tunnel                   (*)  X          X         X         X
+ 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 --git a/net/haproxy/patches/012-BUG-MAJOR-checks-segfault-during-tcpcheck_main.patch b/net/haproxy/patches/012-BUG-MAJOR-checks-segfault-during-tcpcheck_main.patch
new file mode 100644
index 000000000..4d9fc029e
--- /dev/null
+++ b/net/haproxy/patches/012-BUG-MAJOR-checks-segfault-during-tcpcheck_main.patch
@@ -0,0 +1,40 @@
+commit ed3951cf6d9c7846fc780042fdddc194dda47c8d
+Author: Ricardo Nabinger Sanchez <rnsanchez@taghos.com.br>
+Date:   Thu Mar 28 21:42:23 2019 -0300
+
+    BUG/MAJOR: checks: segfault during tcpcheck_main
+    
+    When using TCP health checks (tcp-check connect), it is possible to
+    crash with a segfault when, for reasons yet to be understood, the
+    protocol family is unknown.
+    
+    In the function tcpcheck_main(), proto is dereferenced without a prior
+    test in case it is NULL, leading to the segfault during proto->connect
+    dereference.
+    
+    The line has been unmodified since it was introduced, in commit
+    69e273f3fcfbfb9cc0fb5a09668faad66cfbd36b.  This was the only use of
+    proto (or more specifically, the return of  protocol_by_family()) that
+    was unprotected; all other callsites perform the test for a NULL
+    pointer.
+    
+    This patch should be backported to 1.9, 1.8, 1.7, and 1.6.
+    
+    (cherry picked from commit 4bccea98912c74fa42c665ec25e417c2cca4eee7)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 2cefb36087f240b66b2aa4824a317ef5f9b85e68)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/checks.c b/src/checks.c
+index e04f1146..fdebf931 100644
+--- a/src/checks.c
++++ b/src/checks.c
+@@ -2771,7 +2771,7 @@ static int tcpcheck_main(struct check *check)
+ 			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 --git a/net/haproxy/patches/013-BUILD-makefile-work-around-an-old-bug-in-GNU-make-3-80.patch b/net/haproxy/patches/013-BUILD-makefile-work-around-an-old-bug-in-GNU-make-3-80.patch
new file mode 100644
index 000000000..ba4ec2c04
--- /dev/null
+++ b/net/haproxy/patches/013-BUILD-makefile-work-around-an-old-bug-in-GNU-make-3-80.patch
@@ -0,0 +1,35 @@
+commit 795773be8c3ddc8380f134adc7e2ccfde2d8469b
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 17:17:52 2019 +0100
+
+    BUILD: makefile: work around an old bug in GNU make-3.80
+    
+    GNU make-3.80 fails on the .build_opts target, expecting the closing
+    brace before the first semi-colon in the shell command, it probably
+    uses a more limited parser for dependencies. Actually it appears it's
+    enough to place this command in a variable and reference the variable
+    there. Since it doesn't affect later versions (and the resulting string
+    is always empty anyway), let's apply the minor change to continue to
+    comply with the announced dependencies.
+    
+    This could be backported as far as 1.6.
+    
+    (cherry picked from commit 509a009c5dd06e680bc2fff6ebc45f7f42aaee3e)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 953b732eef96689f2b11bc2768ba05f28feac9a5)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/Makefile b/Makefile
+index 94e04738..bdf5a2d0 100644
+--- a/Makefile
++++ b/Makefile
+@@ -905,7 +905,8 @@ INCLUDES = $(wildcard include/*/*.h ebtree/*.h)
+ 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 --git a/net/haproxy/patches/014-MINOR-tools-make-memvprintf-never-pass-a-NULL-target-to-vsnprintf.patch b/net/haproxy/patches/014-MINOR-tools-make-memvprintf-never-pass-a-NULL-target-to-vsnprintf.patch
new file mode 100644
index 000000000..776fae4b1
--- /dev/null
+++ b/net/haproxy/patches/014-MINOR-tools-make-memvprintf-never-pass-a-NULL-target-to-vsnprintf.patch
@@ -0,0 +1,42 @@
+commit 36b50ee589a4fda66d222af7de8ad866d30613c7
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 19:13:23 2019 +0100
+
+    MINOR: tools: make memvprintf() never pass a NULL target to vsnprintf()
+    
+    Most modern platforms don't touch the output buffer when the size
+    argument is null, but there exist a few old ones (like AIX 5 and
+    possibly Tru64) where the output will be dereferenced anyway, probably
+    to write the trailing null, crashing the process. memprintf() uses this
+    to measure the desired length.
+    
+    There is a very simple workaround to this consisting in passing a pointer
+    to a character instead of a NULL pointer. It was confirmed to fix the issue
+    on AIX 5.1.
+    
+    (cherry picked from commit e0609f5f49f55b122e7da9bd1d3b1b786366e80c)
+    [wt: it likely makes sense to backport this to all supported branches]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 1719b6be375bf9478c2cfe78caccd818d37a4d50)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/standard.c b/src/standard.c
+index 38c4f3f2..69cddcea 100644
+--- a/src/standard.c
++++ b/src/standard.c
+@@ -3402,12 +3402,14 @@ char *memvprintf(char **out, const char *format, va_list orig_args)
+ 		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 --git a/net/haproxy/patches/015-BUILD-makefile-fix-build-of-IPv6-header-on-aix51.patch b/net/haproxy/patches/015-BUILD-makefile-fix-build-of-IPv6-header-on-aix51.patch
new file mode 100644
index 000000000..6a81dc4a6
--- /dev/null
+++ b/net/haproxy/patches/015-BUILD-makefile-fix-build-of-IPv6-header-on-aix51.patch
@@ -0,0 +1,27 @@
+commit 369d595d95f4945f0e14dd02757cf64eaf8512d9
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 17:40:23 2019 +0100
+
+    BUILD: makefile: fix build of IPv6 header on aix51
+    
+    ip6_hdr is called ip6hdr there and is only defined when STEVENS_API is
+    defined.
+    
+    (cherry picked from commit 6f4fd1b183fc70863926bdc31d7f0b4739c92c56)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 99903a0c6419edb515a07a6e1fba4b8bc78babd1)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/Makefile b/Makefile
+index bdf5a2d0..81e70e02 100644
+--- a/Makefile
++++ b/Makefile
+@@ -358,7 +358,7 @@ ifeq ($(TARGET),aix51)
+   # This is for AIX 5.1
+   USE_POLL        = implicit
+   USE_LIBCRYPT    = implicit
+-  TARGET_CFLAGS   = -Dss_family=__ss_family
++  TARGET_CFLAGS   = -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API
+   DEBUG_CFLAGS    =
+ else
+ ifeq ($(TARGET),aix52)
diff --git a/net/haproxy/patches/016-BUILD-makefile-add-_LINUX_SOURCE_COMPAT-to-build-on-AIX-51.patch b/net/haproxy/patches/016-BUILD-makefile-add-_LINUX_SOURCE_COMPAT-to-build-on-AIX-51.patch
new file mode 100644
index 000000000..9c7d9809c
--- /dev/null
+++ b/net/haproxy/patches/016-BUILD-makefile-add-_LINUX_SOURCE_COMPAT-to-build-on-AIX-51.patch
@@ -0,0 +1,27 @@
+commit 0ddf04ee66d3a2ff9c47d0c91a2d3c7bc06b34e9
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 17:56:13 2019 +0100
+
+    BUILD: makefile: add _LINUX_SOURCE_COMPAT to build on AIX-51
+    
+    Not tested on later versions, but at least there _LINUX_SOURCE_COMPAT
+    must be defined to access the CMSG_SPACE() and CMSG_LEN() macros.
+    
+    (cherry picked from commit 891d65a67280bea35f8ae38e4dcfe7c2330ddd10)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 20faac416072cabffb13a7e41a58dd5b56fc21b0)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/Makefile b/Makefile
+index 81e70e02..955f1188 100644
+--- a/Makefile
++++ b/Makefile
+@@ -358,7 +358,7 @@ ifeq ($(TARGET),aix51)
+   # This is for AIX 5.1
+   USE_POLL        = implicit
+   USE_LIBCRYPT    = implicit
+-  TARGET_CFLAGS   = -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API
++  TARGET_CFLAGS   = -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API -D_LINUX_SOURCE_COMPAT
+   DEBUG_CFLAGS    =
+ else
+ ifeq ($(TARGET),aix52)
diff --git a/net/haproxy/patches/017-BUILD-Makefile-disable-shared-cache-on-AIX-5-1.patch b/net/haproxy/patches/017-BUILD-Makefile-disable-shared-cache-on-AIX-5-1.patch
new file mode 100644
index 000000000..39fe46d51
--- /dev/null
+++ b/net/haproxy/patches/017-BUILD-Makefile-disable-shared-cache-on-AIX-5-1.patch
@@ -0,0 +1,35 @@
+commit f78f501857cec8bb682b76faa9cbd5cc1e0dcad4
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 18:56:54 2019 +0100
+
+    BUILD: Makefile: disable shared cache on AIX 5.1
+    
+    AIX 5.1 is missing the following builtins used for atomic locking of the
+    shared inter-process cache :
+    
+       .__sync_val_compare_and_swap_4
+       .__sync_lock_test_and_set_4
+       .__sync_sub_and_fetch_4
+    
+    Let's simply use the private cache by default since nobody cares on
+    such old systems. No test was made on a more recent version.
+    
+    (cherry picked from commit 13d9b0231abe6e1d6c404725746308a98bdab8c6)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 3349375d3f5820f261f9c3058ca6e5ced67f3505)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/Makefile b/Makefile
+index 955f1188..36df7b29 100644
+--- a/Makefile
++++ b/Makefile
+@@ -358,7 +358,8 @@ ifeq ($(TARGET),aix51)
+   # This is for AIX 5.1
+   USE_POLL        = implicit
+   USE_LIBCRYPT    = implicit
+-  TARGET_CFLAGS   = -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API -D_LINUX_SOURCE_COMPAT
++  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)
diff --git a/net/haproxy/patches/018-BUG-MINOR-cli-correctly-handle-abns-in-show-cli-sockets.patch b/net/haproxy/patches/018-BUG-MINOR-cli-correctly-handle-abns-in-show-cli-sockets.patch
new file mode 100644
index 000000000..baf41ee78
--- /dev/null
+++ b/net/haproxy/patches/018-BUG-MINOR-cli-correctly-handle-abns-in-show-cli-sockets.patch
@@ -0,0 +1,33 @@
+commit 9ffd35ec59b1ade094b4828b880bdb4971f0c69e
+Author: William Lallemand <wlallemand@haproxy.com>
+Date:   Mon Apr 1 11:30:04 2019 +0200
+
+    BUG/MINOR: cli: correctly handle abns in 'show cli sockets'
+    
+    The 'show cli sockets' was not handling the abns sockets. This is a
+    problem since it uses the AF_UNIX family, it displays nothing
+    in the path column because the path starts by \0.
+    
+    Should be backported to 1.9 and 1.8.
+    
+    (cherry picked from commit 75812a7a3cdc853ceee0b3fb2173db060057ba35)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit d06619b5adf8a718ad840dbddbc9d2c83fbb01b1)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/cli.c b/src/cli.c
+index 079d8d9b..39744c7a 100644
+--- a/src/cli.c
++++ b/src/cli.c
+@@ -972,7 +972,10 @@ static int cli_io_handler_show_cli_sock(struct appctx *appctx)
+ 							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, "%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));
diff --git a/net/haproxy/patches/019-MINOR-cli-start-addresses-by-a-prefix-in-show-cli-sockets.patch b/net/haproxy/patches/019-MINOR-cli-start-addresses-by-a-prefix-in-show-cli-sockets.patch
new file mode 100644
index 000000000..006305cb6
--- /dev/null
+++ b/net/haproxy/patches/019-MINOR-cli-start-addresses-by-a-prefix-in-show-cli-sockets.patch
@@ -0,0 +1,45 @@
+commit d33b1dd5193df4dfc1dcbea22ade1ee53c89009e
+Author: William Lallemand <wlallemand@haproxy.com>
+Date:   Mon Apr 1 11:30:05 2019 +0200
+
+    MINOR: cli: start addresses by a prefix in 'show cli sockets'
+    
+    Displays a prefix for every addresses in 'show cli sockets'.
+    It could be 'unix@', 'ipv4@', 'ipv6@', 'abns@' or 'sockpair@'.
+    
+    Could be backported in 1.9 and 1.8.
+    
+    (cherry picked from commit e58915f07f7e7a83a7aece909f115bb40887cd55)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit 97a9b60016159140ba3c001f7427d8ff52d1d311)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/cli.c b/src/cli.c
+index 39744c7a..f0c41b06 100644
+--- a/src/cli.c
++++ b/src/cli.c
+@@ -972,18 +972,19 @@ static int cli_io_handler_show_cli_sock(struct appctx *appctx)
+ 							const struct sockaddr_un *un;
+ 
+ 							un = (struct sockaddr_un *)&l->addr;
+-							if (un->sun_path[0] == '\0')
++							if (un->sun_path[0] == '\0') {
+ 								chunk_appendf(&trash, "abns@%s ", un->sun_path+1);
+-							else
+-								chunk_appendf(&trash, "%s ", un->sun_path);
++							} 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 --git a/net/haproxy/patches/020-BUG-MEDIUM-peers-fix-a-case-where-peer-session-is-not-cleanly-reset-on-release.patch b/net/haproxy/patches/020-BUG-MEDIUM-peers-fix-a-case-where-peer-session-is-not-cleanly-reset-on-release.patch
new file mode 100644
index 000000000..277667dc1
--- /dev/null
+++ b/net/haproxy/patches/020-BUG-MEDIUM-peers-fix-a-case-where-peer-session-is-not-cleanly-reset-on-release.patch
@@ -0,0 +1,168 @@
+commit 3bb33335816c1c9549d21bcc14bed29519b938a3
+Author: Emeric Brun <ebrun@haproxy.com>
+Date:   Tue Apr 2 17:22:01 2019 +0200
+
+    BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
+    
+    The deinit took place in only peer_session_release, but in the a case of a
+    previous call to peer_session_forceshutdown, the session cursors
+    won't be reset, resulting in a bad state for new session of the same
+    peer. For instance, a table definition message could be dropped and
+    so all update messages will be dropped by the remote peer.
+    
+    This patch move the deinit processing directly in the force shutdown
+    funtion. Killed session remains in "ST_END" state but ref on peer was
+    reset to NULL and deinit will be skipped on session release function.
+    
+    The session release continue to assure the deinit for "active" sessions.
+    
+    This patch should be backported on all stable version since proto
+    peers v2.
+    
+    (cherry picked from commit 9ef2ad7844e577b505019695c59284f4a439fc33)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit 14831989a081f3944cf891afd56e6d9f6086c3ed)
+    [cf: global variabled connected_peers and active_peers don't exist in 1.8]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/peers.c b/src/peers.c
+index 465ffe85..d7dc51d8 100644
+--- a/src/peers.c
++++ b/src/peers.c
+@@ -172,7 +172,7 @@ enum {
+ #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
+@@ -492,15 +492,53 @@ static int peer_prepare_ackmsg(struct shared_table *st, char *msg, size_t size)
+ 	return (cursor - msg) + datalen;
+ }
+ 
++/*
++ * 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 @@ static void peer_session_release(struct appctx *appctx)
+ 	/* 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 @@ switchstate:
+ 					 * 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 @@ static struct applet peer_applet = {
+ 	.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 @@ static void peer_session_forceshutdown(struct appctx *appctx)
+ 	if (appctx->applet != &peer_applet)
+ 		return;
+ 
++	__peer_session_deinit(peer);
++
+ 	appctx->st0 = PEER_SESS_ST_END;
+ 	appctx_wakeup(appctx);
+ }
+@@ -2094,8 +2122,7 @@ static struct task *process_peer_sync(struct task * task)
+ 				 */
+ 				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 --git a/net/haproxy/patches/021-BUILD-use-inttypes-h-instead-of-stdint-h.patch b/net/haproxy/patches/021-BUILD-use-inttypes-h-instead-of-stdint-h.patch
new file mode 100644
index 000000000..ca79b057c
--- /dev/null
+++ b/net/haproxy/patches/021-BUILD-use-inttypes-h-instead-of-stdint-h.patch
@@ -0,0 +1,251 @@
+commit 7948348cdc115389700242901c91d323192850a8
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 17:26:33 2019 +0100
+
+    BUILD: use inttypes.h instead of stdint.h
+    
+    I found on an (old) AIX 5.1 machine that stdint.h didn't exist while
+    inttypes.h which is expected to include it does exist and provides the
+    desired functionalities.
+    
+    As explained here, stdint being just a subset of inttypes for use in
+    freestanding environments, it's probably always OK to switch to inttypes
+    instead:
+    
+      https://pubs.opengroup.org/onlinepubs/009696799/basedefs/stdint.h.html
+    
+    Also it's even clearer here in the autoconf doc :
+    
+      https://www.gnu.org/software/autoconf/manual/autoconf-2.61/html_node/Header-Portability.html
+    
+      "The C99 standard says that inttypes.h includes stdint.h, so there's
+       no need to include stdint.h separately in a standard environment.
+       Some implementations have inttypes.h but not stdint.h (e.g., Solaris
+       7), but we don't know of any implementation that has stdint.h but not
+       inttypes.h"
+    
+    (cherry picked from commit a1bd1faeebd03825677d111a1350ee04d625f165)
+    [wt: dropped include/proto/protocol_buffers.h]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 19f364bb4ad0205e134dc527e5164b7a21c2ad07)
+    [cf: missing files removed]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/contrib/hpack/gen-rht.c b/contrib/hpack/gen-rht.c
+index b1b90317..4260ffbe 100644
+--- a/contrib/hpack/gen-rht.c
++++ b/contrib/hpack/gen-rht.c
+@@ -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 --git a/contrib/plug_qdisc/plug_qdisc.c b/contrib/plug_qdisc/plug_qdisc.c
+index 294994eb..606a834c 100644
+--- a/contrib/plug_qdisc/plug_qdisc.c
++++ b/contrib/plug_qdisc/plug_qdisc.c
+@@ -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 --git a/contrib/spoa_example/include/spop_functions.h b/contrib/spoa_example/include/spop_functions.h
+index 8319e41b..cff45321 100644
+--- a/contrib/spoa_example/include/spop_functions.h
++++ b/contrib/spoa_example/include/spop_functions.h
+@@ -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 --git a/contrib/wireshark-dissectors/peers/packet-happp.c b/contrib/wireshark-dissectors/peers/packet-happp.c
+index a1983316..6fca353a 100644
+--- a/contrib/wireshark-dissectors/peers/packet-happp.c
++++ b/contrib/wireshark-dissectors/peers/packet-happp.c
+@@ -22,7 +22,7 @@
+  */
+ 
+ #include <stdio.h>
+-#include <stdint.h>
++#include <inttypes.h>
+ #include <inttypes.h>
+ #include <arpa/inet.h>
+ 
+diff --git a/include/common/hpack-dec.h b/include/common/hpack-dec.h
+index b03398a4..bea2d521 100644
+--- a/include/common/hpack-dec.h
++++ b/include/common/hpack-dec.h
+@@ -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 --git a/include/common/hpack-enc.h b/include/common/hpack-enc.h
+index 0a44dfc7..fee56fd4 100644
+--- a/include/common/hpack-enc.h
++++ b/include/common/hpack-enc.h
+@@ -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 --git a/include/common/hpack-huff.h b/include/common/hpack-huff.h
+index 85ca4171..04276d2c 100644
+--- a/include/common/hpack-huff.h
++++ b/include/common/hpack-huff.h
+@@ -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 --git a/include/common/hpack-tbl.h b/include/common/hpack-tbl.h
+index 2cbc2bf6..ca3f2aa9 100644
+--- a/include/common/hpack-tbl.h
++++ b/include/common/hpack-tbl.h
+@@ -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 --git a/include/common/http-hdr.h b/include/common/http-hdr.h
+index a0bb341b..db1bfa14 100644
+--- a/include/common/http-hdr.h
++++ b/include/common/http-hdr.h
+@@ -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 --git a/include/proto/shctx.h b/include/proto/shctx.h
+index 55cb2a77..3b42ed3b 100644
+--- a/include/proto/shctx.h
++++ b/include/proto/shctx.h
+@@ -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 --git a/src/h2.c b/src/h2.c
+index 5c83d6b6..d7a03405 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -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 --git a/src/hpack-dec.c b/src/hpack-dec.c
+index 3fd4224d..ad5b23a8 100644
+--- a/src/hpack-dec.c
++++ b/src/hpack-dec.c
+@@ -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 --git a/src/hpack-enc.c b/src/hpack-enc.c
+index cb0767ed..685c9f3d 100644
+--- a/src/hpack-enc.c
++++ b/src/hpack-enc.c
+@@ -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 --git a/src/hpack-huff.c b/src/hpack-huff.c
+index cbf1fa02..bdcff7fe 100644
+--- a/src/hpack-huff.c
++++ b/src/hpack-huff.c
+@@ -26,7 +26,7 @@
+  */
+ 
+ #include <stdio.h>
+-#include <stdint.h>
++#include <inttypes.h>
+ #include <string.h>
+ 
+ #include <common/config.h>
+diff --git a/src/hpack-tbl.c b/src/hpack-tbl.c
+index e2d4426f..21aa4bc8 100644
+--- a/src/hpack-tbl.c
++++ b/src/hpack-tbl.c
+@@ -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 --git a/src/sha1.c b/src/sha1.c
+index 3b562b55..b7c2d709 100644
+--- a/src/sha1.c
++++ b/src/sha1.c
+@@ -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 --git a/src/xxhash.c b/src/xxhash.c
+index 5702e64f..4792f128 100644
+--- a/src/xxhash.c
++++ b/src/xxhash.c
+@@ -98,7 +98,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size)
+ // 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 --git a/net/haproxy/patches/022-BUILD-connection-fix-naming-of-ip_v-field.patch b/net/haproxy/patches/022-BUILD-connection-fix-naming-of-ip_v-field.patch
new file mode 100644
index 000000000..a3a245b1d
--- /dev/null
+++ b/net/haproxy/patches/022-BUILD-connection-fix-naming-of-ip_v-field.patch
@@ -0,0 +1,50 @@
+commit a49725beede82687afd6603384f318afe9e60432
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Mar 29 17:35:32 2019 +0100
+
+    BUILD: connection: fix naming of ip_v field
+    
+    AIX defines ip_v as ip_ff.ip_fv in netinet/ip.h using a macro, and
+    unfortunately we do have a local variable with such a name and which
+    uses the same header file. Let's rename the variable to ip_ver to fix
+    this.
+    
+    (cherry picked from commit 0ca24aa028159874d77677076a835930de79ba8d)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 0a5e7a9a39e14dccba4caa7df20cd3970f354078)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/connection.c b/src/connection.c
+index 7403e8ae..f57ef60a 100644
+--- a/src/connection.c
++++ b/src/connection.c
+@@ -699,7 +699,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
+ {
+ 	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 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
+ 		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 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
+ 
+ 		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 --git a/net/haproxy/patches/023-BUG-MEDIUM-pattern-assign-pattern-IDs-after-checking-the-config-validity.patch b/net/haproxy/patches/023-BUG-MEDIUM-pattern-assign-pattern-IDs-after-checking-the-config-validity.patch
new file mode 100644
index 000000000..cea387229
--- /dev/null
+++ b/net/haproxy/patches/023-BUG-MEDIUM-pattern-assign-pattern-IDs-after-checking-the-config-validity.patch
@@ -0,0 +1,54 @@
+commit 3bd00f356783d331deba80de76c989d416e4a52e
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Apr 11 14:47:08 2019 +0200
+
+    BUG/MEDIUM: pattern: assign pattern IDs after checking the config validity
+    
+    Pavlos Parissis reported an interesting case where some map identifiers
+    were not assigned (appearing as -1 in show map). It turns out that it
+    only happens for log-format expressions parsed in check_config_validity()
+    that involve maps (log-format, use_backend, unique-id-header), as in the
+    sample configuration below :
+    
+        frontend foo
+            bind :8001
+            unique-id-format %[src,map(addr.lst)]
+            log-format %[src,map(addr.lst)]
+            use_backend %[src,map(addr.lst)]
+    
+    The reason stems from the initial introduction of unique IDs in 1.5 via
+    commit af5a29d5f ("MINOR: pattern: Each pattern is identified by unique
+    id.") : the unique_id assignment was done before calling
+    check_config_validity() so all maps loaded after this call are not
+    properly configured. From what the function does, it seems they will not
+    be able to use a cache, will not have a unique_id assigned and will not
+    be updatable from the CLI.
+    
+    This fix must be backported to all supported versions.
+    
+    (cherry picked from commit 0f93672dfea805268d674c97573711fbff7e0e70)
+    Signed-off-by: William Lallemand <wlallemand@haproxy.org>
+    (cherry picked from commit ba475a5b390f58450756da67dbf54bf063f2dbef)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/haproxy.c b/src/haproxy.c
+index 5c3febdd..105cde6f 100644
+--- a/src/haproxy.c
++++ b/src/haproxy.c
+@@ -1570,14 +1570,14 @@ static void init(int argc, char **argv)
+ 		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).
+ 	 */
diff --git a/net/haproxy/patches/024-BUG-MEDIUM-spoe-Queue-message-only-if-no-SPOE-applet-is-attached-to-the-stream.patch b/net/haproxy/patches/024-BUG-MEDIUM-spoe-Queue-message-only-if-no-SPOE-applet-is-attached-to-the-stream.patch
new file mode 100644
index 000000000..cecf42f0f
--- /dev/null
+++ b/net/haproxy/patches/024-BUG-MEDIUM-spoe-Queue-message-only-if-no-SPOE-applet-is-attached-to-the-stream.patch
@@ -0,0 +1,42 @@
+commit 308f39235ca8ce09442bf89cd8aa7f4f6b74f214
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Wed Apr 10 14:02:12 2019 +0200
+
+    BUG/MEDIUM: spoe: Queue message only if no SPOE applet is attached to the stream
+    
+    If a SPOE applet is already attached to a stream to handle its messages, we must
+    not queue them. Otherwise it could be handled by another applet leading to
+    errors. This happens with fragmented messages only. When the first framgnent is
+    sent, the SPOE applet sending it is attached to the stream. It should be used to
+    send all other fragments.
+    
+    This patch must be backported to 1.9 and 1.8.
+    
+    (cherry picked from commit 3e86cec05ec9cf848abd8f9a79928410874b778d)
+    [wla: s/_HA_ATOMIC_ADD/HA_ATOMIC_ADD/ in context]
+    Signed-off-by: William Lallemand <wlallemand@haproxy.org>
+    (cherry picked from commit c3468fe1de262c9977510efb1ae47ff1a04c299c)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/flt_spoe.c b/src/flt_spoe.c
+index 66d26f34..64601e3f 100644
+--- a/src/flt_spoe.c
++++ b/src/flt_spoe.c
+@@ -2086,11 +2086,14 @@ spoe_queue_context(struct spoe_context *ctx)
+ 		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"
diff --git a/net/haproxy/patches/025-BUG-MEDIUM-spoe-Return-an-error-if-nothing-is-encoded-for-fragmented-messages.patch b/net/haproxy/patches/025-BUG-MEDIUM-spoe-Return-an-error-if-nothing-is-encoded-for-fragmented-messages.patch
new file mode 100644
index 000000000..0c89d2dcd
--- /dev/null
+++ b/net/haproxy/patches/025-BUG-MEDIUM-spoe-Return-an-error-if-nothing-is-encoded-for-fragmented-messages.patch
@@ -0,0 +1,34 @@
+commit ebc65295f5ab943955ea6ae9772932c32e39d02c
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Wed Apr 10 14:21:51 2019 +0200
+
+    BUG/MEDIUM: spoe: Return an error if nothing is encoded for fragmented messages
+    
+    If the maximum frame size is very small with a large message or argument name,
+    it is possible to be unable to encode anything. In such case, it is important to
+    stop processing returning an error otherwise we will retry in loop to encode the
+    message, failing each time because of the too small frame size.
+    
+    This patch must be backported to 1.9 and 1.8.
+    
+    (cherry picked from commit a715ea82eacf4ccf7f447bf4dd4111cc29fe171e)
+    Signed-off-by: William Lallemand <wlallemand@haproxy.org>
+    (cherry picked from commit 3c76e4d79669329ae972f3348e441fea7316813f)
+    [cf: Adapted to use old buffer API]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/flt_spoe.c b/src/flt_spoe.c
+index 64601e3f..95f30898 100644
+--- a/src/flt_spoe.c
++++ b/src/flt_spoe.c
+@@ -2276,7 +2276,9 @@ spoe_encode_messages(struct stream *s, struct spoe_context *ctx,
+ 	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;
+ 	}
diff --git a/net/haproxy/patches/026-BUG-MINOR-threads-fix-the-process-range-of-thread-masks.patch b/net/haproxy/patches/026-BUG-MINOR-threads-fix-the-process-range-of-thread-masks.patch
new file mode 100644
index 000000000..791cf2c96
--- /dev/null
+++ b/net/haproxy/patches/026-BUG-MINOR-threads-fix-the-process-range-of-thread-masks.patch
@@ -0,0 +1,30 @@
+commit c56c82b4a55f0e03b28248f1230d6d6cd4f40484
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Sat Feb 2 13:18:01 2019 +0100
+
+    BUG/MINOR: threads: fix the process range of thread masks
+    
+    Commit 421f02e ("MINOR: threads: add a MAX_THREADS define instead of
+    LONGBITS") used a MAX_THREADS macros to fix threads limits. However,
+    one change was wrong as it affected the upper bound of the process
+    loop when setting threads masks. No backport is needed.
+    
+    (cherry picked from commit bbcf2b9e0d17d83609ac529a21a258d2f2ea7bb8)
+    [wt: this should be backported to 1.8 as well]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 1a3ae41964f934a4317e37ed0e0680f252dea4af)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/listener.c b/src/listener.c
+index b94d823c..45d9c252 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -954,7 +954,7 @@ static int bind_parse_process(char **args, int cur_arg, struct proxy *px, struct
+ 
+ 	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;
+ 	}
diff --git a/net/haproxy/patches/027-MINOR-lists-Implement-locked-variations.patch b/net/haproxy/patches/027-MINOR-lists-Implement-locked-variations.patch
new file mode 100644
index 000000000..b8f082daa
--- /dev/null
+++ b/net/haproxy/patches/027-MINOR-lists-Implement-locked-variations.patch
@@ -0,0 +1,175 @@
+commit d66183efc6ee57c86400afba3b9b3f8635d3245e
+Author: Olivier Houchard <ohouchard@haproxy.com>
+Date:   Fri Jan 18 17:26:26 2019 +0100
+
+    MINOR: lists: Implement locked variations.
+    
+    Implement LIST_ADD_LOCKED(), LIST_ADDQ_LOCKED(), LIST_DEL_LOCKED() and
+    LIST_POP_LOCKED().
+    
+    LIST_ADD_LOCKED, LIST_ADDQ_LOCKED and LIST_DEL_LOCKED work the same as
+    LIST_ADD, LIST_ADDQ and LIST_DEL, except before any manipulation it locks
+    the relevant elements of the list, so it's safe to manipulate the list
+    with multiple threads.
+    LIST_POP_LOCKED() removes the first element from the list, and returns its
+    data.
+    
+    (cherry picked from commit a8434ec14612d9a04e50e1c51e58f663dad46e96)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 15a9450b508a3c9fc2ad2463931e89157c4331f1)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 2988d2c2..b3f396ef 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -163,5 +163,149 @@ struct cond_wordlist {
+ 	     &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;                                       \
++			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)->n = p;                               \
++				__ha_barrier_store();                      \
++				continue;                                  \
++			}                                                  \
++			(el)->n = n;                                       \
++			(el)->p = p;                                       \
++			n->p = (el);                                       \
++			__ha_barrier_store();                              \
++			p->n = (el);                                       \
++			__ha_barrier_store();                              \
++			break;                                             \
++		}                                                          \
++	} while (0)
++
++#define LIST_DEL_LOCKED(el)                                                \
++	do {                                                               \
++		while (1) {                                                \
++			struct list *n, *n2;                               \
++			struct list *p, *p2;                               \
++			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) {                    \
++					p2->n = (el);                      \
++					(el)->p = p;                       \
++					(el)->n = n;                       \
++					__ha_barrier_store();              \
++					continue;                          \
++				}                                          \
++			}                                                  \
++			n->p = p;                                          \
++			p->n = n;                                          \
++			__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;                             \
++				 _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;                                 \
++				 (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;                                 \
++				 (lh)->n = n;                              \
++				 __ha_barrier_store();                     \
++				 continue;                                 \
++			 }                                                 \
++			 (lh)->n = n2;                                     \
++			 (n2)->p = (lh);                                   \
++			 __ha_barrier_store();                             \
++			 _ret = LIST_ELEM(n, pt, el);                      \
++			 break;                                            \
++		 }                                                         \
++		 (_ret);                                                   \
++	 })
+ 
+ #endif /* _COMMON_MINI_CLIST_H */
diff --git a/net/haproxy/patches/028-BUG-MEDIUM-lists-Properly-handle-the-case-were-removing-the-first-elt.patch b/net/haproxy/patches/028-BUG-MEDIUM-lists-Properly-handle-the-case-were-removing-the-first-elt.patch
new file mode 100644
index 000000000..80306cea6
--- /dev/null
+++ b/net/haproxy/patches/028-BUG-MEDIUM-lists-Properly-handle-the-case-were-removing-the-first-elt.patch
@@ -0,0 +1,37 @@
+commit 982bf2a0481648a0885b100cc565add399762028
+Author: Olivier Houchard <ohouchard@haproxy.com>
+Date:   Tue Feb 26 18:46:07 2019 +0100
+
+    BUG/MEDIUM: lists: Properly handle the case we're removing the first elt.
+    
+    In LIST_DEL_LOCKED(), initialize p2 to NULL, and only attempt to set it back
+    to its previous value if we had a previous element, and thus p2 is non-NULL.
+    
+    (cherry picked from commit db64489aac2135c6ceceec47fe98dc42c0558466)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit a3d6a2b9dac9775c55a10ed6b60deca219f06ff6)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index b3f396ef..aebeec38 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -226,7 +226,7 @@ struct cond_wordlist {
+ 	do {                                                               \
+ 		while (1) {                                                \
+ 			struct list *n, *n2;                               \
+-			struct list *p, *p2;                               \
++			struct list *p, *p2 = NULL;                        \
+ 			n = HA_ATOMIC_XCHG(&(el)->n, LLIST_BUSY);          \
+ 			if (n == LLIST_BUSY)                               \
+ 			        continue;                                  \
+@@ -248,7 +248,8 @@ struct cond_wordlist {
+ 			if (n != (el)) {                                   \
+ 			        n2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY);    \
+ 				if (n2 == LLIST_BUSY) {                    \
+-					p2->n = (el);                      \
++					if (p2 != NULL)                    \
++						p2->n = (el);              \
+ 					(el)->p = p;                       \
+ 					(el)->n = n;                       \
+ 					__ha_barrier_store();              \
diff --git a/net/haproxy/patches/029-BUG-MEDIUM-list-fix-the-rollback-on-addq-in-the-locked-liss.patch b/net/haproxy/patches/029-BUG-MEDIUM-list-fix-the-rollback-on-addq-in-the-locked-liss.patch
new file mode 100644
index 000000000..f959dd88d
--- /dev/null
+++ b/net/haproxy/patches/029-BUG-MEDIUM-list-fix-the-rollback-on-addq-in-the-locked-liss.patch
@@ -0,0 +1,33 @@
+commit 66322aef6533597ed5100916696c0f552513911d
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 11:09:56 2019 +0100
+
+    BUG/MEDIUM: list: fix the rollback on addq in the locked liss
+    
+    Commit a8434ec14 ("MINOR: lists: Implement locked variations.")
+    introduced locked lists which use the elements pointers as locks
+    for concurrent operations. A copy-paste typo in LIST_ADDQ_LOCKED()
+    causes corruption in the list in case the next pointer is already
+    held, as it restores the previous pointer into the next one. It
+    may impact the server pools.
+    
+    This will have to be backported if the commit above is backported.
+    
+    (cherry picked from commit bd20ad58748eafbded464f574ed84dbbdad31e8d)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit d4b726dc9e1659cb7fe3508862dfa8b3d23d823a)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index aebeec38..779f81da 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -208,7 +208,7 @@ struct cond_wordlist {
+ 			__ha_barrier_store();                              \
+ 			n = HA_ATOMIC_XCHG(&p->n, LLIST_BUSY);             \
+ 			if (n == LLIST_BUSY) {                             \
+-				(lh)->n = p;                               \
++				(lh)->p = p;                               \
+ 				__ha_barrier_store();                      \
+ 				continue;                                  \
+ 			}                                                  \
diff --git a/net/haproxy/patches/030-BUG-MEDIUM-list-fix-LIST_POP_LOCKEDs-removal-of-the-last-pointer.patch b/net/haproxy/patches/030-BUG-MEDIUM-list-fix-LIST_POP_LOCKEDs-removal-of-the-last-pointer.patch
new file mode 100644
index 000000000..92ff5a0ee
--- /dev/null
+++ b/net/haproxy/patches/030-BUG-MEDIUM-list-fix-LIST_POP_LOCKEDs-removal-of-the-last-pointer.patch
@@ -0,0 +1,34 @@
+commit 8caa2434cd52ac4056f4ec32b423d11a4dc7eaf5
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 15:55:18 2019 +0100
+
+    BUG/MEDIUM: list: fix LIST_POP_LOCKED's removal of the last pointer
+    
+    There was a typo making the last updated pointer be the pre-last element's
+    prev instead of the last's prev element. It didn't show up during early
+    tests because the contention is very rare on this one  and it's implicitly
+    recovered when updating the pointers to go to the next element, but it was
+    clearly visible in the listener_accept() tests by having all threads block
+    on LIST_POP_LOCKED() with n==p==LLIST_BUSY.
+    
+    This will have to be backported if commit a8434ec14 ("MINOR: lists:
+    Implement locked variations.") is backported.
+    
+    (cherry picked from commit 285192564d2a7d6eff077d91758b603ba7f2b10a)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 20fcf3a0e188551ef185c02c7fb28314de6e412e)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 779f81da..51c61051 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -292,7 +292,7 @@ struct cond_wordlist {
+ 				 __ha_barrier_store();                     \
+ 				 continue;                                 \
+ 			 }                                                 \
+-			 p2 = HA_ATOMIC_XCHG(&n2->p, LLIST_BUSY);          \
++			 p2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY);           \
+ 			 if (p2 == LLIST_BUSY) {                           \
+ 				 n->n = n2;                                \
+ 				 n->p = p;                                 \
diff --git a/net/haproxy/patches/031-BUG-MEDIUM-list-add-missing-store-barriers-when-updating-elements-and-head.patch b/net/haproxy/patches/031-BUG-MEDIUM-list-add-missing-store-barriers-when-updating-elements-and-head.patch
new file mode 100644
index 000000000..a4810c795
--- /dev/null
+++ b/net/haproxy/patches/031-BUG-MEDIUM-list-add-missing-store-barriers-when-updating-elements-and-head.patch
@@ -0,0 +1,66 @@
+commit cee000f97c9300dbbae50118838c6d3e8d5eb9cf
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 11:14:22 2019 +0100
+
+    BUG/MEDIUM: list: add missing store barriers when updating elements and head
+    
+    Commit a8434ec14 ("MINOR: lists: Implement locked variations.")
+    introduced locked lists which use the elements pointers as locks
+    for concurrent operations. Under heavy stress the lists occasionally
+    fail. The cause is a missing barrier at some points when updating
+    the list element and the head : nothing prevents the compiler (or
+    CPU) from updating the list head first before updating the element,
+    making another thread jump to a wrong location. This patch simply
+    adds the missing barriers before these two opeations.
+    
+    This will have to be backported if the commit above is backported.
+    
+    (cherry picked from commit 690d2ad4d207da5c8821b84ab467090bd515eedf)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit c2aa5cb8b8ff3af27f1a962541e53f792745bc4a)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 51c61051..92a995c9 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -189,6 +189,7 @@ struct cond_wordlist {
+ 			}                                                  \
+ 			(el)->n = n;                                       \
+ 			(el)->p = p;                                       \
++			__ha_barrier_store();                              \
+ 			n->p = (el);                                       \
+ 			__ha_barrier_store();                              \
+ 			p->n = (el);                                       \
+@@ -214,6 +215,7 @@ struct cond_wordlist {
+ 			}                                                  \
+ 			(el)->n = n;                                       \
+ 			(el)->p = p;                                       \
++			__ha_barrier_store();                              \
+ 			n->p = (el);                                       \
+ 			__ha_barrier_store();                              \
+ 			p->n = (el);                                       \
+@@ -276,6 +278,7 @@ struct cond_wordlist {
+ 			         continue;                                 \
+ 			 if (n == (lh)) {                                  \
+ 				 (lh)->n = lh;                             \
++				 __ha_barrier_store();                     \
+ 				 _ret = NULL;                              \
+ 				 break;                                    \
+ 			 }                                                 \
+@@ -288,6 +291,7 @@ struct cond_wordlist {
+ 			 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;                                 \
+@@ -296,6 +300,7 @@ struct cond_wordlist {
+ 			 if (p2 == LLIST_BUSY) {                           \
+ 				 n->n = n2;                                \
+ 				 n->p = p;                                 \
++				 __ha_barrier_store();                     \
+ 				 (lh)->n = n;                              \
+ 				 __ha_barrier_store();                     \
+ 				 continue;                                 \
diff --git a/net/haproxy/patches/032-MINOR-list-make-the-delete-and-pop-operations-idempotent.patch b/net/haproxy/patches/032-MINOR-list-make-the-delete-and-pop-operations-idempotent.patch
new file mode 100644
index 000000000..292b1a4b9
--- /dev/null
+++ b/net/haproxy/patches/032-MINOR-list-make-the-delete-and-pop-operations-idempotent.patch
@@ -0,0 +1,44 @@
+commit f4be23cefd779894ca85680d85b1d66cd22d42b6
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 15:05:53 2019 +0100
+
+    MINOR: list: make the delete and pop operations idempotent
+    
+    These operations previously used to return a "locked" element, which is
+    a constraint when multiple threads try to delete the same element, because
+    the second one will block indefinitely. Instead, let's make sure that both
+    LIST_DEL_LOCKED() and LIST_POP_LOCKED() always reinitialize the element
+    after deleting it. This ensures that the second thread will immediately
+    unblock and succeed with the removal. It also secures the pop vs delete
+    competition that may happen when trying to remove an element that's about
+    to be dequeued.
+    
+    (cherry picked from commit 4c747e86cda5d7eab46390779447f216ce9aa5de)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 731853a3e19b2ce314c1626360dc5b1dcba5baa1)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 92a995c9..d4861ccc 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -261,6 +261,9 @@ struct cond_wordlist {
+ 			n->p = p;                                          \
+ 			p->n = n;                                          \
+ 			__ha_barrier_store();                              \
++			(el)->p = (el);                                    \
++			(el)->n = (el);	                                   \
++			__ha_barrier_store();                              \
+ 			break;                                             \
+ 		}                                                          \
+ 	} while (0)
+@@ -308,6 +311,9 @@ struct cond_wordlist {
+ 			 (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;                                            \
+ 		 }                                                         \
diff --git a/net/haproxy/patches/033-BUG-MEDIUM-list-correct-fix-for-LIST_POP_LOCKEDs-removal-of-last-element.patch b/net/haproxy/patches/033-BUG-MEDIUM-list-correct-fix-for-LIST_POP_LOCKEDs-removal-of-last-element.patch
new file mode 100644
index 000000000..3a22df987
--- /dev/null
+++ b/net/haproxy/patches/033-BUG-MEDIUM-list-correct-fix-for-LIST_POP_LOCKEDs-removal-of-last-element.patch
@@ -0,0 +1,44 @@
+commit c4a54648f510771e792ed0c0bc16e4cf8be8bb9a
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 16:51:28 2019 +0100
+
+    BUG/MEDIUM: list: correct fix for LIST_POP_LOCKED's removal of last element
+    
+    As seen with Olivier, in the end the fix in commit 285192564 ("BUG/MEDIUM:
+    list: fix LIST_POP_LOCKED's removal of the last pointer") is wrong,
+    the code there was right but the bug was triggered by another bug in
+    LIST_ADDQ_LOCKED() which doesn't properly update the list's head by
+    inserting in the wrong order.
+    
+    This will have to be backported if the commit above is backported.
+    
+    (cherry picked from commit 4ef6801cd4db450b4ac3a21e58ca5fce5256189b)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 92f771c7efd9a82ef189d2be7c2fcfa6a6703e07)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index d4861ccc..9ad53aa0 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -216,9 +216,9 @@ struct cond_wordlist {
+ 			(el)->n = n;                                       \
+ 			(el)->p = p;                                       \
+ 			__ha_barrier_store();                              \
+-			n->p = (el);                                       \
++			n->n = (el);                                       \
+ 			__ha_barrier_store();                              \
+-			p->n = (el);                                       \
++			p->p = (el);                                       \
+ 			__ha_barrier_store();                              \
+ 			break;                                             \
+ 		}                                                          \
+@@ -299,7 +299,7 @@ struct cond_wordlist {
+ 				 __ha_barrier_store();                     \
+ 				 continue;                                 \
+ 			 }                                                 \
+-			 p2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY);           \
++			 p2 = HA_ATOMIC_XCHG(&n2->p, LLIST_BUSY);          \
+ 			 if (p2 == LLIST_BUSY) {                           \
+ 				 n->n = n2;                                \
+ 				 n->p = p;                                 \
diff --git a/net/haproxy/patches/034-BUG-MEDIUM-list-fix-again-LIST_ADDQ_LOCKED.patch b/net/haproxy/patches/034-BUG-MEDIUM-list-fix-again-LIST_ADDQ_LOCKED.patch
new file mode 100644
index 000000000..5a4770ab0
--- /dev/null
+++ b/net/haproxy/patches/034-BUG-MEDIUM-list-fix-again-LIST_ADDQ_LOCKED.patch
@@ -0,0 +1,43 @@
+commit 43dbd48e8f39b56f77493a4a0e786bd310a8e682
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Mon Mar 4 11:19:49 2019 +0100
+
+    BUG/MEDIUM: list: fix again LIST_ADDQ_LOCKED
+    
+    Well, that's becoming embarrassing. Now this fixes commit 4ef6801c
+    ("BUG/MEDIUM: list: correct fix for LIST_POP_LOCKED's removal of last
+    element") which itself tried to fix commit 285192564. This fix only
+    works under low contention and was tested with the listener's queue.
+    With the idle conns it's obvious that it's still wrong since adding
+    more than one element to the list leaves a LLIST_BUSY pointer into
+    the list's head. This was visible when accumulating idle connections
+    in a server's list.
+    
+    This new version of the fix almost goes back to the original code,
+    except that since then we addressed issues with expectedly idempotent
+    operations that were not. Now the code has been verified on paper again
+    and has survived 300 million connections spread over 4 threads.
+    
+    This will have to be backported if the commit above is backported.
+    
+    (cherry picked from commit 967de20a43665715e4513c7cc7a67e36a36a9955)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 76eeabc45943cc6a493a2212130cedcde803e432)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 9ad53aa0..27128a2c 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -216,9 +216,9 @@ struct cond_wordlist {
+ 			(el)->n = n;                                       \
+ 			(el)->p = p;                                       \
+ 			__ha_barrier_store();                              \
+-			n->n = (el);                                       \
++			p->n = (el);                                       \
+ 			__ha_barrier_store();                              \
+-			p->p = (el);                                       \
++			n->p = (el);                                       \
+ 			__ha_barrier_store();                              \
+ 			break;                                             \
+ 		}                                                          \
diff --git a/net/haproxy/patches/035-BUG-MEDIUM-list-fix-incorrect-pointer-unlocking-in-LIST_DEL_LOCKED.patch b/net/haproxy/patches/035-BUG-MEDIUM-list-fix-incorrect-pointer-unlocking-in-LIST_DEL_LOCKED.patch
new file mode 100644
index 000000000..c1b0d3127
--- /dev/null
+++ b/net/haproxy/patches/035-BUG-MEDIUM-list-fix-incorrect-pointer-unlocking-in-LIST_DEL_LOCKED.patch
@@ -0,0 +1,32 @@
+commit 4c20fedc4302aec6e5f4409274b832d524aef44d
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Wed Mar 13 14:03:28 2019 +0100
+
+    BUG/MEDIUM: list: fix incorrect pointer unlocking in LIST_DEL_LOCKED()
+    
+    Injecting on a saturated listener started to exhibit some deadlocks
+    again between LIST_POP_LOCKED() and LIST_DEL_LOCKED(). Olivier found
+    it was due to a leftover from a previous debugging session. This patch
+    fixes it.
+    
+    This will have to be backported if the other LIST_*_LOCKED() patches
+    are backported.
+    
+    (cherry picked from commit b0cef35b097c89ff675e055186e71239e105eb01)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit bf7cc16958e288219989949add02c8a97ed9cf6f)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
+index 27128a2c..454089ff 100644
+--- a/include/common/mini-clist.h
++++ b/include/common/mini-clist.h
+@@ -251,7 +251,7 @@ struct cond_wordlist {
+ 			        n2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY);    \
+ 				if (n2 == LLIST_BUSY) {                    \
+ 					if (p2 != NULL)                    \
+-						p2->n = (el);              \
++						p->n = p2;                 \
+ 					(el)->p = p;                       \
+ 					(el)->n = n;                       \
+ 					__ha_barrier_store();              \
diff --git a/net/haproxy/patches/036-MAJOR-listener-do-not-hold-the-listener-lock-in-listener_accept.patch b/net/haproxy/patches/036-MAJOR-listener-do-not-hold-the-listener-lock-in-listener_accept.patch
new file mode 100644
index 000000000..f30696cdc
--- /dev/null
+++ b/net/haproxy/patches/036-MAJOR-listener-do-not-hold-the-listener-lock-in-listener_accept.patch
@@ -0,0 +1,274 @@
+commit db4bf546d72a37f998a7bf25f00126611af58184
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Mon Feb 25 19:23:37 2019 +0100
+
+    MAJOR: listener: do not hold the listener lock in listener_accept()
+    
+    This function used to hold the listener's lock as a way to stay safe
+    against concurrent manipulations, but it turns out this is wrong. First,
+    the lock is held during l->accept(), which itself might indirectly call
+    listener_release(), which, if the listener is marked full, could result
+    in __resume_listener() to be called and the lock being taken twice. In
+    practice it doesn't happen right now because the listener's FULL state
+    cannot change while we're doing this.
+    
+    Second, all the code does is now protected against concurrent accesses.
+    It used not to be the case in the early days of threads : the frequency
+    counters are thread-safe. The rate limiting doesn't require extreme
+    precision. Only the nbconn check is not thread safe.
+    
+    Third, the parts called here will have to be called from different
+    threads without holding this lock, and this becomes a bigger issue
+    if we need to keep this one.
+    
+    This patch does 3 things which need to be addressed at once :
+      1) it moves the lock to the only 2 functions that were not protected
+         since called form listener_accept() :
+         - limit_listener()
+         - listener_full()
+    
+      2) it makes sure delete_listener() properly checks its state within
+         the lock.
+    
+      3) it updates the l->nbconn tracking to make sure that it is always
+         properly reported and accounted for. There is a point of particular
+         care around the situation where the listener's maxconn is reached
+         because the listener has to be marked full before accepting the
+         connection, then resumed if the connection finally gets dropped.
+         It is not possible to perform this change without removing the
+         lock due to the deadlock issue explained above.
+    
+    This patch almost doubles the accept rate in multi-thread on a shared
+    port between 8 threads, and multiplies by 4 the connection rate on a
+    tcp-request connection reject rule.
+    
+    (cherry picked from commit 3f0d02bbc2d12cd083fe1c1a051c42cdccb7bc4a)
+    [wt: this patch is mandatory for the next fixes to be backported,
+     it has been cooking almost 2 months in 2.0 with no bad behaviour
+     and seems reasonable to backport now]
+    
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit b44ae2d0a6eeffe2af3edd37f7829a8d26b85d43)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/listener.c b/src/listener.c
+index 45d9c252..9ef3d5e8 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -226,32 +226,30 @@ int resume_listener(struct listener *l)
+ 
+ /* 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);
+ 		}
+-
+-		fd_stop_recv(l->fd);
+-		l->state = LI_FULL;
++		if (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);
+@@ -259,6 +257,7 @@ static void limit_listener(struct listener *l, struct list *list)
+ 		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
+@@ -422,15 +421,14 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
+  */
+ 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);
+ }
+ 
+@@ -443,6 +441,7 @@ void listener_accept(int fd)
+ 	struct listener *l = fdtab[fd].owner;
+ 	struct proxy *p;
+ 	int max_accept;
++	int next_conn = 0;
+ 	int expire;
+ 	int cfd;
+ 	int ret;
+@@ -454,8 +453,6 @@ void listener_accept(int fd)
+ 		return;
+ 	p = l->bind_conf->frontend;
+ 	max_accept = l->maxaccept ? l->maxaccept : 1;
+-	if (HA_SPIN_TRYLOCK(LISTENER_LOCK, &l->lock))
+-		return;
+ 
+ 	if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) {
+ 		int max = freq_ctr_remain(&global.sess_per_sec, global.sps_lim, 0);
+@@ -515,11 +512,29 @@ void listener_accept(int fd)
+ 	 * worst case. If we fail due to system limits or temporary resource
+ 	 * shortage, we try again 100ms later in the worst case.
+ 	 */
+-	while (l->nbconn < l->maxconn && max_accept--) {
++	for (; max_accept-- > 0; next_conn = 0) {
+ 		struct sockaddr_storage addr;
+ 		socklen_t laddr = sizeof(addr);
+ 		unsigned int count;
+ 
++		/* pre-increase the number of connections without going too far */
++		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, &count, next_conn));
++
++		if (next_conn == l->maxconn) {
++			/* we filled it, mark it full */
++			listener_full(l);
++		}
++
+ 		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 */
+@@ -562,6 +577,7 @@ void listener_accept(int fd)
+ 				goto transient_error;
+ 			case EINTR:
+ 			case ECONNABORTED:
++				HA_ATOMIC_SUB(&l->nbconn, 1);
+ 				continue;
+ 			case ENFILE:
+ 				if (p)
+@@ -588,26 +604,34 @@ void listener_accept(int fd)
+ 			}
+ 		}
+ 
++		/* The connection was accepted, it must be counted as such */
++		if (l->counters)
++			HA_ATOMIC_UPDATE_MAX(&l->counters->conn_max, next_conn);
++
++		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);
++		}
++
+ 		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",
+ 				 p->id);
++			if (!(l->options & LI_O_UNLIMITED))
++				HA_ATOMIC_SUB(&actconn, 1);
+ 			close(cfd);
+ 			limit_listener(l, &global_listener_queue);
+ 			task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
+ 			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 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;
+ 
+ 		ret = l->accept(l, cfd, &addr);
+ 		if (unlikely(ret <= 0)) {
+@@ -622,7 +646,9 @@ void listener_accept(int fd)
+ 			goto transient_error;
+ 		}
+ 
+-		/* 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);
+@@ -634,7 +660,7 @@ void listener_accept(int fd)
+ 		}
+ #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:
+@@ -649,10 +675,21 @@ void listener_accept(int fd)
+ 	limit_listener(l, &global_listener_queue);
+ 	task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire));
+  end:
+-	if (l->nbconn >= l->maxconn)
+-		listener_full(l);
++	if (next_conn)
++		HA_ATOMIC_SUB(&l->nbconn, 1);
+ 
+-	HA_SPIN_UNLOCK(LISTENER_LOCK, &l->lock);
++	if (l->nbconn < l->maxconn && l->state == LI_FULL) {
++		/* 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
diff --git a/net/haproxy/patches/037-BUG-MEDIUM-listener-use-a-self-locked-list-for-the-dequeue-lists.patch b/net/haproxy/patches/037-BUG-MEDIUM-listener-use-a-self-locked-list-for-the-dequeue-lists.patch
new file mode 100644
index 000000000..f565f9282
--- /dev/null
+++ b/net/haproxy/patches/037-BUG-MEDIUM-listener-use-a-self-locked-list-for-the-dequeue-lists.patch
@@ -0,0 +1,247 @@
+commit e75d8efec35de2d22d14bf03f4aa9b8490658788
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Thu Feb 28 10:27:18 2019 +0100
+
+    BUG/MEDIUM: listener: use a self-locked list for the dequeue lists
+    
+    There is a very difficult to reproduce race in the listener's accept
+    code, which is much easier to reproduce once connection limits are
+    properly enforced. It's an ABBA lock issue :
+    
+      - the following functions take l->lock then lq_lock :
+          disable_listener, pause_listener, listener_full, limit_listener,
+          do_unbind_listener
+    
+      - the following ones take lq_lock then l->lock :
+          resume_listener, dequeue_all_listener
+    
+    This is because __resume_listener() only takes the listener's lock
+    and expects to be called with lq_lock held. The problem can easily
+    happen when listener_full() and limit_listener() are called a lot
+    while in parallel another thread releases sessions for the same
+    listener using listener_release() which in turn calls resume_listener().
+    
+    This scenario is more prevalent in 2.0-dev since the removal of the
+    accept lock in listener_accept(). However in 1.9 and before, a different
+    but extremely unlikely scenario can happen :
+    
+          thread1                                  thread2
+             ............................  enter listener_accept()
+      limit_listener()
+             ............................  long pause before taking the lock
+      session_free()
+        dequeue_all_listeners()
+          lock(lq_lock) [1]
+             ............................  try_lock(l->lock) [2]
+          __resume_listener()
+            spin_lock(l->lock) =>WAIT[2]
+             ............................  accept()
+                                           l->accept()
+                                           nbconn==maxconn =>
+                                             listener_full()
+                                               state==LI_LIMITED =>
+                                                 lock(lq_lock) =>DEADLOCK[1]!
+    
+    In practice it is almost impossible to trigger it because it requires
+    to limit both on the listener's maxconn and the frontend's rate limit,
+    at the same time, and to release the listener when the connection rate
+    goes below the limit between poll() returns the FD and the lock is
+    taken (a few nanoseconds). But maybe with threads competing on the
+    same core it has more chances to appear.
+    
+    This patch removes the lq_lock and replaces it with a lockless queue
+    for the listener's wait queue (well, technically speaking a self-locked
+    queue) brought by commit a8434ec14 ("MINOR: lists: Implement locked
+    variations.") and its few subsequent fixes. This relieves us from the
+    need of the lq_lock and removes the deadlock. It also gets rid of the
+    distinction between __resume_listener() and resume_listener() since the
+    only difference was the lq_lock. All listener removals from the list
+    are now unconditional to avoid races on the state. It's worth noting
+    that the list used to never be initialized and that it used to work
+    only thanks to the state tests, so the initialization has now been
+    added.
+    
+    This patch must carefully be backported to 1.9 and very likely 1.8.
+    It is mandatory to be careful about replacing all manipulations of
+    l->wait_queue, global.listener_queue and p->listener_queue.
+    
+    (cherry picked from commit 01abd025084b4fe50e84189d1a83499cbf4825ed)
+    [wt: there are some suspicions that this bug might have been hit in
+     1.9 so it's about time to backport this fix. All occurrences of the
+     elements switched to self-locked list were inspected and none of
+     them differred from 2.0so that the patch doesn't need to be adjusted]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 434c7f8419fc38b6ced1945fa4ce6e84c063e835)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/common/hathreads.h b/include/common/hathreads.h
+index 8a738aaf..8134839a 100644
+--- a/include/common/hathreads.h
++++ b/include/common/hathreads.h
+@@ -344,7 +344,6 @@ enum lock_label {
+ 	TASK_WQ_LOCK,
+ 	POOL_LOCK,
+ 	LISTENER_LOCK,
+-	LISTENER_QUEUE_LOCK,
+ 	PROXY_LOCK,
+ 	SERVER_LOCK,
+ 	UPDATED_SERVERS_LOCK,
+@@ -467,7 +466,6 @@ static inline const char *lock_label(enum lock_label label)
+ 	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 --git a/src/listener.c b/src/listener.c
+index 9ef3d5e8..dab07a5e 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -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 @@ static void disable_listener(struct listener *listener)
+ 		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 @@ int pause_listener(struct listener *l)
+ 			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 @@ int pause_listener(struct listener *l)
+  * 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 @@ static int __resume_listener(struct listener *l)
+ 	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,16 +202,6 @@ static int __resume_listener(struct listener *l)
+ 	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().
+  */
+@@ -231,11 +209,7 @@ 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;
+@@ -251,9 +225,7 @@ 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;
+ 	}
+@@ -292,17 +264,14 @@ int disable_all_listeners(struct protocol *proto)
+ /* 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
+@@ -313,11 +282,7 @@ void do_unbind_listener(struct listener *listener, int do_close)
+ 	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) {
+@@ -399,6 +364,7 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
+ 
+ 		l->fd = fd;
+ 		memcpy(&l->addr, ss, sizeof(*ss));
++		LIST_INIT(&l->wait_queue);
+ 		l->state = LI_INIT;
+ 
+ 		proto->add(l, port);
+@@ -1039,7 +1005,6 @@ static void __listener_init(void)
+ 	sample_register_fetches(&smp_kws);
+ 	acl_register_keywords(&acl_kws);
+ 	bind_register_keywords(&bind_kws);
+-	HA_SPIN_INIT(&lq_lock);
+ }
+ 
+ /*
diff --git a/net/haproxy/patches/038-BUG-MEDIUM-listener-make-sure-the-listener-never-accepts-too-many-conns.patch b/net/haproxy/patches/038-BUG-MEDIUM-listener-make-sure-the-listener-never-accepts-too-many-conns.patch
new file mode 100644
index 000000000..a1ca73b2e
--- /dev/null
+++ b/net/haproxy/patches/038-BUG-MEDIUM-listener-make-sure-the-listener-never-accepts-too-many-conns.patch
@@ -0,0 +1,217 @@
+commit c98cdf7cc755c579a8b9cceee4809089267615ce
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Wed Feb 27 19:32:32 2019 +0100
+
+    BUG/MEDIUM: listener: make sure the listener never accepts too many conns
+    
+    We were not checking p->feconn nor the global actconn soon enough. In
+    older versions this could result in a frontend accepting more connections
+    than allowed by its maxconn or the global maxconn, exactly N-1 extra
+    connections where N is the number of threads, provided each of these
+    threads were running a different listener. But with the lock removal,
+    it became worse, the excess could be the listener's maxconn multiplied
+    by the number of threads. Among the nasty side effect was that LI_FULL
+    could be removed while the limit was still over and in some cases the
+    polling on the socket was no re-enabled.
+    
+    This commit takes care of updating and checking p->feconn and the global
+    actconn *before* processing the connection, so that the listener can be
+    turned off before accepting the socket if needed. This requires to move
+    some of the bookkeeping operations form session to listen, which totally
+    makes sense in this context.
+    
+    Now the limits are properly respected, even if a listener's maxconn is
+    over a frontend's. This only applies on top of the listener lock removal
+    series and doesn't have to be backported.
+    
+    (cherry picked from commit 82c9789ac4f0cba9a74d16c1b730fc64e1f95a6e)
+    [wt: backported since it fixes the previous patch set]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit f54a86a229e1ee4b256d5614c0a65924f447df09)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/listener.c b/src/listener.c
+index dab07a5e..68c84fbe 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -408,6 +408,8 @@ void listener_accept(int fd)
+ 	struct proxy *p;
+ 	int max_accept;
+ 	int next_conn = 0;
++	int next_feconn = 0;
++	int next_actconn = 0;
+ 	int expire;
+ 	int cfd;
+ 	int ret;
+@@ -478,12 +480,15 @@ void listener_accept(int fd)
+ 	 * worst case. If we fail due to system limits or temporary resource
+ 	 * shortage, we try again 100ms later in the worst case.
+ 	 */
+-	for (; max_accept-- > 0; next_conn = 0) {
++	for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) {
+ 		struct sockaddr_storage addr;
+ 		socklen_t laddr = sizeof(addr);
+ 		unsigned int count;
+ 
+-		/* pre-increase the number of connections without going too far */
++		/* 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) {
+@@ -501,15 +506,42 @@ void listener_accept(int fd)
+ 			listener_full(l);
+ 		}
+ 
+-		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;
++		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 (unlikely(p && p->feconn >= p->maxconn)) {
+-			limit_listener(l, &p->listener_queue);
+-			goto end;
++		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, &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
+@@ -544,6 +576,10 @@ void listener_accept(int fd)
+ 			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)
+@@ -574,18 +610,20 @@ void listener_accept(int fd)
+ 		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);
+-			HA_ATOMIC_ADD(&actconn, 1);
+ 		}
+ 
+ 		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",
+ 				 p->id);
+-			if (!(l->options & LI_O_UNLIMITED))
+-				HA_ATOMIC_SUB(&actconn, 1);
+ 			close(cfd);
+ 			limit_listener(l, &global_listener_queue);
+ 			task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
+@@ -593,11 +631,13 @@ void listener_accept(int fd)
+ 		}
+ 
+ 		/* past this point, l->accept() will automatically decrement
+-		 * l->nbconn 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.
++		 * 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)) {
+@@ -644,7 +684,14 @@ void listener_accept(int fd)
+ 	if (next_conn)
+ 		HA_ATOMIC_SUB(&l->nbconn, 1);
+ 
+-	if (l->nbconn < l->maxconn && l->state == LI_FULL) {
++	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);
+ 
+@@ -668,8 +715,11 @@ void listener_release(struct listener *l)
+ 
+ 	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 */
+diff --git a/src/session.c b/src/session.c
+index b91d67ee..c1515261 100644
+--- a/src/session.c
++++ b/src/session.c
+@@ -53,10 +53,6 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type
+ 		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 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type
+ 
+ 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 --git a/net/haproxy/patches/039-BUILD-MINOR-listener-Silent-a-few-signedness-warnings.patch b/net/haproxy/patches/039-BUILD-MINOR-listener-Silent-a-few-signedness-warnings.patch
new file mode 100644
index 000000000..02a851ea7
--- /dev/null
+++ b/net/haproxy/patches/039-BUILD-MINOR-listener-Silent-a-few-signedness-warnings.patch
@@ -0,0 +1,37 @@
+commit 06ffb1175eb87684eaccb4fd7ac9d4936ca9b8f7
+Author: David Carlier <devnexen@gmail.com>
+Date:   Wed Mar 27 16:08:42 2019 +0000
+
+    BUILD/MINOR: listener: Silent a few signedness warnings.
+    
+    Silenting couple of warnings related to signedness, due to a mismatch of
+    signed and unsigned ints with l->nbconn, actconn and p->feconn.
+    
+    (cherry picked from commit 5671662f08536c979ff91bc46f94d086bf286540)
+    [wt: s/_HA/HA/]
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit f5e9bf696b0b46c140d742cee23d0d54df66bb2f)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/listener.c b/src/listener.c
+index 68c84fbe..821c931a 100644
+--- a/src/listener.c
++++ b/src/listener.c
+@@ -499,7 +499,7 @@ void listener_accept(int fd)
+ 				goto end;
+ 			}
+ 			next_conn = count + 1;
+-		} while (!HA_ATOMIC_CAS(&l->nbconn, &count, next_conn));
++		} while (!HA_ATOMIC_CAS(&l->nbconn, (int *)&count, next_conn));
+ 
+ 		if (next_conn == l->maxconn) {
+ 			/* we filled it, mark it full */
+@@ -536,7 +536,7 @@ void listener_accept(int fd)
+ 					goto end;
+ 				}
+ 				next_actconn = count + 1;
+-			} while (!HA_ATOMIC_CAS(&actconn, &count, next_actconn));
++			} while (!HA_ATOMIC_CAS(&actconn, (int *)&count, next_actconn));
+ 
+ 			if (unlikely(next_actconn == global.maxconn)) {
+ 				limit_listener(l, &global_listener_queue);
diff --git a/net/haproxy/patches/040-MINOR-skip-get_gmtime-where-tm-is-unused.patch b/net/haproxy/patches/040-MINOR-skip-get_gmtime-where-tm-is-unused.patch
new file mode 100644
index 000000000..fab1cb301
--- /dev/null
+++ b/net/haproxy/patches/040-MINOR-skip-get_gmtime-where-tm-is-unused.patch
@@ -0,0 +1,28 @@
+commit 5d9e3238ae9474051b2020a04af2cbb11b613f98
+Author: Robin H. Johnson <robbat2@gentoo.org>
+Date:   Wed Apr 10 21:08:15 2019 +0000
+
+    MINOR: skip get_gmtime where tm is unused
+    
+    For LOG_FMT_TS (%Ts), the tm variable is not used, so save some cycles
+    on the call to get_gmtime.
+    
+    Backport: 1.9 1.8
+    Signed-off-by: Robin H. Johnson <rjohnson@digitalocean.com>
+    (cherry picked from commit 543d4507ca4ddd9ece5eb4e869b20ee1d2afedac)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 0ab133673a28fb91679f2b8471ed13ce265aa8a6)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/log.c b/src/log.c
+index 9c112255..313fa55d 100644
+--- a/src/log.c
++++ b/src/log.c
+@@ -1651,7 +1651,6 @@ int build_logline(struct stream *s, char *dst, size_t maxsize, struct list *list
+ 				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 --git a/net/haproxy/patches/041-BUG-MAJOR-http_fetch-Get-the-channel-depending-on-the-keyword-used.patch b/net/haproxy/patches/041-BUG-MAJOR-http_fetch-Get-the-channel-depending-on-the-keyword-used.patch
new file mode 100644
index 000000000..3f8fb1c32
--- /dev/null
+++ b/net/haproxy/patches/041-BUG-MAJOR-http_fetch-Get-the-channel-depending-on-the-keyword-used.patch
@@ -0,0 +1,976 @@
+commit b05ee4aa74a95be49c78198ca601000b47c93da2
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Wed Apr 17 12:02:59 2019 +0200
+
+    BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
+    
+    All HTTP samples are buggy because the channel tested in the prefetch functions
+    (HTX and legacy HTTP) is chosen depending on the sample direction and not the
+    keyword really used. It means the request channel is used if the sample is
+    called during the request analysis and the response channel is used if it is
+    called during the response analysis, regardless the sample really called. For
+    instance, if you use the sample "req.ver" in an http-response rule, the response
+    channel will be prefeched because it is called during the response analysis,
+    while the request channel should have been used instead. So some assumptions on
+    the validity of the sample may be made on the wrong channel. It is the first
+    bug.
+    
+    Then the same error is done in some samples themselves. So fetches are performed
+    on the wrong channel. For instance, the header extraction (req.fhdr, res.fhdr,
+    req.hdr, res.hdr...). If the sample "req.hdr" is used in an http-response rule,
+    then the matching is done on the response headers and not the request ones. It
+    is the second bug.
+    
+    Finally, the last one but not the least, in some samples, the right channel is
+    used. But because the prefetch was done on the wrong one, this channel may be in
+    a undefined state. For instance, using the sample "req.ver" in an http-response
+    rule leads to a matching on a posibility released buffer.
+    
+    To fix all these bugs, the right channel is now chosen in sample fetches, before
+    the prefetch. If the same function is used to fetch requests and responses
+    elements, then the keyword is used to choose the right one. This channel is then
+    used by the functions smp_prefetch_htx() and smp_prefetch_http(). Of course, it
+    is also used by the samples themselves to extract information.
+    
+    This patch must be backported to all supported versions. For version 1.8 and
+    priors, it must be totally refactored. First because there is no HTX into these
+    versions. Then the buffers API has changed in HAProxy 1.9. The files
+    http_fetch.{ch} doesn't exist on old versions.
+    
+    (cherry picked from commit 89dc49935997856dd4f864b654d3601107ec1967)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit a89ca0b50b6b30ab75fbb7193a1132c0f89520fc)
+    [cf: Changes made in src/proto_http.c because src/http_fetch.c doesn't exist]
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
+index 50efff4c..a2b365da 100644
+--- a/include/proto/proto_http.h
++++ b/include/proto/proto_http.h
+@@ -132,7 +132,7 @@ struct action_kw *action_http_res_custom(const char *kw);
+ 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 @@ int parse_qvalue(const char *qvalue, const char **end);
+ /* 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 --git a/src/hlua.c b/src/hlua.c
+index 93cb86d2..d40c012a 100644
+--- a/src/hlua.c
++++ b/src/hlua.c
+@@ -6458,7 +6458,7 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st
+ 	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 --git a/src/proto_http.c b/src/proto_http.c
+index 8b087c5b..9beaa137 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -9447,6 +9447,8 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
+ /************************************************************************/
+ /*        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,
+@@ -9463,7 +9465,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st
+  *   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;
+@@ -9472,7 +9474,7 @@ int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
+ 	 * 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) {
+@@ -9481,78 +9483,78 @@ int smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
+ 		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 (unlikely(txn->req.msg_state < HTTP_MSG_BODY)) {
+-			if (msg->msg_state == HTTP_MSG_ERROR)
+-				return 0;
++	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;
++	}
+ 
+-			/* Try to decode HTTP request */
+-			if (likely(msg->next < s->req.buf->i))
+-				http_msg_analyzer(msg, &txn->hdr_idx);
++	/* Check for a dependency on a request */
++	msg = &txn->req;
+ 
+-			/* 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;
+@@ -9592,19 +9594,21 @@ static int pat_parse_meth(const char *text, struct pattern *pattern, int mflags,
+ 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;
+@@ -9646,15 +9650,16 @@ static struct pattern *pat_match_meth(struct sample *smp, struct pattern_expr *e
+ 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)
+@@ -9671,18 +9676,17 @@ smp_fetch_rqver(const struct arg *args, struct sample *smp, const char *kw, void
+ 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)
+@@ -9700,18 +9704,19 @@ smp_fetch_stver(const struct arg *args, struct sample *smp, const char *kw, void
+ 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);
+@@ -9746,20 +9751,21 @@ smp_fetch_uniqueid(const struct arg *args, struct sample *smp, const char *kw, v
+ 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;
+ }
+@@ -9780,7 +9786,7 @@ smp_fetch_hdrs(const struct arg *args, struct sample *smp, const char *kw, void
+ 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;
+@@ -9793,7 +9799,7 @@ smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, v
+ 	char *buf;
+ 	char *end;
+ 
+-	CHECK_HTTP_MESSAGE_FIRST();
++	CHECK_HTTP_MESSAGE_FIRST(chn);
+ 
+ 	temp = get_trash_chunk();
+ 	buf = temp->str;
+@@ -9801,11 +9807,10 @@ smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, v
+ 
+ 	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)
+@@ -9880,25 +9885,23 @@ smp_fetch_hdrs_bin(const struct arg *args, struct sample *smp, const char *kw, v
+ 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) */
+@@ -9911,7 +9914,7 @@ smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void
+ 		/* 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;
+@@ -9927,15 +9930,12 @@ smp_fetch_body(const struct arg *args, struct sample *smp, const char *kw, void
+ 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);
+ 
+@@ -9951,15 +9951,12 @@ smp_fetch_body_len(const struct arg *args, struct sample *smp, const char *kw, v
+ 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;
+ 
+@@ -9972,14 +9969,15 @@ smp_fetch_body_size(const struct arg *args, struct sample *smp, const char *kw,
+ 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;
+ }
+@@ -9987,13 +9985,14 @@ smp_fetch_url(const struct arg *args, struct sample *smp, const char *kw, void *
+ 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;
+ 
+@@ -10006,13 +10005,14 @@ smp_fetch_url_ip(const struct arg *args, struct sample *smp, const char *kw, voi
+ 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;
+ 
+@@ -10032,6 +10032,8 @@ smp_fetch_url_port(const struct arg *args, struct sample *smp, const char *kw, v
+ 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;
+@@ -10056,10 +10058,9 @@ smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char *kw, void
+ 			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 */
+@@ -10089,9 +10090,10 @@ smp_fetch_fhdr(const struct arg *args, struct sample *smp, const char *kw, void
+ 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;
+@@ -10101,14 +10103,12 @@ smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const char *kw, v
+ 		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;
+@@ -10120,24 +10120,24 @@ smp_fetch_fhdr_cnt(const struct arg *args, struct sample *smp, const char *kw, v
+ 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);
+@@ -10160,6 +10160,8 @@ smp_fetch_hdr_names(const struct arg *args, struct sample *smp, const char *kw,
+ 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;
+@@ -10184,10 +10186,10 @@ smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *
+ 			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 */
+@@ -10216,9 +10218,10 @@ smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void *
+ 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;
+@@ -10228,14 +10231,13 @@ smp_fetch_hdr_cnt(const struct arg *args, struct sample *smp, const char *kw, vo
+ 		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;
+@@ -10300,13 +10302,14 @@ smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const char *kw, voi
+ 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;
+@@ -10333,16 +10336,17 @@ smp_fetch_path(const struct arg *args, struct sample *smp, const char *kw, void
+ 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 */
+@@ -10353,7 +10357,7 @@ smp_fetch_base(const struct arg *args, struct sample *smp, const char *kw, void
+ 	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;
+@@ -10380,17 +10384,18 @@ smp_fetch_base(const struct arg *args, struct sample *smp, const char *kw, void
+ 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;
+@@ -10399,7 +10404,7 @@ smp_fetch_base32(const struct arg *args, struct sample *smp, const char *kw, voi
+ 	}
+ 
+ 	/* 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;
+@@ -10466,13 +10471,14 @@ smp_fetch_base32_src(const struct arg *args, struct sample *smp, const char *kw,
+ 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 '?' */
+@@ -10491,11 +10497,13 @@ smp_fetch_query(const struct arg *args, struct sample *smp, const char *kw, void
+ 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;
+@@ -10515,11 +10523,12 @@ smp_fetch_http_first_req(const struct arg *args, struct sample *smp, const char
+ 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;
+@@ -10534,10 +10543,12 @@ smp_fetch_http_auth(const struct arg *args, struct sample *smp, const char *kw,
+ 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;
+@@ -10828,10 +10839,10 @@ smp_fetch_capture_res_ver(const struct arg *args, struct sample *smp, const char
+  */
+ 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;
+@@ -10848,17 +10859,14 @@ int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw,
+ 		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;
+ 	}
+@@ -10872,7 +10880,7 @@ int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw,
+ 	 * 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.
+@@ -10929,10 +10937,10 @@ int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw,
+ 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;
+@@ -10942,22 +10950,19 @@ smp_fetch_cookie_cnt(const struct arg *args, struct sample *smp, const char *kw,
+ 	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;
+@@ -11287,6 +11292,7 @@ smp_fetch_param(char delim, const char *name, int name_len, const struct arg *ar
+ 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;
+@@ -11308,16 +11314,16 @@ smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw,
+ 		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.
+@@ -11339,6 +11345,7 @@ smp_fetch_url_param(const struct arg *args, struct sample *smp, const char *kw,
+ 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;
+@@ -11357,19 +11364,15 @@ smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw,
+ 	}
+ 
+ 	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) */
+@@ -11386,8 +11389,8 @@ smp_fetch_body_param(const struct arg *args, struct sample *smp, const char *kw,
+ 			/* 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);
+@@ -11422,17 +11425,18 @@ smp_fetch_url_param_val(const struct arg *args, struct sample *smp, const char *
+ 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;
+@@ -11441,7 +11445,7 @@ smp_fetch_url32(const struct arg *args, struct sample *smp, const char *kw, void
+ 	}
+ 
+ 	/* 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 --git a/net/haproxy/patches/042-BUG-MEDIUM-maps-only-try-to-parse-the-default-value-when-its-present.patch b/net/haproxy/patches/042-BUG-MEDIUM-maps-only-try-to-parse-the-default-value-when-its-present.patch
new file mode 100644
index 000000000..9ba38fe8c
--- /dev/null
+++ b/net/haproxy/patches/042-BUG-MEDIUM-maps-only-try-to-parse-the-default-value-when-its-present.patch
@@ -0,0 +1,38 @@
+commit 814ca94cbcba61a11485dedf80f6b35c34e4d74b
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Apr 19 11:35:22 2019 +0200
+
+    BUG/MEDIUM: maps: only try to parse the default value when it's present
+    
+    Maps returning an IP address (e.g. map_str_ip) support an optional
+    default value which must be parsed. Unfortunately the parsing code does
+    not check for this argument's existence and uncondtionally tries to
+    resolve the argument whenever the output is of type address, resulting
+    in segfaults at parsing time when no such argument is provided. This
+    patch adds the appropriate check.
+    
+    This fix may be backported as far as 1.6.
+    
+    (cherry picked from commit aa5801bcaade82ce58b9a70f320b7d0389e444b0)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit 0ad6d18945467f4d6defaad619ae49f939770ba2)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/map.c b/src/map.c
+index da399088..211d1911 100644
+--- a/src/map.c
++++ b/src/map.c
+@@ -142,10 +142,10 @@ int sample_load_map(struct arg *arg, struct sample_conv *conv,
+ 	                            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 --git a/net/haproxy/patches/043-BUG-MINOR-acl-properly-detect-pattern-type-SMP_T_ADDR.patch b/net/haproxy/patches/043-BUG-MINOR-acl-properly-detect-pattern-type-SMP_T_ADDR.patch
new file mode 100644
index 000000000..1c03f87a0
--- /dev/null
+++ b/net/haproxy/patches/043-BUG-MINOR-acl-properly-detect-pattern-type-SMP_T_ADDR.patch
@@ -0,0 +1,34 @@
+commit 4aa6348c04bc854b1dc47227b6931d43e704968d
+Author: Willy Tarreau <w@1wt.eu>
+Date:   Fri Apr 19 11:45:20 2019 +0200
+
+    BUG/MINOR: acl: properly detect pattern type SMP_T_ADDR
+    
+    Since 1.6-dev4 with commit b2f8f087f ("MINOR: map: The map can return
+    IPv4 and IPv6"), maps can return both IPv4 and IPv6 addresses, which
+    is represented as SMP_T_ADDR at the output of the map converter. But
+    the ACL parser only checks for either SMP_T_IPV4 or SMP_T_IPV6 and
+    requires to see an explicit matching method specified. Given that it
+    uses the same pattern parser for both address families, it implicitly
+    is also compatible with SMP_T_ADDR, which ought to have been added
+    there.
+    
+    This fix should be backported as far as 1.6.
+    
+    (cherry picked from commit 78c5eec9497e1e60565492bc69581aea439e54cc)
+    Signed-off-by: Willy Tarreau <w@1wt.eu>
+    (cherry picked from commit ce727199a5b1a7c58cce1b0cfe79b91c6c138935)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/acl.c b/src/acl.c
+index f19b2d20..42339b43 100644
+--- a/src/acl.c
++++ b/src/acl.c
+@@ -400,6 +400,7 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
+ 			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 --git a/net/haproxy/patches/044-BUG-MEDIUM-thread-http-Add-missing-locks-in-set-map-and-add-acl-HTTP-rules.patch b/net/haproxy/patches/044-BUG-MEDIUM-thread-http-Add-missing-locks-in-set-map-and-add-acl-HTTP-rules.patch
new file mode 100644
index 000000000..55ccfa6c2
--- /dev/null
+++ b/net/haproxy/patches/044-BUG-MEDIUM-thread-http-Add-missing-locks-in-set-map-and-add-acl-HTTP-rules.patch
@@ -0,0 +1,48 @@
+commit 8276ea30400887cb25186571ac62252da97b91df
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Fri Apr 19 14:50:55 2019 +0200
+
+    BUG/MEDIUM: thread/http: Add missing locks in set-map and add-acl HTTP rules
+    
+    Locks are missing in the rules "http-request set-map" and "http-response
+    add-acl" when an acl or map update is performed. Pattern elements must be
+    locked.
+    
+    This patch must be backported to 1.9 and 1.8. For the 1.8, the HTX part must be
+    ignored.
+    
+    (cherry picked from commit e84289e5854aa3b00cd19032387f435ca6748491)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit 82dedc4add923bd1ff1b47a559a23e83886521a8)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index 9beaa137..ccacd6a4 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -2717,12 +2717,14 @@ resume_execution:
+ 			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 @@ resume_execution:
+ 
+ 			/* 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;
diff --git a/net/haproxy/patches/045-BUG-MINOR-51d-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch b/net/haproxy/patches/045-BUG-MINOR-51d-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch
new file mode 100644
index 000000000..85d55548c
--- /dev/null
+++ b/net/haproxy/patches/045-BUG-MINOR-51d-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch
@@ -0,0 +1,30 @@
+commit 02fd3cd55a2232703494ad5c317907aba21783fe
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Fri Apr 19 15:22:29 2019 +0200
+
+    BUG/MINOR: 51d: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
+    
+    Since the commit 89dc49935 ("BUG/MAJOR: http_fetch: Get the channel depending on
+    the keyword used"), the right channel must be passed as argument when the macro
+    CHECK_HTTP_MESSAGE_FIRST is called.
+    
+    This patch must be backported to 1.9.
+    
+    (cherry picked from commit 2db9dac4c81bbb97b45c9f0ff73ed9fe24a2ba83)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit 4fc4c6a9d5effccab3f63909cc86bca452f1be1e)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/51d.c b/src/51d.c
+index 03101136..a0b683b1 100644
+--- a/src/51d.c
++++ b/src/51d.c
+@@ -384,7 +384,7 @@ static int _51d_fetch(const struct arg *args, struct sample *smp, const char *kw
+ 	 * 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*/
diff --git a/net/haproxy/patches/046-BUG-MINOR-da-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch b/net/haproxy/patches/046-BUG-MINOR-da-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch
new file mode 100644
index 000000000..a245ed003
--- /dev/null
+++ b/net/haproxy/patches/046-BUG-MINOR-da-Get-the-request-channel-to-call-CHECK_HTTP_MESSAGE_FIRST.patch
@@ -0,0 +1,30 @@
+commit 01d9157013729859fdb7470887d78d67a3cdf6b9
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Fri Apr 19 15:26:01 2019 +0200
+
+    BUG/MINOR: da: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
+    
+    Since the commit 89dc49935 ("BUG/MAJOR: http_fetch: Get the channel depending on
+    the keyword used"), the right channel must be passed as argument when the macro
+    CHECK_HTTP_MESSAGE_FIRST is called.
+    
+    This patch must be backported to 1.9.
+    
+    (cherry picked from commit f48552f2c10a2f956d7bd1eb02a6d694d2b5c5d3)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit 2a38fa09b588d8b30fabc77282e66ef613336ee7)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/da.c b/src/da.c
+index 685a79d1..cd4050bf 100644
+--- a/src/da.c
++++ b/src/da.c
+@@ -293,7 +293,7 @@ static int da_haproxy_fetch(const struct arg *args, struct sample *smp, const ch
+ 		return 1;
+ 	}
+ 
+-	CHECK_HTTP_MESSAGE_FIRST();
++	CHECK_HTTP_MESSAGE_FIRST((smp->strm ? &smp->strm->req : NULL));
+ 	smp->data.type = SMP_T_STR;
+ 
+ 	/**
diff --git a/net/haproxy/patches/047-BUG-MINOR-spoe-Dont-systematically-wakeup-SPOE-stream-in-the-applet-handler.patch b/net/haproxy/patches/047-BUG-MINOR-spoe-Dont-systematically-wakeup-SPOE-stream-in-the-applet-handler.patch
new file mode 100644
index 000000000..3165d8a7e
--- /dev/null
+++ b/net/haproxy/patches/047-BUG-MINOR-spoe-Dont-systematically-wakeup-SPOE-stream-in-the-applet-handler.patch
@@ -0,0 +1,29 @@
+commit 1526ce4e6f5fb241ca236bd2ac870cdb30e054fd
+Author: Christopher Faulet <cfaulet@haproxy.com>
+Date:   Tue Apr 23 15:39:32 2019 +0200
+
+    BUG/MINOR: spoe: Don't systematically wakeup SPOE stream in the applet handler
+    
+    This can lead to wakeups in loop between the SPOE stream and the SPOE applets
+    waiting to receive agent messages (mainly AGENT-HELLO and AGENT-DISCONNECT).
+    
+    This patch must be backported to 1.9 and 1.8.
+    
+    (cherry picked from commit 371723b0c2a2e38ae14e1e6f6a7581ef3e2491cf)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+    (cherry picked from commit fe0ccea6bb93406ca0a7339cdf17357b1a283e59)
+    Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
+
+diff --git a/src/flt_spoe.c b/src/flt_spoe.c
+index 95f30898..f6109778 100644
+--- a/src/flt_spoe.c
++++ b/src/flt_spoe.c
+@@ -1929,8 +1929,6 @@ spoe_handle_appctx(struct appctx *appctx)
+ 
+ 	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 = {
diff --git a/net/haproxy/patches/008-deprecated-openssl.patch b/net/haproxy/patches/048-deprecated-openssl.patch
similarity index 100%
rename from net/haproxy/patches/008-deprecated-openssl.patch
rename to net/haproxy/patches/048-deprecated-openssl.patch