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 */