[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#928461: marked as done (unblock: haproxy/1.8.20-1 (pre-approval))



Your message dated Sun, 5 May 2019 15:31:01 +0200
with message-id <20190505133059.saqjxn54dxtw6g3o@debian.org>
and subject line Re: unblock: haproxy/1.8.20-1 (pre-approval)
has caused the Debian Bug report #928461,
regarding unblock: haproxy/1.8.20-1 (pre-approval)
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
928461: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928461
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hey!

HAProxy 1.8.20 was released last week. This is a bugfix only release.

Upstream has stated his dislike of cherry-picking only some of the
fixes and would prefer us to ship a pristine 1.8.19 instead of a
patched version if we do not want to ship 1.8.20 as is. See the full
rationale here:
 <https://www.mail-archive.com/haproxy@formilux.org/msg33550.html>

Here is upstream changelog:

    - BUG/MAJOR: listener: Make sure the listener exist before using it.
    - BUG/MINOR: listener: keep accept rate counters accurate under saturation
    - BUG/MEDIUM: logs: Only attempt to free startup_logs once.
    - BUG/MEDIUM: 51d: fix possible segfault on deinit_51degrees()
    - BUG/MINOR: ssl: fix warning about ssl-min/max-ver support
    - MEDIUM: threads: Use __ATOMIC_SEQ_CST when using the newer atomic API.
    - BUG/MEDIUM: threads/fd: do not forget to take into account epoll_fd/pipes
    - BUG/MAJOR: spoe: Fix initialization of thread-dependent fields
    - BUG/MAJOR: stats: Fix how huge POST data are read from the channel
    - BUG/MINOR: http/counters: fix missing increment of fe->srv_aborts
    - BUG/MEDIUM: ssl: ability to set TLS 1.3 ciphers using ssl-default-server-ciphersuites
    - DOC: The option httplog is no longer valid in a backend.
    - BUG/MAJOR: checks: segfault during tcpcheck_main
    - BUILD: makefile: work around an old bug in GNU make-3.80
    - MINOR: tools: make memvprintf() never pass a NULL target to vsnprintf()
    - BUILD: makefile: fix build of IPv6 header on aix51
    - BUILD: makefile: add _LINUX_SOURCE_COMPAT to build on AIX-51
    - BUILD: Makefile: disable shared cache on AIX 5.1
    - BUG/MINOR: cli: correctly handle abns in 'show cli sockets'
    - MINOR: cli: start addresses by a prefix in 'show cli sockets'
    - BUG/MEDIUM: peers: fix a case where peer session is not cleanly reset on release.
    - BUILD: use inttypes.h instead of stdint.h
    - BUILD: connection: fix naming of ip_v field
    - BUG/MEDIUM: pattern: assign pattern IDs after checking the config validity
    - BUG/MEDIUM: spoe: Queue message only if no SPOE applet is attached to the stream
    - BUG/MEDIUM: spoe: Return an error if nothing is encoded for fragmented messages
    - BUG/MINOR: threads: fix the process range of thread masks
    - MINOR: lists: Implement locked variations.
    - BUG/MEDIUM: lists: Properly handle the case we're removing the first elt.
    - BUG/MEDIUM: list: fix the rollback on addq in the locked liss
    - BUG/MEDIUM: list: fix LIST_POP_LOCKED's removal of the last pointer
    - BUG/MEDIUM: list: add missing store barriers when updating elements and head
    - MINOR: list: make the delete and pop operations idempotent
    - BUG/MEDIUM: list: correct fix for LIST_POP_LOCKED's removal of last element
    - BUG/MEDIUM: list: fix again LIST_ADDQ_LOCKED
    - BUG/MEDIUM: list: fix incorrect pointer unlocking in LIST_DEL_LOCKED()
    - MAJOR: listener: do not hold the listener lock in listener_accept()
    - BUG/MEDIUM: listener: use a self-locked list for the dequeue lists
    - BUG/MEDIUM: listener: make sure the listener never accepts too many conns
    - BUILD/MINOR: listener: Silent a few signedness warnings.
    - MINOR: skip get_gmtime where tm is unused
    - BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
    - BUG/MEDIUM: maps: only try to parse the default value when it's present
    - BUG/MINOR: acl: properly detect pattern type SMP_T_ADDR
    - BUG/MEDIUM: thread/http: Add missing locks in set-map and add-acl HTTP rules
    - BUG/MINOR: 51d: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
    - BUG/MINOR: da: Get the request channel to call CHECK_HTTP_MESSAGE_FIRST()
    - BUG/MINOR: spoe: Don't systematically wakeup SPOE stream in the applet handler

Here is a diffstat:

 CHANGELOG                                         |   50 +++
 Makefile                                          |    6
 README                                            |    2
 VERDATE                                           |    2
 VERSION                                           |    2
 contrib/hpack/gen-rht.c                           |    2
 contrib/plug_qdisc/plug_qdisc.c                   |    2
 contrib/spoa_example/include/spop_functions.h     |    2
 contrib/wireshark-dissectors/peers/packet-happp.c |    2
 debian/changelog                                  |   11
 debian/tests/control                              |    4
 debian/tests/proxy-localhost                      |   48 +++
 doc/configuration.txt                             |    4
 examples/haproxy.spec                             |    5
 include/common/hathreads.h                        |   18 -
 include/common/hpack-dec.h                        |    2
 include/common/hpack-enc.h                        |    2
 include/common/hpack-huff.h                       |    2
 include/common/hpack-tbl.h                        |    2
 include/common/http-hdr.h                         |    2
 include/common/mini-clist.h                       |  156 ++++++++++
 include/proto/proto_http.h                        |   10
 include/proto/shctx.h                             |    2
 src/51d.c                                         |    5
 src/acl.c                                         |    1
 src/checks.c                                      |    2
 src/cli.c                                         |   10
 src/connection.c                                  |    8
 src/da.c                                          |    2
 src/flt_spoe.c                                    |   33 +-
 src/h2.c                                          |    2
 src/haproxy.c                                     |    7
 src/hlua.c                                        |    2
 src/hpack-dec.c                                   |    2
 src/hpack-enc.c                                   |    2
 src/hpack-huff.c                                  |    2
 src/hpack-tbl.c                                   |    2
 src/listener.c                                    |  247 +++++++++-------
 src/log.c                                         |    7
 src/map.c                                         |    6
 src/peers.c                                       |   77 +++-
 src/proto_http.c                                  |  339 +++++++++++-----------
 src/session.c                                     |    5
 src/sha1.c                                        |    2
 src/ssl_sock.c                                    |    4
 src/standard.c                                    |    4
 src/stats.c                                       |   25 +
 src/xxhash.c                                      |    2
 48 files changed, 756 insertions(+), 380 deletions(-)

The two main contributors to these changes are:

BUG/MAJOR: http_fetch: Get the channel depending on the keyword used
<http://git.haproxy.org/?p=haproxy-1.8.git;a=commitdiff;h=b05ee4aa74a95be49c78198ca601000b47c93da2>

BUG/MEDIUM: listener: make sure the listener never accepts too many conns
<http://git.haproxy.org/?p=haproxy-1.8.git;a=commitdiff;h=c98cdf7cc755c579a8b9cceee4809089267615ce>

I am attaching the full debdiff.

Is it OK to push this version in unstable?

unblock haproxy/1.8.20-1

- -- System Information:
Debian Release: 10.0
  APT prefers unstable-debug
  APT policy: (500, 'unstable-debug'), (500, 'unstable'), (101, 'experimental-debug'), (101, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-4-amd64 (SMP w/4 CPU cores)
Kernel taint flags: TAINT_USER, TAINT_WARN, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=fr_FR.utf8, LC_CTYPE=fr_FR.utf8 (charmap=UTF-8), LANGUAGE=en_US:en (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

-----BEGIN PGP SIGNATURE-----

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

--- End Message ---
--- Begin Message ---
Hi

On Sun, May 05, 2019 at 09:50:16AM +0200, Vincent Bernat wrote:
> HAProxy 1.8.20 was released last week. This is a bugfix only release.
> 
> Upstream has stated his dislike of cherry-picking only some of the
> fixes and would prefer us to ship a pristine 1.8.19 instead of a
> patched version if we do not want to ship 1.8.20 as is. See the full
> rationale here:
>  <https://www.mail-archive.com/haproxy@formilux.org/msg33550.html>

The fact that upstream disagrees with the freeze policy is not a reason for an
unblock. So haproxy 1.8.20 will not be unblocked.

Thanks,

Ivo

--- End Message ---

Reply to: