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

Reply via email to