Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package haproxy for openSUSE:Factory checked 
in at 2023-03-19 00:30:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/haproxy (Old)
 and      /work/SRC/openSUSE:Factory/.haproxy.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "haproxy"

Sun Mar 19 00:30:30 2023 rev:128 rq:1072696 version:2.7.5+git0.8d230219e

Changes:
--------
--- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes  2023-03-12 
16:26:56.793478350 +0100
+++ /work/SRC/openSUSE:Factory/.haproxy.new.31432/haproxy.changes       
2023-03-19 00:30:33.200084132 +0100
@@ -1,0 +2,32 @@
+Fri Mar 17 16:42:07 UTC 2023 - mrueck...@suse.de
+
+- Update to version 2.7.5+git0.8d230219e:
+  * [RELEASE] Released version 2.7.5
+  * OPTIM: mux-h1: limit first read size to avoid wrapping
+  * BUG/MAJOR: qpack: fix possible read out of bounds in static table
+  * BUG/MINOR: sock_unix: match finalname with tempname in sock_unix_addrcmp()
+  * BUG/MINOR: protocol: fix minor memory leak in protocol_bind_all()
+  * BUG/MINOR: proto_ux: report correct error when bind_listener fails
+  * BUG/MEDIUM: spoe: Don't set the default traget for the SPOE agent frontend
+  * BUG/MINOR: mux-h2: Fix possible null pointer deref on h2c in 
_h2_trace_header()
+  * MEDIUM: mux-h2/trace: add tracing support for headers
+  * MINOR: h2: add h2_phdr_to_ist() to make ISTs from pseudo headers
+  * MEDIUM: bwlim: Support constants limit or period on set-bandwidth-limit 
actions
+  * BUG/MEDIUM: listener: duplicate inherited FDs if needed
+  * BUG/MINOR: quic: Missing STREAM frame data pointer updates
+  * BUG/MINOR: mux-h2: set CO_SFL_STREAMER when sending lots of data
+  * BUG/MEDIUM: mux-h2: only restart sending when mux buffer is decongested
+  * MINOR: buffer: add br_single() to check if a buffer ring has more than one 
buf
+  * BUG/MINOR: mux-h2: make sure the h2c task exists before refreshing it
+  * BUG/MEDIUM: connection: Preserve flags when a conn is removed from an idle 
list
+  * BUG/MINOR: quic: Missing STREAM frame length updates
+  * BUG/MINOR: tcp_sample: fix a bug in fc_dst_port and fc_dst_is_local sample 
fetches
+  * BUG/MEDIUM: mux-h1: Don't block SE_FL_ERROR if EOS is not reported on H1C
+  * DEBUG: ssl-sock/show_fd: Display SSL error code
+  * DEBUG: cli/show_fd: Display connection error code
+  * BUG/MEDIUM: resolvers: Properly stop server resolutions on soft-stop
+  * BUG/MEDIUM: proxy: properly stop backends on soft-stop
+  * BUG/MINOR: mux-h1: Don't report an H1C error on client timeout
+  * BUG/MEDIUM: mux-pt: Set EOS on error on sending path if read0 was received
+
+-------------------------------------------------------------------

Old:
----
  haproxy-2.7.4+git0.d28541d1f.tar.gz

New:
----
  haproxy-2.7.5+git0.8d230219e.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ haproxy.spec ++++++
--- /var/tmp/diff_new_pack.Oj25NM/_old  2023-03-19 00:30:33.864087282 +0100
+++ /var/tmp/diff_new_pack.Oj25NM/_new  2023-03-19 00:30:33.872087320 +0100
@@ -51,7 +51,7 @@
 %endif
 
 Name:           haproxy
-Version:        2.7.4+git0.d28541d1f
+Version:        2.7.5+git0.8d230219e
 Release:        0
 #
 #

++++++ _service ++++++
--- /var/tmp/diff_new_pack.Oj25NM/_old  2023-03-19 00:30:33.908087491 +0100
+++ /var/tmp/diff_new_pack.Oj25NM/_new  2023-03-19 00:30:33.912087510 +0100
@@ -6,7 +6,7 @@
     <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="versionrewrite-replacement">\1</param>
-    <param name="revision">v2.7.4</param>
+    <param name="revision">v2.7.5</param>
     <param name="changesgenerate">enable</param>
   </service>
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.Oj25NM/_old  2023-03-19 00:30:33.948087680 +0100
+++ /var/tmp/diff_new_pack.Oj25NM/_new  2023-03-19 00:30:33.952087700 +0100
@@ -1,7 +1,7 @@
 <servicedata>
   <service name="tar_scm">
     <param name="url">http://git.haproxy.org/git/haproxy-2.7.git</param>
-    <param 
name="changesrevision">d28541d1fa946adb74510c969bd50b06c27bbad7</param>
+    <param 
name="changesrevision">8d230219e15295a3c4757f94916aafcf540a7337</param>
   </service>
 </servicedata>
 (No newline at EOF)

++++++ haproxy-2.7.4+git0.d28541d1f.tar.gz -> 
haproxy-2.7.5+git0.8d230219e.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/CHANGELOG 
new/haproxy-2.7.5+git0.8d230219e/CHANGELOG
--- old/haproxy-2.7.4+git0.d28541d1f/CHANGELOG  2023-03-10 16:29:03.000000000 
+0100
+++ new/haproxy-2.7.5+git0.8d230219e/CHANGELOG  2023-03-17 17:35:40.000000000 
+0100
@@ -1,6 +1,34 @@
 ChangeLog :
 ===========
 
+2023/03/17 : 2.7.5
+    - BUG/MEDIUM: mux-pt: Set EOS on error on sending path if read0 was 
received
+    - BUG/MINOR: mux-h1: Don't report an H1C error on client timeout
+    - BUG/MEDIUM: proxy: properly stop backends on soft-stop
+    - BUG/MEDIUM: resolvers: Properly stop server resolutions on soft-stop
+    - DEBUG: cli/show_fd: Display connection error code
+    - DEBUG: ssl-sock/show_fd: Display SSL error code
+    - BUG/MEDIUM: mux-h1: Don't block SE_FL_ERROR if EOS is not reported on H1C
+    - BUG/MINOR: tcp_sample: fix a bug in fc_dst_port and fc_dst_is_local 
sample fetches
+    - BUG/MINOR: quic: Missing STREAM frame length updates
+    - BUG/MEDIUM: connection: Preserve flags when a conn is removed from an 
idle list
+    - BUG/MINOR: mux-h2: make sure the h2c task exists before refreshing it
+    - MINOR: buffer: add br_single() to check if a buffer ring has more than 
one buf
+    - BUG/MEDIUM: mux-h2: only restart sending when mux buffer is decongested
+    - BUG/MINOR: mux-h2: set CO_SFL_STREAMER when sending lots of data
+    - BUG/MINOR: quic: Missing STREAM frame data pointer updates
+    - BUG/MEDIUM: listener: duplicate inherited FDs if needed
+    - MEDIUM: bwlim: Support constants limit or period on set-bandwidth-limit 
actions
+    - MINOR: h2: add h2_phdr_to_ist() to make ISTs from pseudo headers
+    - MEDIUM: mux-h2/trace: add tracing support for headers
+    - BUG/MINOR: mux-h2: Fix possible null pointer deref on h2c in 
_h2_trace_header()
+    - BUG/MEDIUM: spoe: Don't set the default traget for the SPOE agent 
frontend
+    - BUG/MINOR: proto_ux: report correct error when bind_listener fails
+    - BUG/MINOR: protocol: fix minor memory leak in protocol_bind_all()
+    - BUG/MINOR: sock_unix: match finalname with tempname in 
sock_unix_addrcmp()
+    - BUG/MAJOR: qpack: fix possible read out of bounds in static table
+    - OPTIM: mux-h1: limit first read size to avoid wrapping
+
 2023/03/10 : 2.7.4
     - BUG/MINOR: mworker: stop doing strtok directly from the env
     - BUG/MEDIUM: mworker: prevent inconsistent reload when upgrading from old 
versions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/VERDATE 
new/haproxy-2.7.5+git0.8d230219e/VERDATE
--- old/haproxy-2.7.4+git0.d28541d1f/VERDATE    2023-03-10 16:29:03.000000000 
+0100
+++ new/haproxy-2.7.5+git0.8d230219e/VERDATE    2023-03-17 17:35:40.000000000 
+0100
@@ -1,2 +1,2 @@
 $Format:%ci$
-2023/03/10
+2023/03/17
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/VERSION 
new/haproxy-2.7.5+git0.8d230219e/VERSION
--- old/haproxy-2.7.4+git0.d28541d1f/VERSION    2023-03-10 16:29:03.000000000 
+0100
+++ new/haproxy-2.7.5+git0.8d230219e/VERSION    2023-03-17 17:35:40.000000000 
+0100
@@ -1 +1 @@
-2.7.4
+2.7.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/doc/configuration.txt 
new/haproxy-2.7.5+git0.8d230219e/doc/configuration.txt
--- old/haproxy-2.7.4+git0.d28541d1f/doc/configuration.txt      2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/doc/configuration.txt      2023-03-17 
17:35:40.000000000 +0100
@@ -3,7 +3,7 @@
                           Configuration Manual
                          ----------------------
                               version 2.7
-                              2023/03/10
+                              2023/03/17
 
 
 This document covers the configuration language as implemented in the version
@@ -6492,7 +6492,7 @@
     - sc-inc-gpc1(<sc-id>)
     - sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
     - sc-set-gpt0(<sc-id>) { <int> | <expr> }
-    - set-bandwidth-limit <name> [limit <expr>] [period <expr>]
+    - set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | 
<time>}]
     - set-dst <expr>
     - set-dst-port <expr>
     - set-header <name> <fmt>
@@ -7163,7 +7163,8 @@
     <group-name>   The SPOE group name as specified in the engine
                    configuration.
 
-http-request set-bandwidth-limit <name> [limit <expr>] [period <expr>] [ { if 
| unless } <condition> ]
+http-request set-bandwidth-limit <name> [limit { <expr> | <size> }]
+                 [period { <expr> | <time> }] [ { if | unless } <condition> ]
 
   This action is used to enable the bandwidth limitation filter <name>, either
   on the upload or download direction depending on the filter type. Custom
@@ -7184,6 +7185,12 @@
             interpreted as a size in bytes for the "limit" parameter and as a
             duration in milliseconds for the "period" parameter.
 
+    <size>  Is a number. It follows the HAProxy size format and is expressed in
+            bytes.
+
+    <time>  Is a number. It follows the HAProxy time format and is expressed in
+            milliseconds.
+
   Example:
     http-request set-bandwidth-limit global-limit
     http-request set-bandwidth-limit my-limit limit 1m period 10s
@@ -7666,7 +7673,7 @@
     - sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
     - sc-set-gpt0(<sc-id>) { <int> | <expr> }
     - send-spoe-group <engine-name> <group-name>
-    - set-bandwidth-limit <name> [limit <expr>] [period <expr>]
+    - set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | 
<time>}]
     - set-header <name> <fmt>
     - set-log-level <level>
     - set-map(<file-name>) <key fmt> <value fmt>
@@ -7862,7 +7869,8 @@
   This action is used to trigger sending of a group of SPOE messages. Please
   refer to "http-request send-spoe-group" for a complete description.
 
-http-response set-bandwidth-limit <name> [limit <expr>] [period <expr>] [ { if 
| unless } <condition> ]
+http-response set-bandwidth-limit <name> [limit { <expr> | <size> }]
+                 [period { <expr> | <time> }] [ { if | unless } <condition> ]
 
   This action is used to enable the bandwidth limitation filter <name>, either
   on the upload or download direction depending on the filter type. Please
@@ -12800,7 +12808,7 @@
     - sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
     - sc-set-gpt0(<sc-id>) { <int> | <expr> }
     - send-spoe-group <engine-name> <group-name>
-    - set-bandwidth-limit <name> [limit <expr>] [period <expr>]
+    - set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | 
<time>}]
     - set-dst <expr>
     - set-dst-port <expr>
     - set-log-level <level>
@@ -12994,8 +13002,8 @@
   Thaction is is used to trigger sending of a group of SPOE messages. Please
   refer to "http-request send-spoe-group" for a complete description.
 
-tcp-request content set-bandwidth-limit <name> [limit <expr>] [period <expr>]
-                    [ { if | unless } <condition> ]
+tcp-request content set-bandwidth-limit <name> [limit { <expr> | <size> }]
+                 [period { <expr> | <time> }] [ { if | unless } <condition> ]
 
   This action is used to enable the bandwidth limitation filter <name>, either
   on the upload or download direction depending on the filter type. Please
@@ -13368,7 +13376,7 @@
     - sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
     - sc-set-gpt0(<sc-id>) { <int> | <expr> }
     - send-spoe-group <engine-name> <group-name>
-    - set-bandwidth-limit <name> [limit <expr>] [period <expr>]
+    - set-bandwidth-limit <name> [limit {<expr> | <size>}] [period {<expr> | 
<time>}]
     - set-log-level <level>
     - set-mark <mark>
     - set-nice <nice>
@@ -13447,8 +13455,8 @@
   refer to "http-request send-spoe-group" for a complete description.
 
 
-tcp-response content set-bandwidth-limit <name> [limit <expr>] [period <expr>]
-                     [ { if | unless } <condition> ]
+tcp-response content set-bandwidth-limit <name> [limit { <expr> | <size> }]
+                 [period { <expr> | <time> }] [ { if | unless } <condition> ]
 
   This action is used to enable the bandwidth limitation filter <name>, either
   on the upload or download direction depending on the filter type. Please
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/buf.h 
new/haproxy-2.7.5+git0.8d230219e/include/haproxy/buf.h
--- old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/buf.h      2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/include/haproxy/buf.h      2023-03-17 
17:35:40.000000000 +0100
@@ -1016,6 +1016,15 @@
        return r->data + 1 == r->head || r->data + 1 == r->head - 1 + r->size;
 }
 
+
+/* Returns true if a single buffer is assigned */
+static inline unsigned int br_single(const struct buffer *r)
+{
+       BUG_ON_HOT(r->area != BUF_RING.area);
+
+       return r->data == r->head;
+}
+
 /* Returns the index of the ring's head buffer */
 static inline unsigned int br_head_idx(const struct buffer *r)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/connection.h 
new/haproxy-2.7.5+git0.8d230219e/include/haproxy/connection.h
--- old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/connection.h       
2023-03-10 16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/include/haproxy/connection.h       
2023-03-17 17:35:40.000000000 +0100
@@ -316,6 +316,16 @@
        }
 }
 
+/* Used to know if a connection is in an idle list. It returns connection flag
+ * corresponding to the idle list if the connection is idle (CO_FL_SAFE_LIST or
+ * CO_FL_IDLE_LIST) or 0 otherwise. Note that if the connection is scheduled to
+ * be removed, 0 is returned, regardless the connection flags.
+ */
+static inline unsigned int conn_get_idle_flag(const struct connection *conn)
+{
+       return (!MT_LIST_INLIST(&conn->toremove_list) ? conn->flags & 
CO_FL_LIST_MASK : 0);
+}
+
 static inline void conn_force_unsubscribe(struct connection *conn)
 {
        if (!conn->subs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/h2.h 
new/haproxy-2.7.5+git0.8d230219e/include/haproxy/h2.h
--- old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/h2.h       2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/include/haproxy/h2.h       2023-03-17 
17:35:40.000000000 +0100
@@ -318,21 +318,29 @@
        return 0;
 }
 
-/* returns the pseudo-header name <num> as a string, or ":UNKNOWN" if unknown 
*/
-static inline const char *h2_phdr_to_str(int phdr)
+/* returns the pseudo-header name <num> as an ist, or ":UNKNOWN" if unknown.
+ * Note that all strings are zero-terminated constants.
+ */
+static inline struct ist h2_phdr_to_ist(int phdr)
 {
        switch (phdr) {
-       case H2_PHDR_IDX_NONE: return ":NONE";
-       case H2_PHDR_IDX_AUTH: return ":authority";
-       case H2_PHDR_IDX_METH: return ":method";
-       case H2_PHDR_IDX_PATH: return ":path";
-       case H2_PHDR_IDX_SCHM: return ":scheme";
-       case H2_PHDR_IDX_STAT: return ":status";
-       case H2_PHDR_IDX_HOST: return "Host";
-       default:               return ":UNKNOWN";
+       case H2_PHDR_IDX_NONE: return ist(":NONE");
+       case H2_PHDR_IDX_AUTH: return ist(":authority");
+       case H2_PHDR_IDX_METH: return ist(":method");
+       case H2_PHDR_IDX_PATH: return ist(":path");
+       case H2_PHDR_IDX_SCHM: return ist(":scheme");
+       case H2_PHDR_IDX_STAT: return ist(":status");
+       case H2_PHDR_IDX_HOST: return ist("Host");
+       default:               return ist(":UNKNOWN");
        }
 }
 
+/* returns the pseudo-header name <num> as a string, or ":UNKNOWN" if unknown 
*/
+static inline const char *h2_phdr_to_str(int phdr)
+{
+       return h2_phdr_to_ist(phdr).ptr;
+}
+
 #endif /* _HAPROXY_H2_H */
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/quic_frame.h 
new/haproxy-2.7.5+git0.8d230219e/include/haproxy/quic_frame.h
--- old/haproxy-2.7.4+git0.d28541d1f/include/haproxy/quic_frame.h       
2023-03-10 16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/include/haproxy/quic_frame.h       
2023-03-17 17:35:40.000000000 +0100
@@ -254,5 +254,18 @@
        *frm = NULL;
 }
 
+/* Move forward <strm> STREAM frame by <data> bytes. */
+static inline void qc_stream_frm_mv_fwd(struct quic_stream *strm, uint64_t 
data)
+{
+       struct buffer cf_buf;
+
+       strm->offset.key += data;
+       strm->len -= data;
+       cf_buf = b_make(b_orig(strm->buf),
+                       b_size(strm->buf),
+                       (char *)strm->data - b_orig(strm->buf), 0);
+       strm->data = (unsigned char *)b_peek(&cf_buf, data);
+}
+
 #endif /* USE_QUIC */
 #endif /* _HAPROXY_QUIC_FRAME_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/cli.c 
new/haproxy-2.7.5+git0.8d230219e/src/cli.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/cli.c  2023-03-10 16:29:03.000000000 
+0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/cli.c  2023-03-17 17:35:40.000000000 
+0100
@@ -1288,6 +1288,7 @@
                const void *ctx = NULL;
                const void *xprt_ctx = NULL;
                uint32_t conn_flags = 0;
+               uint8_t conn_err = 0;
                int is_back = 0;
                int suspicious = 0;
 
@@ -1305,6 +1306,7 @@
                else if (fdt.iocb == sock_conn_iocb) {
                        conn = (const struct connection *)fdt.owner;
                        conn_flags = conn->flags;
+                       conn_err   = conn->err_code;
                        mux        = conn->mux;
                        ctx        = conn->ctx;
                        xprt       = conn->xprt;
@@ -1354,7 +1356,7 @@
                        chunk_appendf(&trash, ")");
                }
                else if (fdt.iocb == sock_conn_iocb) {
-                       chunk_appendf(&trash, ") back=%d cflg=0x%08x", is_back, 
conn_flags);
+                       chunk_appendf(&trash, ") back=%d cflg=0x%08x cerr=%d", 
is_back, conn_flags, conn_err);
 
                        if (conn->handle.fd != fd) {
                                chunk_appendf(&trash, " fd=%d(BOGUS)", 
conn->handle.fd);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/connection.c 
new/haproxy-2.7.5+git0.8d230219e/src/connection.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/connection.c   2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/connection.c   2023-03-17 
17:35:40.000000000 +0100
@@ -146,7 +146,7 @@
             ((conn->flags ^ old_flags) & CO_FL_NOTIFY_DONE) ||
             ((old_flags & CO_FL_WAIT_XPRT) && !(conn->flags & 
CO_FL_WAIT_XPRT))) &&
            conn->mux && conn->mux->wake) {
-               uint conn_in_list = conn->flags & CO_FL_LIST_MASK;
+               uint conn_in_list = conn_get_idle_flag(conn);
                struct server *srv = objt_server(conn->target);
 
                if (conn_in_list) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/flt_bwlim.c 
new/haproxy-2.7.5+git0.8d230219e/src/flt_bwlim.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/flt_bwlim.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/flt_bwlim.c    2023-03-17 
17:35:40.000000000 +0100
@@ -35,6 +35,11 @@
 #define BWLIM_FL_OUT     0x00000002 /* Limit clients downloads */
 #define BWLIM_FL_SHARED  0x00000004 /* Limit shared between clients (using 
stick-tables) */
 
+#define BWLIM_ACT_LIMIT_EXPR   0x00000001
+#define BWLIM_ACT_LIMIT_CONST  0x00000002
+#define BWLIM_ACT_PERIOD_EXPR  0x00000004
+#define BWLIM_ACT_PERIOD_CONST 0x00000008
+
 struct bwlim_config {
        struct proxy *proxy;
        char         *name;
@@ -384,16 +389,21 @@
 
                st->limit = 0;
                st->period = 0;
-               if (rule->arg.act.p[1]) {
+               if (rule->action & BWLIM_ACT_LIMIT_EXPR) {
                        smp = sample_fetch_as_type(px, sess, s, opt, 
rule->arg.act.p[1], SMP_T_SINT);
                        if (smp && smp->data.u.sint > 0)
                                st->limit = smp->data.u.sint;
                }
-               if (rule->arg.act.p[2]) {
+               else if (rule->action & BWLIM_ACT_LIMIT_CONST)
+                       st->limit = (uintptr_t)rule->arg.act.p[1];
+
+               if (rule->action & BWLIM_ACT_PERIOD_EXPR) {
                        smp = sample_fetch_as_type(px, sess, s, opt, 
rule->arg.act.p[2], SMP_T_SINT);
                        if (smp && smp->data.u.sint > 0)
                                st->period = smp->data.u.sint;
                }
+               else if (rule->action & BWLIM_ACT_PERIOD_CONST)
+                       st->period = (uintptr_t)rule->arg.act.p[2];
        }
 
        st->exp = TICK_ETERNITY;
@@ -461,7 +471,7 @@
                        where |= SMP_VAL_BE_HRS_HDR;
        }
 
-       if (rule->arg.act.p[1]) {
+       if ((rule->action & BWLIM_ACT_LIMIT_EXPR) && rule->arg.act.p[1]) {
                struct sample_expr *expr = rule->arg.act.p[1];
 
                if (!(expr->fetch->val & where)) {
@@ -490,7 +500,7 @@
                }
        }
 
-       if (rule->arg.act.p[2]) {
+       if ((rule->action & BWLIM_ACT_PERIOD_EXPR) && rule->arg.act.p[2]) {
                struct sample_expr *expr = rule->arg.act.p[2];
 
                if (!(expr->fetch->val & where)) {
@@ -555,11 +565,11 @@
 static void release_bwlim_action(struct act_rule *rule)
 {
        ha_free(&rule->arg.act.p[0]);
-       if (rule->arg.act.p[1]) {
+       if ((rule->action & BWLIM_ACT_LIMIT_EXPR) && rule->arg.act.p[1]) {
                release_sample_expr(rule->arg.act.p[1]);
                rule->arg.act.p[1] = NULL;
        }
-       if (rule->arg.act.p[2]) {
+       if ((rule->action & BWLIM_ACT_PERIOD_EXPR) && rule->arg.act.p[2]) {
                release_sample_expr(rule->arg.act.p[2]);
                rule->arg.act.p[2] = NULL;
        }
@@ -599,27 +609,55 @@
 
        while (1) {
                if (strcmp(args[cur_arg], "limit") == 0) {
+                       const char *res;
+                       unsigned int limit;
+
                        cur_arg++;
                        if (!args[cur_arg]) {
-                               memprintf(err, "missing limit expression");
+                               memprintf(err, "missing limit value or 
expression");
                                goto error;
                        }
 
-                       expr = sample_parse_expr((char **)args, &cur_arg, 
px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
-                       if (!expr)
+                       res = parse_size_err(args[cur_arg], &limit);
+                       if (!res) {
+                               rule->action |= BWLIM_ACT_LIMIT_CONST;
+                               rule->arg.act.p[1] = (void *)(uintptr_t)limit;
+                               cur_arg++;
+                               continue;
+                       }
+
+                       expr = sample_parse_expr((char **)args, &cur_arg, 
px->conf.args.file, px->conf.args.line, NULL, &px->conf.args, NULL);
+                       if (!expr) {
+                               memprintf(err, "'%s': invalid size value or 
unknown fetch method '%s'", args[cur_arg-1], args[cur_arg]);
                                goto error;
+                       }
+                       rule->action |= BWLIM_ACT_LIMIT_EXPR;
                        rule->arg.act.p[1] = expr;
                }
                else if (strcmp(args[cur_arg], "period") == 0) {
+                       const char *res;
+                       unsigned int period;
+
                        cur_arg++;
                        if (!args[cur_arg]) {
-                               memprintf(err, "missing period expression");
+                               memprintf(err, "missing period value or 
expression");
                                goto error;
                        }
 
-                       expr = sample_parse_expr((char **)args, &cur_arg, 
px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
-                       if (!expr)
+                       res = parse_time_err(args[cur_arg], &period, 
TIME_UNIT_MS);
+                       if (!res) {
+                               rule->action |= BWLIM_ACT_PERIOD_CONST;
+                               rule->arg.act.p[2] = (void *)(uintptr_t)period;
+                               cur_arg++;
+                               continue;
+                       }
+
+                       expr = sample_parse_expr((char **)args, &cur_arg, 
px->conf.args.file, px->conf.args.line, NULL, &px->conf.args, NULL);
+                       if (!expr) {
+                               memprintf(err, "'%s': invalid time value or 
unknown fetch method '%s'", args[cur_arg-1], args[cur_arg]);
                                goto error;
+                       }
+                       rule->action |= BWLIM_ACT_PERIOD_EXPR;
                        rule->arg.act.p[2] = expr;
                }
                else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/flt_spoe.c 
new/haproxy-2.7.5+git0.8d230219e/src/flt_spoe.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/flt_spoe.c     2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/flt_spoe.c     2023-03-17 
17:35:40.000000000 +0100
@@ -3053,7 +3053,6 @@
         conf->agent_fe.accept = frontend_accept;
         conf->agent_fe.srv = NULL;
         conf->agent_fe.timeout.client = TICK_ETERNITY;
-       conf->agent_fe.default_target = &spoe_applet.obj_type;
        conf->agent_fe.fe_req_ana = AN_REQ_SWITCHING_RULES;
 
        if (!sighandler_registered) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/mux_fcgi.c 
new/haproxy-2.7.5+git0.8d230219e/src/mux_fcgi.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/mux_fcgi.c     2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/mux_fcgi.c     2023-03-17 
17:35:40.000000000 +0100
@@ -2957,7 +2957,7 @@
                conn = fconn->conn;
                TRACE_POINT(FCGI_EV_FCONN_WAKE, conn);
 
-               conn_in_list = conn->flags & CO_FL_LIST_MASK;
+               conn_in_list = conn_get_idle_flag(conn);
                if (conn_in_list)
                        conn_delete_from_tree(&conn->hash_node->node);
 
@@ -3140,10 +3140,8 @@
                /* We're about to destroy the connection, so make sure nobody 
attempts
                 * to steal it from us.
                 */
-               if (fconn->conn->flags & CO_FL_LIST_MASK) {
+               if (fconn->conn->flags & CO_FL_LIST_MASK)
                        conn_delete_from_tree(&fconn->conn->hash_node->node);
-                       fconn->conn->flags &= ~CO_FL_LIST_MASK;
-               }
 
                HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/mux_h1.c 
new/haproxy-2.7.5+git0.8d230219e/src/mux_h1.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/mux_h1.c       2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/mux_h1.c       2023-03-17 
17:35:40.000000000 +0100
@@ -1919,6 +1919,11 @@
                                TRACE_STATE("Re-enable output processing", 
H1_EV_TX_DATA|H1_EV_H1S_BLK|H1_EV_STRM_WAKE, h1c->conn, h1s);
                        }
                }
+               if (h1c->flags & H1C_F_ERROR) {
+                       /* Report a terminal error to the SE if a previous read 
error was detected */
+                       se_fl_set(h1s->sd, SE_FL_ERROR);
+                       TRACE_STATE("report ERROR to SE", 
H1_EV_RX_DATA|H1_EV_H1S_ERR, h1c->conn, h1s);
+               }
        }
 
   end:
@@ -2806,13 +2811,30 @@
        if (b_data(&h1c->ibuf) > 0 && b_data(&h1c->ibuf) < 128)
                b_slow_realign_ofs(&h1c->ibuf, trash.area, sizeof(struct htx));
 
+       max = buf_room_for_htx_data(&h1c->ibuf);
+
        /* avoid useless reads after first responses */
        if (!h1c->h1s ||
            (!(h1c->flags & H1C_F_IS_BACK) && h1c->h1s->req.state == 
H1_MSG_RQBEFORE) ||
-           ((h1c->flags & H1C_F_IS_BACK) && h1c->h1s->res.state == 
H1_MSG_RPBEFORE))
+           ((h1c->flags & H1C_F_IS_BACK) && h1c->h1s->res.state == 
H1_MSG_RPBEFORE)) {
                flags |= CO_RFL_READ_ONCE;
 
-       max = buf_room_for_htx_data(&h1c->ibuf);
+               /* we know that the first read will be constrained to a smaller
+                * read by the stream layer in order to respect the reserve.
+                * Reading too much will result in global.tune.maxrewrite being
+                * left at the end of the buffer, and in a very small read
+                * being performed again to complete them (typically 16 bytes
+                * freed in the index after headers were consumed) before
+                * another larger read. Instead, given that we know we're
+                * waiting for a header and we'll be limited, let's perform a
+                * shorter first read that the upper layer can retrieve by just
+                * a pointer swap and the next read will be doable at once in
+                * an empty buffer.
+                */
+               if (max > global.tune.bufsize - global.tune.maxrewrite)
+                       max = global.tune.bufsize - global.tune.maxrewrite;
+       }
+
        if (max) {
                if (h1c->flags & H1C_F_IN_FULL) {
                        h1c->flags &= ~H1C_F_IN_FULL;
@@ -3170,7 +3192,7 @@
                /* Remove the connection from the list, to be sure nobody 
attempts
                 * to use it while we handle the I/O events
                 */
-               conn_in_list = conn->flags & CO_FL_LIST_MASK;
+               conn_in_list = conn_get_idle_flag(conn);
                if (conn_in_list)
                        conn_delete_from_tree(&conn->hash_node->node);
 
@@ -3269,7 +3291,6 @@
 
                /* Try to send an error to the client */
                if (h1c->state != H1_CS_CLOSING && !(h1c->flags & 
(H1C_F_IS_BACK|H1C_F_ERROR|H1C_F_ABRT_PENDING))) {
-                       h1c->flags |= H1C_F_ERROR;
                        TRACE_DEVEL("timeout error detected", 
H1_EV_H1C_WAKE|H1_EV_H1C_ERR, h1c->conn, h1c->h1s);
                        if (h1_handle_req_tout(h1c))
                                h1_send(h1c);
@@ -3294,10 +3315,8 @@
                /* We're about to destroy the connection, so make sure nobody 
attempts
                 * to steal it from us.
                 */
-               if (h1c->conn->flags & CO_FL_LIST_MASK) {
+               if (h1c->conn->flags & CO_FL_LIST_MASK)
                        conn_delete_from_tree(&h1c->conn->hash_node->node);
-                       h1c->conn->flags &= ~CO_FL_LIST_MASK;
-               }
 
                HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/mux_h2.c 
new/haproxy-2.7.5+git0.8d230219e/src/mux_h2.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/mux_h2.c       2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/mux_h2.c       2023-03-17 
17:35:40.000000000 +0100
@@ -844,6 +844,80 @@
        return ret1;
 }
 
+/* inconditionally produce a trace of the header. Please do not call this one
+ * and use h2_trace_header() instead which first checks if traces are enabled.
+ */
+void _h2_trace_header(const struct ist hn, const struct ist hv,
+                     uint64_t mask, const struct ist trc_loc, const char *func,
+                     const struct h2c *h2c, const struct h2s *h2s)
+{
+       struct ist n_ist, v_ist;
+       const char *c_str, *s_str;
+
+       chunk_reset(&trash);
+       c_str = chunk_newstr(&trash);
+       if (h2c) {
+               chunk_appendf(&trash, "h2c=%p(%c,%s) ",
+                             h2c, (h2c->flags & H2_CF_IS_BACK) ? 'B' : 'F', 
h2c_st_to_str(h2c->st0));
+       }
+
+       s_str = chunk_newstr(&trash);
+       if (h2s) {
+               if (h2s->id <= 0)
+                       chunk_appendf(&trash, "dsi=%d ", h2s->h2c->dsi);
+               chunk_appendf(&trash, "h2s=%p(%d,%s) ", h2s, h2s->id, 
h2s_st_to_str(h2s->st));
+       }
+       else if (h2c)
+               chunk_appendf(&trash, "dsi=%d ", h2c->dsi);
+
+       n_ist = ist2(chunk_newstr(&trash), 0);
+       istscpy(&n_ist, hn, 256);
+       trash.data += n_ist.len;
+       if (n_ist.len != hn.len)
+               chunk_appendf(&trash, " (... +%ld)", (long)(hn.len - 
n_ist.len));
+
+       v_ist = ist2(chunk_newstr(&trash), 0);
+       istscpy(&v_ist, hv, 1024);
+       trash.data += v_ist.len;
+       if (v_ist.len != hv.len)
+               chunk_appendf(&trash, " (... +%ld)", (long)(hv.len - 
v_ist.len));
+
+       TRACE_PRINTF_LOC(TRACE_LEVEL_USER, mask, trc_loc, func,
+                        (h2c ? h2c->conn : 0), 0, 0, 0,
+                        "%s%s%s %s: %s", c_str, s_str,
+                        (mask & H2_EV_TX_HDR) ? "sndh" : "rcvh",
+                        n_ist.ptr, v_ist.ptr);
+}
+
+/* produce a trace of the header after checking that tracing is enabled */
+static inline void h2_trace_header(const struct ist hn, const struct ist hv,
+                                  uint64_t mask, const struct ist trc_loc, 
const char *func,
+                                  const struct h2c *h2c, const struct h2s *h2s)
+{
+       if ((TRACE_SOURCE)->verbosity >= H2_VERB_ADVANCED &&
+           TRACE_ENABLED(TRACE_LEVEL_USER, mask, h2c ? h2c->conn : 0, h2s, 0, 
0))
+               _h2_trace_header(hn, hv, mask, trc_loc, func, h2c, h2s);
+}
+
+/* hpack-encode header name <hn> and value <hv>, possibly emitting a trace if
+ * currently enabled. This is done on behalf of function <func> at <trc_loc>
+ * passed as ist(TRC_LOC), h2c <h2c>, and h2s <h2s>, all of which may be NULL.
+ * The trace is only emitted if the header is emitted (in which case non-zero
+ * is returned). The trash is modified. In the traces, the header's name will
+ * be truncated to 256 chars and the header's value to 1024 chars.
+ */
+static inline int h2_encode_header(struct buffer *buf, const struct ist hn, 
const struct ist hv,
+                                  uint64_t mask, const struct ist trc_loc, 
const char *func,
+                                  const struct h2c *h2c, const struct h2s *h2s)
+{
+       int ret;
+
+       ret = hpack_encode_header(buf, hn, hv);
+       if (ret)
+               h2_trace_header(hn, hv, mask, trc_loc, func, h2c, h2s);
+
+       return ret;
+}
 
 /*****************************************************************/
 /* functions below are dedicated to the mux setup and management */
@@ -3738,6 +3812,16 @@
                if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MROOM))
                        flags |= CO_SFL_MSG_MORE;
 
+               if (!br_single(h2c->mbuf)) {
+                       /* usually we want to emit small TLS records to speed
+                        * up the decoding on the client. That's what is being
+                        * done by default. However if there is more than one
+                        * buffer being allocated, we're streaming large data
+                        * so we stich to large records.
+                        */
+                       flags |= CO_SFL_STREAMER;
+               }
+
                for (buf = br_head(h2c->mbuf); b_size(buf); buf = 
br_del_head(h2c->mbuf)) {
                        if (b_data(buf)) {
                                int ret = conn->xprt->snd_buf(conn, 
conn->xprt_ctx, buf, b_data(buf), flags);
@@ -3760,8 +3844,17 @@
                if (released)
                        offer_buffers(NULL, released);
 
-               /* wrote at least one byte, the buffer is not full anymore */
-               if (sent)
+               /* Normally if wrote at least one byte, the buffer is not full
+                * anymore. However, if it was marked full because all of its
+                * buffers were used, we don't want to instantly wake up many
+                * streams because we'd create a thundering herd effect, notably
+                * when data are flushed in small chunks. Instead we wait for
+                * the buffer to be decongested again before allowing to send
+                * again. It also has the added benefit of not pumping more
+                * data from the other side when it's known that this one is
+                * still congested.
+                */
+               if (sent && br_single(h2c->mbuf))
                        h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM);
        }
 
@@ -3820,11 +3913,10 @@
                conn = h2c->conn;
                TRACE_ENTER(H2_EV_H2C_WAKE, conn);
 
-               conn_in_list = conn->flags & CO_FL_LIST_MASK;
-
                /* Remove the connection from the list, to be sure nobody 
attempts
                 * to use it while we handle the I/O events
                 */
+               conn_in_list = conn_get_idle_flag(conn);
                if (conn_in_list)
                        conn_delete_from_tree(&conn->hash_node->node);
 
@@ -3956,7 +4048,6 @@
                if (conn->flags & CO_FL_LIST_MASK) {
                        HA_SPIN_LOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
                        conn_delete_from_tree(&conn->hash_node->node);
-                       conn->flags &= ~CO_FL_LIST_MASK;
                        HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
                }
        }
@@ -3965,7 +4056,6 @@
                if (conn->flags & CO_FL_LIST_MASK) {
                        HA_SPIN_LOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
                        conn_delete_from_tree(&conn->hash_node->node);
-                       conn->flags &= ~CO_FL_LIST_MASK;
                        HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
                }
        }
@@ -4045,10 +4135,8 @@
                /* We're about to destroy the connection, so make sure nobody 
attempts
                 * to steal it from us.
                 */
-               if (h2c->conn->flags & CO_FL_LIST_MASK) {
+               if (h2c->conn->flags & CO_FL_LIST_MASK)
                        conn_delete_from_tree(&h2c->conn->hash_node->node);
-                       h2c->conn->flags &= ~CO_FL_LIST_MASK;
-               }
 
                HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
        }
@@ -4101,7 +4189,6 @@
        if (h2c->conn->flags & CO_FL_LIST_MASK) {
                HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
                conn_delete_from_tree(&h2c->conn->hash_node->node);
-               h2c->conn->flags &= ~CO_FL_LIST_MASK;
                HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
        }
 
@@ -4243,7 +4330,7 @@
                /* refresh the timeout if none was active, so that the last
                 * leaving stream may arm it.
                 */
-               if (!tick_isset(h2c->task->expire))
+               if (h2c->task && !tick_isset(h2c->task->expire))
                        h2c_update_timeout(h2c);
                return;
        }
@@ -4740,6 +4827,26 @@
        /* past this point we cannot roll back in case of error */
        outlen = hpack_decode_frame(h2c->ddht, hdrs, flen, list,
                                    sizeof(list)/sizeof(list[0]), tmp);
+
+       if (outlen > 0 &&
+           (TRACE_SOURCE)->verbosity >= H2_VERB_ADVANCED &&
+           TRACE_ENABLED(TRACE_LEVEL_USER, H2_EV_RX_FRAME|H2_EV_RX_HDR, 
h2c->conn, 0, 0, 0)) {
+               struct ist n;
+               int i;
+
+               for (i = 0; list[i].n.len; i++) {
+                       n = list[i].n;
+
+                       if (!isttest(n)) {
+                               /* this is in fact a pseudo header whose number 
is in n.len */
+                               n = h2_phdr_to_ist(n.len);
+                       }
+
+                       h2_trace_header(n, list[i].v, 
H2_EV_RX_FRAME|H2_EV_RX_HDR,
+                                       ist(TRC_LOC), __FUNCTION__, h2c, NULL);
+               }
+       }
+
        if (outlen < 0) {
                TRACE_STATE("failed to decompress HPACK", 
H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
                h2c_error(h2c, H2_ERR_COMPRESSION_ERROR);
@@ -5124,6 +5231,14 @@
                goto full;
        }
 
+       if ((TRACE_SOURCE)->verbosity >= H2_VERB_ADVANCED) {
+               char sts[4];
+
+               h2_trace_header(ist(":status"), ist(ultoa_r(h2s->status, sts, 
sizeof(sts))),
+                                   H2_EV_TX_FRAME|H2_EV_TX_HDR, ist(TRC_LOC), 
__FUNCTION__,
+                                   h2c, h2s);
+       }
+
        /* encode all headers, stop at empty name */
        for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) {
                /* these ones do not exist in H2 and must be dropped. */
@@ -5141,7 +5256,8 @@
                if (isteq(list[hdr].n, ist("")))
                        break; // end
 
-               if (!hpack_encode_header(&outbuf, list[hdr].n, list[hdr].v)) {
+               if (!h2_encode_header(&outbuf, list[hdr].n, list[hdr].v, 
H2_EV_TX_FRAME|H2_EV_TX_HDR,
+                                     ist(TRC_LOC), __FUNCTION__, h2c, h2s)) {
                        /* output full */
                        if (b_space_wraps(mbuf))
                                goto realign_again;
@@ -5401,6 +5517,8 @@
                goto full;
        }
 
+       h2_trace_header(ist(":method"), meth, H2_EV_TX_FRAME|H2_EV_TX_HDR, 
ist(TRC_LOC), __FUNCTION__, h2c, h2s);
+
        auth = ist(NULL);
 
        /* RFC7540 #8.3: the CONNECT method must have :
@@ -5414,12 +5532,14 @@
        if (unlikely(sl->info.req.meth == HTTP_METH_CONNECT) && 
!extended_connect) {
                auth = uri;
 
-               if (!hpack_encode_header(&outbuf, ist(":authority"), auth)) {
+               if (!h2_encode_header(&outbuf, ist(":authority"), auth, 
H2_EV_TX_FRAME|H2_EV_TX_HDR,
+                                     ist(TRC_LOC), __FUNCTION__, h2c, h2s)) {
                        /* output full */
                        if (b_space_wraps(mbuf))
                                goto realign_again;
                        goto full;
                }
+
                h2s->flags |= H2_SF_BODY_TUNNEL;
        } else {
                /* other methods need a :scheme. If an authority is known from
@@ -5479,7 +5599,9 @@
                        goto full;
                }
 
-               if (auth.len && !hpack_encode_header(&outbuf, 
ist(":authority"), auth)) {
+               if (auth.len &&
+                   !h2_encode_header(&outbuf, ist(":authority"), auth, 
H2_EV_TX_FRAME|H2_EV_TX_HDR,
+                                     ist(TRC_LOC), __FUNCTION__, h2c, h2s)) {
                        /* output full */
                        if (b_space_wraps(mbuf))
                                goto realign_again;
@@ -5503,15 +5625,16 @@
                        goto full;
                }
 
+               h2_trace_header(ist(":path"), uri, H2_EV_TX_FRAME|H2_EV_TX_HDR, 
ist(TRC_LOC), __FUNCTION__, h2c, h2s);
+
                /* encode the pseudo-header protocol from rfc8441 if using
                 * Extended CONNECT method.
                 */
                if (unlikely(extended_connect)) {
                        const struct ist protocol = ist(h2s->upgrade_protocol);
                        if (isttest(protocol)) {
-                               if (!hpack_encode_header(&outbuf,
-                                                        ist(":protocol"),
-                                                        protocol)) {
+                               if (!h2_encode_header(&outbuf, 
ist(":protocol"), protocol, H2_EV_TX_FRAME|H2_EV_TX_HDR,
+                                                     ist(TRC_LOC), 
__FUNCTION__, h2c, h2s)) {
                                        /* output full */
                                        if (b_space_wraps(mbuf))
                                                goto realign_again;
@@ -5554,7 +5677,7 @@
                if (isteq(n, ist("")))
                        break; // end
 
-               if (!hpack_encode_header(&outbuf, n, v)) {
+               if (!h2_encode_header(&outbuf, n, v, 
H2_EV_TX_FRAME|H2_EV_TX_HDR, ist(TRC_LOC), __FUNCTION__, h2c, h2s)) {
                        /* output full */
                        if (b_space_wraps(mbuf))
                                goto realign_again;
@@ -6102,7 +6225,8 @@
                if (*(list[idx].n.ptr) == ':')
                        continue;
 
-               if (!hpack_encode_header(&outbuf, list[idx].n, list[idx].v)) {
+               if (!h2_encode_header(&outbuf, list[idx].n, list[idx].v, 
H2_EV_TX_FRAME|H2_EV_TX_HDR,
+                                     ist(TRC_LOC), __FUNCTION__, h2c, h2s)) {
                        /* output full */
                        if (b_space_wraps(mbuf))
                                goto realign_again;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/mux_pt.c 
new/haproxy-2.7.5+git0.8d230219e/src/mux_pt.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/mux_pt.c       2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/mux_pt.c       2023-03-17 
17:35:40.000000000 +0100
@@ -557,6 +557,8 @@
                b_del(buf, ret);
 
        if (conn->flags & CO_FL_ERROR) {
+               if (conn_xprt_read0_pending(conn))
+                       se_fl_set(ctx->sd, SE_FL_EOS);
                se_fl_set_error(ctx->sd);
                TRACE_DEVEL("error on connection", 
PT_EV_TX_DATA|PT_EV_CONN_ERR, conn, sc);
        }
@@ -625,6 +627,8 @@
        ret = conn->xprt->snd_pipe(conn, conn->xprt_ctx, pipe);
 
        if (conn->flags & CO_FL_ERROR) {
+               if (conn_xprt_read0_pending(conn))
+                       se_fl_set(ctx->sd, SE_FL_EOS);
                se_fl_set_error(ctx->sd);
                TRACE_DEVEL("error on connection", 
PT_EV_TX_DATA|PT_EV_CONN_ERR, conn, sc);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/proto_uxdg.c 
new/haproxy-2.7.5+git0.8d230219e/src/proto_uxdg.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/proto_uxdg.c   2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/proto_uxdg.c   2023-03-17 
17:35:40.000000000 +0100
@@ -95,6 +95,7 @@
 
        if (!(listener->rx.flags & RX_F_BOUND)) {
                msg = "receiving socket not bound";
+               err |= ERR_FATAL | ERR_ALERT;
                goto uxdg_return;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/proto_uxst.c 
new/haproxy-2.7.5+git0.8d230219e/src/proto_uxst.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/proto_uxst.c   2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/proto_uxst.c   2023-03-17 
17:35:40.000000000 +0100
@@ -119,6 +119,7 @@
 
        if (!(listener->rx.flags & RX_F_BOUND)) {
                msg = "receiving socket not bound";
+               err |= ERR_FATAL | ERR_ALERT;
                goto uxst_return;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/protocol.c 
new/haproxy-2.7.5+git0.8d230219e/src/protocol.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/protocol.c     2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/protocol.c     2023-03-17 
17:35:40.000000000 +0100
@@ -99,8 +99,10 @@
                                        ha_warning("Binding [%s:%d] for %s %s: 
%s\n",
                                                   listener->bind_conf->file, 
listener->bind_conf->line,
                                                   proxy_type_str(px), px->id, 
errmsg);
-                               ha_free(&errmsg);
                        }
+                       if (lerr != ERR_NONE)
+                               ha_free(&errmsg);
+
                        if (lerr & ERR_ABORT)
                                break;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/proxy.c 
new/haproxy-2.7.5+git0.8d230219e/src/proxy.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/proxy.c        2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/proxy.c        2023-03-17 
17:35:40.000000000 +0100
@@ -2200,6 +2200,7 @@
 /* perform the soft-stop right now (i.e. unbind listeners) */
 static void do_soft_stop_now()
 {
+       struct proxy *p;
        struct task *task;
 
        /* disable busy polling to avoid cpu eating for the new process */
@@ -2229,6 +2230,15 @@
 
        thread_release();
 
+       /* Loop on proxies to stop backends */
+       p = proxies_list;
+       while (p) {
+               HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
+               proxy_cond_disable(p);
+               HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
+               p = p->next;
+       }
+
        /* signal zero is used to broadcast the "stopping" event */
        signal_handler(0);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/qpack-dec.c 
new/haproxy-2.7.5+git0.8d230219e/src/qpack-dec.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/qpack-dec.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/qpack-dec.c    2023-03-17 
17:35:40.000000000 +0100
@@ -335,7 +335,7 @@
                                goto out;
                        }
 
-                       if (static_tbl) {
+                       if (static_tbl && index < QPACK_SHT_SIZE) {
                                name = qpack_sht[index].n;
                                value = qpack_sht[index].v;
                        }
@@ -370,7 +370,7 @@
                                goto out;
                        }
 
-                       if (static_tbl) {
+                       if (static_tbl && index < QPACK_SHT_SIZE) {
                                name = qpack_sht[index].n;
                        }
                        else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/quic_conn.c 
new/haproxy-2.7.5+git0.8d230219e/src/quic_conn.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/quic_conn.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/quic_conn.c    2023-03-17 
17:35:40.000000000 +0100
@@ -1897,7 +1897,9 @@
                                continue;
                        }
                        else if (strm_frm->offset.key < 
stream_desc->ack_offset) {
-                               strm_frm->offset.key = stream_desc->ack_offset;
+                               uint64_t diff = stream_desc->ack_offset - 
strm_frm->offset.key;
+
+                               qc_stream_frm_mv_fwd(strm_frm, diff);
                                TRACE_DEVEL("updated partially acked frame",
                                            QUIC_EV_CONN_PRSAFRM, qc, frm);
                        }
@@ -2552,7 +2554,9 @@
                                continue;
                        }
                        else if (strm_frm->offset.key < 
stream_desc->ack_offset) {
-                               strm_frm->offset.key = stream_desc->ack_offset;
+                               uint64_t diff = stream_desc->ack_offset - 
strm_frm->offset.key;
+
+                               qc_stream_frm_mv_fwd(strm_frm, diff);
                                TRACE_DEVEL("updated partially acked frame",
                                            QUIC_EV_CONN_PRSAFRM, qc, frm);
                        }
@@ -7287,7 +7291,9 @@
                                        continue;
                                }
                                else if (strm->offset.key < 
stream_desc->ack_offset) {
-                                       strm->offset.key = 
stream_desc->ack_offset;
+                                       uint64_t diff = stream_desc->ack_offset 
- strm->offset.key;
+
+                                       qc_stream_frm_mv_fwd(strm, diff);
                                        TRACE_DEVEL("updated partially acked 
frame",
                                                    QUIC_EV_CONN_PRSAFRM, qc, 
cf);
                                }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/resolvers.c 
new/haproxy-2.7.5+git0.8d230219e/src/resolvers.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/resolvers.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/resolvers.c    2023-03-17 
17:35:40.000000000 +0100
@@ -2394,6 +2394,48 @@
 
        /* Handle all resolutions in the wait list */
        list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, 
list) {
+
+               if (unlikely(stopping)) {
+                       /* If haproxy is stopping, check if the resolution to 
know if it must be run or not.
+                        * If at least a requester is a stream (because of a 
do-resolv action) or if there
+                        * is a requester attached to a running proxy, the 
resolution is performed.
+                        * Otherwise, it is skipped for now.
+                        */
+                       struct resolv_requester *req;
+                       int must_run = 0;
+
+                       list_for_each_entry(req, &res->requesters, list) {
+                               struct proxy *px = NULL;
+
+                               switch (obj_type(req->owner)) {
+                                       case OBJ_TYPE_SERVER:
+                                               px = 
__objt_server(req->owner)->proxy;
+                                               break;
+                                       case OBJ_TYPE_SRVRQ:
+                                               px = 
__objt_resolv_srvrq(req->owner)->proxy;
+                                               break;
+                                       case OBJ_TYPE_STREAM:
+                                               /* Always perform the 
resolution */
+                                               must_run = 1;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               /* Perform the resolution if the proxy is not 
stopped or disabled */
+                               if (px && !(px->flags & 
(PR_FL_DISABLED|PR_FL_STOPPED)))
+                                       must_run = 1;
+
+                               if (must_run)
+                                       break;
+                       }
+
+                       if (!must_run) {
+                               /* Skip the reolsution. reset it and wait for 
the next wakeup */
+                               resolv_reset_resolution(res);
+                               continue;
+                       }
+               }
+
                if (LIST_ISEMPTY(&res->requesters)) {
                        abort_resolution(res);
                        continue;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/server.c 
new/haproxy-2.7.5+git0.8d230219e/src/server.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/server.c       2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/server.c       2023-03-17 
17:35:40.000000000 +0100
@@ -5729,7 +5729,6 @@
 
                hash_node = ebmb_entry(node, struct conn_hash_node, node);
                eb_delete(node);
-               hash_node->conn->flags &= ~CO_FL_LIST_MASK;
                MT_LIST_APPEND(toremove_list, &hash_node->conn->toremove_list);
                i++;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/sock_inet.c 
new/haproxy-2.7.5+git0.8d230219e/src/sock_inet.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/sock_inet.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/sock_inet.c    2023-03-17 
17:35:40.000000000 +0100
@@ -312,6 +312,24 @@
                }
        }
 
+       if (ext && fd < global.maxsock && fdtab[fd].owner) {
+               /* This FD was already bound so this means that it was already
+                * known and registered before parsing, hence it's an inherited
+                * FD. The only reason why it's already known here is that it
+                * has been registered multiple times (multiple listeners on the
+                * same, or a "shards" directive on the line). There cannot be
+                * multiple listeners on one FD but at least we can create a
+                * new one from the original one. We won't reconfigure it,
+                * however, as this was already done for the first one.
+                */
+               fd = dup(fd);
+               if (fd == -1) {
+                       err |= ERR_RETRYABLE | ERR_ALERT;
+                       memprintf(errmsg, "cannot dup() receiving socket (%s)", 
strerror(errno));
+                       goto bind_return;
+               }
+       }
+
        if (fd >= global.maxsock) {
                err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
                memprintf(errmsg, "not enough free sockets (raise '-n' 
parameter)");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/sock_unix.c 
new/haproxy-2.7.5+git0.8d230219e/src/sock_unix.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/sock_unix.c    2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/sock_unix.c    2023-03-17 
17:35:40.000000000 +0100
@@ -93,7 +93,21 @@
 
        /* Now we have a difference. It's OK if they are within or after a
         * sequence of digits following a dot, and are followed by ".tmp".
+        *
+        * make sure to perform the check against tempname if the compared
+        * string is in "final" format (does not end with ".XXXX.tmp").
+        *
+        * Examples:
+        *     /tmp/test matches with /tmp/test.1822.tmp
+        *     /tmp/test.1822.tmp matches with /tmp/test.XXXX.tmp
         */
+       if (au->sun_path[idx] == 0 || bu->sun_path[idx] == 0) {
+               if (au->sun_path[idx] == '.' || bu->sun_path[idx] == '.')
+                       dot = idx; /* try to match against temp path */
+               else
+                       return -1; /* invalid temp path */
+       }
+
        if (!dot)
                return -1;
 
@@ -226,6 +240,24 @@
        }
 
  fd_ready:
+       if (ext && fd < global.maxsock && fdtab[fd].owner) {
+               /* This FD was already bound so this means that it was already
+                * known and registered before parsing, hence it's an inherited
+                * FD. The only reason why it's already known here is that it
+                * has been registered multiple times (multiple listeners on the
+                * same, or a "shards" directive on the line). There cannot be
+                * multiple listeners on one FD but at least we can create a
+                * new one from the original one. We won't reconfigure it,
+                * however, as this was already done for the first one.
+                */
+               fd = dup(fd);
+               if (fd == -1) {
+                       err |= ERR_RETRYABLE | ERR_ALERT;
+                       memprintf(errmsg, "cannot dup() receiving socket (%s)", 
strerror(errno));
+                       goto bind_return;
+               }
+       }
+
        if (fd >= global.maxsock) {
                err |= ERR_FATAL | ERR_ABORT | ERR_ALERT;
                memprintf(errmsg, "not enough free sockets (raise '-n' 
parameter)");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/ssl_sock.c 
new/haproxy-2.7.5+git0.8d230219e/src/ssl_sock.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/ssl_sock.c     2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/ssl_sock.c     2023-03-17 
17:35:40.000000000 +0100
@@ -6499,7 +6499,7 @@
                        return NULL;
                }
                conn = ctx->conn;
-               conn_in_list = conn->flags & CO_FL_LIST_MASK;
+               conn_in_list = conn_get_idle_flag(conn);
                if (conn_in_list)
                        conn_delete_from_tree(&conn->hash_node->node);
                HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, 
&idle_conns[tid].idle_conns_lock);
@@ -7300,7 +7300,7 @@
                chunk_appendf(&trash, " xctx.conn=%p(BOGUS)", sctx->conn);
                ret = 1;
        }
-       chunk_appendf(&trash, " xctx.st=%d", sctx->xprt_st);
+       chunk_appendf(&trash, " xctx.st=%d .err=%ld", sctx->xprt_st, 
sctx->error_code);
 
        if (sctx->xprt) {
                chunk_appendf(&trash, " .xprt=%s", sctx->xprt->name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.7.4+git0.d28541d1f/src/tcp_sample.c 
new/haproxy-2.7.5+git0.8d230219e/src/tcp_sample.c
--- old/haproxy-2.7.4+git0.d28541d1f/src/tcp_sample.c   2023-03-10 
16:29:03.000000000 +0100
+++ new/haproxy-2.7.5+git0.8d230219e/src/tcp_sample.c   2023-03-17 
17:35:40.000000000 +0100
@@ -176,7 +176,7 @@
        if (kw[0] == 'f') { /* fc_dst_is_local */
                struct connection *conn = objt_conn(smp->sess->origin);
 
-               if (conn && conn_get_src(conn))
+               if (conn && conn_get_dst(conn))
                        dst = conn_dst(conn);
        }
        else /* dst_is_local */
@@ -232,10 +232,10 @@
                if (conn && conn_get_dst(conn))
                        dst = conn_dst(conn);
        }
-       else if (kw[0] == 'f') { /* fc_dst_post */
+       else if (kw[0] == 'f') { /* fc_dst_port */
                struct connection *conn = objt_conn(smp->sess->origin);
 
-               if (conn && conn_get_src(conn))
+               if (conn && conn_get_dst(conn))
                        dst = conn_dst(conn);
        }
         else /* dst_port */

Reply via email to